diff --git a/.circleci/config.yml b/.circleci/config.yml index bb84cd73d..dc801cd2c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,27 @@ version: 2.1 orbs: - prodsec: snyk/prodsec-orb@1.0 + prodsec: snyk/prodsec-orb@1 + +commands: + install: + steps: + - run: + name: Install + command: npm ci + +jobs: + security-scans: + resource_class: small + docker: + - image: cimg/node:lts + steps: + - checkout + - install + - prodsec/security_scans: + mode: auto + open-source-additional-arguments: --exclude=mocked_data + iac-scan: disabled workflows: version: 2 @@ -11,4 +31,11 @@ workflows: name: Scan repository for secrets context: - snyk-bot-slack - channel: hammerhead-alerts + channel: snyk-on-snyk-devex_ide + filters: + branches: + ignore: + - main + + - security-scans: + context: devex_ide \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index 8f3ffe67a..df06bf6e1 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -53,6 +53,9 @@ "no-continue": "off", "@typescript-eslint/restrict-template-expressions": "off", "@typescript-eslint/no-unsafe-assignment": "warn", + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-redundant-type-constituents": "warn", + "@typescript-eslint/no-unsafe-enum-comparison": "warn", "import/no-extraneous-dependencies": "off", "no-useless-constructor": "off", "@typescript-eslint/no-useless-constructor": ["error"], diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2861b275a..41a2652e0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1 @@ -* @snyk/hammerhead -src/snyk/common/services/learnService.ts @snyk/owl -src/test/unit/common/services/learnService.test.ts @snyk/owl -src/snyk/snykCode/codeSettings.ts @snyk/hammerhead @snyk/zenith @snyk/nebula -src/test/unit/snykCode/codeSettings.test.ts @snyk/hammerhead @snyk/zenith @snyk/nebula +* @snyk/ide diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5fc5678d7..3743a1357 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -2,11 +2,9 @@ name: CI on: pull_request: branches: - - main + - 'main' workflow_call: - secrets: - ITERATIVELY_KEY: - required: true + jobs: build: name: Build and Test @@ -21,7 +19,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v2 with: - node-version: '14' + node-version: '18' - name: Cache NPM files uses: actions/cache@v2 @@ -42,3 +40,14 @@ jobs: - name: Run unit tests run: npm run test:unit + + - name: Run integration tests + run: | + sudo apt-get install xvfb + xvfb-run --auto-servernum npm run test:integration + if: runner.os == 'Linux' + - name: Run integration tests + run: npm run test:integration + if: runner.os != 'Linux' + + diff --git a/.github/workflows/readme-sync.yaml b/.github/workflows/readme-sync.yaml index c342ab38c..2a2a9d1cb 100644 --- a/.github/workflows/readme-sync.yaml +++ b/.github/workflows/readme-sync.yaml @@ -52,7 +52,7 @@ jobs: echo "No documentation changes detected, exiting." fi env: - SOURCE_PATH: ./docs/docs/integrations/ide-tools/visual-studio-code-extension/README.md + SOURCE_PATH: ./docs/docs/scm-ide-and-ci-cd-integrations/snyk-ide-plugins-and-extensions/visual-studio-code-extension/README.md FILE_TO_COMMIT: README.md DESTINATION_REPOSITORY: vscode-extension DESTINATION_BRANCH: docs/automatic-gitbook-update diff --git a/.github/workflows/release-preview.yaml b/.github/workflows/release-preview.yaml index fa7ad1a51..00f12ef43 100644 --- a/.github/workflows/release-preview.yaml +++ b/.github/workflows/release-preview.yaml @@ -2,14 +2,11 @@ name: Build and Release "Preview" on: push: branches: - # TODO: revert back to main once this feature is released - - feat/HEAD-78_oss_via_ls + - main jobs: build: uses: snyk/vscode-extension/.github/workflows/ci.yaml@main - secrets: - ITERATIVELY_KEY: ${{ secrets.ITERATIVELY_KEY }} - + release-preview: name: Release Preview runs-on: ubuntu-latest @@ -25,13 +22,10 @@ jobs: - name: Install dependencies run: npm ci - - name: Verify analytics events - run: npm run ampli:verify -- -t ${{ secrets.ITERATIVELY_KEY }} - + # Naming convention for the preview version means we can only release one preview per hour - name: Patch to preview version run: npm run patch-preview env: - SNYK_VSCE_SEGMENT_WRITE_KEY: ${{ secrets.SNYK_VSCE_SEGMENT_WRITE_KEY }} SNYK_VSCE_AMPLITUDE_EXPERIMENT_API_KEY: ${{ secrets.SNYK_VSCE_AMPLITUDE_EXPERIMENT_API_KEY }} SNYK_VSCE_SENTRY_DSN_KEY: ${{ secrets.SNYK_VSCE_SENTRY_DSN_KEY }} diff --git a/.github/workflows/release-stable.yaml b/.github/workflows/release-stable.yaml index d6ae0d4fd..521f479aa 100644 --- a/.github/workflows/release-stable.yaml +++ b/.github/workflows/release-stable.yaml @@ -2,14 +2,14 @@ name: Build and Release on: workflow_dispatch: - schedule: - - cron: '0 9 * * 2' # every Tuesday at 9 am UTC + branches: + - main + # schedule: TODO: align release schedule with CLI + # - cron: '0 9 * * 2' # every Tuesday at 9 am UTC jobs: build: uses: snyk/vscode-extension/.github/workflows/ci.yaml@main - secrets: - ITERATIVELY_KEY: ${{ secrets.ITERATIVELY_KEY }} publish: runs-on: ubuntu-latest @@ -29,21 +29,17 @@ jobs: - name: Install dependencies run: npm ci - - name: Verify analytics events - run: npm run ampli:verify -- -t ${{ secrets.ITERATIVELY_KEY }} - - name: Bump patch version id: patched-tag uses: mathieudutour/github-tag-action@v6.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} - release_branches: main + release_branches: main,fix.*,chore.* default_bump: patch - name: Add Credentials run: | sed -i \ - -e 's|${env.SNYK_VSCE_SEGMENT_WRITE_KEY}|${{ secrets.SNYK_VSCE_SEGMENT_WRITE_KEY }}|g' \ -e 's|${env.SNYK_VSCE_AMPLITUDE_EXPERIMENT_API_KEY}|${{ secrets.SNYK_VSCE_AMPLITUDE_EXPERIMENT_API_KEY }}|g' \ -e 's|${env.SNYK_VSCE_SENTRY_DSN_KEY}|${{ secrets.SNYK_VSCE_SENTRY_DSN_KEY }}|g' \ snyk.config.json @@ -67,7 +63,14 @@ jobs: run: npm ci - name: Package VSIX - run: echo y | vsce package --no-git-tag-version --no-update-package-json ${{ needs.publish.outputs.new-version }} + run: | + run: | + sed -i \ + -e 's|${env.SNYK_VSCE_AMPLITUDE_EXPERIMENT_API_KEY}|${{ secrets.SNYK_VSCE_AMPLITUDE_EXPERIMENT_API_KEY }}|g' \ + -e 's|${env.SNYK_VSCE_SENTRY_DSN_KEY}|${{ secrets.SNYK_VSCE_SENTRY_DSN_KEY }}|g' \ + snyk.config.json + + echo y | vsce package --no-git-tag-version --no-update-package-json ${{ needs.publish.outputs.new-version }} - name: Extract release notes id: extract-release-notes diff --git a/.gitignore b/.gitignore index 8df088185..ee0dab6e3 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ yarn-error.log ################################# .idea/ *.iml +.vscode/ ################################# # Logs and temp files # diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..df5f0bcd6 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18.19 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..de056073a --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +**/*.md diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index f349f8625..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,21 +0,0 @@ -// Place your settings in this file to overwrite default and user settings. -{ - "files.exclude": { - "out": false, // set this to true to hide the "out" folder with the compiled JS files - "media/**/*.css": true // exclude css to prevent from editing CSS instead of SASS accidentally - }, - "search.exclude": { - "out": true, // set this to false to include "out" folder in search results - "media/**/*.css": true // exclude css to prevent from editing CSS instead of SASS accidentally - }, - // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off", - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.organizeImports": true - }, - "[scss]": { - "editor.defaultFormatter": "michelemelluso.code-beautifier" - } -} diff --git a/CHANGELOG.md b/CHANGELOG.md index e893b4352..2e1100a3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,193 @@ -# Snyk Security - Code and Open Source Dependencies Changelog +# Snyk Security Changelog + +## [2.20.0] +- reduce hover verbosity to only title and description +- If $/snyk.hasAuthenticated transmits an API URL, this is saved in the settings. +- Added CLI release channel. +- Added option to change base URL to download CLI. +- Run Snyk language Server from the CLI extension. +- Change default CLI download path to be in extension directory. +- Delete sentry reporting. +- send analytics event "plugin installed" the first time the extension is started + +## [2.19.2] +- Update download endpoint to downloads.snyk.io. +- Send correct FixId to AI Fix endpoint. +- Hide AI Fix div if no fixes found. + +## [2.19.1] +- Adjust OSS panel font size + +## [2.19.0] +- Moved delta scan preview setting to settings page. +- New error message in UI when net new scan is done on an invalid repository. Net new scans only work on Git. +- Clear in Memory cache when branch is changed. +- Added Clear Persisted Cache command. +- Add support for ai fix feedback analytic when pressing apply on a fix. + +## [2.18.2] +- Update Language Server Protocol version to 15. + +## [2.18.0] +- Added base branch selection for IaC and OSS + +## [2.17.0] +- render IaC via Language Server + +## [2.16.3] +- fix readability of `code` elements within the **overview** section when using high-contrast themes (both dark and light). Text color now matches the background. + +## [2.16.2] +- updated the language server protocol version to 14 to support new communication model. + +## [2.16.1] +- updated the language server protocol version to 13 to support delta findings. +- added setting for choosing authentication method +- renamed vulnerabilities to issues +- only display DeepCode AI fix tree node when issues were found + +## [2.16.0] +- Reorganize settings page into categorized sections: + - General Settings + - Product Selection + - Severity Selection + - Project Settings + - Executable Settings + - User Experience + - Advanced + +## [2.15.0] +- Sync with LS to retrieve and persist folderConfigs changes. +- Add command to select the base branch. + +## [2.14.0] +- Add UI components for selecting a base branch for delta findings for Code and Code Quality behind a feature flag. + +### [2.13.1] +- Refactor the Suggestion Panel for OSS so it's more secure and will be supported in other IDEs + +## [2.13.0] +- Fix `.suggestion` class to ensure it is scrollable and not overlapped by the `.suggestion-actions` fixed element. This change prevents the suggestion content from being hidden. +- transmit required protocol version to language server +- Remove unused stylesheet and refactor stylesheets + +## [2.12.3] +- Fix a bug in AI Applyfix on Windows. +- Changes some of the colours used in the HTML panel so it's consistent with designs. + +## [2.12.2] +- Refactors the feature flag logic into its own service. +- Fix multi-file links in the DataFlow HTML panel. + +## [2.12.1] +- Fix applying AI fixes on Windows. +- Add CSS rules for `.light-only` and `.dark-only` to the LSP implementation. This allows the LSP to apply different styles based on the current theme. +- Update to LS protocol version 12. + +## [2.12.0] +- Fix Code Suggestion rendering issue on Windows. +- Renders the AI Fix panel and adds more custom styling for VSCode. +- Adds position line interaction. + +## [2.11.0] +- Add warning messages in the Tree View for the issue view options used in consistent ignores. +- Add Data Flow and Ignore Footer intractions for Consistent Ignores flows. +- Fix endpoint computation based on custom endpoint. +- Remove snyk/codeclient dependancy. + +## [2.10.0] +- Injects custom styling for the HTML panel used by Snyk Code for consistent ignores. + +## [2.9.0] +- Lower the strictness of custom endpoint regex validation so that single tenant APIs are allowed. + +## [2.8.0] +- Add the Issue View Options panel to the Snyk Security Settings. + +## [2.7.0] +- Fetch Snyk Consistent Ignores feature flag from the Language Server +- Conditionally render Code details panel from Language Server + +## [2.6.1] +- Improve the validation of the custom endpoint and change the default to https://api.snyk.io. + +## [2.6.0] +- Improve UX of AI fixes by adding previews and options + +## [2.4.1] +- updated the language server protocol version to 11 to support global ignores + +## [2.4.0] +- Added the [ Ignored ] text if the finding should be marked as ignored. + +## [2.3.10] +### Added +- Added the [ Ignored ] text if the finding should be marked as ignored. + +## [2.3.9] +### Fixes +- do not restrict activation of extension (auto-scan on startup) + +## [2.3.8] + +### Fixes +- fix: shortened plugin name to just Snyk Security + +## [2.3.6] + +### Changes +- Removed Amplitude telemetry and corresponding setting from VSCode + +## [2.3.5] + +### Documentation + +- Updated the `README.md` file to correct and improve the links to the Visual Studio Code extension documentation. + +## [2.3.4] + +### Fixes + +- Changing the custom endpoints has an effect on whether we sent Amplitude events or not + +## [2.3.3] + +### Fixed + +- Snyk Code: Added `isExampleLineEncoded` boolean flag to `CommitChangeLine` type to prevent re-encoding strings in the UI of the example code blocks. + +## [2.3.2] + +### Fixed + +- Only send Amplitude events when connected to a MT US environment + +## [2.2.1] + +### Fixed + +- Snyk Code: Optimized performance by caching DOM element references in `suggestion-details`. This minimizes repetitive DOM queries, enhancing the responsiveness and efficiency of the webview. +- Snyk Code: Corrected the visibility toggling behavior in the `#suggestion-details` section. Replaced inline styling with CSS class-based approach. + +## [2.2.0] + +### Added + +- Snyk Code: New UI section `#suggestion-details` for displaying suggestion details in snykCode. +- Snyk Code: Added a collapsible section for suggestion details. This includes a 'Read more' button to toggle the full display of suggestion details. + +## [2.1.0] + +### Added + +- Snyk LS: Snyk Open Source Security features now use Language Server backend +- Snyk OSS: Squiggly warning underlines for direct and transitive vulnerabilities +- Snyk OSS: Squiggly underlines colour coded based on severity +- Snyk OSS: Vulnerability count text includes transitive vulnerabilities +- Snyk OSS: Vulnerability count text includes breakdown of vulnerabilities by severity +- Snyk OSS: Hovers lists vulnerabilities and shows summary (without typo) +- Snyk OSS: Hovers show information from security.snyk.io/vuln database +- Snyk OSS: CodeActions shows actions available for all vulnerabilities ## [1.26.1] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 16faa4f5f..382ef7b3b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ ## Run extension and debug -Clone the repository, then run `npm install` in the directory. +Clone the repository, then run `npm install && npm run build` in the directory. - Open repository directory in VS Code and press `F5` to run extension in a new VS Code window. - This allows extension debugging within VS Code. @@ -25,13 +25,15 @@ Code changes require extension reload when run in debug. ## Run tests and debug - Unit tests - - Run `npm run test:unit` for a single execution, `npm run test:unit:watch` to watch for changes. - Make sure to re-run the command to pick up new files, if new `**.test.ts` is added. - Integration tests - Run `npm run test:integration`. +- Run Lint + - npm `npm run lint` + You can debug tests via VS Code debugger, selecting "Extension Unit Tests" or "Extension Integration Tests" respectively. ## Analytics, experimentation and error reporting @@ -43,8 +45,6 @@ To test for analytics, experimentation and error reporting integrations, create The code is organized in folders grouped by [feature](https://phauer.com/2020/package-by-feature/), unless it's product unrelated code. The overall layering tree loks like that: ``` -├── ampli -│ └── Amplitude CLI generated code. ├── snyk │ ├── common │ │ ├── Common code that is shared between different products. @@ -68,37 +68,3 @@ The code is organized in folders grouped by [feature](https://phauer.com/2020/pa ### Explore the VS Code API You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. - -### Usage with local package `@snyk/code-client` - -In order to test plugin with local package `@snyk/code-client` you should make the following steps. - -1. Clone package repository: - -```shell script -$ git clone https://github.com/snyk/code-client.git -``` - -2. Go to the package folder, install dependencies, build package and create symlink: - -```shell script -$ cd tsc -$ npm install -$ npm run build -$ npm link -``` - -3. Go to the extension folder and install package from local symlink: - -```shell script -$ cd vscode-extension -$ npm link @snyk/code-client -``` - -After that you can add package to your `package.json`: - -```json -"dependencies": { - "@snyk/code-client": "^2.4.1" -} -``` diff --git a/README.md b/README.md index bc959d4cb..bb4038944 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,48 @@ # Visual Studio Code extension -The Snyk Visual Studio Code plugin scans and provides analysis of your code including open source dependencies and infrastructure as code configurations. Download the plugin at any time free of charge and use it with any Snyk account. Scan your code early in the development lifecycle to help you pass security reviews and avoid costly fixes later in the development cycle. +## **Scan early, fix as you develop: elevate your security posture** -Snyk scans for vulnerabilities and returns results with security issues categorized by issue type and severity. +Integrating security checks early in your development lifecycle helps you pass security reviews seamlessly and avoid expensive fixes down the line. -For open source, you receive automated algorithm-based fix suggestions for both direct and transitive dependencies. +The Snyk Visual Studio Code extension allows you to analyze your code, open-source dependencies, and Infrastructure as Code (IaC) configurations. With actionable insights directly in your IDE, you can address issues as they arise. -Results appear in context, in line with code in your IDE. +**Key features:** -This single plugin provides a Java vulnerability scanner, a custom code vulnerability scanner, and an open-source security scanner. +* **In-line issue highlighting:** Security issues are flagged directly within your code, categorized by type and severity for quick identification and resolution. +* **Comprehensive scanning:** The extension scans for a wide range of security issues, including: + * [**Open Source Security**](https://snyk.io/product/open-source-security-management/)**:** Detects vulnerabilities and license issues in both direct and transitive open-source dependencies. Automated fix suggestions simplify remediation. Explore more in the [Snyk Open Source documentation](https://docs.snyk.io/scan-using-snyk/snyk-open-source). + * [**Code Security**](https://snyk.io/product/snyk-code/)**:** Identifies security vulnerabilities in your custom code. Explore more in the [Snyk Code documentation](https://docs.snyk.io/scan-using-snyk/snyk-code). + * [**IaC Security**](https://snyk.io/product/infrastructure-as-code-security/)**:** Uncovers configuration issues in your Infrastructure as Code templates (Terraform, Kubernetes, CloudFormation, Azure Resource Manager). Explore more in the [IaC documentation](https://docs.snyk.io/scan-using-snyk/snyk-iac). +* **Broad language and framework support:** Snyk Open Source and Snyk Code cover a wide array of package managers, programming languages, and frameworks, with ongoing updates to support the latest technologies. For the most up-to-date information on supported languages, package managers, and frameworks, see the [supported language technologies pages](https://docs.snyk.io/supported-languages-package-managers-and-frameworks). -In using the Visual Studio Code extension, you have the advantage of relying on the [Snyk Vulnerability Database](https://docs.snyk.io/introducing-snyk/getting-started-snyk-intel-vuln-db-access). You also have available the [Snyk Code AI Engine](https://docs.snyk.io/products/snyk-code/introducing-snyk-code/key-features/ai-engine). - -Snyk scans for the following types of issues: - -* [**Open Source Security**](https://snyk.io/product/open-source-security-management/) - security vulnerabilities and license issues in both direct and in-direct (transitive) open-source dependencies pulled into the Snyk Project.\ - See also the [Open Source docs](https://docs.snyk.io/products/snyk-open-source). -* [**Code Security and Code Quality**](https://snyk.io/product/snyk-code/) - security vulnerabilities and quality issues in your own code. See also the [Snyk Code](../../../scan-application-code/snyk-code/) docs. -* [**Infrastructure as Code (IaC) Security**](https://snyk.io/product/infrastructure-as-code-security/) - configuration issues in your IaC templates: Terraform, Kubernetes, CloudFormation, and Azure Resource Manager. See also the [IaC](https://docs.snyk.io/products/snyk-infrastructure-as-code) and [Snyk Cloud](https://docs.snyk.io/products/snyk-cloud) docs. - -This page explains installation of the Visual Studio Code extension. **After you complete the steps on this page**, you will continue by following the instructions in the other Visual studio Code extension docs: - -* [Visual Studio Code extension configuration](https://docs.snyk.io/ide-tools/visual-studio-code-extension-for-snyk-code/visual-studio-code-extension-configuration) -* [Visual Studio Code extension authentication](https://docs.snyk.io/ide-tools/visual-studio-code-extension-for-snyk-code/visual-studio-code-extension-authentication) -* [Create a .dcignore file](https://docs.snyk.io/ide-tools/visual-studio-code-extension-for-snyk-code/create-a-.dcignore-file) -* [Run an analysis with Visual Studio Code extension](https://docs.snyk.io/ide-tools/visual-studio-code-extension-for-snyk-code/run-an-analysis-with-visual-studio-code-extension) -* [View analysis results from Visual Studio Code extension](https://docs.snyk.io/ide-tools/visual-studio-code-extension-for-snyk-code/view-analysis-results-from-visual-studio-code-extension) -* [Troubleshooting for Visual Studio Code extension](https://docs.snyk.io/ide-tools/visual-studio-code-extension-for-snyk-code/troubleshooting-for-visual-studio-code-extension) - -## Supported languages, package managers, and frameworks - -Supported languages and frameworks include C#, JavaScript, TypeScript, Java, Go, Ruby, Python, Ruby, PHP, Scala, Swift, Objective-C, Kubernetes, Terraform, CloudFormation, Azure Resource Manager (ARM) - -* For Snyk Open Source, the VS Code extension supports all the languages and package managers supported by Snyk Open Source and the CLI. See the full [list in the docs](https://docs.snyk.io/products/snyk-open-source/language-and-package-manager-support). -* For Snyk Code, the VS Code extension supports all the [languages and frameworks supported by Snyk Code](https://docs.snyk.io/products/snyk-code/snyk-code-language-and-framework-support#language-support-with-snyk-code-ai-engine). - -## Supported operating systems and architecture +## How to install and set up the extension You can use the Snyk Visual Studio Code extension in the following environments: * Linux: AMD64 and ARM64 -* Windows: 386 and AMD64 -* MacOS: AMD64 and ARM64 +* Windows: 386, AMD64, and ARM64 +* macOS: AMD64 and ARM64 + +Snyk Visual Studio Code extension does not support remote and containerized environments: -## Install the extension +* [Cloud VS Code IDE](https://code.visualstudio.com/docs/editor/vscode-web) +* [VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview) +* [Inside a Container](https://code.visualstudio.com/docs/devcontainers/containers) -The Snyk Visual Studio Code extension is available for installation on the [Visual Studio code marketplace](https://marketplace.visualstudio.com/items?itemName=snyk-security.snyk-vulnerability-scanner). +Install the plugin at any time free of charge from the [Visual Studio Code marketplace](https://marketplace.visualstudio.com/items?itemName=snyk-security.snyk-vulnerability-scanner) and use it with any Snyk account, including a Free account. For more information, see the[VS Code extension installation guide](https://code.visualstudio.com/docs/editor/extension-marketplace#\_install-an-extension). -Follow these steps to install: +When the extension is installed, it automatically downloads the [Snyk CLI,](https://docs.snyk.io/snyk-cli) which includes the [Language Server](https://docs.snyk.io/scm-ide-and-ci-cd-integrations/snyk-ide-plugins-and-extensions/snyk-language-server). -* Open the settings or preferences in your IDE. -* Navigate to the [Snyk Extension on the Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=snyk-security.snyk-vulnerability-scanner) and click **Install**.\ - For more information see the [installation instructions](https://code.visualstudio.com/docs/editor/extension-marketplace#\_install-an-extension). -* Configure the Snyk CLI (downloaded when the extension in installed); see [Visual Studio Code extension configuration](https://docs.snyk.io/ide-tools/visual-studio-code-extension-for-snyk-code/visual-studio-code-extension-configuration). -* Authenticate with Snyk; see [Visual Studio Code extension authentication](https://docs.snyk.io/ide-tools/visual-studio-code-extension-for-snyk-code/visual-studio-code-extension-authentication). -* Navigate back to the IDE; the first scan starts automatically. +Continue by following the instructions in the other Visual Studio Code extension docs: + +* [Visual Studio Code extension configuration](https://docs.snyk.io/scm-ide-and-ci-cd-integrations/snyk-ide-plugins-and-extensions/visual-studio-code-extension/visual-studio-code-extension-authentication) +* [Visual Studio Code extension authentication](https://docs.snyk.io/scm-ide-and-ci-cd-integrations/snyk-ide-plugins-and-extensions/visual-studio-code-extension/visual-studio-code-extension-authentication) +* [Visual Studio Code Workspace trust](https://docs.snyk.io/scm-ide-and-ci-cd-integrations/snyk-ide-plugins-and-extensions/visual-studio-code-extension/workspace-trust) +* [Run an analysis with Visual Studio Code extension](https://docs.snyk.io/integrate-with-snyk/use-snyk-in-your-ide/visual-studio-code-extension/run-an-analysis-with-visual-studio-code-extension) +* [View analysis results from Visual Studio Code extension](https://docs.snyk.io/integrate-with-snyk/use-snyk-in-your-ide/visual-studio-code-extension/view-analysis-results-from-visual-studio-code-extension) ## Support +For troubleshooting and known issues, see [Troubleshooting for Visual Studio Code extension](https://docs.snyk.io/scm-ide-and-ci-cd-integrations/snyk-ide-plugins-and-extensions/visual-studio-code-extension/troubleshooting-for-visual-studio-code-extension). + If you need help, submit a request to [Snyk Support](https://support.snyk.io/hc/en-us/requests/new). diff --git a/catalog-info.yaml b/catalog-info.yaml index 206caefd4..682a07e00 100644 --- a/catalog-info.yaml +++ b/catalog-info.yaml @@ -4,8 +4,8 @@ metadata: name: vscode-extension annotations: github.com/project-slug: snyk/vscode-extension - github.com/team-slug: snyk/hammerhead + github.com/team-slug: snyk/ide spec: type: ide-plugin lifecycle: "-" - owner: hammerhead + owner: ide diff --git a/media/images/branch-dark.svg b/media/images/branch-dark.svg new file mode 100644 index 000000000..870771a1e --- /dev/null +++ b/media/images/branch-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/media/images/branch-light.svg b/media/images/branch-light.svg new file mode 100644 index 000000000..9ef778737 --- /dev/null +++ b/media/images/branch-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/media/images/icon-external.svg b/media/images/icon-external.svg index 59307674f..84ad7ed08 100644 --- a/media/images/icon-external.svg +++ b/media/images/icon-external.svg @@ -1,4 +1,4 @@ - - - + + + diff --git a/media/images/pencil-dark.svg b/media/images/pencil-dark.svg new file mode 100644 index 000000000..f682f5453 --- /dev/null +++ b/media/images/pencil-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/media/images/pencil-light.svg b/media/images/pencil-light.svg new file mode 100644 index 000000000..7af23297f --- /dev/null +++ b/media/images/pencil-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/media/views/common/learn.scss b/media/views/common/learn.scss deleted file mode 100644 index 16ff34e50..000000000 --- a/media/views/common/learn.scss +++ /dev/null @@ -1,25 +0,0 @@ -.learn { - opacity: 0; - height: 0; - margin-top: 0; - color: var(--vscode-textLink-foreground); - font-size: 1.3rem; - - &.show { - margin-top: 6px; - opacity: 1; - height: auto; - transition-duration: 500ms; - transition-property: height, opacity, margin-top; - } - - &--link { - margin-left: 3px; - } - - &__code { - .learn--link { - color: var(--vscode-textLink-foreground); - } - } -} diff --git a/media/views/common/suggestionHeader.scss b/media/views/common/suggestionHeader.scss deleted file mode 100644 index 3cdcbee95..000000000 --- a/media/views/common/suggestionHeader.scss +++ /dev/null @@ -1,48 +0,0 @@ -.suggestion { - position: relative; - display: flex; - flex-direction: column; - width: 100%; - height: 100%; -} - -.suggestion .suggestion-text { - padding: 0.4rem 0; - margin-bottom: 0.8rem; - font-size: 1.8rem; - font-weight: 500; - line-height: 2.4rem; -} - -.severity { - display: flex; - flex-direction: column; - flex-grow: 0; - float: left; - margin: 0 1rem 0 0; - text-align: center; -} - -.severity .icon { - width: 32px; - height: 32px; -} - -.icon { - vertical-align: middle; - width: 16px; - height: 16px; -} - -.identifiers { - font-size: 1.3rem; - line-height: 2rem; -} - -.vscode-dark .light-only { - display: none; -} - -.vscode-light .dark-only { - display: none; -} diff --git a/media/views/common/variables.scss b/media/views/common/variables.scss deleted file mode 100644 index 2ca88154b..000000000 --- a/media/views/common/variables.scss +++ /dev/null @@ -1,2 +0,0 @@ -$editor-background-color: rgba(0, 0, 0, 0.15); -$editor-font-color: #ccc; diff --git a/media/views/common/vscode.scss b/media/views/common/vscode.scss deleted file mode 100644 index f8a4ba86c..000000000 --- a/media/views/common/vscode.scss +++ /dev/null @@ -1,96 +0,0 @@ -/* - VS Code styles to reuse native views look and feel. Copied from: - https://github.com/microsoft/vscode-extension-samples/blob/main/webview-view-sample/media/vscode.css -*/ - -:root { - --container-paddding: 20px; - --input-padding-vertical: 6px; - --input-padding-horizontal: 4px; - --input-margin-vertical: 4px; - --input-margin-horizontal: 0; -} - -body { - padding: 0 var(--container-paddding); - color: var(--vscode-foreground); - font-size: var(--vscode-font-size); - font-weight: var(--vscode-font-weight); - font-family: var(--vscode-font-family); - background-color: var(--vscode-editor-background); -} - -ol, -ul { - padding-left: var(--container-paddding); -} - -body > *, -form > * { - margin-block-start: var(--input-margin-vertical); - margin-block-end: var(--input-margin-vertical); -} - -*:focus { - outline-color: var(--vscode-focusBorder) !important; -} - -a { - color: var(--vscode-textLink-foreground); -} - -a:hover, -a:active { - color: var(--vscode-textLink-activeForeground); -} - -code { - font-size: var(--vscode-editor-font-size); - font-family: var(--vscode-editor-font-family); -} - -button { - border: none; - padding: var(--input-padding-vertical) var(--input-padding-horizontal); - width: 100%; - text-align: center; - outline: 1px solid transparent; - outline-offset: 2px !important; - color: var(--vscode-button-foreground); - background: var(--vscode-button-background); -} - -button:hover { - cursor: pointer; - background: var(--vscode-button-hoverBackground); -} - -button:focus { - outline-color: var(--vscode-focusBorder); -} - -button.secondary { - color: var(--vscode-button-secondaryForeground); - background: var(--vscode-button-secondaryBackground); -} - -button.secondary:hover { - background: var(--vscode-button-secondaryHoverBackground); -} - -input:not([type='checkbox']), -textarea { - display: block; - width: 100%; - border: none; - font-family: var(--vscode-font-family); - padding: var(--input-padding-vertical) var(--input-padding-horizontal); - color: var(--vscode-input-foreground); - outline-color: var(--vscode-input-border); - background-color: var(--vscode-input-background); -} - -input::placeholder, -textarea::placeholder { - color: var(--vscode-input-placeholderForeground); -} diff --git a/media/views/common/webview.scss b/media/views/common/webview.scss index 51b6dcb11..336d22eec 100644 --- a/media/views/common/webview.scss +++ b/media/views/common/webview.scss @@ -1,10 +1,8 @@ html { height: 100%; - font-size: 62.5%; } body { - padding: 0; line-height: 1.5; } @@ -12,34 +10,6 @@ body * { box-sizing: border-box; } -h2, h3 { - font-size: 1.1rem; - margin-block-start: 0; - margin-block-end: 0.4rem; - font-weight: 700; - text-transform: uppercase; -} - -a { - cursor: pointer; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -table { - width: 100%; - border-collapse: collapse; -} - -table td { - background: var(--vscode-editor-background); - border: 1px solid var(--vscode-button-border); - padding: 3px; -} - .font-light { opacity: 0.75; } @@ -69,10 +39,6 @@ table td { border-top: 1px solid rgba(255, 255, 255, 0.075); } -section { - padding: 20px; -} - .hidden { display: none !important; } diff --git a/media/views/featureSelection/featureSelection.scss b/media/views/featureSelection/featureSelection.scss deleted file mode 100644 index cc4cef76f..000000000 --- a/media/views/featureSelection/featureSelection.scss +++ /dev/null @@ -1,19 +0,0 @@ -body { - background-color: transparent; -} - -.welcome { - text-align: center; -} - -.avatar { - width: 62px; -} - -.checkbox { - display: block; -} - -button { - margin-block-start: 1em; -} diff --git a/media/views/oss/suggestion/suggestion.scss b/media/views/oss/suggestion/suggestion.scss index 150e88372..c282b4d5b 100644 --- a/media/views/oss/suggestion/suggestion.scss +++ b/media/views/oss/suggestion/suggestion.scss @@ -1,51 +1,30 @@ @import '../../common/webview'; -@import '../../common/suggestionHeader'; -.clickable:hover { - cursor: pointer; -} - -.delimiter { - width: 0; - height: 1.3rem; - margin: 0 0.8rem 0 0.8rem; - border-right:1px solid var(--vscode-input-border); - line-height: 1rem; +:root { + font-size: var(--vscode-editor-font-size); } -.summary .summary-item { - display: flex; - margin: 0.3em 0 0.3em 0; +.vscode-dark .light-only { + display: none; } -.summary .label { - width: 160px; +.vscode-light .dark-only { + display: none; } - -.summary .content { - flex: 70%; +body { + font-size: var(--vscode-editor-font-size); } -.summary .remediation { - margin-bottom: 1.6rem +h2 { + font-size: 1.2rem; } -.summary .detailed-path:last-child .remediation { - margin-bottom: 0 +/* High-contrast dark mode */ +.vscode-high-contrast:not(.vscode-high-contrast-light) .vulnerability-overview code { + color: var(--vscode-editor-background); } -.vulnerability-overview pre { - padding: 8px 16px; - overflow-x: auto; - border-radius: 4px; - font-size: var(--vscode-editor-font-size); - font-family: var(--vscode-editor-font-family); - background-color: var(--vscode-editor-background); - border: 1px solid var(--vscode-input-border); +/* High-contrast light mode */ +.vscode-high-contrast.vscode-high-contrast-light .vulnerability-overview code { + color: var(--vscode-editor-background); } - -.vulnerability-overview code { - color: var(--vscode-foreground); - font-size: var(--vscode-editor-font-size); - font-family: var(--vscode-editor-font-family); -} \ No newline at end of file diff --git a/media/views/snykCode/falsePositive/falsePositive.scss b/media/views/snykCode/falsePositive/falsePositive.scss deleted file mode 100644 index 0ef74af56..000000000 --- a/media/views/snykCode/falsePositive/falsePositive.scss +++ /dev/null @@ -1,47 +0,0 @@ -@import '../../common/variables'; -@import '../../common/vscode'; -@import '../../common/webview'; -@import '../../common/suggestionHeader'; - -body { - height: 99%; -} - -.editor-section { - flex: 2; -} - -.editor { - width: 100%; - height: 100%; - resize: vertical; - color: $editor-font-color; - background-color: $editor-background-color; - border-color: $editor-background-color; - - font-size: var(--vscode-editor-font-size); - font-family: var(--vscode-editor-font-family); - - &:focus { - outline: none; - } -} - -.warning { - display: flex; - align-items: center; - - span { - margin-left: 0.3em; - } -} - -.actions { - display: flex; - flex-direction: row-reverse; -} - -.actions .button { - margin: 0 1rem 2rem; - flex: 0 0 30%; -} diff --git a/media/views/snykCode/suggestion/suggestion.scss b/media/views/snykCode/suggestion/suggestion.scss deleted file mode 100644 index dfe2f0c59..000000000 --- a/media/views/snykCode/suggestion/suggestion.scss +++ /dev/null @@ -1,234 +0,0 @@ -@import '../../common/variables'; -@import '../../common/webview'; - -.row { - display: flex; - flex-direction: row; - width: 100%; -} - -.row.between { - justify-content: space-between; -} - -.row.center { - justify-content: center; -} - -.icon { - vertical-align: middle; - width: 18px; - height: 18px; -} - -.suggestion { - position: relative; - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - margin: 0; - font-size: 1.4rem; -} - -.suggestion-title { - padding: 0.4rem 0; - margin-bottom: 0.8rem; - font-size: 1.8rem; - font-weight: 500; - line-height: 2.4rem; -} - -.suggestion-text { - line-height: 1.6; -} - -.cwe-list { - display: inline-block; - margin: 0; - padding: 0; -} - -.suggestion-metas { - font-size: 1.3rem; - line-height: 2rem; -} - -.suggestion-meta, -.suggestion-position { - display: inline-block; - padding: 0 8px; - border-right: 1px solid var(--vscode-input-border); - line-height: 1; - text-transform: capitalize; -} - -.suggestion-meta:first-child { - padding-left: 0 -} - -.suggestion-position { - border: none; - padding-left: 5px; - text-transform: none; -} - -.suggestion--header { - background-image: linear-gradient(0, --vscode-tab-activeBackground, transparent); -} - -.mark-position { - font-weight: 400; - font-family: 'Courier New', Courier, monospace; -} - -.mark-message { - font-weight: 600; -} - -#severity { - display: flex; - flex-direction: column; - flex-grow: 0; - float: left; - margin: 0 1rem 0 0; - text-align: center; -} - -#severity .icon { - width: 32px; - height: 32px; - color: var(--vscode-icon-foreground); -} - -.vscode-dark .light-only { - display: none; -} - -.vscode-light .dark-only { - display: none; -} - -.clickable:hover { - cursor: pointer; -} - -#info-top { - margin-bottom: 8px; -} - -#example-top { - margin-bottom: 16px; -} - -.repo { - display: flex; - gap: 8px; -} - -.arrow { - display: inline-block; - width: 20px; - height: 20px; - padding: 4px; - cursor: pointer; - border-radius: 4px; - text-align: center; - line-height: 1; -} - -.arrow:hover { - background-color: var(--vscode-toolbar-hoverBackground); -} - -.examples-nav { - display: flex; - gap: 4px; -} - -#example-text { - width: 86px; - text-align: center; -} - -#example { - width: 100%; - border: 1px solid var(--vscode-input-border); - border-radius: 3px; - line-height: 1.5; - background-color: var(--vscode-editor-background); -} - -.example-line.removed { - background-color: rgb(255, 215, 213); -} - -.example-line.removed::before { - content: "-"; - position: absolute; - padding: 0 4px; - line-height: 1; -} - -.example-line.added { - background-color: rgb(204, 255, 216); -} - -.example-line.added::before { - content: "+"; - position: absolute; - padding: 0 4px; - line-height: 1; -} - -.example-line>code { - display: block; - padding-left: 30px; - white-space: pre-wrap; - color: var(--vscode-editor-foreground); - font-weight: 400; -} - -.vscode-dark .removed { - background-color: rgba(84, 36, 38, 1); - color: #fff; -} - -.vscode-dark .added { - background-color: rgba(28, 68, 40, 1); - color: #fff; -} - - -.vscode-dark .added>code { - color: #fff; -} - -.vscode-dark .removed>code { - color: #fff; -} - -.suggestion-links { - display: flex; - width: 100%; - line-height: 1; -} - -#lead-url { - margin-left: auto; -} - -.actions { - justify-content: space-between; - display: flex; -} - -.actions .button { - margin: 0 0 2rem; - flex: 0 0 30%; - border-radius: 3px; -} - -.report-fp-actions { - margin-left: auto; -} \ No newline at end of file diff --git a/media/views/snykCode/suggestion/suggestionLS.scss b/media/views/snykCode/suggestion/suggestionLS.scss new file mode 100644 index 000000000..a09e67dd9 --- /dev/null +++ b/media/views/snykCode/suggestion/suggestionLS.scss @@ -0,0 +1,65 @@ +@import '../../common/webview'; + +.vscode-dark .data-flow-number{ + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.075)); +} +.vscode-light .data-flow-number{ + background-image: linear-gradient(45deg, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.05)); +} +.data-flow-text { + font-family: "Courier New", Courier, monospace; +} + +.example-line > code { + font-family: "Courier New", Courier, monospace; +} + +.example-line.added { + background-color: rgb(204, 255, 216); +} + +.example-line.removed { + background-color: rgb(255, 215, 213); +} + +.vscode-dark .example-line.removed { + background-color: rgba(84, 36, 38, 1); + color: #fff; +} + +.vscode-dark .example-line.added { + background-color: rgba(28, 68, 40, 1); + color: #fff; +} + +.vscode-dark .example-line.added>code { + color: #fff; + background-color: transparent; +} + +.vscode-dark .example-line.removed>code { + color: #fff; + background-color: transparent; +} + +.vscode-high-contrast:not(.vscode-high-contrast-light) .example-line.removed { + background-color: #542426; + color: #fff; +} + +.vscode-dark .added, +.vscode-high-contrast:not(.vscode-high-contrast-light) .example-line.added { + background-color: #1C4428; + color: #fff; +} + + +.vscode-dark .light-only, +.vscode-high-contrast:not(.vscode-high-contrast-light) .light-only { + display: none; +} + +.vscode-light .dark-only, +.vscode-high-contrast.vscode-high-contrast-light .dark-only { + display: none; +} diff --git a/package-lock.json b/package-lock.json index a4fb2f853..6ffcf13ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,63 +8,60 @@ "name": "snyk-vulnerability-scanner", "version": "0.0.0", "dependencies": { - "@amplitude/experiment-node-server": "^1.3.0", - "@babel/parser": "^7.12.11", - "@babel/traverse": "^7.12.12", - "@babel/types": "^7.12.12", - "@itly/plugin-amplitude-node": "^2.5.0", - "@itly/plugin-schema-validator": "^2.4.0", - "@itly/plugin-segment-node": "^2.4.0", - "@itly/sdk": "^2.3.1", - "@sentry/node": "^6.16.1", - "@sentry/tracing": "^6.19.7", - "@snyk/code-client": "^4.12.4", - "analytics-node": "^4.0.1", - "axios": "^0.27.2", - "glob": "^7.2.0", + "@amplitude/experiment-node-server": "^1.8.2", + "@babel/parser": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", + "@deepcode/dcignore": "^1.0.4", + "axios": "^1.7.8", + "diff": "^5.2.0", + "glob": "^9.3.5", + "he": "^1.2.0", "htmlparser2": "^7.2.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "lodash": "^4.17.21", - "marked": "^4.0.16", + "marked": "^11.2.0", + "needle": "^3.3.1", "open": "^7.4.2", - "rxjs": "^7.5.5", - "string-argv": "^0.3.1", + "rxjs": "^7.8.1", + "string-argv": "^0.3.2", "uuid": "^8.3.2", "validate-npm-package-name": "^3.0.0", "vscode-languageclient": "8.1.0", - "vscode-languageserver-textdocument": "^1.0.8" + "vscode-languageserver-textdocument": "^1.0.10" }, "devDependencies": { "@amplitude/ampli": "^1.29.0", - "@types/analytics-node": "^3.1.4", "@types/babel__traverse": "^7.12.2", + "@types/diff": "^5.0.9", "@types/find-package-json": "^1.2.2", - "@types/glob": "^7.1.3", - "@types/lodash": "^4.14.161", - "@types/marked": "^3.0.0", + "@types/glob": "^8.1.0", + "@types/he": "^1.2.3", + "@types/lodash": "^4.17.0", + "@types/marked": "^6.0.0", "@types/mocha": "^8.0.3", "@types/needle": "^2.5.2", - "@types/node": "^14.6.2", + "@types/node": "^18.19.26", "@types/sinon": "^10.0.2", "@types/uuid": "^8.3.0", "@types/validate-npm-package-name": "^3.0.3", "@types/vscode": "^1.58.0", - "@typescript-eslint/eslint-plugin": "^5.52.0", - "@typescript-eslint/parser": "^5.16.0", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.4.0", + "@vscode/test-electron": "^2.4.0", "concurrently": "^7.0.0", - "eslint": "^8.11.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^8.5.0", - "eslint-import-resolver-typescript": "^2.7.0", - "eslint-plugin-import": "^2.25.4", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-prettier": "^4.0.0", "mocha": "10.1.0", "prettier": "^2.6.1", "sass": "^1.48.0", - "sentry-testkit": "^3.3.7", "sinon": "^11.1.1", "ts-node": "^10.7.0", - "typescript": "^4.3.4", + "typescript": "^5.4.3", "vscode-test": "^1.4.0", "yalc": "^1.0.0-pre.44" }, @@ -72,6 +69,15 @@ "vscode": "^1.58.0" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@amplitude/ampli": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/@amplitude/ampli/-/ampli-1.29.0.tgz", @@ -137,6 +143,76 @@ "node": ">=12.0.0" } }, + "node_modules/@amplitude/ampli/node_modules/@phenomnomnominal/tsquery": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-3.0.0.tgz", + "integrity": "sha512-SW8lKitBHWJ9fAYkJ9kJivuctwNYCh3BUxLdH0+XiR1GPBiu+7qiZzh8p8jqlj1LgVC1TbvfNFroaEsmYlL8Iw==", + "dev": true, + "dependencies": { + "esquery": "^1.0.1" + }, + "peerDependencies": { + "typescript": "^3" + } + }, + "node_modules/@amplitude/ampli/node_modules/@sentry/core": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.19.7.tgz", + "integrity": "sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==", + "dev": true, + "dependencies": { + "@sentry/hub": "6.19.7", + "@sentry/minimal": "6.19.7", + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@amplitude/ampli/node_modules/@sentry/node": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-6.19.7.tgz", + "integrity": "sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg==", + "dev": true, + "dependencies": { + "@sentry/core": "6.19.7", + "@sentry/hub": "6.19.7", + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@amplitude/ampli/node_modules/@sentry/utils": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.19.7.tgz", + "integrity": "sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==", + "dev": true, + "dependencies": { + "@sentry/types": "6.19.7", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@amplitude/ampli/node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, "node_modules/@amplitude/ampli/node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -151,6 +227,26 @@ "node": ">=4" } }, + "node_modules/@amplitude/ampli/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@amplitude/ampli/node_modules/globby": { "version": "10.0.2", "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", @@ -219,23 +315,63 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/@amplitude/evaluation-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@amplitude/evaluation-js/-/evaluation-js-1.0.0.tgz", - "integrity": "sha512-U2ibGJ+5XLwfyHPmwDdxkqWhxxmZBs/gnPWalKBnmcY4zGXfBi2XkGbHsghlAD3XD3vZ1eMl7xqhHp3CWtpp/g==" + "node_modules/@amplitude/analytics-core": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-1.2.5.tgz", + "integrity": "sha512-V7CVlHVN+1diKiOpdp2bCPZ0mbS4CmUYF+v+eXDwVfJL3M/t3sVcT1apXnmVYGYi14cGu9hQOD11rD6qKbUOsw==", + "dependencies": { + "@amplitude/analytics-types": "^1.3.4", + "tslib": "^2.4.1" + } + }, + "node_modules/@amplitude/analytics-core/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/@amplitude/analytics-node": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-node/-/analytics-node-1.3.5.tgz", + "integrity": "sha512-PVdCs3duu4OQNIQ3ENCKdm6wnoMAOdpSZD3tpWbEQVKh08FlxWLrR8eQN48nvhs+i6yEwGGVr1SfRDPpsMog1w==", + "dependencies": { + "@amplitude/analytics-core": "^1.2.5", + "@amplitude/analytics-types": "^1.3.4", + "tslib": "^2.4.1" + } + }, + "node_modules/@amplitude/analytics-node/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/@amplitude/analytics-types": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-1.3.4.tgz", + "integrity": "sha512-tR70gzqFkEzX9QpxvWYMfLCledT7vMhgd3d4/bkp3nnGXTOORaVUOCcSgOyxyuFdSx84T61aP/eZPKIcZcaP+A==" + }, + "node_modules/@amplitude/experiment-core": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@amplitude/experiment-core/-/experiment-core-0.7.2.tgz", + "integrity": "sha512-Wc2NWvgQ+bLJLeF0A9wBSPIaw0XuqqgkPKsoNFQrmS7r5Djd56um75In05tqmVntPJZRvGKU46pAp8o5tdf4mA==", + "dependencies": { + "js-base64": "^3.7.5" + } }, "node_modules/@amplitude/experiment-node-server": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@amplitude/experiment-node-server/-/experiment-node-server-1.3.0.tgz", - "integrity": "sha512-ahkN1H+9nHteqVaktitzjs43UTUJ0iwVplz0Brm6XKd7wT/w7ICbyPjvfPepqu6l71j5065DhVA7g1hdufkP/Q==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@amplitude/experiment-node-server/-/experiment-node-server-1.8.2.tgz", + "integrity": "sha512-R1+eDUb/Syn70f+TbFUF4/+Mg8aCBRx4mvAIB7JE0ICCrYpb351hAF7wnLKAZcScY0cKJ45/JF517WW757JwmA==", "dependencies": { - "@amplitude/evaluation-js": "1.0.0" + "@amplitude/analytics-node": "^1.3.4", + "@amplitude/analytics-types": "^1.3.1", + "@amplitude/experiment-core": "^0.7.2" } }, "node_modules/@amplitude/identify": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/@amplitude/identify/-/identify-1.10.2.tgz", "integrity": "sha512-ywxeabS8ukMdJWNwx3rG/EBngXFg/4NsPhlyAxbBUcI7HzBXEJUKepiZfkz8K6Y7f0mpc23Qz1aBf48ZJDZmkQ==", + "dev": true, "dependencies": { "@amplitude/types": "^1.10.2", "@amplitude/utils": "^1.10.2", @@ -248,12 +384,14 @@ "node_modules/@amplitude/identify/node_modules/tslib": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true }, "node_modules/@amplitude/node": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/@amplitude/node/-/node-1.10.2.tgz", "integrity": "sha512-E3xp8DOpkF5ThjrRlAmSocnrEYsTPpd3Zg4WdBLms0ackQSgQpw6z84+YMcoPerZHJJ/LEqdo4Cg4Z5Za3D+3Q==", + "dev": true, "dependencies": { "@amplitude/identify": "^1.10.2", "@amplitude/types": "^1.10.2", @@ -267,12 +405,14 @@ "node_modules/@amplitude/node/node_modules/tslib": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true }, "node_modules/@amplitude/types": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/@amplitude/types/-/types-1.10.2.tgz", "integrity": "sha512-I8qenRI7uU6wKNb9LiZrAosSHVoNHziXouKY81CrqxH9xhVTEIJFXeuCV0hbtBr0Al/8ejnGjQRx+S2SvU/pPg==", + "dev": true, "engines": { "node": ">=10" } @@ -281,6 +421,7 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/@amplitude/utils/-/utils-1.10.2.tgz", "integrity": "sha512-tVsHXu61jITEtRjB7NugQ5cVDd4QDzne8T3ifmZye7TiJeUfVRvqe44gDtf55A+7VqhDhyEIIXTA1iVcDGqlEw==", + "dev": true, "dependencies": { "@amplitude/types": "^1.10.2", "tslib": "^2.0.0" @@ -292,14 +433,15 @@ "node_modules/@amplitude/utils/node_modules/tslib": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dependencies": { - "@babel/highlight": "^7.22.13", + "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" }, "engines": { @@ -320,11 +462,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dependencies": { - "@babel/types": "^7.23.0", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -376,9 +518,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "engines": { "node": ">=6.9.0" } @@ -392,9 +534,9 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -418,9 +560,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", + "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", "bin": { "parser": "bin/babel-parser.js" }, @@ -442,19 +584,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", + "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -470,11 +612,11 @@ } }, "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, @@ -508,24 +650,51 @@ "resolved": "https://registry.npmjs.org/@deepcode/dcignore/-/dcignore-1.0.4.tgz", "integrity": "sha512-gsLh2FJ43Mz3kA6aqMq3BOUCMS5ub8pJZOpRgrZ1h0f/rkzphriUGLnC37+Jn86CFckxWlwHk/q28tyf0g4NBw==" }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", - "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.1", - "globals": "^13.9.0", + "espree": "^9.6.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/eslintrc/node_modules/argparse": { @@ -546,127 +715,73 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@itly/plugin-amplitude-node": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@itly/plugin-amplitude-node/-/plugin-amplitude-node-2.5.0.tgz", - "integrity": "sha512-STWJgTLykMPW8uUtix0qlrX96E+aICN6IDA/gdbxsGaT2Ul30zrSVH+CEsrB6vttOdAIER3ukV7nKB+QRP173g==", - "dependencies": { - "@amplitude/identify": "^1.8.4", - "@amplitude/node": "^1.8.4" - }, - "peerDependencies": { - "@itly/sdk": "^2.0.0" - } - }, - "node_modules/@itly/plugin-schema-validator": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@itly/plugin-schema-validator/-/plugin-schema-validator-2.4.0.tgz", - "integrity": "sha512-qh1q4cMp0tPmHRMAJzKe2Fmh21a4cekyCtxVEzXJrjuwZzo6JxA1SAgt9dZKugZzsx209VFp2tJRoJ9kIeI8bw==", - "dependencies": { - "jsonschema": "^1.4.0", - "url": "^0.11.0" - }, - "peerDependencies": { - "@itly/sdk": "^2.0.0" - } - }, - "node_modules/@itly/plugin-segment-node": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@itly/plugin-segment-node/-/plugin-segment-node-2.4.0.tgz", - "integrity": "sha512-22ZMkofNy96DJv8FQ20bLf5s/A+IC8nkyT4kCVgDkn3uM5z86BUcpMSfWVijRpIeIUp2hZekpXrUVUcoFv/C9g==", - "dependencies": { - "@types/analytics-node": "^3.1.4", - "analytics-node": "^3.4.0-beta.3" - }, - "peerDependencies": { - "@itly/sdk": "^2.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@itly/plugin-segment-node/node_modules/analytics-node": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/analytics-node/-/analytics-node-3.5.0.tgz", - "integrity": "sha512-XgQq6ejZHCehUSnZS4V7QJPLIP7S9OAWwQDYl4WTLtsRvc5fCxIwzK/yihzmIW51v9PnyBmrl9dMcqvwfOE8WA==", + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, "dependencies": { - "@segment/loosely-validate-event": "^2.0.0", - "axios": "^0.21.1", - "axios-retry": "^3.0.2", - "lodash.isstring": "^4.0.1", - "md5": "^2.2.1", - "ms": "^2.0.0", - "remove-trailing-slash": "^0.1.0", - "uuid": "^3.2.1" + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { - "node": ">=4" - } - }, - "node_modules/@itly/plugin-segment-node/node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dependencies": { - "follow-redirects": "^1.14.0" + "node": ">=10.10.0" } }, - "node_modules/@itly/plugin-segment-node/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@itly/sdk": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@itly/sdk/-/sdk-2.4.0.tgz", - "integrity": "sha512-EnJii6kCCNVgjRmDEzGi+E5CnSkqHvTiUGMyyt2CuzFjp0ipULP5VRNi42mRzGYF02qbYUiBhAXcJtPbm3wX7A==" + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } @@ -677,20 +792,21 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@nodelib/fs.scandir": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", - "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "dependencies": { - "@nodelib/fs.stat": "2.0.4", + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" }, "engines": { @@ -698,19 +814,21 @@ } }, "node_modules/@nodelib/fs.stat": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", - "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", - "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.4", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" }, "engines": { @@ -1355,49 +1473,27 @@ "node": ">=8.0.0" } }, - "node_modules/@phenomnomnominal/tsquery": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-3.0.0.tgz", - "integrity": "sha512-SW8lKitBHWJ9fAYkJ9kJivuctwNYCh3BUxLdH0+XiR1GPBiu+7qiZzh8p8jqlj1LgVC1TbvfNFroaEsmYlL8Iw==", + "node_modules/@sentry/hub": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.19.7.tgz", + "integrity": "sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==", "dev": true, "dependencies": { - "esquery": "^1.0.1" - }, - "peerDependencies": { - "typescript": "^3" - } - }, - "node_modules/@segment/loosely-validate-event": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz", - "integrity": "sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==", - "dependencies": { - "component-type": "^1.2.1", - "join-component": "^1.1.0" - } - }, - "node_modules/@sentry/core": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.16.1.tgz", - "integrity": "sha512-UFI0264CPUc5cR1zJH+S2UPOANpm6dLJOnsvnIGTjsrwzR0h8Hdl6rC2R/GPq+WNbnipo9hkiIwDlqbqvIU5vw==", - "dependencies": { - "@sentry/hub": "6.16.1", - "@sentry/minimal": "6.16.1", - "@sentry/types": "6.16.1", - "@sentry/utils": "6.16.1", + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", "tslib": "^1.9.3" }, "engines": { "node": ">=6" } }, - "node_modules/@sentry/hub": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.16.1.tgz", - "integrity": "sha512-4PGtg6AfpqMkreTpL7ymDeQ/U1uXv03bKUuFdtsSTn/FRf9TLS4JB0KuTZCxfp1IRgAA+iFg6B784dDkT8R9eg==", + "node_modules/@sentry/hub/node_modules/@sentry/utils": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.19.7.tgz", + "integrity": "sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==", + "dev": true, "dependencies": { - "@sentry/types": "6.16.1", - "@sentry/utils": "6.16.1", + "@sentry/types": "6.19.7", "tslib": "^1.9.3" }, "engines": { @@ -1405,146 +1501,41 @@ } }, "node_modules/@sentry/minimal": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.16.1.tgz", - "integrity": "sha512-dq+mI1EQIvUM+zJtGCVgH3/B3Sbx4hKlGf2Usovm9KoqWYA+QpfVBholYDe/H2RXgO7LFEefDLvOdHDkqeJoyA==", + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.19.7.tgz", + "integrity": "sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==", + "dev": true, "dependencies": { - "@sentry/hub": "6.16.1", - "@sentry/types": "6.16.1", + "@sentry/hub": "6.19.7", + "@sentry/types": "6.19.7", "tslib": "^1.9.3" }, "engines": { "node": ">=6" } }, - "node_modules/@sentry/node": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-6.16.1.tgz", - "integrity": "sha512-SeDDoug2kUxeF1D7JGPa3h5EXxKtmA01mITBPYx5xbJ0sMksnv5I5bC1SJ8arRRzq6+W1C4IEeDBQtrVCk6ixA==", - "dependencies": { - "@sentry/core": "6.16.1", - "@sentry/hub": "6.16.1", - "@sentry/tracing": "6.16.1", - "@sentry/types": "6.16.1", - "@sentry/utils": "6.16.1", - "cookie": "^0.4.1", - "https-proxy-agent": "^5.0.0", - "lru_map": "^0.3.3", - "tslib": "^1.9.3" - }, + "node_modules/@sentry/types": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.19.7.tgz", + "integrity": "sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==", + "dev": true, "engines": { "node": ">=6" } }, - "node_modules/@sentry/node/node_modules/@sentry/tracing": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.16.1.tgz", - "integrity": "sha512-MPSbqXX59P+OEeST+U2V/8Hu/8QjpTUxTNeNyTHWIbbchdcMMjDbXTS3etCgajZR6Ro+DHElOz5cdSxH6IBGlA==", + "node_modules/@servie/events": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@servie/events/-/events-1.0.0.tgz", + "integrity": "sha512-sBSO19KzdrJCM3gdx6eIxV8M9Gxfgg6iDQmH5TIAGaUu+X9VDdsINXJOnoiZ1Kx3TrHdH4bt5UVglkjsEGBcvw==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, "dependencies": { - "@sentry/hub": "6.16.1", - "@sentry/minimal": "6.16.1", - "@sentry/types": "6.16.1", - "@sentry/utils": "6.16.1", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/tracing": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.19.7.tgz", - "integrity": "sha512-ol4TupNnv9Zd+bZei7B6Ygnr9N3Gp1PUrNI761QSlHtPC25xXC5ssSD3GMhBgyQrcvpuRcCFHVNNM97tN5cZiA==", - "dependencies": { - "@sentry/hub": "6.19.7", - "@sentry/minimal": "6.19.7", - "@sentry/types": "6.19.7", - "@sentry/utils": "6.19.7", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/tracing/node_modules/@sentry/hub": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.19.7.tgz", - "integrity": "sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==", - "dependencies": { - "@sentry/types": "6.19.7", - "@sentry/utils": "6.19.7", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/tracing/node_modules/@sentry/minimal": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.19.7.tgz", - "integrity": "sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==", - "dependencies": { - "@sentry/hub": "6.19.7", - "@sentry/types": "6.19.7", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/tracing/node_modules/@sentry/types": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.19.7.tgz", - "integrity": "sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/tracing/node_modules/@sentry/utils": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.19.7.tgz", - "integrity": "sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==", - "dependencies": { - "@sentry/types": "6.19.7", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/types": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.16.1.tgz", - "integrity": "sha512-Wh354g30UsJ5kYJbercektGX4ZMc9MHU++1NjeN2bTMnbofEcpUDWIiKeulZEY65IC1iU+1zRQQgtYO+/hgCUQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/utils": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.16.1.tgz", - "integrity": "sha512-7ngq/i4R8JZitJo9Sl8PDnjSbDehOxgr1vsoMmerIsyRZ651C/8B+jVkMhaAPgSdyJ0AlE3O7DKKTP1FXFw9qw==", - "dependencies": { - "@sentry/types": "6.16.1", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@servie/events": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@servie/events/-/events-1.0.0.tgz", - "integrity": "sha512-sBSO19KzdrJCM3gdx6eIxV8M9Gxfgg6iDQmH5TIAGaUu+X9VDdsINXJOnoiZ1Kx3TrHdH4bt5UVglkjsEGBcvw==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" + "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { @@ -1573,30 +1564,6 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, - "node_modules/@snyk/code-client": { - "version": "4.12.4", - "resolved": "https://registry.npmjs.org/@snyk/code-client/-/code-client-4.12.4.tgz", - "integrity": "sha512-K2k8J761iJfKxWI026ZAWw15Xaw3Vff4Wmy9SPx5QR3aU6qrHn1d872v+9B8nnrHfbgJbU45t/iLzCv/fiotNg==", - "dependencies": { - "@deepcode/dcignore": "^1.0.4", - "@types/flat-cache": "^2.0.0", - "@types/lodash.omit": "^4.5.6", - "@types/lodash.pick": "^4.4.6", - "@types/lodash.union": "^4.6.6", - "@types/sarif": "^2.1.4", - "@types/uuid": "^8.3.1", - "fast-glob": "^3.2.11", - "ignore": "^5.1.8", - "lodash.omit": "^4.5.0", - "lodash.pick": "^4.4.0", - "lodash.union": "^4.6.0", - "multimatch": "^5.0.0", - "needle": "~3.0.0", - "p-map": "^3.0.0", - "uuid": "^8.3.2", - "yaml": "^1.10.2" - } - }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -1629,11 +1596,6 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, - "node_modules/@types/analytics-node": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/analytics-node/-/analytics-node-3.1.4.tgz", - "integrity": "sha512-i6cqjFotMq1dEwXxyXRqnzp/HmWPCskptrVUQ1UzRIGs/zICFWM2bIJyLt6f9A9/+qE98wls1AHWPQ4WXYS0HA==" - }, "node_modules/@types/babel__traverse": { "version": "7.14.2", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", @@ -1649,6 +1611,12 @@ "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", "dev": true }, + "node_modules/@types/diff": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.0.9.tgz", + "integrity": "sha512-RWVEhh/zGXpAVF/ZChwNnv7r4rvqzJ7lYNSmZSVTxjV0PBLf6Qu7RNg+SUtkpzxmiNkjCx0Xn2tPp7FIkshJwQ==", + "dev": true + }, "node_modules/@types/find-package-json": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@types/find-package-json/-/find-package-json-1.2.2.tgz", @@ -1658,21 +1626,28 @@ "@types/node": "*" } }, - "node_modules/@types/flat-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/flat-cache/-/flat-cache-2.0.0.tgz", - "integrity": "sha512-fHeEsm9hvmZ+QHpw6Fkvf19KIhuqnYLU6vtWLjd5BsMd/qVi7iTkMioDZl0mQmfNRA1A6NwvhrSRNr9hGYZGww==" - }, "node_modules/@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", "dev": true, "dependencies": { - "@types/minimatch": "*", + "@types/minimatch": "^5.1.2", "@types/node": "*" } }, + "node_modules/@types/glob/node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/he": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/he/-/he-1.2.3.tgz", + "integrity": "sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA==", + "dev": true + }, "node_modules/@types/inquirer": { "version": "8.2.5", "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.2.5.tgz", @@ -1683,56 +1658,38 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "node_modules/@types/lodash": { - "version": "4.14.168", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz", - "integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==" - }, - "node_modules/@types/lodash.omit": { - "version": "4.5.6", - "resolved": "https://registry.npmjs.org/@types/lodash.omit/-/lodash.omit-4.5.6.tgz", - "integrity": "sha512-KXPpOSNX2h0DAG2w7ajpk7TXvWF28ZHs5nJhOJyP0BQHkehgr948RVsToItMme6oi0XJkp19CbuNXkIX8FiBlQ==", - "dependencies": { - "@types/lodash": "*" - } - }, - "node_modules/@types/lodash.pick": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@types/lodash.pick/-/lodash.pick-4.4.6.tgz", - "integrity": "sha512-u8bzA16qQ+8dY280z3aK7PoWb3fzX5ATJ0rJB6F+uqchOX2VYF02Aqa+8aYiHiHgPzQiITqCgeimlyKFy4OA6g==", - "dependencies": { - "@types/lodash": "*" - } + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", + "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==", + "dev": true }, - "node_modules/@types/lodash.union": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.6.tgz", - "integrity": "sha512-Wu0ZEVNcyCz8eAn6TlUbYWZoGbH9E+iOHxAZbwUoCEXdUiy6qpcz5o44mMXViM4vlPLLCPlkAubEP1gokoSZaw==", + "node_modules/@types/marked": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-6.0.0.tgz", + "integrity": "sha512-jmjpa4BwUsmhxcfsgUit/7A9KbrC48Q0q8KvnY107ogcjGgTFDlIL3RpihNpx2Mu1hM4mdFQjoVc4O6JoGKHsA==", + "deprecated": "This is a stub types definition. marked provides its own type definitions, so you do not need this installed.", + "dev": true, "dependencies": { - "@types/lodash": "*" + "marked": "*" } }, - "node_modules/@types/marked": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-3.0.0.tgz", - "integrity": "sha512-vof90OIWT+Tzq3MBRXgV9fsH8PC3WZ4OQg9Qa04vOtP0TcyiNfl7BTonYCmTapHZ5lRZh6ihUYkAy7St1hmk/A==", - "dev": true - }, "node_modules/@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==" + "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", + "dev": true }, "node_modules/@types/mocha": { "version": "8.2.3", @@ -1750,15 +1707,13 @@ } }, "node_modules/@types/node": { - "version": "14.14.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz", - "integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==", - "dev": true - }, - "node_modules/@types/sarif": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.4.tgz", - "integrity": "sha512-4xKHMdg3foh3Va1fxTzY1qt8QVqmaJpGWsVvtjQrJBn+/bkig2pWFKJ4FPI2yLI4PAj0SUKiPO4Vd7ggYIMZjQ==" + "version": "18.19.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.26.tgz", + "integrity": "sha512-+wiMJsIwLOYCvUqSdKTrfkS8mpTp+MPINe6+Np4TAGFWWRWiBQ5kSq9nZGCSPkzx9mvT+uEukzpX4MOSCydcvw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/semver": { "version": "5.5.0", @@ -1791,9 +1746,10 @@ "dev": true }, "node_modules/@types/uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==" + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true }, "node_modules/@types/validate-npm-package-name": { "version": "3.0.3", @@ -1808,32 +1764,33 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", - "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz", + "integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/type-utils": "5.52.0", - "@typescript-eslint/utils": "5.52.0", + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/type-utils": "7.4.0", + "@typescript-eslint/utils": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -1841,73 +1798,27 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", - "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", - "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", - "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.52.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.16.0.tgz", - "integrity": "sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz", + "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.16.0", - "@typescript-eslint/types": "5.16.0", - "@typescript-eslint/typescript-estree": "5.16.0", - "debug": "^4.3.2" + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -1916,16 +1827,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz", - "integrity": "sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz", + "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.16.0", - "@typescript-eslint/visitor-keys": "5.16.0" + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1933,25 +1844,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", - "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz", + "integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.52.0", - "@typescript-eslint/utils": "5.52.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/utils": "7.4.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -1959,35 +1870,36 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", - "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "node_modules/@typescript-eslint/types": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz", + "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", - "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz", + "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1999,203 +1911,298 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", - "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.52.0", - "eslint-visitor-keys": "^3.3.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=16 || 14 >=14.17" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@typescript-eslint/types": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.16.0.tgz", - "integrity": "sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g==", + "node_modules/@typescript-eslint/utils": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz", + "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==", "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "semver": "^7.5.4" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz", - "integrity": "sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ==", + "node_modules/@typescript-eslint/utils/node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz", + "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.16.0", - "@typescript-eslint/visitor-keys": "5.16.0", - "debug": "^4.3.2", - "globby": "^11.0.4", - "is-glob": "^4.0.3", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "@typescript-eslint/types": "7.4.0", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vscode/test-electron": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.0.tgz", + "integrity": "sha512-yojuDFEjohx6Jb+x949JRNtSn6Wk2FAh4MldLE3ck9cfvCqzwxF32QsNy1T9Oe4oT+ZfFcg0uPUCajJzOmPlTA==", + "dev": true, + "dependencies": { + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.4", + "jszip": "^3.10.1", + "ora": "^7.0.1", + "semver": "^7.6.2" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": ">=16" } }, - "node_modules/@typescript-eslint/utils": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", - "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", + "node_modules/@vscode/test-electron/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/typescript-estree": "5.52.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" + "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 14" + } + }, + "node_modules/@vscode/test-electron/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@vscode/test-electron/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@typescript-eslint/utils/node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "node_modules/@vscode/test-electron/node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vscode/test-electron/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", "dev": true }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", - "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", + "node_modules/@vscode/test-electron/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 14" + } + }, + "node_modules/@vscode/test-electron/node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@vscode/test-electron/node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "engines": { + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", - "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "node_modules/@vscode/test-electron/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", - "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "node_modules/@vscode/test-electron/node_modules/log-symbols": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", + "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "chalk": "^5.0.0", + "is-unicode-supported": "^1.1.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vscode/test-electron/node_modules/ora": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz", + "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==", + "dev": true, + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^4.0.0", + "cli-spinners": "^2.9.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^1.3.0", + "log-symbols": "^5.1.0", + "stdin-discarder": "^0.1.0", + "string-width": "^6.1.0", + "strip-ansi": "^7.1.0" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", - "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", + "node_modules/@vscode/test-electron/node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.52.0", - "eslint-visitor-keys": "^3.3.0" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz", - "integrity": "sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g==", + "node_modules/@vscode/test-electron/node_modules/string-width": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz", + "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.16.0", - "eslint-visitor-keys": "^3.0.0" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^10.2.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=16" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "node_modules/@vscode/test-electron/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -2233,26 +2240,6 @@ "node": ">= 6.0.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/aggregate-error/node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "engines": { - "node": ">=6" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2269,41 +2256,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/analytics-node": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/analytics-node/-/analytics-node-4.0.1.tgz", - "integrity": "sha512-+zXOOTB+eTRW6R9+pfvPfk1dHraFJzhNnAyZiYJIDGOjHQgfk9qfqgoJX9MfR4qY0J/E1YJ3FBncrLGadTDW1A==", - "dependencies": { - "@segment/loosely-validate-event": "^2.0.0", - "axios": "^0.21.1", - "axios-retry": "^3.0.2", - "lodash.isstring": "^4.0.1", - "md5": "^2.2.1", - "ms": "^2.0.0", - "remove-trailing-slash": "^0.1.0", - "uuid": "^3.2.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/analytics-node/node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dependencies": { - "follow-redirects": "^1.14.0" - } - }, - "node_modules/analytics-node/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, "node_modules/ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -2400,30 +2352,33 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/array-differ": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", - "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, "node_modules/array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" }, "engines": { @@ -2437,6 +2392,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, "engines": { "node": ">=8" } @@ -2450,15 +2406,36 @@ "node": ">=0.10.0" } }, - "node_modules/array.prototype.flat": { + "node_modules/array.prototype.findlastindex": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -2467,12 +2444,44 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/asynckit": { @@ -2489,21 +2498,29 @@ "node": ">= 4.0.0" } }, - "node_modules/axios": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", - "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, "dependencies": { - "follow-redirects": "^1.14.9", - "form-data": "^4.0.0" + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/axios-retry": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.1.9.tgz", - "integrity": "sha512-NFCoNIHq8lYkJa6ku4m+V1837TP6lCa7n79Iuf8/AqATAHYB0ISaAS1eyIenDOfHOLtym34W65Sjke2xjg2fsA==", + "node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "dependencies": { - "is-retry-allowed": "^1.1.0" + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/axios/node_modules/form-data": { @@ -2591,46 +2608,11 @@ "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", "dev": true }, - "node_modules/body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", - "dev": true, - "dependencies": { - "bytes": "3.1.1", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.6", - "raw-body": "2.4.2", - "type-is": "~1.6.18" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2640,6 +2622,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -2737,23 +2720,20 @@ "integrity": "sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==", "dev": true }, - "node_modules/bytes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", - "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2869,14 +2849,6 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, - "node_modules/charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", - "engines": { - "node": "*" - } - }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -2963,9 +2935,9 @@ } }, "node_modules/cli-spinners": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz", - "integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, "engines": { "node": ">=6" @@ -3147,15 +3119,11 @@ "node": ">= 0.8" } }, - "node_modules/component-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz", - "integrity": "sha1-ikeQFwAjjk/DIml3EjAibyS0Fak=" - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "node_modules/concurrently": { "version": "7.0.0", @@ -3248,18 +3216,6 @@ "semver": "bin/semver.js" } }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -3273,16 +3229,11 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "dev": true, "engines": { "node": ">= 0.6" } }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -3318,12 +3269,55 @@ "node": ">= 8" } }, - "node_modules/crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, "engines": { - "node": "*" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/date-fns": { @@ -3380,9 +3374,9 @@ } }, "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, "node_modules/defaults": { @@ -3394,16 +3388,38 @@ "clone": "^1.0.2" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "dependencies": { - "object-keys": "^1.0.12" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/delayed-stream": { @@ -3414,21 +3430,6 @@ "node": ">=0.4.0" } }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, "node_modules/detect-indent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", @@ -3439,10 +3440,9 @@ } }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "engines": { "node": ">=0.3.1" } @@ -3560,10 +3560,10 @@ "readable-stream": "^2.0.2" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, "node_modules/emoji-regex": { @@ -3572,15 +3572,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -3590,6 +3581,19 @@ "once": "^1.4.0" } }, + "node_modules/enhanced-resolve": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/entities": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", @@ -3620,31 +3624,57 @@ } }, "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz", + "integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.5", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -3653,6 +3683,62 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, "node_modules/es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -3679,12 +3765,6 @@ "node": ">=6" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -3694,46 +3774,49 @@ } }, "node_modules/eslint": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz", - "integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.2.1", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" @@ -3758,13 +3841,14 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, "dependencies": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -3777,19 +3861,24 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.0.tgz", - "integrity": "sha512-MNHS3u5pebvROX4MjGP9coda589ZGfL1SqdxUV4kSrcclfDRWvNE2D+eljbnWVMvWDVRgT89nhscMHPKYGcObQ==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", "dev": true, "dependencies": { "debug": "^4.3.4", - "glob": "^7.2.0", - "is-glob": "^4.0.3", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" }, "engines": { - "node": ">=4" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" }, "peerDependencies": { "eslint": "*", @@ -3797,16 +3886,20 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, "dependencies": { - "debug": "^3.2.7", - "find-up": "^2.1.0" + "debug": "^3.2.7" }, "engines": { "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, "node_modules/eslint-module-utils/node_modules/debug": { @@ -3819,24 +3912,28 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", - "has": "^1.0.3", - "is-core-module": "^2.8.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", "is-glob": "^4.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" @@ -3846,12 +3943,12 @@ } }, "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { @@ -3866,11 +3963,14 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, "node_modules/eslint-plugin-prettier": { "version": "4.0.0", @@ -3894,52 +3994,31 @@ } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "estraverse": "^5.2.0" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/argparse": { @@ -3960,28 +4039,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -4007,17 +4064,20 @@ } }, "node_modules/espree": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", - "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.3.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -4034,9 +4094,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -4045,15 +4105,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -4066,7 +4117,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -4075,15 +4126,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -4093,77 +4135,6 @@ "node": ">=0.10.0" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", - "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", - "dev": true, - "dependencies": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.4.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.9.6", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", - "setprototypeof": "1.2.0", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -4212,9 +4183,10 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -4235,13 +4207,14 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "node_modules/fastq": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -4286,6 +4259,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4293,49 +4267,29 @@ "node": ">=8" } }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "node_modules/find-up/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/flat": { @@ -4367,9 +4321,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -4385,6 +4339,15 @@ } } }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/form-data": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", @@ -4399,24 +4362,6 @@ "node": ">= 6" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -4471,29 +4416,73 @@ "node": ">=0.6" } }, + "node_modules/fstream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fstream/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "dependencies": { - "glob": "^7.1.3" + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-caller-file": { "version": "2.0.5", @@ -4505,14 +4494,19 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4531,13 +4525,14 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" }, "engines": { "node": ">= 0.4" @@ -4546,20 +4541,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4569,6 +4574,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -4576,10 +4582,32 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { - "version": "13.13.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", - "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -4591,16 +4619,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globals/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/globby": { @@ -4623,16 +4654,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", "dev": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "node_modules/graphql": { @@ -4679,22 +4722,10 @@ "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", "dev": true }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4708,6 +4739,30 @@ "node": ">=4" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -4721,12 +4776,12 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -4735,11 +4790,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, "bin": { "he": "bin/he" } @@ -4792,22 +4858,6 @@ "node": ">=4" } }, - "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/http-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", @@ -4846,6 +4896,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -4874,9 +4925,10 @@ ] }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, "engines": { "node": ">= 4" } @@ -4890,6 +4942,12 @@ "minimatch": "^3.0.4" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true + }, "node_modules/immutable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", @@ -4925,6 +4983,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, "engines": { "node": ">=8" } @@ -4933,6 +4992,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -4941,7 +5001,8 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "node_modules/ini": { "version": "2.0.0", @@ -5046,13 +5107,13 @@ } }, "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "hasown": "^2.0.0", "side-channel": "^1.0.4" }, "engines": { @@ -5068,13 +5129,20 @@ "node": ">=4" } }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, "engines": { - "node": ">= 0.10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-arrayish": { @@ -5123,15 +5191,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "engines": { "node": ">= 0.4" @@ -5141,12 +5204,27 @@ } }, "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dev": true, "dependencies": { - "has": "^1.0.3" + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5185,6 +5263,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -5202,6 +5281,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -5219,9 +5299,9 @@ } }, "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "engines": { "node": ">= 0.4" @@ -5234,14 +5314,15 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "engines": { "node": ">=0.12.0" } }, "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -5262,6 +5343,15 @@ "node": ">=8" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -5291,15 +5381,22 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5343,6 +5440,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -5396,10 +5508,10 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "node_modules/join-component": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/join-component/-/join-component-1.1.0.tgz", - "integrity": "sha1-uEF7dQZho5K+4sJTfGiyqdSXfNU=" + "node_modules/js-base64": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", + "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" }, "node_modules/js-tokens": { "version": "4.0.0", @@ -5455,9 +5567,9 @@ "dev": true }, "node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" @@ -5475,12 +5587,16 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsonschema": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.0.tgz", - "integrity": "sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==", - "engines": { - "node": "*" + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" } }, "node_modules/just-extend": { @@ -5502,6 +5618,15 @@ "node": ">= 0.8.0" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", @@ -5509,16 +5634,18 @@ "dev": true }, "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "^5.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lodash": { @@ -5538,27 +5665,12 @@ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", "dev": true }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.omit": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", - "integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=" - }, - "node_modules/lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" - }, "node_modules/lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -5578,11 +5690,6 @@ "lodash._reinterpolate": "^3.0.0" } }, - "node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" - }, "node_modules/log-chopper": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-chopper/-/log-chopper-1.0.2.tgz", @@ -5614,18 +5721,8 @@ "node_modules/lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true }, "node_modules/make-dir": { "version": "3.1.0", @@ -5667,62 +5764,30 @@ } }, "node_modules/marked": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz", - "integrity": "sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz", + "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==", "bin": { "marked": "bin/marked.js" }, "engines": { - "node": ">= 12" - } - }, - "node_modules/md5": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", - "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", - "dependencies": { - "charenc": "0.0.2", - "crypt": "0.0.2", - "is-buffer": "~1.1.6" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true, - "engines": { - "node": ">= 0.6" + "node": ">= 18" } }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", "dev": true, "engines": { - "node": ">= 0.6" + "node": ">= 8" } }, "node_modules/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -5731,18 +5796,6 @@ "node": ">=8.6" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/mime-db": { "version": "1.48.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", @@ -5775,6 +5828,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5788,6 +5842,14 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, + "node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -5846,27 +5908,20 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/mocha/node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.3.1" } }, - "node_modules/mocha/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, "engines": { "node": ">=10" }, @@ -5927,21 +5982,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/mocha/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mocha/node_modules/minimatch": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", @@ -5969,45 +6009,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/mocha/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -6037,24 +6038,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "node_modules/multimatch": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", - "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", - "dependencies": { - "@types/minimatch": "^3.0.3", - "array-differ": "^3.0.0", - "array-union": "^2.1.0", - "arrify": "^2.0.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -6079,12 +6062,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, "node_modules/natural-orderby": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-2.0.3.tgz", @@ -6095,12 +6072,11 @@ } }, "node_modules/needle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.0.0.tgz", - "integrity": "sha512-eGr0qnfHxAjr+Eptl1zr2lgUQUPC1SZfTkg2kFi0kxr1ChJonHUVYobkug8siBKMlyUVVp56MSkp6CSeXH/jgw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "dependencies": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", + "iconv-lite": "^0.6.3", "sax": "^1.2.4" }, "bin": { @@ -6110,21 +6086,15 @@ "node": ">= 4.4.x" } }, - "node_modules/needle/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "dev": true, + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, "node_modules/nice-try": { @@ -6191,9 +6161,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6218,14 +6188,14 @@ } }, "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, "engines": { @@ -6235,15 +6205,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -6252,22 +6223,42 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, "dependencies": { - "ee-first": "1.1.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "dependencies": { "wrappy": "1" } @@ -6303,17 +6294,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -6492,48 +6483,40 @@ } }, "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "p-try": "^1.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "dependencies": { - "p-limit": "^1.1.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=4" - } - }, - "node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dependencies": { - "aggregate-error": "^3.0.0" + "node": ">=10" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true }, "node_modules/parent-module": { "version": "1.0.1", @@ -6556,15 +6539,6 @@ "@types/node": "*" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/password-prompt": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.2.tgz", @@ -6664,6 +6638,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -6683,6 +6658,37 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/path-to-regexp": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", @@ -6723,6 +6729,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "engines": { "node": ">=8.6" }, @@ -6886,6 +6893,15 @@ "servie": "^4.0.0" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -6928,18 +6944,10 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/psl": { "version": "1.9.0", @@ -6958,39 +6966,19 @@ } }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" } }, - "node_modules/qs": { - "version": "6.9.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", - "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", - "dev": true, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -7037,30 +7025,6 @@ "integrity": "sha1-Z0yZdgkBw8QRJ3GjHlIdw0nMCew=", "dev": true }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", - "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", - "dev": true, - "dependencies": { - "bytes": "3.1.1", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -7103,23 +7067,24 @@ "esprima": "~4.0.0" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/remove-trailing-slash": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz", - "integrity": "sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA==" - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -7130,12 +7095,12 @@ } }, "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -7155,6 +7120,15 @@ "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -7172,6 +7146,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -7183,10 +7158,30 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "dependencies": { - "glob": "^7.1.3" + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": "*" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -7205,6 +7200,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -7224,9 +7220,9 @@ } }, "node_modules/rxjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", - "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dependencies": { "tslib": "^2.1.0" } @@ -7236,6 +7232,30 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -7256,6 +7276,23 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -7279,17 +7316,14 @@ } }, "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -7297,61 +7331,6 @@ "node": ">=10" } }, - "node_modules/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/sentry-testkit": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/sentry-testkit/-/sentry-testkit-3.3.7.tgz", - "integrity": "sha512-ZKDQS/IPAK7NwDOuT6gDMdextoMyCeOFIO1kBcdfqemQov5UXZkn92ylLs/MFEf47v+M6vbwgGCsepb2jUf0YQ==", - "dev": true, - "dependencies": { - "body-parser": "^1.19.0", - "express": "^4.17.1" - } - }, "node_modules/serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -7361,21 +7340,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", - "dev": true, - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/servie": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/servie/-/servie-4.3.3.tgz", @@ -7387,18 +7351,44 @@ "ts-expect": "^1.1.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", "dev": true }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -7421,14 +7411,18 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7509,13 +7503,68 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "node_modules/stdin-discarder": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", + "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", "dev": true, + "dependencies": { + "bl": "^5.0.0" + }, "engines": { - "node": ">= 0.6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stdin-discarder/node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/stdin-discarder/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/stdin-discarder/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/stoppable": { @@ -7544,9 +7593,9 @@ "dev": true }, "node_modules/string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "engines": { "node": ">=0.6.19" } @@ -7565,27 +7614,50 @@ "node": ">=8" } }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7606,7 +7678,7 @@ "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "engines": { "node": ">=4" @@ -7681,6 +7753,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/tar-fs": { "version": "1.16.3", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", @@ -7759,6 +7840,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -7766,15 +7848,6 @@ "node": ">=8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, "node_modules/tough-cookie": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", @@ -7816,6 +7889,18 @@ "node": ">=0.6" } }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/ts-expect": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-expect/-/ts-expect-1.3.0.tgz", @@ -7875,13 +7960,13 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", - "json5": "^1.0.1", + "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } @@ -7889,22 +7974,8 @@ "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true }, "node_modules/tunnel-agent": { "version": "0.6.0", @@ -7939,17 +8010,89 @@ "node": ">=4" } }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/typedarray-to-buffer": { @@ -7962,33 +8105,39 @@ } }, "node_modules/typescript": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", - "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -7998,15 +8147,6 @@ "node": ">= 4.0.0" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/unzipper": { "version": "0.10.11", "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", @@ -8034,35 +8174,12 @@ "punycode": "^2.1.0" } }, - "node_modules/url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -8071,12 +8188,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", @@ -8091,15 +8202,6 @@ "builtins": "^1.0.3" } }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/vscode-jsonrpc": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz", @@ -8150,9 +8252,9 @@ } }, "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", - "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==" + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.10.tgz", + "integrity": "sha512-dPA6WqtAQJ/Iopm0Hrj11VvaKxsEcm62jpqyaYbY0xuvUffeWAn77f3VKr2SCsJphSyEw4Fjkjqm2gQ24KQfrA==" }, "node_modules/vscode-languageserver-types": { "version": "3.17.3", @@ -8251,6 +8353,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", @@ -8263,15 +8384,6 @@ "node": ">=8" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", @@ -8331,7 +8443,8 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "node_modules/write-file-atomic": { "version": "3.0.3", @@ -8382,17 +8495,24 @@ "yalc": "src/yalc.js" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "node_modules/yalc/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "engines": { - "node": ">= 6" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/yargs": { @@ -8472,6 +8592,12 @@ } }, "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, "@amplitude/ampli": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/@amplitude/ampli/-/ampli-1.29.0.tgz", @@ -8531,6 +8657,64 @@ "vue-parser": "^1.1.6" }, "dependencies": { + "@phenomnomnominal/tsquery": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-3.0.0.tgz", + "integrity": "sha512-SW8lKitBHWJ9fAYkJ9kJivuctwNYCh3BUxLdH0+XiR1GPBiu+7qiZzh8p8jqlj1LgVC1TbvfNFroaEsmYlL8Iw==", + "dev": true, + "requires": { + "esquery": "^1.0.1" + } + }, + "@sentry/core": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.19.7.tgz", + "integrity": "sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==", + "dev": true, + "requires": { + "@sentry/hub": "6.19.7", + "@sentry/minimal": "6.19.7", + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "tslib": "^1.9.3" + } + }, + "@sentry/node": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-6.19.7.tgz", + "integrity": "sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg==", + "dev": true, + "requires": { + "@sentry/core": "6.19.7", + "@sentry/hub": "6.19.7", + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + } + }, + "@sentry/utils": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.19.7.tgz", + "integrity": "sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==", + "dev": true, + "requires": { + "@sentry/types": "6.19.7", + "tslib": "^1.9.3" + } + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -8542,6 +8726,20 @@ "supports-color": "^5.3.0" } }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "globby": { "version": "10.0.2", "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", @@ -8590,23 +8788,67 @@ } } }, - "@amplitude/evaluation-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@amplitude/evaluation-js/-/evaluation-js-1.0.0.tgz", - "integrity": "sha512-U2ibGJ+5XLwfyHPmwDdxkqWhxxmZBs/gnPWalKBnmcY4zGXfBi2XkGbHsghlAD3XD3vZ1eMl7xqhHp3CWtpp/g==" + "@amplitude/analytics-core": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-1.2.5.tgz", + "integrity": "sha512-V7CVlHVN+1diKiOpdp2bCPZ0mbS4CmUYF+v+eXDwVfJL3M/t3sVcT1apXnmVYGYi14cGu9hQOD11rD6qKbUOsw==", + "requires": { + "@amplitude/analytics-types": "^1.3.4", + "tslib": "^2.4.1" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + } + } + }, + "@amplitude/analytics-node": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-node/-/analytics-node-1.3.5.tgz", + "integrity": "sha512-PVdCs3duu4OQNIQ3ENCKdm6wnoMAOdpSZD3tpWbEQVKh08FlxWLrR8eQN48nvhs+i6yEwGGVr1SfRDPpsMog1w==", + "requires": { + "@amplitude/analytics-core": "^1.2.5", + "@amplitude/analytics-types": "^1.3.4", + "tslib": "^2.4.1" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + } + } + }, + "@amplitude/analytics-types": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-1.3.4.tgz", + "integrity": "sha512-tR70gzqFkEzX9QpxvWYMfLCledT7vMhgd3d4/bkp3nnGXTOORaVUOCcSgOyxyuFdSx84T61aP/eZPKIcZcaP+A==" + }, + "@amplitude/experiment-core": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@amplitude/experiment-core/-/experiment-core-0.7.2.tgz", + "integrity": "sha512-Wc2NWvgQ+bLJLeF0A9wBSPIaw0XuqqgkPKsoNFQrmS7r5Djd56um75In05tqmVntPJZRvGKU46pAp8o5tdf4mA==", + "requires": { + "js-base64": "^3.7.5" + } }, "@amplitude/experiment-node-server": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@amplitude/experiment-node-server/-/experiment-node-server-1.3.0.tgz", - "integrity": "sha512-ahkN1H+9nHteqVaktitzjs43UTUJ0iwVplz0Brm6XKd7wT/w7ICbyPjvfPepqu6l71j5065DhVA7g1hdufkP/Q==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@amplitude/experiment-node-server/-/experiment-node-server-1.8.2.tgz", + "integrity": "sha512-R1+eDUb/Syn70f+TbFUF4/+Mg8aCBRx4mvAIB7JE0ICCrYpb351hAF7wnLKAZcScY0cKJ45/JF517WW757JwmA==", "requires": { - "@amplitude/evaluation-js": "1.0.0" + "@amplitude/analytics-node": "^1.3.4", + "@amplitude/analytics-types": "^1.3.1", + "@amplitude/experiment-core": "^0.7.2" } }, "@amplitude/identify": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/@amplitude/identify/-/identify-1.10.2.tgz", "integrity": "sha512-ywxeabS8ukMdJWNwx3rG/EBngXFg/4NsPhlyAxbBUcI7HzBXEJUKepiZfkz8K6Y7f0mpc23Qz1aBf48ZJDZmkQ==", + "dev": true, "requires": { "@amplitude/types": "^1.10.2", "@amplitude/utils": "^1.10.2", @@ -8616,7 +8858,8 @@ "tslib": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true } } }, @@ -8624,6 +8867,7 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/@amplitude/node/-/node-1.10.2.tgz", "integrity": "sha512-E3xp8DOpkF5ThjrRlAmSocnrEYsTPpd3Zg4WdBLms0ackQSgQpw6z84+YMcoPerZHJJ/LEqdo4Cg4Z5Za3D+3Q==", + "dev": true, "requires": { "@amplitude/identify": "^1.10.2", "@amplitude/types": "^1.10.2", @@ -8634,19 +8878,22 @@ "tslib": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true } } }, "@amplitude/types": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/@amplitude/types/-/types-1.10.2.tgz", - "integrity": "sha512-I8qenRI7uU6wKNb9LiZrAosSHVoNHziXouKY81CrqxH9xhVTEIJFXeuCV0hbtBr0Al/8ejnGjQRx+S2SvU/pPg==" + "integrity": "sha512-I8qenRI7uU6wKNb9LiZrAosSHVoNHziXouKY81CrqxH9xhVTEIJFXeuCV0hbtBr0Al/8ejnGjQRx+S2SvU/pPg==", + "dev": true }, "@amplitude/utils": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/@amplitude/utils/-/utils-1.10.2.tgz", "integrity": "sha512-tVsHXu61jITEtRjB7NugQ5cVDd4QDzne8T3ifmZye7TiJeUfVRvqe44gDtf55A+7VqhDhyEIIXTA1iVcDGqlEw==", + "dev": true, "requires": { "@amplitude/types": "^1.10.2", "tslib": "^2.0.0" @@ -8655,16 +8902,17 @@ "tslib": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true } } }, "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "requires": { - "@babel/highlight": "^7.22.13", + "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" }, "dependencies": { @@ -8681,11 +8929,11 @@ } }, "@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "requires": { - "@babel/types": "^7.23.0", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -8722,9 +8970,9 @@ } }, "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==" }, "@babel/helper-validator-identifier": { "version": "7.22.20", @@ -8732,9 +8980,9 @@ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "requires": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -8754,9 +9002,9 @@ } }, "@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", + "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==" }, "@babel/template": { "version": "7.22.15", @@ -8769,19 +9017,19 @@ } }, "@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", + "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9", + "debug": "^4.3.1", "globals": "^11.1.0" }, "dependencies": { @@ -8793,11 +9041,11 @@ } }, "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", "requires": { - "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } @@ -8822,20 +9070,35 @@ "resolved": "https://registry.npmjs.org/@deepcode/dcignore/-/dcignore-1.0.4.tgz", "integrity": "sha512-gsLh2FJ43Mz3kA6aqMq3BOUCMS5ub8pJZOpRgrZ1h0f/rkzphriUGLnC37+Jn86CFckxWlwHk/q28tyf0g4NBw==" }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true + }, "@eslint/eslintrc": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", - "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.1", - "globals": "^13.9.0", + "espree": "^9.6.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "dependencies": { @@ -8856,104 +9119,54 @@ } } }, + "@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true + }, "@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" } }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true }, - "@itly/plugin-amplitude-node": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@itly/plugin-amplitude-node/-/plugin-amplitude-node-2.5.0.tgz", - "integrity": "sha512-STWJgTLykMPW8uUtix0qlrX96E+aICN6IDA/gdbxsGaT2Ul30zrSVH+CEsrB6vttOdAIER3ukV7nKB+QRP173g==", - "requires": { - "@amplitude/identify": "^1.8.4", - "@amplitude/node": "^1.8.4" - } - }, - "@itly/plugin-schema-validator": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@itly/plugin-schema-validator/-/plugin-schema-validator-2.4.0.tgz", - "integrity": "sha512-qh1q4cMp0tPmHRMAJzKe2Fmh21a4cekyCtxVEzXJrjuwZzo6JxA1SAgt9dZKugZzsx209VFp2tJRoJ9kIeI8bw==", - "requires": { - "jsonschema": "^1.4.0", - "url": "^0.11.0" - } - }, - "@itly/plugin-segment-node": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@itly/plugin-segment-node/-/plugin-segment-node-2.4.0.tgz", - "integrity": "sha512-22ZMkofNy96DJv8FQ20bLf5s/A+IC8nkyT4kCVgDkn3uM5z86BUcpMSfWVijRpIeIUp2hZekpXrUVUcoFv/C9g==", - "requires": { - "@types/analytics-node": "^3.1.4", - "analytics-node": "^3.4.0-beta.3" - }, - "dependencies": { - "analytics-node": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/analytics-node/-/analytics-node-3.5.0.tgz", - "integrity": "sha512-XgQq6ejZHCehUSnZS4V7QJPLIP7S9OAWwQDYl4WTLtsRvc5fCxIwzK/yihzmIW51v9PnyBmrl9dMcqvwfOE8WA==", - "requires": { - "@segment/loosely-validate-event": "^2.0.0", - "axios": "^0.21.1", - "axios-retry": "^3.0.2", - "lodash.isstring": "^4.0.1", - "md5": "^2.2.1", - "ms": "^2.0.0", - "remove-trailing-slash": "^0.1.0", - "uuid": "^3.2.1" - } - }, - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "requires": { - "follow-redirects": "^1.14.0" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - } - } - }, - "@itly/sdk": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@itly/sdk/-/sdk-2.4.0.tgz", - "integrity": "sha512-EnJii6kCCNVgjRmDEzGi+E5CnSkqHvTiUGMyyt2CuzFjp0ipULP5VRNi42mRzGYF02qbYUiBhAXcJtPbm3wX7A==" + "@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true }, "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "requires": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" } }, "@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" }, "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" }, "@jridgewell/sourcemap-codec": { "version": "1.4.15", @@ -8961,34 +9174,37 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "requires": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@nodelib/fs.scandir": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", - "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.4", + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", - "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", - "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.4", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, @@ -9476,152 +9692,47 @@ "supports-color": "^5.3.0" } }, - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true - } - } - }, - "@oclif/screen": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-1.0.4.tgz", - "integrity": "sha512-60CHpq+eqnTxLZQ4PGHYNwUX572hgpMHGPtTWMjdTMsAvlm69lZV/4ly6O3sAYkomo4NggGcomrDpBe34rxUqw==", - "dev": true - }, - "@phenomnomnominal/tsquery": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-3.0.0.tgz", - "integrity": "sha512-SW8lKitBHWJ9fAYkJ9kJivuctwNYCh3BUxLdH0+XiR1GPBiu+7qiZzh8p8jqlj1LgVC1TbvfNFroaEsmYlL8Iw==", - "dev": true, - "requires": { - "esquery": "^1.0.1" - } - }, - "@segment/loosely-validate-event": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz", - "integrity": "sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==", - "requires": { - "component-type": "^1.2.1", - "join-component": "^1.1.0" - } - }, - "@sentry/core": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.16.1.tgz", - "integrity": "sha512-UFI0264CPUc5cR1zJH+S2UPOANpm6dLJOnsvnIGTjsrwzR0h8Hdl6rC2R/GPq+WNbnipo9hkiIwDlqbqvIU5vw==", - "requires": { - "@sentry/hub": "6.16.1", - "@sentry/minimal": "6.16.1", - "@sentry/types": "6.16.1", - "@sentry/utils": "6.16.1", - "tslib": "^1.9.3" - } - }, - "@sentry/hub": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.16.1.tgz", - "integrity": "sha512-4PGtg6AfpqMkreTpL7ymDeQ/U1uXv03bKUuFdtsSTn/FRf9TLS4JB0KuTZCxfp1IRgAA+iFg6B784dDkT8R9eg==", - "requires": { - "@sentry/types": "6.16.1", - "@sentry/utils": "6.16.1", - "tslib": "^1.9.3" - } - }, - "@sentry/minimal": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.16.1.tgz", - "integrity": "sha512-dq+mI1EQIvUM+zJtGCVgH3/B3Sbx4hKlGf2Usovm9KoqWYA+QpfVBholYDe/H2RXgO7LFEefDLvOdHDkqeJoyA==", - "requires": { - "@sentry/hub": "6.16.1", - "@sentry/types": "6.16.1", - "tslib": "^1.9.3" - } - }, - "@sentry/node": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-6.16.1.tgz", - "integrity": "sha512-SeDDoug2kUxeF1D7JGPa3h5EXxKtmA01mITBPYx5xbJ0sMksnv5I5bC1SJ8arRRzq6+W1C4IEeDBQtrVCk6ixA==", - "requires": { - "@sentry/core": "6.16.1", - "@sentry/hub": "6.16.1", - "@sentry/tracing": "6.16.1", - "@sentry/types": "6.16.1", - "@sentry/utils": "6.16.1", - "cookie": "^0.4.1", - "https-proxy-agent": "^5.0.0", - "lru_map": "^0.3.3", - "tslib": "^1.9.3" - }, - "dependencies": { - "@sentry/tracing": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.16.1.tgz", - "integrity": "sha512-MPSbqXX59P+OEeST+U2V/8Hu/8QjpTUxTNeNyTHWIbbchdcMMjDbXTS3etCgajZR6Ro+DHElOz5cdSxH6IBGlA==", + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, "requires": { - "@sentry/hub": "6.16.1", - "@sentry/minimal": "6.16.1", - "@sentry/types": "6.16.1", - "@sentry/utils": "6.16.1", - "tslib": "^1.9.3" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true } } }, - "@sentry/tracing": { + "@oclif/screen": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-1.0.4.tgz", + "integrity": "sha512-60CHpq+eqnTxLZQ4PGHYNwUX572hgpMHGPtTWMjdTMsAvlm69lZV/4ly6O3sAYkomo4NggGcomrDpBe34rxUqw==", + "dev": true + }, + "@sentry/hub": { "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.19.7.tgz", - "integrity": "sha512-ol4TupNnv9Zd+bZei7B6Ygnr9N3Gp1PUrNI761QSlHtPC25xXC5ssSD3GMhBgyQrcvpuRcCFHVNNM97tN5cZiA==", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.19.7.tgz", + "integrity": "sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==", + "dev": true, "requires": { - "@sentry/hub": "6.19.7", - "@sentry/minimal": "6.19.7", "@sentry/types": "6.19.7", "@sentry/utils": "6.19.7", "tslib": "^1.9.3" }, "dependencies": { - "@sentry/hub": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.19.7.tgz", - "integrity": "sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==", - "requires": { - "@sentry/types": "6.19.7", - "@sentry/utils": "6.19.7", - "tslib": "^1.9.3" - } - }, - "@sentry/minimal": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.19.7.tgz", - "integrity": "sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==", - "requires": { - "@sentry/hub": "6.19.7", - "@sentry/types": "6.19.7", - "tslib": "^1.9.3" - } - }, - "@sentry/types": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.19.7.tgz", - "integrity": "sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==" - }, "@sentry/utils": { "version": "6.19.7", "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.19.7.tgz", "integrity": "sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==", + "dev": true, "requires": { "@sentry/types": "6.19.7", "tslib": "^1.9.3" @@ -9629,20 +9740,23 @@ } } }, - "@sentry/types": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.16.1.tgz", - "integrity": "sha512-Wh354g30UsJ5kYJbercektGX4ZMc9MHU++1NjeN2bTMnbofEcpUDWIiKeulZEY65IC1iU+1zRQQgtYO+/hgCUQ==" - }, - "@sentry/utils": { - "version": "6.16.1", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.16.1.tgz", - "integrity": "sha512-7ngq/i4R8JZitJo9Sl8PDnjSbDehOxgr1vsoMmerIsyRZ651C/8B+jVkMhaAPgSdyJ0AlE3O7DKKTP1FXFw9qw==", + "@sentry/minimal": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.19.7.tgz", + "integrity": "sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==", + "dev": true, "requires": { - "@sentry/types": "6.16.1", + "@sentry/hub": "6.19.7", + "@sentry/types": "6.19.7", "tslib": "^1.9.3" } }, + "@sentry/types": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.19.7.tgz", + "integrity": "sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==", + "dev": true + }, "@servie/events": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@servie/events/-/events-1.0.0.tgz", @@ -9684,30 +9798,6 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, - "@snyk/code-client": { - "version": "4.12.4", - "resolved": "https://registry.npmjs.org/@snyk/code-client/-/code-client-4.12.4.tgz", - "integrity": "sha512-K2k8J761iJfKxWI026ZAWw15Xaw3Vff4Wmy9SPx5QR3aU6qrHn1d872v+9B8nnrHfbgJbU45t/iLzCv/fiotNg==", - "requires": { - "@deepcode/dcignore": "^1.0.4", - "@types/flat-cache": "^2.0.0", - "@types/lodash.omit": "^4.5.6", - "@types/lodash.pick": "^4.4.6", - "@types/lodash.union": "^4.6.6", - "@types/sarif": "^2.1.4", - "@types/uuid": "^8.3.1", - "fast-glob": "^3.2.11", - "ignore": "^5.1.8", - "lodash.omit": "^4.5.0", - "lodash.pick": "^4.4.0", - "lodash.union": "^4.6.0", - "multimatch": "^5.0.0", - "needle": "~3.0.0", - "p-map": "^3.0.0", - "uuid": "^8.3.2", - "yaml": "^1.10.2" - } - }, "@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -9737,11 +9827,6 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, - "@types/analytics-node": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/analytics-node/-/analytics-node-3.1.4.tgz", - "integrity": "sha512-i6cqjFotMq1dEwXxyXRqnzp/HmWPCskptrVUQ1UzRIGs/zICFWM2bIJyLt6f9A9/+qE98wls1AHWPQ4WXYS0HA==" - }, "@types/babel__traverse": { "version": "7.14.2", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", @@ -9757,6 +9842,12 @@ "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", "dev": true }, + "@types/diff": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.0.9.tgz", + "integrity": "sha512-RWVEhh/zGXpAVF/ZChwNnv7r4rvqzJ7lYNSmZSVTxjV0PBLf6Qu7RNg+SUtkpzxmiNkjCx0Xn2tPp7FIkshJwQ==", + "dev": true + }, "@types/find-package-json": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@types/find-package-json/-/find-package-json-1.2.2.tgz", @@ -9766,21 +9857,30 @@ "@types/node": "*" } }, - "@types/flat-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/flat-cache/-/flat-cache-2.0.0.tgz", - "integrity": "sha512-fHeEsm9hvmZ+QHpw6Fkvf19KIhuqnYLU6vtWLjd5BsMd/qVi7iTkMioDZl0mQmfNRA1A6NwvhrSRNr9hGYZGww==" - }, "@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", "dev": true, "requires": { - "@types/minimatch": "*", + "@types/minimatch": "^5.1.2", "@types/node": "*" + }, + "dependencies": { + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + } } }, + "@types/he": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/he/-/he-1.2.3.tgz", + "integrity": "sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA==", + "dev": true + }, "@types/inquirer": { "version": "8.2.5", "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.2.5.tgz", @@ -9791,56 +9891,37 @@ } }, "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "@types/lodash": { - "version": "4.14.168", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz", - "integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==" - }, - "@types/lodash.omit": { - "version": "4.5.6", - "resolved": "https://registry.npmjs.org/@types/lodash.omit/-/lodash.omit-4.5.6.tgz", - "integrity": "sha512-KXPpOSNX2h0DAG2w7ajpk7TXvWF28ZHs5nJhOJyP0BQHkehgr948RVsToItMme6oi0XJkp19CbuNXkIX8FiBlQ==", - "requires": { - "@types/lodash": "*" - } - }, - "@types/lodash.pick": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@types/lodash.pick/-/lodash.pick-4.4.6.tgz", - "integrity": "sha512-u8bzA16qQ+8dY280z3aK7PoWb3fzX5ATJ0rJB6F+uqchOX2VYF02Aqa+8aYiHiHgPzQiITqCgeimlyKFy4OA6g==", - "requires": { - "@types/lodash": "*" - } + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", + "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==", + "dev": true }, - "@types/lodash.union": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.6.tgz", - "integrity": "sha512-Wu0ZEVNcyCz8eAn6TlUbYWZoGbH9E+iOHxAZbwUoCEXdUiy6qpcz5o44mMXViM4vlPLLCPlkAubEP1gokoSZaw==", + "@types/marked": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-6.0.0.tgz", + "integrity": "sha512-jmjpa4BwUsmhxcfsgUit/7A9KbrC48Q0q8KvnY107ogcjGgTFDlIL3RpihNpx2Mu1hM4mdFQjoVc4O6JoGKHsA==", + "dev": true, "requires": { - "@types/lodash": "*" + "marked": "*" } }, - "@types/marked": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-3.0.0.tgz", - "integrity": "sha512-vof90OIWT+Tzq3MBRXgV9fsH8PC3WZ4OQg9Qa04vOtP0TcyiNfl7BTonYCmTapHZ5lRZh6ihUYkAy7St1hmk/A==", - "dev": true - }, "@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==" + "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", + "dev": true }, "@types/mocha": { "version": "8.2.3", @@ -9858,15 +9939,13 @@ } }, "@types/node": { - "version": "14.14.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz", - "integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==", - "dev": true - }, - "@types/sarif": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.4.tgz", - "integrity": "sha512-4xKHMdg3foh3Va1fxTzY1qt8QVqmaJpGWsVvtjQrJBn+/bkig2pWFKJ4FPI2yLI4PAj0SUKiPO4Vd7ggYIMZjQ==" + "version": "18.19.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.26.tgz", + "integrity": "sha512-+wiMJsIwLOYCvUqSdKTrfkS8mpTp+MPINe6+Np4TAGFWWRWiBQ5kSq9nZGCSPkzx9mvT+uEukzpX4MOSCydcvw==", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } }, "@types/semver": { "version": "5.5.0", @@ -9899,9 +9978,10 @@ "dev": true }, "@types/uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==" + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true }, "@types/validate-npm-package-name": { "version": "3.0.3", @@ -9916,228 +9996,284 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", - "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz", + "integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/type-utils": "5.52.0", - "@typescript-eslint/utils": "5.52.0", + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/type-utils": "7.4.0", + "@typescript-eslint/utils": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "dependencies": { - "@typescript-eslint/scope-manager": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", - "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0" - } - }, - "@typescript-eslint/types": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", - "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", - "dev": true - }, - "@typescript-eslint/visitor-keys": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", - "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.52.0", - "eslint-visitor-keys": "^3.3.0" - } - } + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" } }, "@typescript-eslint/parser": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.16.0.tgz", - "integrity": "sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz", + "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.16.0", - "@typescript-eslint/types": "5.16.0", - "@typescript-eslint/typescript-estree": "5.16.0", - "debug": "^4.3.2" + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz", - "integrity": "sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz", + "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.16.0", - "@typescript-eslint/visitor-keys": "5.16.0" + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0" } }, "@typescript-eslint/type-utils": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", - "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz", + "integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/utils": "7.4.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/types": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz", + "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz", + "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.52.0", - "@typescript-eslint/utils": "5.52.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "dependencies": { - "@typescript-eslint/types": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", - "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", - "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "balanced-match": "^1.0.0" } }, - "@typescript-eslint/visitor-keys": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", - "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.52.0", - "eslint-visitor-keys": "^3.3.0" + "brace-expansion": "^2.0.1" } } } }, - "@typescript-eslint/types": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.16.0.tgz", - "integrity": "sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g==", - "dev": true + "@typescript-eslint/utils": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz", + "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "semver": "^7.5.4" + }, + "dependencies": { + "@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + } + } }, - "@typescript-eslint/typescript-estree": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz", - "integrity": "sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ==", + "@typescript-eslint/visitor-keys": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz", + "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.16.0", - "@typescript-eslint/visitor-keys": "5.16.0", - "debug": "^4.3.2", - "globby": "^11.0.4", - "is-glob": "^4.0.3", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "@typescript-eslint/types": "7.4.0", + "eslint-visitor-keys": "^3.4.1" } }, - "@typescript-eslint/utils": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", - "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "@vscode/test-electron": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.0.tgz", + "integrity": "sha512-yojuDFEjohx6Jb+x949JRNtSn6Wk2FAh4MldLE3ck9cfvCqzwxF32QsNy1T9Oe4oT+ZfFcg0uPUCajJzOmPlTA==", "dev": true, "requires": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/typescript-estree": "5.52.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.4", + "jszip": "^3.10.1", + "ora": "^7.0.1", + "semver": "^7.6.2" }, "dependencies": { - "@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true + }, + "cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "requires": { + "restore-cursor": "^4.0.0" + } + }, + "emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", "dev": true }, - "@typescript-eslint/scope-manager": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", - "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0" + "agent-base": "^7.0.2", + "debug": "4" } }, - "@typescript-eslint/types": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", - "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true + }, + "is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", "dev": true }, - "@typescript-eslint/typescript-estree": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", - "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "log-symbols": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", + "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", + "dev": true, + "requires": { + "chalk": "^5.0.0", + "is-unicode-supported": "^1.1.0" + } + }, + "ora": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz", + "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==", + "dev": true, + "requires": { + "chalk": "^5.3.0", + "cli-cursor": "^4.0.0", + "cli-spinners": "^2.9.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^1.3.0", + "log-symbols": "^5.1.0", + "stdin-discarder": "^0.1.0", + "string-width": "^6.1.0", + "strip-ansi": "^7.1.0" + } + }, + "restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "string-width": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz", + "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^10.2.1", + "strip-ansi": "^7.0.1" } }, - "@typescript-eslint/visitor-keys": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", - "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.52.0", - "eslint-visitor-keys": "^3.3.0" + "ansi-regex": "^6.0.1" } } } }, - "@typescript-eslint/visitor-keys": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz", - "integrity": "sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.16.0", - "eslint-visitor-keys": "^3.0.0" - } - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dev": true, - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true }, "acorn-jsx": { @@ -10161,22 +10297,6 @@ "debug": "4" } }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "dependencies": { - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" - } - } - }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -10189,36 +10309,6 @@ "uri-js": "^4.2.2" } }, - "analytics-node": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/analytics-node/-/analytics-node-4.0.1.tgz", - "integrity": "sha512-+zXOOTB+eTRW6R9+pfvPfk1dHraFJzhNnAyZiYJIDGOjHQgfk9qfqgoJX9MfR4qY0J/E1YJ3FBncrLGadTDW1A==", - "requires": { - "@segment/loosely-validate-event": "^2.0.0", - "axios": "^0.21.1", - "axios-retry": "^3.0.2", - "lodash.isstring": "^4.0.1", - "md5": "^2.2.1", - "ms": "^2.0.0", - "remove-trailing-slash": "^0.1.0", - "uuid": "^3.2.1" - }, - "dependencies": { - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "requires": { - "follow-redirects": "^1.14.0" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - } - } - }, "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -10293,34 +10383,35 @@ "sprintf-js": "~1.0.2" } }, - "array-differ": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", - "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==" - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true + "array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "requires": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + } }, "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" } }, "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true }, "array-uniq": { "version": "1.0.2", @@ -10328,21 +10419,59 @@ "integrity": "sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0=", "dev": true }, - "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" } }, - "arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + "arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + } }, "asynckit": { "version": "0.4.0", @@ -10355,13 +10484,23 @@ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, + "available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "requires": { + "possible-typed-array-names": "^1.0.0" + } + }, "axios": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", - "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "requires": { - "follow-redirects": "^1.14.9", - "form-data": "^4.0.0" + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" }, "dependencies": { "form-data": { @@ -10376,14 +10515,6 @@ } } }, - "axios-retry": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.1.9.tgz", - "integrity": "sha512-NFCoNIHq8lYkJa6ku4m+V1837TP6lCa7n79Iuf8/AqATAHYB0ISaAS1eyIenDOfHOLtym34W65Sjke2xjg2fsA==", - "requires": { - "is-retry-allowed": "^1.1.0" - } - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -10433,45 +10564,11 @@ "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", "dev": true }, - "body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", - "dev": true, - "requires": { - "bytes": "3.1.1", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.6", - "raw-body": "2.4.2", - "type-is": "~1.6.18" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -10481,6 +10578,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -10552,20 +10650,17 @@ "integrity": "sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==", "dev": true }, - "bytes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", - "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", - "dev": true - }, "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" } }, "callsites": { @@ -10650,11 +10745,6 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" - }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -10714,9 +10804,9 @@ } }, "cli-spinners": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz", - "integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true }, "cli-ux": { @@ -10860,15 +10950,11 @@ "delayed-stream": "~1.0.0" } }, - "component-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz", - "integrity": "sha1-ikeQFwAjjk/DIml3EjAibyS0Fak=" - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "concurrently": { "version": "7.0.0", @@ -10938,15 +11024,6 @@ } } }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "requires": { - "safe-buffer": "5.2.1" - } - }, "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -10956,12 +11033,7 @@ "cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", "dev": true }, "core-util-is": { @@ -10996,10 +11068,38 @@ "which": "^2.0.1" } }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + "data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } }, "date-fns": { "version": "2.28.0", @@ -11031,9 +11131,9 @@ "dev": true }, "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, "defaults": { @@ -11045,13 +11145,26 @@ "clone": "^1.0.2" } }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "requires": { - "object-keys": "^1.0.12" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" } }, "delayed-stream": { @@ -11059,18 +11172,6 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, "detect-indent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", @@ -11078,10 +11179,9 @@ "dev": true }, "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==" }, "dir-glob": { "version": "3.0.1", @@ -11165,10 +11265,10 @@ "readable-stream": "^2.0.2" } }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, "emoji-regex": { @@ -11177,12 +11277,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -11192,6 +11286,16 @@ "once": "^1.4.0" } }, + "enhanced-resolve": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, "entities": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", @@ -11213,31 +11317,101 @@ } }, "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz", + "integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.5", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + } + }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true + }, + "es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "requires": { + "es-errors": "^1.3.0" + } + }, + "es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + } + }, + "es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" } }, "es-to-primitive": { @@ -11257,58 +11431,55 @@ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz", - "integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.2.1", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "dependencies": { "argparse": { @@ -11323,22 +11494,6 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, "glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -11367,13 +11522,14 @@ "requires": {} }, "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, "requires": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" }, "dependencies": { "debug": { @@ -11388,26 +11544,27 @@ } }, "eslint-import-resolver-typescript": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.0.tgz", - "integrity": "sha512-MNHS3u5pebvROX4MjGP9coda589ZGfL1SqdxUV4kSrcclfDRWvNE2D+eljbnWVMvWDVRgT89nhscMHPKYGcObQ==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", "dev": true, "requires": { "debug": "^4.3.4", - "glob": "^7.2.0", - "is-glob": "^4.0.3", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" } }, "eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, "requires": { - "debug": "^3.2.7", - "find-up": "^2.1.0" + "debug": "^3.2.7" }, "dependencies": { "debug": { @@ -11422,33 +11579,37 @@ } }, "eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", - "has": "^1.0.3", - "is-core-module": "^2.8.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", "is-glob": "^4.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "doctrine": { @@ -11460,10 +11621,10 @@ "esutils": "^2.0.2" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -11478,47 +11639,30 @@ } }, "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "requires": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } + "estraverse": "^5.2.0" } }, "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true }, "espree": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", - "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "requires": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.3.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" } }, "esprima": { @@ -11528,20 +11672,12 @@ "dev": true }, "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "requires": { "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } } }, "esrecurse": { @@ -11551,20 +11687,12 @@ "dev": true, "requires": { "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "esutils": { @@ -11573,73 +11701,6 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true - }, - "express": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", - "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", - "dev": true, - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.4.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.9.6", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", - "setprototypeof": "1.2.0", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - } - } - }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -11676,9 +11737,10 @@ "dev": true }, "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -11696,13 +11758,14 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "fastq": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, "requires": { "reusify": "^1.0.4" } @@ -11735,51 +11798,29 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "requires": { "to-regex-range": "^5.0.1" } }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true } } }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, "flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -11803,9 +11844,18 @@ "dev": true }, "follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } }, "form-data": { "version": "3.0.1", @@ -11818,18 +11868,6 @@ "mime-types": "^2.1.12" } }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -11871,6 +11909,20 @@ "rimraf": "2" }, "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -11883,15 +11935,27 @@ } }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true }, "get-caller-file": { @@ -11901,14 +11965,16 @@ "dev": true }, "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" } }, "get-port": { @@ -11918,51 +11984,79 @@ "dev": true }, "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + } + }, + "get-tsconfig": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" } }, "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "requires": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "requires": { "is-glob": "^4.0.1" } }, "globals": { - "version": "13.13.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", - "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "requires": { "type-fest": "^0.20.2" - }, - "dependencies": { - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } + } + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" } }, "globby": { @@ -11979,16 +12073,25 @@ "slash": "^3.0.0" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", "dev": true }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "graphql": { @@ -12025,19 +12128,10 @@ } } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true }, "has-flag": { @@ -12045,6 +12139,21 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -12052,19 +12161,27 @@ "dev": true }, "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "requires": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" + } + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" } }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, "htmlparser2": { "version": "7.2.0", @@ -12103,19 +12220,6 @@ } } }, - "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - } - }, "http-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", @@ -12145,6 +12249,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -12156,9 +12261,10 @@ "dev": true }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true }, "ignore-walk": { "version": "3.0.3", @@ -12169,6 +12275,12 @@ "minimatch": "^3.0.4" } }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true + }, "immutable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", @@ -12194,12 +12306,14 @@ "indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -12208,7 +12322,8 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "ini": { "version": "2.0.0", @@ -12294,13 +12409,13 @@ } }, "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "hasown": "^2.0.0", "side-channel": "^1.0.4" } }, @@ -12310,11 +12425,15 @@ "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", "dev": true }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true + "is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + } }, "is-arrayish": { "version": "0.2.1", @@ -12350,24 +12469,28 @@ "has-tostringtag": "^1.0.0" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true }, "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dev": true, "requires": { - "has": "^1.0.3" + "is-typed-array": "^1.1.13" } }, "is-date-object": { @@ -12387,7 +12510,8 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -12399,6 +12523,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -12410,20 +12535,21 @@ "dev": true }, "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "requires": { "has-tostringtag": "^1.0.0" @@ -12435,6 +12561,12 @@ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -12454,13 +12586,17 @@ "is-retry-allowed": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true }, "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "requires": { + "call-bind": "^1.0.7" + } }, "is-stream": { "version": "2.0.0", @@ -12486,6 +12622,15 @@ "has-symbols": "^1.0.2" } }, + "is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "requires": { + "which-typed-array": "^1.1.14" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -12527,10 +12672,10 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "join-component": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/join-component/-/join-component-1.1.0.tgz", - "integrity": "sha1-uEF7dQZho5K+4sJTfGiyqdSXfNU=" + "js-base64": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", + "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" }, "js-tokens": { "version": "4.0.0", @@ -12577,9 +12722,9 @@ "dev": true }, "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -12594,10 +12739,17 @@ "graceful-fs": "^4.1.6" } }, - "jsonschema": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.0.tgz", - "integrity": "sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==" + "jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } }, "just-extend": { "version": "4.2.1", @@ -12615,6 +12767,15 @@ "type-check": "~0.4.0" } }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } + }, "listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", @@ -12622,13 +12783,12 @@ "dev": true }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "^5.0.0" } }, "lodash": { @@ -12648,27 +12808,12 @@ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", "dev": true }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" - }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.omit": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", - "integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=" - }, - "lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" - }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -12688,11 +12833,6 @@ "lodash._reinterpolate": "^3.0.0" } }, - "lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" - }, "log-chopper": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-chopper/-/log-chopper-1.0.2.tgz", @@ -12715,15 +12855,8 @@ "lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=" - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true }, "make-dir": { "version": "3.1.0", @@ -12758,58 +12891,26 @@ } }, "marked": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz", - "integrity": "sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA==" - }, - "md5": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", - "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", - "requires": { - "charenc": "0.0.2", - "crypt": "0.0.2", - "is-buffer": "~1.1.6" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz", + "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==" }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, "micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, "requires": { "braces": "^3.0.2", "picomatch": "^2.3.1" } }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, "mime-db": { "version": "1.48.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", @@ -12833,6 +12934,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -12843,6 +12945,11 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, + "minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==" + }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -12887,22 +12994,18 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -12943,15 +13046,6 @@ "argparse": "^2.0.1" } }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, "minimatch": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", @@ -12978,30 +13072,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -13024,18 +13094,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "multimatch": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", - "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", - "requires": { - "@types/minimatch": "^3.0.3", - "array-differ": "^3.0.0", - "array-union": "^2.1.0", - "arrify": "^2.0.1", - "minimatch": "^3.0.4" - } - }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -13054,12 +13112,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, "natural-orderby": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-2.0.3.tgz", @@ -13067,31 +13119,24 @@ "dev": true }, "needle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.0.0.tgz", - "integrity": "sha512-eGr0qnfHxAjr+Eptl1zr2lgUQUPC1SZfTkg2kFi0kxr1ChJonHUVYobkug8siBKMlyUVVp56MSkp6CSeXH/jgw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", + "iconv-lite": "^0.6.3", "sax": "^1.2.4" }, "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "requires": { - "ms": "^2.1.1" + "safer-buffer": ">= 2.1.2 < 3.0.0" } } } }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "dev": true - }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -13150,9 +13195,9 @@ } }, "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true }, "object-keys": { @@ -13168,41 +13213,56 @@ "dev": true }, "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" } }, - "object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" } }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + } + }, + "object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, "requires": { - "ee-first": "1.1.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" } }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } @@ -13226,17 +13286,17 @@ } }, "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" } }, "ora": { @@ -13374,35 +13434,27 @@ "dev": true }, "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { - "p-try": "^1.0.0" + "yocto-queue": "^0.1.0" } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, "requires": { - "aggregate-error": "^3.0.0" + "p-limit": "^3.0.2" } }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, "parent-module": { @@ -13423,12 +13475,6 @@ "@types/node": "*" } }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true - }, "password-prompt": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.2.tgz", @@ -13505,7 +13551,8 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-key": { "version": "3.1.1", @@ -13519,6 +13566,27 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "requires": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==" + }, + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==" + } + } + }, "path-to-regexp": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", @@ -13557,7 +13625,8 @@ "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true }, "pkce-challenge": { "version": "2.2.0", @@ -13682,6 +13751,12 @@ "dev": true, "requires": {} }, + "possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -13709,15 +13784,10 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "psl": { "version": "1.9.0", @@ -13736,26 +13806,16 @@ } }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.9.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", - "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true }, "randombytes": { "version": "2.1.0", @@ -13784,24 +13844,6 @@ } } }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true - }, - "raw-body": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", - "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", - "dev": true, - "requires": { - "bytes": "3.1.1", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -13843,16 +13885,17 @@ "esprima": "~4.0.0" } }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "remove-trailing-slash": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz", - "integrity": "sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA==" + "regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + } }, "require-directory": { "version": "2.1.1", @@ -13861,12 +13904,12 @@ "dev": true }, "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "requires": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -13877,6 +13920,12 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -13890,7 +13939,8 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true }, "rimraf": { "version": "3.0.2", @@ -13899,6 +13949,22 @@ "dev": true, "requires": { "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } } }, "run-async": { @@ -13911,14 +13977,15 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "requires": { "queue-microtask": "^1.2.2" } }, "rxjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", - "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "requires": { "tslib": "^2.1.0" }, @@ -13930,12 +13997,43 @@ } } }, + "safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, + "safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -13953,73 +14051,14 @@ } }, "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" }, "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } - } - }, - "sentry-testkit": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/sentry-testkit/-/sentry-testkit-3.3.7.tgz", - "integrity": "sha512-ZKDQS/IPAK7NwDOuT6gDMdextoMyCeOFIO1kBcdfqemQov5UXZkn92ylLs/MFEf47v+M6vbwgGCsepb2jUf0YQ==", - "dev": true, - "requires": { - "body-parser": "^1.19.0", - "express": "^4.17.1" - } + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==" }, "serialize-javascript": { "version": "6.0.0", @@ -14030,18 +14069,6 @@ "randombytes": "^2.1.0" } }, - "serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.2" - } - }, "servie": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/servie/-/servie-4.3.3.tgz", @@ -14053,18 +14080,38 @@ "ts-expect": "^1.1.0" } }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, + "set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + } + }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", "dev": true }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -14081,14 +14128,15 @@ "dev": true }, "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" } }, "signal-exit": { @@ -14152,11 +14200,48 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true + "stdin-discarder": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", + "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", + "dev": true, + "requires": { + "bl": "^5.0.0" + }, + "dependencies": { + "bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } }, "stoppable": { "version": "1.1.0", @@ -14182,9 +14267,9 @@ } }, "string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==" + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==" }, "string-width": { "version": "4.2.2", @@ -14197,24 +14282,38 @@ "strip-ansi": "^6.0.0" } }, + "string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + } + }, "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" } }, "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" } }, "strip-ansi": { @@ -14229,7 +14328,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true }, "strip-json-comments": { @@ -14279,6 +14378,12 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, "tar-fs": { "version": "1.16.3", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", @@ -14348,16 +14453,11 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "requires": { "is-number": "^7.0.0" } }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true - }, "tough-cookie": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", @@ -14387,6 +14487,13 @@ "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", "dev": true }, + "ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "requires": {} + }, "ts-expect": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-expect/-/ts-expect-1.3.0.tgz", @@ -14423,13 +14530,13 @@ } }, "tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "requires": { "@types/json5": "^0.0.29", - "json5": "^1.0.1", + "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } @@ -14437,16 +14544,8 @@ "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true }, "tunnel-agent": { "version": "0.6.0", @@ -14472,14 +14571,62 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" } }, "typedarray-to-buffer": { @@ -14492,35 +14639,35 @@ } }, "typescript": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", - "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", "dev": true }, "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" } }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true - }, "unzipper": { "version": "0.10.11", "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", @@ -14548,45 +14695,17 @@ "punycode": "^2.1.0" } }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - } - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true - }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "v8-compile-cache-lib": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", @@ -14601,12 +14720,6 @@ "builtins": "^1.0.3" } }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, "vscode-jsonrpc": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz", @@ -14650,9 +14763,9 @@ } }, "vscode-languageserver-textdocument": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", - "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==" + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.10.tgz", + "integrity": "sha512-dPA6WqtAQJ/Iopm0Hrj11VvaKxsEcm62jpqyaYbY0xuvUffeWAn77f3VKr2SCsJphSyEw4Fjkjqm2gQ24KQfrA==" }, "vscode-languageserver-types": { "version": "3.17.3", @@ -14730,6 +14843,19 @@ "is-symbol": "^1.0.3" } }, + "which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + } + }, "widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", @@ -14739,12 +14865,6 @@ "string-width": "^4.0.0" } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, "workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", @@ -14791,7 +14911,8 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "write-file-atomic": { "version": "3.0.3", @@ -14831,18 +14952,24 @@ "ini": "^2.0.0", "npm-packlist": "^1.4.1", "yargs": "^16.1.1" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } } }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" - }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", diff --git a/package.json b/package.json index fb321914a..628aed4a3 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "snyk-vulnerability-scanner", "//": "Changing display name requires change in general.ts", - "displayName": "Snyk Security - Code, Open Source Dependencies, IaC Configurations", + "displayName": "Snyk Security", "version": "0.0.0", - "description": "Easily find and fix vulnerabilities in your code, open source dependencies, infrastructure as code configurations with fast and accurate scans.", + "description": "Easily find and fix issues in your code, open source dependencies, infrastructure as code configurations with fast and accurate scans.", "icon": "media/images/readme/snyk_extension_icon.png", "publisher": "snyk-security", "homepage": "https://snyk.io", @@ -53,70 +53,28 @@ "contributes": { "configuration": [ { - "title": "Snyk Security - Code and Open Source Dependencies", + "id": "snyk", + "title": "Snyk Security", + "properties": {} + }, + { + "id": "account", + "title": "Snyk Account", + "order": 1, "properties": { - "snyk.yesCrashReport": { - "//": "Name starts with y to put it at the end, as configs are sorted alphbetically", - "type": "boolean", - "default": true, - "markdownDescription": "Send error reports to Snyk", - "scope": "application" - }, - "snyk.yesTelemetry": { - "//": "Name starts with y to put it at the end, as configs are sorted alphbetically", - "type": "boolean", - "default": true, - "markdownDescription": "Send usage statistics to Snyk", - "scope": "application" - }, - "snyk.yesWelcomeNotification": { - "//": "Name starts with y to put it at the end, as configs are sorted alphbetically", - "type": "boolean", - "default": true, - "markdownDescription": "Show welcome notification after installation and restart", - "scope": "application" - }, - "snyk.yesBackgroundOssNotification": { - "//": "Name starts with y to put it at the end, as configs are sorted alphbetically", - "type": "boolean", - "default": true, - "markdownDescription": "Show scan notification for critical Open Source Security vulnerabilities when Snyk view is hidden", - "scope": "application" - }, - "snyk.advanced.autoScanOpenSourceSecurity": { - "type": "boolean", - "default": false, - "description": "Run Snyk Open Source Security vulnerability analysis in automatic mode.", - "scope": "application" - }, - "snyk.scanningMode": { + "snyk.advanced.authenticationMethod": { "type": "string", + "default": "OAuth2 authentication", + "description": "Specifies whether to authenticate with OAuth2 or with an API token. \n\nNote: OAuth2 authentication is recommended as it provides enhanced security.", "enum": [ - "auto", - "manual" + "OAuth2 authentication", + "Token authentication" ], "enumDescriptions": [ - "Scan automatically in the background.", - "Do not scan automatically, only scan when you run the `Snyk: Rescan` command." + "Uses the OAuth2 authentication", + "Uses the legacy Snyk Token authentication." ], - "default": "auto", - "title": "Snyk Code scanning mode", - "description": "Choose whether to run Snyk Code scans in the background, or only when you run the `Snyk: Rescan` command." - }, - "snyk.advanced.additionalParameters": { - "type": "string", - "description": "Parameters to pass to Snyk CLI for Open Source security tests.", - "scope": "window" - }, - "snyk.advanced.customEndpoint": { - "type": "string", - "markdownDescription": "Sets API endpoint to use for Snyk requests. Useful for custom Snyk setups. E.g. `https://app.eu.snyk.io/api`.", - "scope": "window" - }, - "snyk.advanced.organization": { - "type": "string", - "markdownDescription": "Specifies an organization slug name to run tests for that organization. \n\nNote: The slug name can be extracted from the URL of your organization in the Snyk UI: `https://app.snyk.io/org/[orgslugname]`. If not specified, preferred organization as defined in your [web account settings](https://app.snyk.io/account) is used to run tests.", - "scope": "window" + "markdownDescription": "Specifies whether to authenticate with OAuth2 or with an API token. \n\nNote: OAuth2 authentication is recommended as it provides enhanced security." }, "snyk.advanced.tokenStorage": { "type": "string", @@ -126,47 +84,61 @@ "default": "Always use VS Code's secret storage", "markdownDescription": "Snyk uses VS Code's [secret storage](https://code.visualstudio.com/api/references/vscode-api#SecretStorage) to safely persist API token instead of saving it in plaintext in `settings.json`. To set the token manually, run the VS Code command [Snyk: Set Token](command:snyk.setToken)." }, - "snyk.advanced.automaticDependencyManagement": { - "type": "boolean", - "default": true, - "scope": "machine", - "markdownDescription": "Snyk will download, install and update dependencies for you. If this option is disabled, make sure valid paths to the dependencies are provided." - }, - "snyk.advanced.cliPath": { + "snyk.advanced.customEndpoint": { "type": "string", - "scope": "machine", - "markdownDescription": "Sets path to Snyk CLI extension dependency." + "markdownDescription": "Sets API endpoint to use for Snyk requests. Useful for custom Snyk setups. E.g. `https://api.eu.snyk.io`.", + "scope": "window", + "pattern": "^(|(https?://)api.*.(snyk|snykgov).io)$" }, - "snyk.advanced.languageServerPath": { + "snyk.advanced.organization": { "type": "string", - "scope": "machine", - "markdownDescription": "Sets path to Snyk Language Server (requires restart)." + "markdownDescription": "Specifies an organization ID to run tests for that organization.\n\nRetrieve the organization ID from the organization settings in the Snyk UI: `https://app.snyk.io/org/[ORG_NAME]/manage/settings` and copy the ID from the **Organization ID** section.\n\nNote: If not specified, the preferred organization as defined in your [web account settings](https://app.snyk.io/account) is used to run tests.", + "scope": "window" }, + "snyk.yesCrashReport": { + "//": "Name starts with y to put it at the end, as configs are sorted alphbetically", + "type": "boolean", + "default": true, + "markdownDescription": "Send error reports to Snyk", + "scope": "application" + } + } + }, + { + "id": "scan", + "title": "Scan Configuration", + "order": 2, + "properties": { "snyk.features.openSourceSecurity": { + "order": 1, "type": "boolean", "title": "Snyk Open Source security issues", - "description": "Find and fix open source vulnerabilities.", + "description": "Find and fix open source dependency issues.", "default": true }, "snyk.features.codeSecurity": { + "order": 2, "type": "boolean", "title": "Snyk Code security issues", - "description": "Find and fix vulnerabilities in your application code in real time.", + "description": "Find and fix security issues in your application code in real time.", "default": true }, "snyk.features.codeQuality": { + "order": 3, "type": "boolean", "title": "Snyk Code quality issues", - "description": "Find and fix code quality issues in your application code in real time.", + "description": "Find and fix quality issues in your application code in real time.", "default": true }, "snyk.features.infrastructureAsCode": { + "order": 4, "type": "boolean", "title": "Snyk Infrastructure as Code issues", "description": "Find and fix your IaC misconfigurations.", "default": true }, "snyk.severity": { + "order": 5, "type": "object", "default": { "critical": true, @@ -196,25 +168,164 @@ "description": "Severity issues to display.", "scope": "window" }, - "snyk.trustedFolders": { + "snyk.allIssuesVsNetNewIssues": { + "type": "string", + "default": "All issues", + "description": "Specifies whether to see all issues or only net new issues. Net new issues option requires a Git repository, where it compares findings with those in the base branch.", + "enum": [ + "All issues", + "Net new issues" + ], + "enumDescriptions": [ + "Shows all issues that have been identified, including both new and existing issues.", + "Shows only new issues filtering out previously known issues in a base branch" + ], + "order": 6 + }, + "snyk.advanced.additionalParameters": { + "type": "string", + "description": "Parameters to pass to Snyk CLI for Open Source security tests.", + "scope": "window", + "order": 7 + } + } + }, + { + "id": "userExperience", + "title": "User Experience", + "order": 3, + "properties": { + "snyk.scanningMode": { + "order": 1, + "type": "string", + "enum": [ + "auto", + "manual" + ], + "enumDescriptions": [ + "Scan automatically in the background.", + "Do not scan automatically, only scan when you run the `Snyk: Rescan` command." + ], + "default": "auto", + "title": "Snyk Code scanning mode", + "description": "Choose whether to run Snyk Code scans in the background, or only when you run the `Snyk: Rescan` command." + }, + "snyk.advanced.autoScanOpenSourceSecurity": { + "order": 2, + "type": "boolean", + "default": false, + "description": "Run Snyk Open Source Security analysis in automatic mode.", + "scope": "application" + }, + "snyk.yesBackgroundOssNotification": { + "order": 3, + "//": "Name starts with y to put it at the end, as configs are sorted alphabetically", + "type": "boolean", + "default": true, + "markdownDescription": "Show scan notification for critical Open Source Security issues when Snyk view is hidden", + "scope": "application" + } + } + }, + { + "id": "experimental", + "title": "Experimental", + "order": 4, + "properties": { + "snyk.issueViewOptions": { + "order": 1, + "type": "object", + "default": { + "openIssues": true, + "ignoredIssues": true + }, + "properties": { + "openIssues": { + "type": "boolean", + "description": "Open Issues", + "default": true + }, + "ignoredIssues": { + "type": "boolean", + "description": "Ignored Issues", + "default": true + } + }, + "additionalProperties": false, + "markdownDescription": "Ignores settings is currently an experimental feature. Please reach out to [support.snyk.io](https://support.snyk.io) for more details.\n\nShow the following issues:", + "scope": "window" + }, + "snyk.folderConfigs": { + "order": 2, "type": "array", "default": [], - "description": "Folders to trust for Snyk scans." + "description": "Folder configuration for Snyk scans." }, "snyk.features.preview": { + "order": 3, "type": "object", "default": {}, "title": "Preview feature toggles", "description": "Preview features that are currently in development. Setting keys will be removed when features become stable.", "propertyNames": true, - "properties": { - "advisor": { - "type": "boolean", - "title": "Enable \"Snyk Advisor\"", - "description": "Discover the health (maintenance, community, popularity & security) status of your open source packages.", - "default": false - } - } + "properties": {} + } + } + }, + { + "id": "initialization", + "title": "Initialization", + "order": 5, + "properties": { + "snyk.yesWelcomeNotification": { + "//": "Name starts with y to put it at the end, as configs are sorted alphabetically", + "type": "boolean", + "default": true, + "markdownDescription": "Show welcome notification after installation and restart", + "scope": "application" + }, + "snyk.trustedFolders": { + "type": "array", + "default": [], + "description": "Folders to trust for Snyk scans." + } + } + }, + { + "id": "cli", + "title": "CLI & Language Server", + "order": 6, + "properties": { + "snyk.advanced.automaticDependencyManagement": { + "order": 1, + "type": "boolean", + "default": true, + "scope": "machine", + "markdownDescription": "Snyk will download, install and update dependencies for you. If this option is disabled, make sure valid paths to the dependencies are provided." + }, + "snyk.advanced.cliBaseDownloadUrl": { + "order": 2, + "type": "string", + "scope": "machine", + "default": "https://downloads.snyk.io", + "markdownDescription": "Base URL to download the CLI." + }, + "snyk.advanced.cliReleaseChannel": { + "order": 3, + "type": "string", + "default": "stable", + "enum": [ + "stable", + "rc", + "preview" + ], + "markdownDescription": "CLI release channel." + }, + "snyk.advanced.cliPath": { + "order": 4, + "type": "string", + "scope": "machine", + "markdownDescription": "Sets path to Snyk CLI extension dependency." } } } @@ -233,7 +344,7 @@ { "id": "snyk.views.welcome", "name": "Snyk", - "when": "!snyk:loggedIn || snyk:error || !snyk:workspaceFound" + "when": "!snyk:loggedIn || snyk:error || !snyk:workspaceFound || snyk:authenticationChanged" }, { "id": "snyk.views.analysis.oss", @@ -269,18 +380,23 @@ "viewsWelcome": [ { "view": "snyk.views.welcome", - "contents": "Snyk has encountered a problem. Please restart the extension: \n[Restart](command:snyk.start 'Restart Snyk')\nIf the error persists, please check your [settings](command:snyk.settings) and [contact us](https://snyk.io/contact-us/?utm_source=vsc)!", - "when": "snyk:error == 'blocking'" + "contents": "Snyk has encountered a problem. Please restart the extension: \n[Restart](command:snyk.start 'Restart Snyk')\nIf the error persists, please check your [settings](command:snyk.settings) and [contact us](https://snyk.io/contact-us/?utm_source=vsc).\n\n You can check the logs to see the exact error in [Snyk Security](command:snyk.showOutputChannel) and [Snyk Language Server](command:snyk.showLsOutputChannel) output channels.\n[Display Error](command:snyk.showErrorFromContext)\n", + "when": "snyk:error" }, { "view": "snyk.views.welcome", - "contents": "Welcome to Snyk for Visual Studio Code. 👋\n👉 Please wait, the extension is loading...", + "contents": "👋 Welcome to Snyk for Visual Studio Code.\n⏱️ Please wait, the extension is loading...", "when": "!snyk:error && !snyk:initialized" }, { "view": "snyk.views.welcome", - "contents": "Welcome to Snyk for Visual Studio Code. 👋\n👉 Connect with Snyk to start your first analysis!\nWhen scanning folder files, Snyk may automatically execute code such as invoking the package manager to get dependency information. You should only scan projects you trust. [More info](https://docs.snyk.io/ide-tools/visual-studio-code-extension/workspace-trust)\n[Trust workspace and connect](command:snyk.initiateLogin 'Connect with Snyk')\nBy connecting your account with Snyk, you agree to the Snyk [Privacy Policy](https://snyk.io/policies/privacy), and the Snyk [Terms of Service](https://snyk.io/policies/terms-of-service).", - "when": "!snyk:error && snyk:initialized && !snyk:loggedIn" + "contents": "👋 Let's secure your code! \nTo scan your project for issues, Snyk needs to:\n 1. Connect to your Snyk account: This allows us to securely analyse your code.\n2. Trust this workspace: This lets Snyk safely gather information about your project (like dependencies).\nYou should only scan projects you trust. [More info](https://docs.snyk.io/ide-tools/visual-studio-code-extension/workspace-trust)\nBy connecting your account with Snyk, you agree to the Snyk [Privacy Policy](https://snyk.io/policies/privacy), and the Snyk [Terms of Service](https://snyk.io/policies/terms-of-service).\n\n[Connect & Trust Workspace](command:snyk.initiateLogin 'Connect with Snyk')", + "when": "!snyk:error && snyk:initialized && !snyk:loggedIn && !snyk:authMethodChanged" + }, + { + "view": "snyk.views.welcome", + "contents": "⚠️ Your authentication method has changed.\n\n👉 Please re-authenticate to continue using Snyk\n\nBy connecting your account with Snyk, you agree to the Snyk [Privacy Policy](https://snyk.io/policies/privacy), and the Snyk [Terms of Service](https://snyk.io/policies/terms-of-service).\n\n[Connect & Trust Workspace](command:snyk.initiateLogin 'Re-authenticate')", + "when": "!snyk:error && snyk:initialized && !snyk:loggedIn && snyk:authMethodChanged" }, { "view": "snyk.views.welcome", @@ -301,12 +417,12 @@ "view/title": [ { "command": "snyk.start", - "when": "view == 'snyk.views.analysis.code.security' || view == 'snyk.views.analysis.code.quality' || view == 'snyk.views.analysis.oss' || view == 'snyk.views.analysis.configuration'", + "when": "view == 'snyk.views.analysis.code.security' || view == 'snyk.views.analysis.code.security.delta' || view == 'snyk.views.analysis.code.quality' || view == 'snyk.views.analysis.code.quality.delta' || view == 'snyk.views.analysis.oss' || view == 'snyk.views.analysis.configuration'", "group": "navigation" }, { "command": "snyk.settings", - "when": "view == 'snyk.views.analysis.code.security' || view == 'snyk.views.analysis.code.quality' || view == 'snyk.views.analysis.oss' || view == 'snyk.views.welcome' || view == 'snyk.views.analysis.configuration'", + "when": "view == 'snyk.views.analysis.code.security' || view == 'snyk.views.analysis.code.security.delta' || view == 'snyk.views.analysis.code.quality' || view == 'snyk.views.analysis.code.quality.delta' || view == 'snyk.views.analysis.oss' || view == 'snyk.views.welcome' || view == 'snyk.views.analysis.configuration'", "group": "navigation" } ], @@ -371,6 +487,11 @@ "command": "snyk.showLsOutputChannel", "title": "Show Language Server Output Channel", "category": "Snyk" + }, + { + "command": "snyk.clearPersistedCache", + "title": "Clear Persisted Cache", + "category": "Snyk" } ] }, @@ -390,68 +511,64 @@ "lint": "npx eslint \"src/**/*.ts\"", "lint:fix": "npx eslint --fix \"src/**/*.ts\"", "vscode:uninstall": "node ./out/uninstall", - "ampli:verify": "ampli status -u --skip-update-on-default-branch", "patch-preview": "node ./scripts/patchPreview.js" }, "devDependencies": { "@amplitude/ampli": "^1.29.0", - "@types/analytics-node": "^3.1.4", "@types/babel__traverse": "^7.12.2", + "@types/diff": "^5.0.9", "@types/find-package-json": "^1.2.2", - "@types/glob": "^7.1.3", - "@types/lodash": "^4.14.161", - "@types/marked": "^3.0.0", + "@types/glob": "^8.1.0", + "@types/he": "^1.2.3", + "@types/lodash": "^4.17.0", + "@types/marked": "^6.0.0", "@types/mocha": "^8.0.3", "@types/needle": "^2.5.2", - "@types/node": "^14.6.2", + "@types/node": "^18.19.26", "@types/sinon": "^10.0.2", "@types/uuid": "^8.3.0", "@types/validate-npm-package-name": "^3.0.3", "@types/vscode": "^1.58.0", - "@typescript-eslint/eslint-plugin": "^5.52.0", - "@typescript-eslint/parser": "^5.16.0", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.4.0", + "@vscode/test-electron": "^2.4.0", "concurrently": "^7.0.0", - "eslint": "^8.11.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^8.5.0", - "eslint-import-resolver-typescript": "^2.7.0", - "eslint-plugin-import": "^2.25.4", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-prettier": "^4.0.0", "mocha": "10.1.0", "prettier": "^2.6.1", "sass": "^1.48.0", - "sentry-testkit": "^3.3.7", "sinon": "^11.1.1", "ts-node": "^10.7.0", - "typescript": "^4.3.4", + "typescript": "^5.4.3", "vscode-test": "^1.4.0", "yalc": "^1.0.0-pre.44" }, "dependencies": { - "@amplitude/experiment-node-server": "^1.3.0", - "@babel/parser": "^7.12.11", - "@babel/traverse": "^7.12.12", - "@babel/types": "^7.12.12", - "@itly/plugin-amplitude-node": "^2.5.0", - "@itly/plugin-schema-validator": "^2.4.0", - "@itly/plugin-segment-node": "^2.4.0", - "@itly/sdk": "^2.3.1", - "@sentry/node": "^6.16.1", - "@sentry/tracing": "^6.19.7", - "@snyk/code-client": "^4.12.4", - "analytics-node": "^4.0.1", - "axios": "^0.27.2", - "glob": "^7.2.0", + "@amplitude/experiment-node-server": "^1.8.2", + "@babel/parser": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", + "@deepcode/dcignore": "^1.0.4", + "axios": "^1.7.8", + "diff": "^5.2.0", + "glob": "^9.3.5", + "he": "^1.2.0", "htmlparser2": "^7.2.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "lodash": "^4.17.21", - "marked": "^4.0.16", + "marked": "^11.2.0", + "needle": "^3.3.1", "open": "^7.4.2", - "rxjs": "^7.5.5", - "string-argv": "^0.3.1", + "rxjs": "^7.8.1", + "string-argv": "^0.3.2", "uuid": "^8.3.2", "validate-npm-package-name": "^3.0.0", "vscode-languageclient": "8.1.0", - "vscode-languageserver-textdocument": "^1.0.8" + "vscode-languageserver-textdocument": "^1.0.10" } } diff --git a/scripts/patchPreview.js b/scripts/patchPreview.js index f8c243f78..4b763fbab 100644 --- a/scripts/patchPreview.js +++ b/scripts/patchPreview.js @@ -27,7 +27,6 @@ fs.writeFileSync('./package.json', json); let snykConfigJson = require('../snyk.config.json'); snykConfigJson = JSON.stringify({ ...snykConfigJson, - segmentWriteKey: process.env.SNYK_VSCE_SEGMENT_WRITE_KEY, amplitudeExperimentApiKey: process.env.SNYK_VSCE_AMPLITUDE_EXPERIMENT_API_KEY, sentryKey: process.env.SNYK_VSCE_SENTRY_DSN_KEY, }); diff --git a/snyk.config.json b/snyk.config.json index 787a9ff4d..e2edd24ad 100644 --- a/snyk.config.json +++ b/snyk.config.json @@ -1,5 +1,4 @@ { - "segmentWriteKey": "${env.SNYK_VSCE_SEGMENT_WRITE_KEY}", "amplitudeExperimentApiKey": "${env.SNYK_VSCE_AMPLITUDE_EXPERIMENT_API_KEY}", "sentryKey": "${env.SNYK_VSCE_SENTRY_DSN_KEY}" } diff --git a/src/ampli/index.ts b/src/ampli/index.ts deleted file mode 100644 index 5fe2b2e1c..000000000 --- a/src/ampli/index.ts +++ /dev/null @@ -1,1280 +0,0 @@ -/** - * This file is auto-generated by Amplitude. - * To update run 'ampli pull visual-studio-code' - * - * Works with versions ^2.0.8 of @itly/sdk and @itly/plugin's - * https://www.npmjs.com/search?q=%40itly - */ - -/* tslint:disable */ -/* eslint-disable */ -import { - ItlyNode, - Options as OptionsBase, - Event as EventBase, - Plugin, - Environment as EnvironmentBase, - Properties as PropertiesBase, - ValidationResponse as ValidationResponseBase, - CallOptions as CallOptionsBase, - PluginCallOptions as PluginCallOptionsBase, -} from '@itly/sdk'; -import SchemaValidatorPlugin from '@itly/plugin-schema-validator'; - -export type Options = OptionsBase; -export type Environment = EnvironmentBase; -export type Event = EventBase; -export type Properties = PropertiesBase; -export type ValidationResponse = ValidationResponseBase; -export type CallOptions = CallOptionsBase; -export type PluginCallOptions = PluginCallOptionsBase; -export { Plugin, Validation, Loggers } from '@itly/sdk'; - -export interface AliasOptions extends CallOptions { -} - -export interface IdentifyOptions extends CallOptions { -} - -export interface GroupOptions extends CallOptions { -} - -export interface PageOptions extends CallOptions { -} - -export interface TrackOptions extends CallOptions { -} - -export interface IdentifyProperties { - /** - * when a User record is an actual user or when it’s a “service account” - */ - accountType?: "user" | "service" | "app-instance" | "automated-test-user"; - /** - * Link to access more information about the user - */ - adminLink?: string; - /** - * Company name as provided by the user in Appcues user profile survey - */ - appcuesCompanyName?: string; - /** - * First name as provided by the user in Appcues user profile survey - */ - appcuesFirstName?: string; - /** - * Job title as provided by the user in Appcues user profile survey - */ - appcuesJobTitle?: string; - /** - * Last name as provided by the user in Appcues user profile survey - */ - appcuesLastName?: string; - /** - * Current goal as provided by the user in Appcues user profile survey - */ - appcuesUserGoal?: string; - /** - * Work email as provided by the user in Appcues user profile survey - */ - appcuesWorkEmail?: string; - /** - * Auth provider (login method) - */ - authProvider?: string; - createdAt?: { - [k: string]: unknown; - }; - /** - * Email address for the user - */ - email?: string; - /** - * User's first name - */ - firstName?: string; - /** - * Whether or not the user has their first integration set up - */ - hasFirstIntegration?: boolean; - /** - * Whether or not the user has their first project imported - */ - hasFirstProject?: boolean; - /** - * Indicates whether user has a personal or business email address - */ - hasPersonalEmail?: boolean; - /** - * Is a user opted in to the new App UI navigation while still in beta (Oct 2022)? - */ - isAppUIBetaEnabled?: boolean; - /** - * Applies to non-user identities, such as Snyk Orgs - */ - isNonUser?: boolean; - /** - * Whether or not the user belongs to the Snyk org (determined by the email address ending with @snyk.io) - */ - isSnyk?: boolean; - /** - * Whether or not the user should be considered a Snyk administrator - */ - isSnykAdmin?: boolean; - /** - * User's last name - */ - lastName?: string; - /** - * An array of the ecosystems(eg: javascript, java, docker, kubernetes) that the user selects as their favorites on the snyk learn app. - */ - learnPreferredEcosystems?: string[]; - /** - * Used by Marketo to determine whether to send product updates emails to users. We are setting this value during product updates consent flow after registration. - */ - productUpdatesConsent?: boolean; - /** - * A trait for users who got redirected to `/product-updates` consent page. - * - * - * Will allow us to differentiate these users in Marketo and ensure they don't receive product updates emails without explicitly opting in. - */ - productUpdatesConsentIsDisplayed?: boolean; - /** - * Public ID of user - */ - user_id?: string; - /** - * Username of the user - */ - username?: string; - /** - * Query utmcampaign. All UTM properties must be in snake\_case. - */ - utm_campaign?: string; - /** - * Query utm\_content. All UTM properties must be in snake\_case. - */ - utm_content?: string; - /** - * Query utm\_medium. All UTM properties must be in snake\_case. - */ - utm_medium?: string; - /** - * Query utm\_source. All UTM properties must be in snake\_case. - */ - utm_source?: string; - /** - * Query utm\_term. All UTM properties must be in snake\_case. - */ - utm_term?: string; -} - -export interface GroupProperties { - "[Amplitude] Group ID"?: { - [k: string]: unknown; - }; - "[Amplitude] Group name"?: { - [k: string]: unknown; - }; - $set?: { - [k: string]: unknown; - }; - $unset?: { - [k: string]: unknown; - }; - "Account ARR"?: { - [k: string]: unknown; - }; - "Account Plan"?: { - [k: string]: unknown; - }; - "Billing Frequency"?: { - [k: string]: unknown; - }; - "Code Licenses"?: { - [k: string]: unknown; - }; - "Container Licenses"?: { - [k: string]: unknown; - }; - countFixesFirst30Days?: { - [k: string]: unknown; - }; - countFixesFirst7Days?: { - [k: string]: unknown; - }; - countFixesPast30Days?: { - [k: string]: unknown; - }; - countFixesPast7Days?: { - [k: string]: unknown; - }; - countFixesTotal?: { - [k: string]: unknown; - }; - currentEngagementState?: { - [k: string]: unknown; - }; - dateLastEngagementStateChange?: { - [k: string]: unknown; - }; - daysSinceLastEngagementStateChange?: { - [k: string]: unknown; - }; - "DB Feed Licenses"?: { - [k: string]: unknown; - }; - "Free Trial End Date"?: { - [k: string]: unknown; - }; - "Free Trial Start Date"?: { - [k: string]: unknown; - }; - /** - * ID that is used in conjunction with a groupType to specify an Org or a Group association: {groupId: 1234, groupType: "org"} - */ - groupId?: string; - /** - * The name of the group associated with the org - */ - groupName?: string; - /** - * Key that is used to specify the name of the Segment Group that a groupId is being set for. - */ - groupType?: "org" | "group" | "account"; - hasFixFirst30Days?: { - [k: string]: unknown; - }; - hasFixFirst7Days?: { - [k: string]: unknown; - }; - hasFixPast30Days?: { - [k: string]: unknown; - }; - hasFixPast7Days?: { - [k: string]: unknown; - }; - "IAC Licenses"?: { - [k: string]: unknown; - }; - id?: { - [k: string]: unknown; - }; - internalName?: { - [k: string]: unknown; - }; - isPassthrough?: { - [k: string]: unknown; - }; - name?: { - [k: string]: unknown; - }; - "Open Source Licenses"?: { - [k: string]: unknown; - }; - /** - * The plan of the org - */ - plan?: string; - priorEngagementState?: { - [k: string]: unknown; - }; - /** - * The types of projects in the org - */ - projectTypes?: string[]; -} - -export interface PageProperties { - /** - * Name of the ecosystem (npm|python|docker...) - */ - ecosystem?: string; - /** - * The name of the package - */ - package?: string; - /** - * cocoapods , composer , golang , hex , maven , npm , nuget , pip , rubygems - */ - packageManager?: string; - /** - * Package version, for example 18.0.1 - */ - packageVersion?: string; - /** - * The canonical path of the page - */ - path?: string; - /** - * The page that linked to this page. - */ - referrer?: string; - /** - * Query parameters in url. - */ - search?: string; - /** - * The page title. - */ - title?: string; - /** - * The url of the page. - */ - url?: string; - /** - * Used for page views on individual vulnerability pages - */ - vulnerabilityId?: string; -} - -export interface AnalysisIsReadyProperties { - /** - * Analysis types selected by the user for the scan: - * - * * open source vulnerabilities - * - * * code quality issues - * - * * code security vulnerabilities - * - * * advisor issues - * - * * infrastructure as code issues - * - * * container vulnerabilities - * - * | Rule | Value | - * |---|---| - * | Enum Values | Snyk Advisor, Snyk Code Quality, Snyk Code Security, Snyk Open Source, Snyk Container, Snyk Infrastructure as Code | - */ - analysisType: - | "Snyk Advisor" - | "Snyk Code Quality" - | "Snyk Code Security" - | "Snyk Open Source" - | "Snyk Container" - | "Snyk Infrastructure as Code"; - /** - * | Rule | Value | - * |---|---| - * | Type | number | - */ - durationInSeconds?: number; - /** - * | Rule | Value | - * |---|---| - * | Type | integer | - */ - fileCount?: number; - /** - * Ide family. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Visual Studio Code, Visual Studio, Eclipse, JetBrains, Other | - */ - ide: "Visual Studio Code" | "Visual Studio" | "Eclipse" | "JetBrains" | "Other"; - /** - * Operating system architecture - */ - osArch?: string; - /** - * Operating system platform - */ - osPlatform?: string; - /** - * | Rule | Value | - * |---|---| - * | Enum Values | Success, Error | - */ - result: "Success" | "Error"; - /** - * IDE plugin runtime name. - */ - runtimeName?: string; - /** - * IDE plugin runtime version. - * - * | Rule | Value | - * |---|---| - * | Min Length | 1 | - */ - runtimeVersion?: string; -} - -export interface AnalysisIsTriggeredProperties { - /** - * Analysis types selected by the user for the scan: open source vulnerabilities, code quality issues and/or code security vulnerabilities. - * - * | Rule | Value | - * |---|---| - * | Min Items | 1 | - * | Unique Items | true | - * | Item Type | string | - * - * @minItems 1 - */ - analysisType: [string, ...string[]]; - /** - * Ide family. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Visual Studio Code, Visual Studio, Eclipse, JetBrains, Other | - */ - ide: "Visual Studio Code" | "Visual Studio" | "Eclipse" | "JetBrains" | "Other"; - /** - * Operating system architecture - */ - osArch?: string; - /** - * Operating system platform - */ - osPlatform?: string; - /** - * IDE plugin runtime name. - */ - runtimeName?: string; - /** - * IDE plugin runtime version. - * - * | Rule | Value | - * |---|---| - * | Min Length | 1 | - */ - runtimeVersion?: string; - /** - * * True means that the analysis was triggered by the User. - * - * * False means that the analysis was triggered automatically by the plugin. - */ - triggeredByUser: boolean; -} - -export interface AuthenticateButtonIsClickedProperties { - /** - * Used to identify the source for multi-source events. - * - * For example, if a given event is shared between Snyk Advisor and Snyk Learn, this property helps to differentiate between the two. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Advisor, App, Learn, IDE, Website, CodeSnippets | - */ - eventSource?: "Advisor" | "App" | "Learn" | "IDE" | "Website" | "CodeSnippets"; - /** - * Ide family. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Visual Studio Code, Visual Studio, Eclipse, JetBrains, Other | - */ - ide: "Visual Studio Code" | "Visual Studio" | "Eclipse" | "JetBrains" | "Other"; - /** - * Operating system architecture - */ - osArch?: string; - /** - * Operating system platform - */ - osPlatform?: string; - /** - * IDE plugin runtime name. - */ - runtimeName?: string; - /** - * IDE plugin runtime version. - * - * | Rule | Value | - * |---|---| - * | Min Length | 1 | - */ - runtimeVersion?: string; -} - -export interface IssueHoverIsDisplayedProperties { - /** - * Ide family. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Visual Studio Code, Visual Studio, Eclipse, JetBrains, Other | - */ - ide: "Visual Studio Code" | "Visual Studio" | "Eclipse" | "JetBrains" | "Other"; - /** - * Issue ID as received from the backend. - */ - issueId?: string; - /** - * Issue type - * - * | Rule | Value | - * |---|---| - * | Enum Values | Advisor, Code Quality Issue, Code Security Vulnerability, Licence Issue, Open Source Vulnerability, Infrastructure as Code Issue, Container Vulnerability | - */ - issueType?: - | "Advisor" - | "Code Quality Issue" - | "Code Security Vulnerability" - | "Licence Issue" - | "Open Source Vulnerability" - | "Infrastructure as Code Issue" - | "Container Vulnerability"; - /** - * Operating system architecture - */ - osArch?: string; - /** - * Operating system platform - */ - osPlatform?: string; - /** - * IDE plugin runtime name. - */ - runtimeName?: string; - /** - * IDE plugin runtime version. - * - * | Rule | Value | - * |---|---| - * | Min Length | 1 | - */ - runtimeVersion?: string; - /** - * Severity of the issue - * - * | Rule | Value | - * |---|---| - * | Enum Values | High, Medium, Low, Critical | - */ - severity?: "High" | "Medium" | "Low" | "Critical"; -} - -export interface IssueInTreeIsClickedProperties { - /** - * Ide family. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Visual Studio Code, Visual Studio, Eclipse, JetBrains, Other | - */ - ide: "Visual Studio Code" | "Visual Studio" | "Eclipse" | "JetBrains" | "Other"; - /** - * Issue ID as received from the backend. - */ - issueId?: string; - /** - * Issue type - * - * | Rule | Value | - * |---|---| - * | Enum Values | Advisor, Code Quality Issue, Code Security Vulnerability, Licence Issue, Open Source Vulnerability, Infrastructure as Code Issue, Container Vulnerability | - */ - issueType?: - | "Advisor" - | "Code Quality Issue" - | "Code Security Vulnerability" - | "Licence Issue" - | "Open Source Vulnerability" - | "Infrastructure as Code Issue" - | "Container Vulnerability"; - /** - * Operating system architecture - */ - osArch?: string; - /** - * Operating system platform - */ - osPlatform?: string; - /** - * IDE plugin runtime name. - */ - runtimeName?: string; - /** - * IDE plugin runtime version. - * - * | Rule | Value | - * |---|---| - * | Min Length | 1 | - */ - runtimeVersion?: string; - /** - * Severity of the issue - * - * | Rule | Value | - * |---|---| - * | Enum Values | High, Medium, Low, Critical | - */ - severity?: "High" | "Medium" | "Low" | "Critical"; -} - -export interface PluginIsInstalledProperties { - /** - * Ide family. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Visual Studio Code, Visual Studio, Eclipse, JetBrains, Other | - */ - ide: "Visual Studio Code" | "Visual Studio" | "Eclipse" | "JetBrains" | "Other"; - /** - * Operating system architecture - */ - osArch?: string; - /** - * Operating system platform - */ - osPlatform?: string; - /** - * IDE plugin runtime name. - */ - runtimeName?: string; - /** - * IDE plugin runtime version. - * - * | Rule | Value | - * |---|---| - * | Min Length | 1 | - */ - runtimeVersion?: string; -} - -export interface QuickFixIsDisplayedProperties { - /** - * Ide family. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Visual Studio Code, Visual Studio, Eclipse, JetBrains, Other | - */ - ide: "Visual Studio Code" | "Visual Studio" | "Eclipse" | "JetBrains" | "Other"; - /** - * Operating system architecture - */ - osArch?: string; - /** - * Operating system platform - */ - osPlatform?: string; - /** - * Quick fix types displayed to the user: - * - * * Show this suggestion - * - * * Ignore this particular suggestion - * - * * Ignore this suggestion in current file - * - * Due to array type definition limitation in Iteratively, the type is enforced in the code as follows: - * - * ``` - * type SupportedQuickFixProperties = - * | 'Show Suggestion' - * | 'Ignore Suggestion In Line' - * | 'Ignore Suggestion In File'; - * ``` - * - * | Rule | Value | - * |---|---| - * | Min Items | 1 | - * | Unique Items | true | - * | Item Type | string | - * - * @minItems 1 - */ - quickFixType: [string, ...string[]]; - /** - * IDE plugin runtime name. - */ - runtimeName?: string; - /** - * IDE plugin runtime version. - * - * | Rule | Value | - * |---|---| - * | Min Length | 1 | - */ - runtimeVersion?: string; -} - -export interface ScanModeIsSelectedProperties { - /** - * Used to identify the source for multi-source events. - * - * For example, if a given event is shared between Snyk Advisor and Snyk Learn, this property helps to differentiate between the two. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Advisor, App, Learn, IDE, Website, CodeSnippets | - */ - eventSource?: "Advisor" | "App" | "Learn" | "IDE" | "Website" | "CodeSnippets"; - /** - * Ide family. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Visual Studio Code, Visual Studio, Eclipse, JetBrains, Other | - */ - ide: "Visual Studio Code" | "Visual Studio" | "Eclipse" | "JetBrains" | "Other"; - /** - * Operating system architecture - */ - osArch?: string; - /** - * Operating system platform - */ - osPlatform?: string; - /** - * IDE plugin runtime name. - */ - runtimeName?: string; - /** - * IDE plugin runtime version. - * - * | Rule | Value | - * |---|---| - * | Min Length | 1 | - */ - runtimeVersion?: string; - /** - * | Rule | Value | - * |---|---| - * | Enum Values | paused, auto, manual, throttled | - */ - scanMode: "paused" | "auto" | "manual" | "throttled"; -} - -export interface WelcomeButtonIsClickedProperties { - /** - * Used to identify the source for multi-source events. - * - * For example, if a given event is shared between Snyk Advisor and Snyk Learn, this property helps to differentiate between the two. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Advisor, App, Learn, IDE, Website, CodeSnippets | - */ - eventSource?: "Advisor" | "App" | "Learn" | "IDE" | "Website" | "CodeSnippets"; - /** - * Ide family. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Visual Studio Code, Visual Studio, Eclipse, JetBrains, Other | - */ - ide: "Visual Studio Code" | "Visual Studio" | "Eclipse" | "JetBrains" | "Other"; - /** - * Operating system architecture - */ - osArch?: string; - /** - * Operating system platform - */ - osPlatform?: string; - /** - * IDE plugin runtime name. - */ - runtimeName?: string; - /** - * IDE plugin runtime version. - * - * | Rule | Value | - * |---|---| - * | Min Length | 1 | - */ - runtimeVersion?: string; -} - -export interface WelcomeIsViewedProperties { - /** - * Ide family. - * - * | Rule | Value | - * |---|---| - * | Enum Values | Visual Studio Code, Visual Studio, Eclipse, JetBrains, Other | - */ - ide: "Visual Studio Code" | "Visual Studio" | "Eclipse" | "JetBrains" | "Other"; - /** - * Operating system architecture - */ - osArch?: string; - /** - * Operating system platform - */ - osPlatform?: string; - /** - * IDE plugin runtime name. - */ - runtimeName?: string; - /** - * IDE plugin runtime version. - * - * | Rule | Value | - * |---|---| - * | Min Length | 1 | - */ - runtimeVersion?: string; -} - -export class AnalysisIsReady implements Event { - name = 'Analysis Is Ready'; - id = 'c9337edb-27a3-416e-a654-092fa4375feb'; - version = '3.0.0'; - properties: AnalysisIsReadyProperties & { - 'itly': true; - }; - - constructor( - properties: AnalysisIsReadyProperties, - ) { - this.properties = { - ...properties, - 'itly': true, - }; - } -} - -export class AnalysisIsTriggered implements Event { - name = 'Analysis Is Triggered'; - id = 'dabf569e-219c-470f-8e31-6e029723f0cd'; - version = '3.0.0'; - properties: AnalysisIsTriggeredProperties & { - 'itly': true; - }; - - constructor( - properties: AnalysisIsTriggeredProperties, - ) { - this.properties = { - ...properties, - 'itly': true, - }; - } -} - -export class AuthenticateButtonIsClicked implements Event { - name = 'Authenticate Button Is Clicked'; - id = '2220c25f-ba76-4d5b-92f7-6d0e1c6165be'; - version = '4.0.0'; - properties: AuthenticateButtonIsClickedProperties & { - 'itly': true; - }; - - constructor( - properties: AuthenticateButtonIsClickedProperties, - ) { - this.properties = { - ...properties, - 'itly': true, - }; - } -} - -export class IssueHoverIsDisplayed implements Event { - name = 'Issue Hover Is Displayed'; - id = '5bcc7fd8-6118-4777-b719-366cda263a13'; - version = '3.0.0'; - properties: IssueHoverIsDisplayedProperties & { - 'itly': true; - }; - - constructor( - properties: IssueHoverIsDisplayedProperties, - ) { - this.properties = { - ...properties, - 'itly': true, - }; - } -} - -export class IssueInTreeIsClicked implements Event { - name = 'Issue In Tree Is Clicked'; - id = 'fae15d02-eab9-49bb-9833-18414e26058b'; - version = '3.0.0'; - properties: IssueInTreeIsClickedProperties & { - 'itly': true; - }; - - constructor( - properties: IssueInTreeIsClickedProperties, - ) { - this.properties = { - ...properties, - 'itly': true, - }; - } -} - -export class PluginIsInstalled implements Event { - name = 'Plugin Is Installed'; - id = '7bb34693-366e-460e-8f4c-5b3f1c71888a'; - version = '2.0.0'; - properties: PluginIsInstalledProperties & { - 'itly': true; - }; - - constructor( - properties: PluginIsInstalledProperties, - ) { - this.properties = { - ...properties, - 'itly': true, - }; - } -} - -export class QuickFixIsDisplayed implements Event { - name = 'Quick Fix Is Displayed'; - id = '170c1284-9ee6-457f-aa82-6c49e49cde93'; - version = '2.0.0'; - properties: QuickFixIsDisplayedProperties & { - 'itly': true; - }; - - constructor( - properties: QuickFixIsDisplayedProperties, - ) { - this.properties = { - ...properties, - 'itly': true, - }; - } -} - -export class ScanModeIsSelected implements Event { - name = 'Scan Mode Is Selected'; - id = '41d49045-d336-46ac-b4c2-1a3ebb5c688a'; - version = '4.0.0'; - properties: ScanModeIsSelectedProperties & { - 'itly': true; - }; - - constructor( - properties: ScanModeIsSelectedProperties, - ) { - this.properties = { - ...properties, - 'itly': true, - }; - } -} - -export class WelcomeButtonIsClicked implements Event { - name = 'Welcome Button Is Clicked'; - id = 'e570e72e-4974-481a-9838-66cca471656b'; - version = '4.0.0'; - properties: WelcomeButtonIsClickedProperties & { - 'itly': true; - }; - - constructor( - properties: WelcomeButtonIsClickedProperties, - ) { - this.properties = { - ...properties, - 'itly': true, - }; - } -} - -export class WelcomeIsViewed implements Event { - name = 'Welcome Is Viewed'; - id = '91114669-bbab-4f58-a7dd-ea7c98c79221'; - version = '2.0.0'; - properties: WelcomeIsViewedProperties & { - 'itly': true; - }; - - constructor( - properties: WelcomeIsViewedProperties, - ) { - this.properties = { - ...properties, - 'itly': true, - }; - } -} - -// prettier-ignore -interface DestinationOptions { - - all?: { - disabled?: boolean; - }; -} - -export interface LoadOptions extends OptionsBase { - /** - * Analytics provider-specific configuration. - */ - destinations?: DestinationOptions; -} - -// prettier-ignore -class Itly { - private itly: ItlyNode; - - constructor() { - this.itly = new ItlyNode(); - } - - /** - * Initialize the Itly SDK. Call once when your application starts. - * @param loadOptions Configuration options to initialize the Itly SDK with. - */ - load(loadOptions: LoadOptions = {}) { - const { - destinations = {} as DestinationOptions, - plugins = [] as Plugin[], - ...options - } = loadOptions; - - const destinationPlugins = destinations.all && destinations.all.disabled - ? [] - : [ - - ]; - - this.itly.load({ - ...options, - plugins: [ - new SchemaValidatorPlugin({ - 'group': {"type":"object","properties":{"[Amplitude] Group ID":{"type":"object"},"[Amplitude] Group name":{"type":"object"},"$set":{"type":"object"},"$unset":{"type":"object"},"Account ARR":{"type":"object"},"Account Plan":{"type":"object"},"Billing Frequency":{"type":"object"},"Code Licenses":{"type":"object"},"Container Licenses":{"type":"object"},"countFixesFirst30Days":{"type":"object"},"countFixesFirst7Days":{"type":"object"},"countFixesPast30Days":{"type":"object"},"countFixesPast7Days":{"type":"object"},"countFixesTotal":{"type":"object"},"currentEngagementState":{"type":"object"},"dateLastEngagementStateChange":{"type":"object"},"daysSinceLastEngagementStateChange":{"type":"object"},"DB Feed Licenses":{"type":"object"},"Free Trial End Date":{"type":"object"},"Free Trial Start Date":{"type":"object"},"groupId":{"type":"string"},"groupName":{"type":"string"},"groupType":{"enum":["org","group","account"]},"hasFixFirst30Days":{"type":"object"},"hasFixFirst7Days":{"type":"object"},"hasFixPast30Days":{"type":"object"},"hasFixPast7Days":{"type":"object"},"IAC Licenses":{"type":"object"},"id":{"type":"object"},"internalName":{"type":"object"},"isPassthrough":{"type":"object"},"name":{"type":"object"},"Open Source Licenses":{"type":"object"},"plan":{"type":"string"},"priorEngagementState":{"type":"object"},"projectTypes":{"items":{"type":"string"},"uniqueItems":true,"type":"array"}},"additionalProperties":false,"required":[]}, - 'identify': {"type":"object","properties":{"accountType":{"enum":["user","service","app-instance","automated-test-user"]},"adminLink":{"type":"string"},"appcuesCompanyName":{"type":"string"},"appcuesFirstName":{"type":"string"},"appcuesJobTitle":{"type":"string"},"appcuesLastName":{"type":"string"},"appcuesUserGoal":{"type":"string"},"appcuesWorkEmail":{"type":"string"},"authProvider":{"type":"string"},"createdAt":{"type":"object"},"email":{"type":"string"},"firstName":{"type":"string"},"hasFirstIntegration":{"type":"boolean"},"hasFirstProject":{"type":"boolean"},"hasPersonalEmail":{"type":"boolean"},"isAppUIBetaEnabled":{"type":"boolean"},"isNonUser":{"type":"boolean"},"isSnyk":{"type":"boolean"},"isSnykAdmin":{"type":"boolean"},"lastName":{"type":"string"},"learnPreferredEcosystems":{"items":{"type":"string"},"uniqueItems":true,"type":"array"},"productUpdatesConsent":{"type":"boolean"},"productUpdatesConsentIsDisplayed":{"type":"boolean"},"user_id":{"type":"string"},"username":{"type":"string"},"utm_campaign":{"type":"string"},"utm_content":{"type":"string"},"utm_medium":{"type":"string"},"utm_source":{"type":"string"},"utm_term":{"type":"string"}},"additionalProperties":false,"required":[]}, - 'page': {"type":"object","properties":{"ecosystem":{"type":"string"},"package":{"type":"string"},"packageManager":{"type":"string"},"packageVersion":{"type":"string"},"path":{"type":"string"},"referrer":{"type":"string"},"search":{"type":"string"},"title":{"type":"string"},"url":{"type":"string"},"vulnerabilityId":{"type":"string"}},"additionalProperties":false,"required":[]}, - 'Analysis Is Ready': {"type":"object","properties":{"analysisType":{"enum":["Snyk Advisor","Snyk Code Quality","Snyk Code Security","Snyk Open Source","Snyk Container","Snyk Infrastructure as Code"]},"durationInSeconds":{"type":"number"},"fileCount":{"type":"integer"},"ide":{"enum":["Visual Studio Code","Visual Studio","Eclipse","JetBrains","Other"]},"itly":{"const":true},"osArch":{"type":"string"},"osPlatform":{"type":"string"},"result":{"enum":["Success","Error"]},"runtimeName":{"type":"string"},"runtimeVersion":{"minLength":1,"type":"string"}},"additionalProperties":false,"required":["analysisType","ide","itly","result"]}, - 'Analysis Is Triggered': {"type":"object","properties":{"analysisType":{"items":{"type":"string"},"minItems":1,"uniqueItems":true,"type":"array"},"ide":{"enum":["Visual Studio Code","Visual Studio","Eclipse","JetBrains","Other"]},"itly":{"const":true},"osArch":{"type":"string"},"osPlatform":{"type":"string"},"runtimeName":{"type":"string"},"runtimeVersion":{"minLength":1,"type":"string"},"triggeredByUser":{"type":"boolean"}},"additionalProperties":false,"required":["analysisType","ide","itly","triggeredByUser"]}, - 'Authenticate Button Is Clicked': {"type":"object","properties":{"eventSource":{"enum":["Advisor","App","Learn","IDE","Website","CodeSnippets"]},"ide":{"enum":["Visual Studio Code","Visual Studio","Eclipse","JetBrains","Other"]},"itly":{"const":true},"osArch":{"type":"string"},"osPlatform":{"type":"string"},"runtimeName":{"type":"string"},"runtimeVersion":{"minLength":1,"type":"string"}},"additionalProperties":false,"required":["ide","itly"]}, - 'Issue Hover Is Displayed': {"type":"object","properties":{"ide":{"enum":["Visual Studio Code","Visual Studio","Eclipse","JetBrains","Other"]},"issueId":{"type":"string"},"issueType":{"enum":["Advisor","Code Quality Issue","Code Security Vulnerability","Licence Issue","Open Source Vulnerability","Infrastructure as Code Issue","Container Vulnerability"]},"itly":{"const":true},"osArch":{"type":"string"},"osPlatform":{"type":"string"},"runtimeName":{"type":"string"},"runtimeVersion":{"minLength":1,"type":"string"},"severity":{"enum":["High","Medium","Low","Critical"]}},"additionalProperties":false,"required":["ide","itly"]}, - 'Issue In Tree Is Clicked': {"type":"object","properties":{"ide":{"enum":["Visual Studio Code","Visual Studio","Eclipse","JetBrains","Other"]},"issueId":{"type":"string"},"issueType":{"enum":["Advisor","Code Quality Issue","Code Security Vulnerability","Licence Issue","Open Source Vulnerability","Infrastructure as Code Issue","Container Vulnerability"]},"itly":{"const":true},"osArch":{"type":"string"},"osPlatform":{"type":"string"},"runtimeName":{"type":"string"},"runtimeVersion":{"minLength":1,"type":"string"},"severity":{"enum":["High","Medium","Low","Critical"]}},"additionalProperties":false,"required":["ide","itly"]}, - 'Plugin Is Installed': {"type":"object","properties":{"ide":{"enum":["Visual Studio Code","Visual Studio","Eclipse","JetBrains","Other"]},"itly":{"const":true},"osArch":{"type":"string"},"osPlatform":{"type":"string"},"runtimeName":{"type":"string"},"runtimeVersion":{"minLength":1,"type":"string"}},"additionalProperties":false,"required":["ide","itly"]}, - 'Quick Fix Is Displayed': {"type":"object","properties":{"ide":{"enum":["Visual Studio Code","Visual Studio","Eclipse","JetBrains","Other"]},"itly":{"const":true},"osArch":{"type":"string"},"osPlatform":{"type":"string"},"quickFixType":{"items":{"type":"string"},"minItems":1,"uniqueItems":true,"type":"array"},"runtimeName":{"type":"string"},"runtimeVersion":{"minLength":1,"type":"string"}},"additionalProperties":false,"required":["ide","itly","quickFixType"]}, - 'Scan Mode Is Selected': {"type":"object","properties":{"eventSource":{"enum":["Advisor","App","Learn","IDE","Website","CodeSnippets"]},"ide":{"enum":["Visual Studio Code","Visual Studio","Eclipse","JetBrains","Other"]},"itly":{"const":true},"osArch":{"type":"string"},"osPlatform":{"type":"string"},"runtimeName":{"type":"string"},"runtimeVersion":{"minLength":1,"type":"string"},"scanMode":{"enum":["paused","auto","manual","throttled"]}},"additionalProperties":false,"required":["ide","itly","scanMode"]}, - 'Welcome Button Is Clicked': {"type":"object","properties":{"eventSource":{"enum":["Advisor","App","Learn","IDE","Website","CodeSnippets"]},"ide":{"enum":["Visual Studio Code","Visual Studio","Eclipse","JetBrains","Other"]},"itly":{"const":true},"osArch":{"type":"string"},"osPlatform":{"type":"string"},"runtimeName":{"type":"string"},"runtimeVersion":{"minLength":1,"type":"string"}},"additionalProperties":false,"required":["ide","itly"]}, - 'Welcome Is Viewed': {"type":"object","properties":{"ide":{"enum":["Visual Studio Code","Visual Studio","Eclipse","JetBrains","Other"]},"itly":{"const":true},"osArch":{"type":"string"},"osPlatform":{"type":"string"},"runtimeName":{"type":"string"},"runtimeVersion":{"minLength":1,"type":"string"}},"additionalProperties":false,"required":["ide","itly"]}, - }), - ...destinationPlugins, - ...plugins, - ], - }); - } - - /** - * Alias a user ID to another user ID. - * @param userId The user's new ID. - * @param previousId The user's previous ID. - * @param options Options for this alias call. - */ - alias(userId: string, previousId: string, options?: AliasOptions) { - this.itly.alias(userId, previousId, options); - } - - /** - * Identify a user and set or update that user's properties. - * @param userId The user's ID. - * @param properties The user's properties. - * @param options Options for this identify call. - */ - identify( - userId: string, - properties?: IdentifyProperties, - options?: IdentifyOptions, - ) { - this.itly.identify(userId, properties, options) - } - - /** - * Associate a user with a group and set or update that group's properties. - * @param userId The user's ID. - * @param groupId The group's ID. - * @param properties The group's properties. - * @param options Options for this group call. - */ - group( - userId: string, - groupId: string, - properties?: GroupProperties, - options?: GroupOptions, - ) { - this.itly.group(userId, groupId, properties, options) - } - - /** - * Triggered when the analysis is loaded within the IDE. - * - * Owner: Georgi Mitev - * @param userId The user's ID. - * @param properties The event's properties (e.g. analysisType) - * @param options Options for this track call. - */ - analysisIsReady( - userId: string, - properties: AnalysisIsReadyProperties, - options?: TrackOptions, - ) { - this.itly.track(userId, new AnalysisIsReady(properties), options); - } - - /** - * User triggers an analysis or analysis is automatically triggered. - * - * Owner: Georgi Mitev - * @param userId The user's ID. - * @param properties The event's properties (e.g. analysisType) - * @param options Options for this track call. - */ - analysisIsTriggered( - userId: string, - properties: AnalysisIsTriggeredProperties, - options?: TrackOptions, - ) { - this.itly.track(userId, new AnalysisIsTriggered(properties), options); - } - - /** - * This Event fires when the authenticate button is clicked. - * - * Owner: Bastian Doetsch - * @param userId The user's ID. - * @param properties The event's properties (e.g. eventSource) - * @param options Options for this track call. - */ - authenticateButtonIsClicked( - userId: string, - properties: AuthenticateButtonIsClickedProperties, - options?: TrackOptions, - ) { - this.itly.track(userId, new AuthenticateButtonIsClicked(properties), options); - } - - /** - * Triggered when issue hover is displayed in the IDE editor. - * - * Owner: Michel Kaporin - * @param userId The user's ID. - * @param properties The event's properties (e.g. ide) - * @param options Options for this track call. - */ - issueHoverIsDisplayed( - userId: string, - properties: IssueHoverIsDisplayedProperties, - options?: TrackOptions, - ) { - this.itly.track(userId, new IssueHoverIsDisplayed(properties), options); - } - - /** - * Triggered when the user selects an issue from the issues list and the issue is loaded. - * - * Owner: Georgi Mitev - * @param userId The user's ID. - * @param properties The event's properties (e.g. ide) - * @param options Options for this track call. - */ - issueInTreeIsClicked( - userId: string, - properties: IssueInTreeIsClickedProperties, - options?: TrackOptions, - ) { - this.itly.track(userId, new IssueInTreeIsClicked(properties), options); - } - - /** - * Triggered when the user installs the plugin. - * - * Owner: Georgi Mitev - * @param userId The user's ID. - * @param properties The event's properties (e.g. ide) - * @param options Options for this track call. - */ - pluginIsInstalled( - userId: string, - properties: PluginIsInstalledProperties, - options?: TrackOptions, - ) { - this.itly.track(userId, new PluginIsInstalled(properties), options); - } - - /** - * Triggered when quick fix options are displayed to the user in IDE. - * - * Owner: Michel Kaporin - * @param userId The user's ID. - * @param properties The event's properties (e.g. ide) - * @param options Options for this track call. - */ - quickFixIsDisplayed( - userId: string, - properties: QuickFixIsDisplayedProperties, - options?: TrackOptions, - ) { - this.itly.track(userId, new QuickFixIsDisplayed(properties), options); - } - - /** - * Owner: Michel Kaporin - * @param userId The user's ID. - * @param properties The event's properties (e.g. eventSource) - * @param options Options for this track call. - */ - scanModeIsSelected( - userId: string, - properties: ScanModeIsSelectedProperties, - options?: TrackOptions, - ) { - this.itly.track(userId, new ScanModeIsSelected(properties), options); - } - - /** - * This event fires when the "Check it out" button is clicked in welcome notification. - * - * Owner: Michel Kaporin - * @param userId The user's ID. - * @param properties The event's properties (e.g. eventSource) - * @param options Options for this track call. - */ - welcomeButtonIsClicked( - userId: string, - properties: WelcomeButtonIsClickedProperties, - options?: TrackOptions, - ) { - this.itly.track(userId, new WelcomeButtonIsClicked(properties), options); - } - - /** - * User installs the IDE plugin and see Snyk's welcome screen. - * - * Owner: Georgi Mitev - * @param userId The user's ID. - * @param properties The event's properties (e.g. ide) - * @param options Options for this track call. - */ - welcomeIsViewed( - userId: string, - properties: WelcomeIsViewedProperties, - options?: TrackOptions, - ) { - this.itly.track(userId, new WelcomeIsViewed(properties), options); - } - - /** - * Track any event. - * @param userId The user's ID. - * @param event The event to track. - * @param options Options for this track call. - */ - track(userId: string, event: Event, options?: TrackOptions) { - this.itly.track(userId, event, options); - } - - // reset() N/A for Node.js - - async flush() { - await this.itly.flush(); - } -} - -export default new Itly(); diff --git a/src/snyk/advisor/advisorTypes.ts b/src/snyk/advisor/advisorTypes.ts deleted file mode 100644 index 43f9e167f..000000000 --- a/src/snyk/advisor/advisorTypes.ts +++ /dev/null @@ -1,15 +0,0 @@ -export type AdvisorScoreLabel = { - popularity: string; - maintenance: string; - community: string; - security: string; -}; - -export type AdvisorScore = { - name: string; - score: number; - pending: boolean; - labels: AdvisorScoreLabel; -} | null; - -export type AdvisorRegistry = 'npm-package' | 'python'; diff --git a/src/snyk/advisor/editor/editorDecorator.ts b/src/snyk/advisor/editor/editorDecorator.ts deleted file mode 100644 index 0699f5a9e..000000000 --- a/src/snyk/advisor/editor/editorDecorator.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { getRenderOptions, LineDecorations, updateDecorations } from '../../common/editor/editorDecorator'; -import { HoverAdapter } from '../../common/vscode/hover'; -import { IVSCodeLanguages } from '../../common/vscode/languages'; -import { IMarkdownStringAdapter } from '../../common/vscode/markdownString'; -import { IThemeColorAdapter } from '../../common/vscode/theme'; -import { Hover, TextEditorDecorationType } from '../../common/vscode/types'; -import { IVSCodeWindow } from '../../common/vscode/window'; -import { AdvisorScore } from '../advisorTypes'; -import { messages } from '../messages/messages'; -import { IAdvisorApiClient } from '../services/advisorApiClient'; - -const { SCORE_PREFIX } = messages; - -export default class EditorDecorator { - private readonly decorationType: TextEditorDecorationType; - private readonly editorLastCharacterIndex = Number.MAX_SAFE_INTEGER; - private readonly fileDecorationLines: Map = new Map(); - - constructor( - private readonly window: IVSCodeWindow, - private readonly languages: IVSCodeLanguages, - private readonly themeColorAdapter: IThemeColorAdapter, - private readonly advisorApiClient: IAdvisorApiClient, - private readonly hoverAdapter: HoverAdapter, - private readonly markdownStringAdapter: IMarkdownStringAdapter, - ) { - this.decorationType = this.window.createTextEditorDecorationType({ - after: { margin: '0 0 0 1rem' }, - }); - } - - addScoresDecorations( - filePath: string, - packageScore: AdvisorScore, - line: number, - decorations: LineDecorations = [], - ): void { - if (!packageScore) { - return; - } - decorations[line] = { - range: this.languages.createRange( - line - 1, - this.editorLastCharacterIndex, - line - 1, - this.editorLastCharacterIndex, - ), - renderOptions: getRenderOptions( - `${SCORE_PREFIX} ${Math.round(packageScore.score * 100)}/100`, - this.themeColorAdapter, - ), - hoverMessage: this.getHoverMessage(packageScore)?.contents, - }; - - this.fileDecorationLines.set(filePath, decorations); - updateDecorations(this.window, filePath, decorations, this.decorationType); - } - - getHoverMessage(score: AdvisorScore): Hover | null { - if (!score) { - return null; - } - const hoverMessageMarkdown = this.markdownStringAdapter.get(``); - hoverMessageMarkdown.isTrusted = true; - const hoverMessage = this.hoverAdapter.create(hoverMessageMarkdown); - hoverMessageMarkdown.appendMarkdown('| | | | |'); - hoverMessageMarkdown.appendMarkdown('\n'); - hoverMessageMarkdown.appendMarkdown('| ---- | ---- | ---- | :---- |'); - hoverMessageMarkdown.appendMarkdown('\n'); - Object.keys(score.labels).forEach(label => { - hoverMessageMarkdown.appendMarkdown(`| ${label}: | | | ${score?.labels[label]} |`); - hoverMessageMarkdown.appendMarkdown('\n'); - }); - hoverMessageMarkdown.appendMarkdown( - `[More Details](${this.advisorApiClient.getAdvisorUrl('npm-package')}/${score.name})`, - ); - - return hoverMessage; - } - - resetDecorations(filePath: string): void { - const decorations: LineDecorations | undefined = this.fileDecorationLines.get(filePath); - if (!decorations) { - return; - } - - const emptyDecorations = decorations.map(d => ({ - ...d, - renderOptions: getRenderOptions('', this.themeColorAdapter), - })); - - updateDecorations(this.window, filePath, emptyDecorations, this.decorationType); - } -} diff --git a/src/snyk/advisor/messages/messages.ts b/src/snyk/advisor/messages/messages.ts deleted file mode 100644 index d05345c16..000000000 --- a/src/snyk/advisor/messages/messages.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const messages = { - SCORE_PREFIX: 'Advisor Score', -}; diff --git a/src/snyk/advisor/services/advisorApiClient.ts b/src/snyk/advisor/services/advisorApiClient.ts deleted file mode 100644 index 9e3e13236..000000000 --- a/src/snyk/advisor/services/advisorApiClient.ts +++ /dev/null @@ -1,59 +0,0 @@ -import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; -import { DEFAULT_API_HEADERS } from '../../common/api/headers'; -import { IConfiguration } from '../../common/configuration/configuration'; -import { ILog } from '../../common/logger/interfaces'; -import { AdvisorRegistry } from '../advisorTypes'; - -export interface IAdvisorApiClient { - post>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise; - apiPath: string; - getAdvisorUrl(registry: AdvisorRegistry): string; -} - -export class AdvisorApiClient implements IAdvisorApiClient { - private instance: AxiosInstance | null = null; - private readonly advisorBaseUrl = 'https://snyk.io/advisor'; - apiPath = `/unstable/advisor/scores/npm-package`; - - constructor(private readonly configuration: IConfiguration, private readonly logger: ILog) {} - - getAdvisorUrl(registry: AdvisorRegistry): string { - return `${this.advisorBaseUrl}/${registry}`; - } - - private get http(): AxiosInstance { - return this.instance != null ? this.instance : this.initHttp(); - } - - initHttp(): AxiosInstance { - const http = axios.create({ - headers: DEFAULT_API_HEADERS, - responseType: 'json', - }); - - http.interceptors.response.use( - response => response, - (error: Error) => { - this.logger.error(`Call to Advisor API failed: ${error.message}`); - return Promise.reject(error); - }, - ); - - this.instance = http; - return http; - } - - async post>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise { - const token = await this.configuration.getToken(); - this.http.interceptors.request.use(req => { - req.baseURL = this.configuration.baseApiUrl; - req.headers = { - ...req.headers, - Authorization: `token ${token}`, - } as { [header: string]: string }; - - return req; - }); - return this.http.post(url, data, config); - } -} diff --git a/src/snyk/advisor/services/advisorProvider.ts b/src/snyk/advisor/services/advisorProvider.ts deleted file mode 100644 index 4d3efb835..000000000 --- a/src/snyk/advisor/services/advisorProvider.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { AxiosResponse } from 'axios'; -import { ILog } from '../../common/logger/interfaces'; -import { ImportedModule } from '../../common/types'; -import { AdvisorScore } from '../advisorTypes'; -import { IAdvisorApiClient } from './advisorApiClient'; - -export default class AdvisorProvider { - protected scores: AdvisorScore[]; - private cachePackages: string[] = []; - - constructor(private readonly advisorApiClient: IAdvisorApiClient, private readonly logger: ILog) {} - - public async getScores(modules: ImportedModule[]): Promise { - const scores: AdvisorScore[] = []; - try { - const packages = modules.map(({ name }) => name); - if (!packages.filter(pkg => !this.cachePackages.includes(pkg)).length) { - return this.scores; - } - if (!packages.length) { - return scores; - } - const res: AxiosResponse = await this.advisorApiClient.post( - this.advisorApiClient.apiPath, - modules.map(({ name }) => name), - ); - - if (res.data) { - this.scores = res.data as AdvisorScore[]; - this.cachePackages = this.scores.map(advisorScore => { - if (!advisorScore) { - return ''; - } - if (!advisorScore.name) { - return ''; - } - return advisorScore.name; - }); - return res.data as AdvisorScore[]; - } - } catch (err) { - if (err instanceof Error) { - this.logger.error(`Failed to get scores: ${err.message}`); - } - } - return scores; - } -} diff --git a/src/snyk/advisor/services/advisorService.ts b/src/snyk/advisor/services/advisorService.ts deleted file mode 100644 index 74a08946a..000000000 --- a/src/snyk/advisor/services/advisorService.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { Subscription } from 'rxjs'; -import { IConfiguration } from '../../common/configuration/configuration'; -import { LineDecorations } from '../../common/editor/editorDecorator'; -import { ILog } from '../../common/logger/interfaces'; -import { getSupportedLanguage, isValidModuleName } from '../../common/parsing'; -import { ModuleParserProvider } from '../../common/services/moduleParserProvider'; -import { ImportedModule, Language } from '../../common/types'; -import { HoverAdapter } from '../../common/vscode/hover'; -import { IVSCodeLanguages } from '../../common/vscode/languages'; -import { IMarkdownStringAdapter } from '../../common/vscode/markdownString'; -import { IThemeColorAdapter } from '../../common/vscode/theme'; -import { Disposable, TextDocument, TextEditor } from '../../common/vscode/types'; -import { IVSCodeWindow } from '../../common/vscode/window'; -import { IVSCodeWorkspace } from '../../common/vscode/workspace'; -import { AdvisorScore } from '../advisorTypes'; -import EditorDecorator from '../editor/editorDecorator'; -import { IAdvisorApiClient } from './advisorApiClient'; -import AdvisorProvider from './advisorProvider'; - -const SCORE_THRESHOLD = 0.7; -export class AdvisorService implements Disposable { - protected disposables: Disposable[] = []; - protected advisorScanFinishedSubscription: Subscription; - protected activeEditor: TextEditor | undefined; - - private readonly editorDecorator: EditorDecorator; - - constructor( - private readonly window: IVSCodeWindow, - private readonly languages: IVSCodeLanguages, - private readonly advisorProvider: AdvisorProvider, - private readonly logger: ILog, - private readonly workspace: IVSCodeWorkspace, - private readonly advisorApiClient: IAdvisorApiClient, - private readonly themeColorAdapter: IThemeColorAdapter, - private readonly hoverAdapter: HoverAdapter, - private readonly markdownStringAdapter: IMarkdownStringAdapter, - private readonly configuration: IConfiguration, - ) { - this.editorDecorator = new EditorDecorator( - window, - this.languages, - this.themeColorAdapter, - this.advisorApiClient, - this.hoverAdapter, - this.markdownStringAdapter, - ); - } - - async activate(): Promise { - if (!this.configuration.getPreviewFeatures().advisor) { - return; - } - - this.activeEditor = this.window.getActiveTextEditor(); - this.registerEditorListeners(); - if (!this.activeEditor) { - return; - } - - await this.handleEditorEvent(this.activeEditor.document); - } - - registerEditorListeners(): void { - this.disposables.push( - this.workspace.onDidChangeTextDocument(async ev => { - if (ev?.contentChanges.length) { - this.editorDecorator.resetDecorations(ev.document.fileName); - } - await this.handleEditorEvent(ev.document); - }), - this.window.onDidChangeActiveTextEditor(async ev => { - if (!ev) { - return; - } - await this.handleEditorEvent(ev.document); - }), - ); - } - - async handleEditorEvent(document: TextDocument): Promise { - const { fileName, languageId } = document; - const supportedLanguage = getSupportedLanguage(fileName, languageId); - if (document.isDirty || !supportedLanguage) { - return; - } - - const modules = this.getModules(fileName, document.getText(), supportedLanguage, this.logger).filter( - isValidModuleName, - ); - - const scores = await this.advisorProvider.getScores(modules); - this.processScores(scores, modules, fileName); - } - - processScores(scores: AdvisorScore[], modules: ImportedModule[], fileName: string): void { - const vulnsLineDecorations: Map = new Map(); - modules.forEach(({ name, line }) => { - vulnsLineDecorations.set(name, line || -1); - }); - const decorations: LineDecorations = []; - for (const [packageName, line] of vulnsLineDecorations) { - if (line < 0) { - continue; - } - const packageScore = scores.find(score => score && score.name === packageName); - if (!packageScore || packageScore.score >= SCORE_THRESHOLD) { - continue; - } - - this.editorDecorator.addScoresDecorations(fileName, packageScore, line, decorations); - } - } - - private getModules(fileName: string, source: string, language: Language, logger: ILog): ImportedModule[] { - const parser = ModuleParserProvider.getInstance(language, logger, this.configuration); - if (!parser) { - return []; - } - - return parser.getModules(fileName, source, language); - } - - dispose(): void { - while (this.disposables.length) { - const disposable = this.disposables.pop(); - if (disposable) { - disposable.dispose(); - } - } - } -} diff --git a/src/snyk/base/messages/loginMessages.ts b/src/snyk/base/messages/loginMessages.ts deleted file mode 100644 index f5711678e..000000000 --- a/src/snyk/base/messages/loginMessages.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const messages = { - loginFailed: 'Login of new user has failed', - sessionCheckFailed: 'Failed to check user session on server', -}; diff --git a/src/snyk/base/modules/baseSnykModule.ts b/src/snyk/base/modules/baseSnykModule.ts index 5a3bee102..3ddf7d2ee 100644 --- a/src/snyk/base/modules/baseSnykModule.ts +++ b/src/snyk/base/modules/baseSnykModule.ts @@ -1,16 +1,13 @@ -import { AdvisorApiClient, IAdvisorApiClient } from '../../advisor/services/advisorApiClient'; -import AdvisorProvider from '../../advisor/services/advisorProvider'; -import { AdvisorService } from '../../advisor/services/advisorService'; -import { IAnalytics } from '../../common/analytics/itly'; import { CommandController } from '../../common/commands/commandController'; -import { configuration } from '../../common/configuration/instance'; +import { FolderConfigs, IFolderConfigs } from '../../common/configuration/folderConfigs'; import { IWorkspaceTrust, WorkspaceTrust } from '../../common/configuration/trustedFolders'; import { ExperimentService } from '../../common/experiment/services/experimentService'; import { ILanguageServer } from '../../common/languageServer/languageServer'; import { CodeIssueData, IacIssueData } from '../../common/languageServer/types'; -import { Logger } from '../../common/logger/logger'; +import { IClearCacheService } from '../../common/services/CacheService'; import { ContextService, IContextService } from '../../common/services/contextService'; import { DownloadService } from '../../common/services/downloadService'; +import { FeatureFlagService } from '../../common/services/featureFlagService'; import { LearnService } from '../../common/services/learnService'; import { INotificationService } from '../../common/services/notificationService'; import { IOpenerService, OpenerService } from '../../common/services/openerService'; @@ -23,7 +20,7 @@ import { IMarkdownStringAdapter, MarkdownStringAdapter } from '../../common/vsco import { IWatcher } from '../../common/watchers/interfaces'; import { ICodeSettings } from '../../snykCode/codeSettings'; import SnykEditorsWatcher from '../../snykCode/watchers/editorsWatcher'; -import { OssService } from '../../snykOss/services/ossService'; +import { OssService } from '../../snykOss/ossService'; import { OssVulnerabilityCountService } from '../../snykOss/services/vulnerabilityCount/ossVulnerabilityCountService'; import { IAuthenticationService } from '../services/authenticationService'; import { ScanModeService } from '../services/scanModeService'; @@ -40,22 +37,21 @@ export default abstract class BaseSnykModule implements IBaseSnykModule { protected configurationWatcher: IWatcher; readonly contextService: IContextService; + cacheService: IClearCacheService; readonly openerService: IOpenerService; readonly viewManagerService: IViewManagerService; protected authService: IAuthenticationService; protected downloadService: DownloadService; protected ossService?: OssService; - protected advisorService?: AdvisorProvider; + protected featureFlagService: FeatureFlagService; + protected commandController: CommandController; protected scanModeService: ScanModeService; protected ossVulnerabilityCountService: OssVulnerabilityCountService; - protected advisorScoreDisposable: AdvisorService; + protected languageServer: ILanguageServer; protected notificationService: INotificationService; - protected analytics: IAnalytics; - - protected advisorApiClient: IAdvisorApiClient; snykCode: IProductService; protected codeSettings: ICodeSettings; @@ -70,6 +66,7 @@ export default abstract class BaseSnykModule implements IBaseSnykModule { protected markdownStringAdapter: IMarkdownStringAdapter; readonly workspaceTrust: IWorkspaceTrust; readonly codeActionKindAdapter: ICodeActionKindAdapter; + readonly folderConfigs: IFolderConfigs; constructor() { this.statusBarItem = new SnykStatusBarItem(); @@ -78,13 +75,11 @@ export default abstract class BaseSnykModule implements IBaseSnykModule { this.contextService = new ContextService(); this.openerService = new OpenerService(); this.loadingBadge = new LoadingBadge(); - this.advisorApiClient = new AdvisorApiClient(configuration, Logger); this.markdownStringAdapter = new MarkdownStringAdapter(); this.workspaceTrust = new WorkspaceTrust(); this.codeActionKindAdapter = new CodeActionKindAdapter(); + this.folderConfigs = new FolderConfigs(); } abstract runScan(): Promise; - - abstract runOssScan(): Promise; } diff --git a/src/snyk/base/modules/interfaces.ts b/src/snyk/base/modules/interfaces.ts index b1748810e..c67f3c283 100644 --- a/src/snyk/base/modules/interfaces.ts +++ b/src/snyk/base/modules/interfaces.ts @@ -1,5 +1,6 @@ import { IWorkspaceTrust } from '../../common/configuration/trustedFolders'; import { IContextService } from '../../common/services/contextService'; +import { DownloadService } from '../../common/services/downloadService'; import { IOpenerService } from '../../common/services/openerService'; import { IViewManagerService } from '../../common/services/viewManagerService'; import { ExtensionContext } from '../../common/vscode/extensionContext'; @@ -17,19 +18,18 @@ export interface IBaseSnykModule { // Abstract methods runScan(): Promise; - runOssScan(manual?: boolean): Promise; } export interface ISnykLib { enableCode(): Promise; checkAdvancedMode(): Promise; + setupFeatureFlags(): Promise; } export interface IExtension extends IBaseSnykModule, ISnykLib { context: ExtensionContext | undefined; activate(context: VSCodeExtensionContext): void; + stopLanguageServer(): Promise; restartLanguageServer(): Promise; + initDependencyDownload(): DownloadService; } - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type errorType = Error | any; diff --git a/src/snyk/base/modules/snykLib.ts b/src/snyk/base/modules/snykLib.ts index 070350d5d..2cd5048c5 100644 --- a/src/snyk/base/modules/snykLib.ts +++ b/src/snyk/base/modules/snykLib.ts @@ -1,19 +1,16 @@ import * as _ from 'lodash'; -import { firstValueFrom } from 'rxjs'; -import { CliError } from '../../cli/services/cliService'; -import { SupportedAnalysisProperties } from '../../common/analytics/itly'; import { configuration } from '../../common/configuration/instance'; -import { DEFAULT_SCAN_DEBOUNCE_INTERVAL, IDE_NAME, OSS_SCAN_DEBOUNCE_INTERVAL } from '../../common/constants/general'; +import { DEFAULT_SCAN_DEBOUNCE_INTERVAL } from '../../common/constants/general'; import { SNYK_CONTEXT } from '../../common/constants/views'; import { ErrorHandler } from '../../common/error/errorHandler'; import { Logger } from '../../common/logger/logger'; import { vsCodeCommands } from '../../common/vscode/commands'; -import { vsCodeWorkspace } from '../../common/vscode/workspace'; import BaseSnykModule from './baseSnykModule'; import { ISnykLib } from './interfaces'; +import { FEATURE_FLAGS } from '../../common/constants/featureFlags'; export default class SnykLib extends BaseSnykModule implements ISnykLib { - private async runFullScan_(manual = false): Promise { + private async runFullScan_(): Promise { await this.contextService.setContext(SNYK_CONTEXT.ERROR, false); this.loadingBadge.setLoadingBadge(false); @@ -23,7 +20,6 @@ export default class SnykLib extends BaseSnykModule implements ISnykLib { return; } - // Only starts OSS scan. Code & IaC scans are managed by LS Logger.info('Starting full scan'); await this.contextService.setContext(SNYK_CONTEXT.AUTHENTICATING, false); @@ -34,13 +30,7 @@ export default class SnykLib extends BaseSnykModule implements ISnykLib { return; } - await this.user.identify(vsCodeCommands, this.analytics); - - const workspacePaths = vsCodeWorkspace.getWorkspaceFolders(); - if (workspacePaths.length) { - this.logFullAnalysisIsTriggered(manual); - void this.startOssAnalysis(manual, false); - } + await this.user.identify(vsCodeCommands); } catch (err) { await ErrorHandler.handleGlobal(err, Logger, this.contextService, this.loadingBadge); } @@ -48,79 +38,54 @@ export default class SnykLib extends BaseSnykModule implements ISnykLib { // This function is called by commands, error handlers, etc. // We should avoid having duplicate parallel executions. - // Only starts OSS scan. Code & IaC scans are managed by LS public runScan = _.debounce(this.runFullScan_.bind(this), DEFAULT_SCAN_DEBOUNCE_INTERVAL, { leading: true }); - public runOssScan = _.debounce(this.startOssAnalysis.bind(this), OSS_SCAN_DEBOUNCE_INTERVAL, { leading: true }); - async enableCode(): Promise { Logger.info('Enabling Snyk Code'); const wasEnabled = await this.codeSettings.enable(); Logger.info(wasEnabled ? 'Snyk Code was enabled' : 'Failed to enable Snyk Code'); } - async onDidChangeWelcomeViewVisibility(visible: boolean): Promise { - if (visible && !(await configuration.getToken())) { - // Track if a user is not authenticated and expanded the analysis view - this.analytics.logWelcomeViewIsViewed(); - } + async checkAdvancedMode(): Promise { + await this.contextService.setContext(SNYK_CONTEXT.ADVANCED, configuration.shouldShowAdvancedView); } - onDidChangeOssTreeVisibility(visible: boolean): void { - if (this.ossService) { - this.ossService.setVulnerabilityTreeVisibility(visible); - } + async setupFeatureFlags(): Promise { + const flags = [ + { flag: FEATURE_FLAGS.consistentIgnores, fallback: false }, + { flag: FEATURE_FLAGS.snykCodeInlineIgnore, fallback: true }, + ]; + + const featureFlagResults = await Promise.allSettled( + flags.map(({ flag, fallback }) => this.fetchFeatureFlagStatus(flag, fallback)), + ); + + const fulfilledResults = featureFlagResults.filter( + (result): result is PromiseFulfilledResult<{ flag: string; isEnabled: boolean }> => result.status === 'fulfilled', + ); + + fulfilledResults.forEach(({ value }) => { + const { flag, isEnabled } = value; + configuration.setFeatureFlag(flag, isEnabled); + Logger.info(`Feature flag ${flag} is ${isEnabled ? 'enabled' : 'disabled'}`); + }); + + const rejectedResults = featureFlagResults.filter( + (result): result is PromiseRejectedResult => result.status === 'rejected', + ); + + rejectedResults.forEach(({ reason }) => { + Logger.warn(`Failed to fetch feature flag: ${reason}`); + }); } - async checkAdvancedMode(): Promise { - await this.contextService.setContext(SNYK_CONTEXT.ADVANCED, configuration.shouldShowAdvancedView); + private async fetchFeatureFlagStatus(flag: string, fallback: boolean): Promise<{ flag: string; isEnabled: boolean }> { + const isEnabled = await this.featureFlagService.fetchFeatureFlag(flag, fallback); + return { flag, isEnabled }; } protected async setWorkspaceContext(workspacePaths: string[]): Promise { const workspaceFound = !!workspacePaths.length; await this.contextService.setContext(SNYK_CONTEXT.WORKSPACE_FOUND, workspaceFound); } - - private async startOssAnalysis(manual = false, reportTriggeredEvent = true): Promise { - if (!configuration.getFeaturesConfiguration()?.ossEnabled) return; - if (!this.ossService) throw new Error('OSS service is not initialized.'); - - // wait until Snyk Language Server is downloaded - await firstValueFrom(this.downloadService.downloadReady$); - - try { - const result = await this.ossService.test(manual, reportTriggeredEvent); - - if (result instanceof CliError || !result) { - return; - } - } catch (err) { - // catch unhandled error cases by reporting test failure - this.ossService.finalizeTest(new CliError(err)); - } - } - - private isSnykCodeAutoscanSuspended(manual: boolean) { - return !manual && !this.scanModeService.isCodeAutoScanAllowed(); - } - - private logFullAnalysisIsTriggered(manual: boolean) { - const analysisType: SupportedAnalysisProperties[] = []; - const enabledFeatures = configuration.getFeaturesConfiguration(); - - // Ensure preconditions are the same as within running specific analysis - if (!this.isSnykCodeAutoscanSuspended(manual)) { - if (enabledFeatures?.codeSecurityEnabled) analysisType.push('Snyk Code Security'); - if (enabledFeatures?.codeQualityEnabled) analysisType.push('Snyk Code Quality'); - } - if (enabledFeatures?.ossEnabled) analysisType.push('Snyk Open Source'); - - if (analysisType.length) { - this.analytics.logAnalysisIsTriggered({ - analysisType: analysisType as [SupportedAnalysisProperties, ...SupportedAnalysisProperties[]], - ide: IDE_NAME, - triggeredByUser: manual, - }); - } - } } diff --git a/src/snyk/base/services/authenticationService.ts b/src/snyk/base/services/authenticationService.ts index b27f574c4..9d9d4407a 100644 --- a/src/snyk/base/services/authenticationService.ts +++ b/src/snyk/base/services/authenticationService.ts @@ -1,5 +1,4 @@ import { validate as uuidValidate } from 'uuid'; -import { IAnalytics } from '../../common/analytics/itly'; import { IConfiguration } from '../../common/configuration/configuration'; import { SNYK_WORKSPACE_SCAN_COMMAND } from '../../common/constants/commands'; import { DID_CHANGE_CONFIGURATION_METHOD } from '../../common/constants/languageServer'; @@ -18,7 +17,7 @@ export interface IAuthenticationService { setToken(): Promise; - updateToken(token: string): Promise; + updateTokenAndEndpoint(token: string, apiUrl: string): Promise; } export type OAuthToken = { @@ -33,14 +32,12 @@ export class AuthenticationService implements IAuthenticationService { private readonly baseModule: IBaseSnykModule, private readonly configuration: IConfiguration, private readonly window: IVSCodeWindow, - private readonly analytics: IAnalytics, private readonly logger: ILog, private readonly clientAdapter: ILanguageClientAdapter, private commands: IVSCodeCommands, ) {} async initiateLogin(): Promise { - this.analytics.logAuthenticateButtonIsClicked(); await this.contextService.setContext(SNYK_CONTEXT.LOGGEDIN, false); await this.contextService.setContext(SNYK_CONTEXT.AUTHENTICATING, true); } @@ -52,7 +49,7 @@ export class AuthenticationService implements IAuthenticationService { async setToken(): Promise { const token = await this.window.showInputBox({ - placeHolder: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + placeHolder: 'UUID for API Token or OAuth2 Token', password: true, validateInput: token => { const valid = this.validateToken(token); @@ -78,22 +75,31 @@ export class AuthenticationService implements IAuthenticationService { oauthToken.access_token.length > 0 && Date.parse(oauthToken.expiry) > Date.now() && oauthToken.refresh_token.length > 0; - this.logger.debug(`Token ${token} parsed`); + this.logger.debug(`Token ${this.maskToken(token)} parsed`); } catch (e) { - this.logger.warn(`Token ${token} is not a valid uuid or json string: ${e}`); + this.logger.warn(`Token ${this.maskToken(token)} is not a valid uuid or json string: ${e}`); } return valid; } - async updateToken(token: string): Promise { + private maskToken(token: string): string { + return `${token.slice(0, 4)}****${token.slice(-4)}`; + } + + async updateTokenAndEndpoint(token: string, apiUrl: string): Promise { if (!token) { await this.initiateLogout(); } else { if (!this.validateToken(token)) return Promise.reject(new Error('The entered token has an invalid format.')); + if (apiUrl !== null && apiUrl !== undefined && apiUrl.trim().length > 0) { + await this.configuration.setEndpoint(apiUrl); + } + await this.configuration.setToken(token); await this.contextService.setContext(SNYK_CONTEXT.AUTHENTICATING, false); await this.contextService.setContext(SNYK_CONTEXT.LOGGEDIN, true); + await this.contextService.setContext(SNYK_CONTEXT.AUTHENTICATION_METHOD_CHANGED, false); this.baseModule.loadingBadge.setLoadingBadge(false); await this.commands.executeCommand(SNYK_WORKSPACE_SCAN_COMMAND); diff --git a/src/snyk/base/services/scanModeService.ts b/src/snyk/base/services/scanModeService.ts index 3c1cc3136..7db72eeca 100644 --- a/src/snyk/base/services/scanModeService.ts +++ b/src/snyk/base/services/scanModeService.ts @@ -1,4 +1,3 @@ -import { IAnalytics } from '../../common/analytics/itly'; import { IConfiguration } from '../../common/configuration/configuration'; import { IContextService } from '../../common/services/contextService'; import { CodeScanMode } from '../../snykCode/constants/modes'; @@ -7,7 +6,7 @@ export class ScanModeService { private _mode = CodeScanMode.AUTO; private _lastThrottledExecution: number | undefined; - constructor(private contextService: IContextService, private config: IConfiguration, private analytics: IAnalytics) {} + constructor(private contextService: IContextService, private config: IConfiguration) {} isOssAutoScanAllowed(): boolean { return this.config.shouldAutoScanOss; diff --git a/src/snyk/base/views/loadingBadge.ts b/src/snyk/base/views/loadingBadge.ts index 4ba987a28..2bbe38651 100644 --- a/src/snyk/base/views/loadingBadge.ts +++ b/src/snyk/base/views/loadingBadge.ts @@ -1,7 +1,7 @@ import * as vscode from 'vscode'; import { SNYK_VIEW_WELCOME } from '../../common/constants/views'; -import { ErrorReporter } from '../../common/error/errorReporter'; import { IPendingTask, PendingTask } from '../pendingTask'; +import { Logger } from '../../common/logger/logger'; export interface ILoadingBadge { setLoadingBadge(value: boolean): void; @@ -30,7 +30,8 @@ export class LoadingBadge implements ILoadingBadge { .withProgress({ location: { viewId: SNYK_VIEW_WELCOME } }, () => self.getProgressBadgePromise()) .then( () => undefined, - error => ErrorReporter.capture(error), + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + error => Logger.error(error), ); } else if (this.progressBadge && !this.progressBadge.isCompleted) { this.progressBadge.complete(); diff --git a/src/snyk/cli/cliExecutable.ts b/src/snyk/cli/cliExecutable.ts index bcb835900..4db555edd 100644 --- a/src/snyk/cli/cliExecutable.ts +++ b/src/snyk/cli/cliExecutable.ts @@ -1,38 +1,111 @@ -import * as fs from 'fs/promises'; import path from 'path'; -import { Platform } from '../common/platform'; -import { Checksum } from './checksum'; +import fs from 'fs/promises'; import { CliSupportedPlatform } from './supportedPlatforms'; +import { Checksum } from './checksum'; +import { Platform } from '../common/platform'; -// TODO: This file is to be removed in VS Code + Language Server feature cleanup. We need to ensure all users have migrated to use CLI path that's set by the language server. export class CliExecutable { - // If values updated, `.vscodeignore` to be changed. + public static defaultPaths: Record = { + linux: process.env.XDG_DATA_HOME ?? '/.local/share/', + // eslint-disable-next-line camelcase + linux_arm64: process.env.XDG_DATA_HOME ?? '/.local/share/', + // eslint-disable-next-line camelcase + linux_alpine: process.env.XDG_DATA_HOME ?? '/.local/share/', + // eslint-disable-next-line camelcase + linux_alpine_arm64: process.env.XDG_DATA_HOME ?? '/.local/share/', + macos: process.env.XDG_DATA_HOME ?? '/Library/Application Support/', + // eslint-disable-next-line camelcase + macos_arm64: process.env.XDG_DATA_HOME ?? '/Library/Application Support/', + windows: process.env.XDG_DATA_HOME ?? '\\AppData\\Local\\', + // eslint-disable-next-line camelcase + windows_arm64: process.env.XDG_DATA_HOME ?? '\\AppData\\Local\\', + }; + public static filenameSuffixes: Record = { linux: 'snyk-linux', - win32: 'snyk-win.exe', - darwin: 'snyk-macos', + // eslint-disable-next-line camelcase + linux_arm64: 'snyk-linux-arm64', + // eslint-disable-next-line camelcase + linux_alpine: 'snyk-alpine', + // eslint-disable-next-line camelcase + linux_alpine_arm64: 'snyk-alpine-arm64', + macos: 'snyk-macos', + // eslint-disable-next-line camelcase + macos_arm64: 'snyk-macos-arm64', + windows: 'snyk-win.exe', + // eslint-disable-next-line camelcase + windows_arm64: 'snyk-win.exe', }; constructor(public readonly version: string, public readonly checksum: Checksum) {} - static getFilename(platform: CliSupportedPlatform): string { + static async getPath(customPath?: string): Promise { + if (customPath) { + return customPath; + } + const platform = await CliExecutable.getCurrentWithArch(); + const homeDir = Platform.getHomeDir(); + const defaultPath = this.defaultPaths[platform]; + const fileName = CliExecutable.getFileName(platform); + const cliDir = path.join(homeDir, defaultPath, 'snyk', 'vscode-cli'); + return path.join(cliDir, fileName); + } + + static getFileName(platform: CliSupportedPlatform): string { return this.filenameSuffixes[platform]; } - static getPath(extensionDir: string, customPath?: string): string { - if (customPath) { - return customPath; + static async getCurrentWithArch(): Promise { + const osName = Platform.getCurrent().toString().toLowerCase(); + const archSuffix = Platform.getArch().toLowerCase(); + const platform = await CliExecutable.getPlatformName(osName); + + let cliName = platform; + if (archSuffix === 'arm64') { + cliName = `${platform}_${archSuffix}`; } + return cliName as CliSupportedPlatform; + } - const platform = Platform.getCurrent(); - const fileName = CliExecutable.getFilename(platform as CliSupportedPlatform); - return path.join(extensionDir, fileName); + static async getPlatformName(osName: string): Promise { + let platform = ''; + if (osName === 'linux') { + if (await CliExecutable.isAlpine()) { + platform = 'linux_alpine'; + } else { + platform = 'linux'; + } + } else if (osName === 'darwin') { + platform = 'macos'; + } else if (osName === 'win32') { + platform = 'windows'; + } + if (!platform) { + throw new Error(`${osName} is unsupported.`); + } + return platform; } - static exists(extensionDir: string, customPath?: string): Promise { + public static isPathInExtensionDirectory(dirPath: string, filePath: string): boolean { + const normalizedDir = path.resolve(dirPath) + path.sep; + const normalizedFile = path.resolve(filePath); + + return normalizedFile.toLowerCase().startsWith(normalizedDir.toLowerCase()); + } + + static async exists(customPath?: string): Promise { return fs - .access(CliExecutable.getPath(extensionDir, customPath)) + .access(await CliExecutable.getPath(customPath)) .then(() => true) .catch(() => false); } + + static async isAlpine(): Promise { + try { + await fs.access('/etc/alpine-release'); + return true; + } catch (e) { + return false; + } + } } diff --git a/src/snyk/cli/process.ts b/src/snyk/cli/process.ts deleted file mode 100644 index d49553ff0..000000000 --- a/src/snyk/cli/process.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { ChildProcessWithoutNullStreams, spawn } from 'child_process'; -import { Configuration, IConfiguration } from '../common/configuration/configuration'; -import { ILog } from '../common/logger/interfaces'; -import { getVsCodeProxy } from '../common/proxy'; -import { IVSCodeWorkspace } from '../common/vscode/workspace'; -import { CLI_INTEGRATION_NAME } from './contants/integration'; -import { CliError } from './services/cliService'; -import { OAuthToken } from '../base/services/authenticationService'; - -export class CliProcess { - private runningProcess: ChildProcessWithoutNullStreams | null; - - constructor( - private readonly logger: ILog, - private readonly config: IConfiguration, - private readonly workspace: IVSCodeWorkspace, - ) {} - - /** - * Returns CLI output given provided arguments. - */ - async spawn(cliPath: string, cwd: string, args: readonly string[]): Promise { - const processEnv = await this.getProcessEnv(); - - return new Promise((resolve, reject) => { - let output = ''; - - this.logger.info(`Running "${cliPath} ${args.join(' ')}".`); - - this.runningProcess = spawn(cliPath, args, { env: { ...process.env, ...processEnv }, cwd }); - - this.runningProcess.stdout.setEncoding('utf8'); - this.runningProcess.stdout.on('data', (data: string | Buffer) => (output += data)); - - this.runningProcess.on('error', err => { - this.cleanupProcess(); - reject(err); - }); - this.runningProcess.on('close', (_, signal) => { - this.cleanupProcess(); - - // Cancellation process kill was issued - if (signal === 'SIGTERM') { - return reject(new CliError('', '', true)); - } - - // Treat as succesful termination - resolve(output); - }); - }); - } - - kill(): boolean { - return !this.runningProcess || this.runningProcess.kill('SIGTERM'); - } - - async getProcessEnv(): Promise { - let env = { - SNYK_INTEGRATION_NAME: CLI_INTEGRATION_NAME, - SNYK_INTEGRATION_VERSION: await Configuration.getVersion(), - SNYK_API: this.config.snykOssApiEndpoint, - SNYK_CFG_ORG: this.config.organization, - } as NodeJS.ProcessEnv; - - if (!this.config.shouldReportEvents) { - env = { ...env, SNYK_CFG_DISABLE_ANALYTICS: '1' }; - } - - const vscodeProxy = getVsCodeProxy(this.workspace); - if (vscodeProxy && !process.env.HTTP_PROXY && !process.env.HTTPS_PROXY) { - env = { - ...env, - HTTP_PROXY: vscodeProxy, - HTTPS_PROXY: vscodeProxy, - }; - } - - const token = await this.config.getToken(); - if (token && this.config.snykOssApiEndpoint.indexOf('snykgov.io') > 1) { - const oauthToken = JSON.parse(token) as OAuthToken; - env = { - ...env, - SNYK_OAUTH_TOKEN: oauthToken.access_token, - }; - } else { - env = { - ...env, - SNYK_TOKEN: token, - }; - } - - return env; - } - - private cleanupProcess() { - if (this.runningProcess) { - this.runningProcess.removeAllListeners(); - this.runningProcess = null; - } - } -} diff --git a/src/snyk/cli/services/cliService.ts b/src/snyk/cli/services/cliService.ts index d4dbc4130..6b6a821a7 100644 --- a/src/snyk/cli/services/cliService.ts +++ b/src/snyk/cli/services/cliService.ts @@ -1,164 +1,3 @@ -import { firstValueFrom } from 'rxjs'; -import parseArgsStringToArgv from 'string-argv'; -import { AnalysisStatusProvider } from '../../common/analysis/statusProvider'; -import { IConfiguration } from '../../common/configuration/configuration'; -import { IWorkspaceTrust } from '../../common/configuration/trustedFolders'; -import { ErrorHandler } from '../../common/error/errorHandler'; -import { ILanguageServer } from '../../common/languageServer/languageServer'; -import { ILog } from '../../common/logger/interfaces'; -import { messages as analysisMessages } from '../../common/messages/analysisMessages'; -import { DownloadService } from '../../common/services/downloadService'; -import { ExtensionContext } from '../../common/vscode/extensionContext'; -import { IVSCodeWorkspace } from '../../common/vscode/workspace'; -import { CliExecutable } from '../cliExecutable'; -import { CliProcess } from '../process'; - export class CliError { constructor(public error: string | Error | unknown, public path?: string, public isCancellation = false) {} } - -export abstract class CliService extends AnalysisStatusProvider { - protected abstract readonly command: string[]; - protected result: CliResult | CliError | undefined; - - private cliProcess?: CliProcess; - private _isCliReady: boolean; - private _isAnyWorkspaceFolderTrusted = true; - - constructor( - protected readonly extensionContext: ExtensionContext, - protected readonly logger: ILog, - protected readonly config: IConfiguration, - protected readonly workspace: IVSCodeWorkspace, - protected readonly downloadService: DownloadService, - protected readonly languageServer: ILanguageServer, - protected readonly workspaceTrust: IWorkspaceTrust, - ) { - super(); - } - - get isCliReady(): boolean { - return this._isCliReady; - } - - get isAnyWorkspaceFolderTrusted(): boolean { - return this._isAnyWorkspaceFolderTrusted; - } - - async test(manualTrigger: boolean, reportTriggeredEvent: boolean): Promise { - this.ensureDependencies(); - - const currentCliPath = CliExecutable.getPath(this.extensionContext.extensionPath, this.config.getCliPath()); - const currentCliPathExists = await CliExecutable.exists( - this.extensionContext.extensionPath, - this.config.getCliPath(), - ); - await this.synchronizeCliPathIfNeeded(currentCliPath, currentCliPathExists); - if (currentCliPathExists) { - const cliPath = this.config.getCliPath(); - if (!cliPath) { - throw new Error('CLI path is not set, probably failed migration.'); - } - - this.logger.info(`Using CLI path ${cliPath}`); - this.languageServer.cliReady$.next(cliPath); - } - - // Prevent from CLI scan until Language Server downloads the CLI. - const cliPath = await firstValueFrom(this.languageServer.cliReady$); - this._isCliReady = true; - - const workspaceFolders = this.workspace.getWorkspaceFolders(); - if (workspaceFolders.length == 0) { - throw new Error('No workspace was opened.'); - } - - const foldersToTest = this.workspaceTrust.getTrustedFolders(this.config, workspaceFolders); - if (foldersToTest.length == 0) { - this.handleNoTrustedFolders(); - this.logger.info(`Skipping Open Source scan. ${analysisMessages.noWorkspaceTrustDescription}`); - return; - } - this._isAnyWorkspaceFolderTrusted = true; - - // Start test - this.analysisStarted(); - this.beforeTest(manualTrigger, reportTriggeredEvent); - this.result = undefined; - - if (this.cliProcess) { - const killed = this.cliProcess.kill(); - if (!killed) this.logger.error('Failed to kill an already running CLI instance.'); - } - - this.cliProcess = new CliProcess(this.logger, this.config, this.workspace); - const args = this.buildArguments(foldersToTest); - - let output: string; - try { - output = await this.cliProcess.spawn(cliPath, foldersToTest[0], args); - } catch (spawnError) { - if (spawnError instanceof CliError) { - return spawnError; - } - - const result = new CliError(spawnError, ''); - this.finalizeTest(result); - return result; - } - - const mappedResult = this.mapToResultType(output); - this.finalizeTest(mappedResult); - - return mappedResult; - } - - // Synchronizes user configuration with CLI path passed to the Snyk LS. - // TODO: Remove in VS Code + Language Server feature cleanup. - private async synchronizeCliPathIfNeeded(cliPath: string, cliPathExists: boolean) { - if (!this.config.getCliPath() && cliPathExists) { - this.logger.info("Synchronising extension's CLI path with Language Server"); - try { - await this.config.setCliPath(cliPath); - } catch (e) { - ErrorHandler.handle(e, this.logger, "Failed to synchronize extension's CLI path with Language Server"); - } - } - - return cliPath; - } - - protected abstract mapToResultType(rawCliResult: string): CliResult; - - protected abstract ensureDependencies(): void; - - protected abstract beforeTest(manualTrigger: boolean, reportTriggeredEvent: boolean): void; - protected abstract afterTest(result: CliResult | CliError): void; - - handleNoTrustedFolders() { - this._isAnyWorkspaceFolderTrusted = false; - } - - private buildArguments(foldersToTest: ReadonlyArray): string[] { - const args = []; - - args.push(...this.command); - args.push(...foldersToTest); - args.push('--json'); - - const additionalParams = this.config.getAdditionalCliParameters(); - if (additionalParams) { - args.push(...parseArgsStringToArgv(additionalParams.trim())); - } - - return args; - } - - // To be called to finalise the analysis - public finalizeTest(result: CliResult | CliError): void { - this.result = result; - - this.analysisFinished(); - this.afterTest(result); - } -} diff --git a/src/snyk/cli/staticCliApi.ts b/src/snyk/cli/staticCliApi.ts new file mode 100644 index 000000000..9646b7246 --- /dev/null +++ b/src/snyk/cli/staticCliApi.ts @@ -0,0 +1,91 @@ +import axios, { CancelTokenSource } from 'axios'; +import { IConfiguration } from '../common/configuration/configuration'; +import { PROTOCOL_VERSION } from '../common/constants/languageServer'; +import { DownloadAxiosResponse } from '../common/download/downloader'; +import { ILog } from '../common/logger/interfaces'; +import { getAxiosConfig } from '../common/proxy'; +import { IVSCodeWorkspace } from '../common/vscode/workspace'; +import { CliExecutable } from './cliExecutable'; +import { CliSupportedPlatform } from './supportedPlatforms'; +import { ERRORS } from '../common/constants/errors'; + +export interface IStaticCliApi { + getLatestCliVersion(releaseChannel: string): Promise; + downloadBinary(platform: CliSupportedPlatform): Promise<[Promise, CancelTokenSource]>; + getSha256Checksum(version: string, platform: CliSupportedPlatform): Promise; +} + +export class StaticCliApi implements IStaticCliApi { + constructor( + private readonly workspace: IVSCodeWorkspace, + private readonly configuration: IConfiguration, + private readonly logger: ILog, + ) {} + + getLatestVersionDownloadUrl(releaseChannel: string): string { + const downloadUrl = `${this.configuration.getCliBaseDownloadUrl()}/cli/${releaseChannel}/ls-protocol-version-${PROTOCOL_VERSION}`; + return downloadUrl; + } + + getDownloadUrl(version: string, platform: CliSupportedPlatform): string { + if (!version.startsWith('v')) { + version = `v${version}`; + } + const downloadUrl = `${this.configuration.getCliBaseDownloadUrl()}/cli/${version}/${this.getFileName(platform)}`; + return downloadUrl; + } + + getSha256DownloadUrl(version: string, platform: CliSupportedPlatform): string { + const downloadUrl = `${this.getDownloadUrl(version, platform)}.sha256`; + return downloadUrl; + } + + getFileName(platform: CliSupportedPlatform): string { + return CliExecutable.getFileName(platform); + } + + async getLatestCliVersion(releaseChannel: string): Promise { + try { + let { data } = await axios.get( + this.getLatestVersionDownloadUrl(releaseChannel), + await getAxiosConfig(this.workspace, this.configuration, this.logger), + ); + data = data.replace('\n', ''); + return data; + } catch (e) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + this.logger.error(e); + throw Error(ERRORS.DOWNLOAD_FAILED); + } + } + + async downloadBinary(platform: CliSupportedPlatform): Promise<[Promise, CancelTokenSource]> { + const axiosCancelToken = axios.CancelToken.source(); + const cliReleaseChannel = await this.configuration.getCliReleaseChannel(); + const latestCliVersion = await this.getLatestCliVersion(cliReleaseChannel); + + const downloadUrl = this.getDownloadUrl(latestCliVersion, platform); + + const response = axios.get(downloadUrl, { + responseType: 'stream', + cancelToken: axiosCancelToken.token, + ...(await getAxiosConfig(this.workspace, this.configuration, this.logger)), + }); + + return [response as Promise, axiosCancelToken]; + } + + async getSha256Checksum(version: string, platform: CliSupportedPlatform): Promise { + const fileName = this.getFileName(platform); + const { data } = await axios.get( + `${this.getSha256DownloadUrl(version, platform)}`, + await getAxiosConfig(this.workspace, this.configuration, this.logger), + ); + + const checksum = data.replace(fileName, '').replace('\n', '').trim(); + + if (!checksum) return Promise.reject(new Error('Checksum not found')); + + return checksum; + } +} diff --git a/src/snyk/cli/supportedPlatforms.ts b/src/snyk/cli/supportedPlatforms.ts index 73fbe5bae..96c85fe6a 100644 --- a/src/snyk/cli/supportedPlatforms.ts +++ b/src/snyk/cli/supportedPlatforms.ts @@ -1,6 +1,11 @@ -export const SupportedCliPlatformsList = ['linux', 'win32', 'darwin'] as const; +const SupportedCliPlatformsList = [ + 'linux', + 'linux_arm64', + 'linux_alpine', + 'linux_alpine_arm64', + 'windows', + 'windows_arm64', + 'macos', + 'macos_arm64', +] as const; export type CliSupportedPlatform = typeof SupportedCliPlatformsList[number]; - -export function isPlatformSupported(platform: NodeJS.Platform): boolean { - return SupportedCliPlatformsList.find(p => p === platform) !== undefined; -} diff --git a/src/snyk/common/analytics/AnalyticsEvent.ts b/src/snyk/common/analytics/AnalyticsEvent.ts new file mode 100644 index 000000000..2e219f4e7 --- /dev/null +++ b/src/snyk/common/analytics/AnalyticsEvent.ts @@ -0,0 +1,75 @@ +import { AbstractAnalyticsEvent } from './AnalyticsSender'; + +export class AnalyticsEvent implements AbstractAnalyticsEvent { + private readonly interactionType: string; + private readonly category: string[]; + private readonly status: string; + private readonly targetId: string; + private readonly timestampMs: number; + private readonly durationMs: number; + private readonly results: Map; + private readonly errors: unknown[]; + private readonly extension: Map; + + constructor( + deviceId: string, + interactionType: string, + category: string[], + status: string = 'success', + targetId: string = 'pkg:filesystem/scrubbed', + timestampMs: number = Date.now(), + durationMs: number = 0, + results: Map = new Map(), + errors: unknown[] = [], + extension: Map = new Map(), + ) { + this.interactionType = interactionType; + this.category = category; + this.status = status ?? 'success'; + this.targetId = targetId ?? 'pkg:filesystem/scrubbed'; + this.timestampMs = timestampMs ?? Date.now(); + this.durationMs = durationMs ?? 0; + this.results = results ?? new Map(); + this.errors = errors ?? []; + this.extension = extension ?? new Map(); + if (deviceId && deviceId.length > 0) { + this.extension.set('device_id', deviceId); + } + } + + public getInteractionType(): string { + return this.interactionType; + } + + public getCategory(): string[] { + return this.category; + } + + public getStatus(): string { + return this.status; + } + + public getTargetId(): string { + return this.targetId; + } + + public getTimestampMs(): number { + return this.timestampMs; + } + + public getDurationMs(): number { + return this.durationMs; + } + + public getResults(): Map { + return this.results; + } + + public getErrors(): unknown[] { + return this.errors; + } + + public getExtension(): Map { + return this.extension; + } +} diff --git a/src/snyk/common/analytics/AnalyticsSender.ts b/src/snyk/common/analytics/AnalyticsSender.ts new file mode 100644 index 000000000..32fdcc0a7 --- /dev/null +++ b/src/snyk/common/analytics/AnalyticsSender.ts @@ -0,0 +1,84 @@ +// noinspection InfiniteLoopJS + +import { ILog } from '../logger/interfaces'; +import { IConfiguration } from '../configuration/configuration'; +import { sleep } from '@amplitude/experiment-node-server/dist/src/util/time'; +import { IVSCodeCommands } from '../vscode/commands'; +import { SNYK_REPORT_ANALYTICS } from '../constants/commands'; +import { IContextService } from '../services/contextService'; +import { SNYK_CONTEXT } from '../constants/views'; + +interface EventPair { + event: AbstractAnalyticsEvent; + callback: (value: void) => void; +} + +// This is just a marker interface, to ensure type security when sending events +export interface AbstractAnalyticsEvent {} + +export class AnalyticsSender { + private static instance: AnalyticsSender; + private eventQueue: EventPair[] = []; + + constructor( + private logger: ILog, + private configuration: IConfiguration, + private commandExecutor: IVSCodeCommands, + private contextService: IContextService, + ) { + void this.start(); + } + + public static getInstance( + logger: ILog, + configuration: IConfiguration, + commandExecutor: IVSCodeCommands, + contextService: IContextService, + ): AnalyticsSender { + if (!AnalyticsSender.instance) { + AnalyticsSender.instance = new AnalyticsSender(logger, configuration, commandExecutor, contextService); + } + return AnalyticsSender.instance; + } + + private async start(): Promise { + // eslint-disable-next-line no-constant-condition + while (true) { + // eslint-disable-next-line no-await-in-loop + const authToken = await this.configuration.getToken(); + const initialized: boolean = (this.contextService.viewContext[SNYK_CONTEXT.INITIALIZED] as boolean) ?? false; + const hasEvents = this.eventQueue.length > 0; + const authenticated = authToken && authToken.trim() !== ''; + const iAmTired = !(initialized && authenticated && hasEvents); + + if (iAmTired) { + // eslint-disable-next-line no-await-in-loop + await sleep(5000); + continue; + } + + const copyForSending = [...this.eventQueue]; + for (let i = 0; i < copyForSending.length; i++) { + const eventPair = copyForSending[i]; + try { + // eslint-disable-next-line no-await-in-loop + await this.commandExecutor.executeCommand(SNYK_REPORT_ANALYTICS, JSON.stringify(eventPair.event)); + eventPair.callback(); + } catch (error) { + // eslint-disable-next-line @typescript-eslint/no-base-to-string + this.logger.error(`could not send ${eventPair.event} ${error}`); + } finally { + // let's not rely on indexes in the eventQueue array not having changed + const index = this.eventQueue.indexOf(eventPair); + if (index > -1) { + this.eventQueue.splice(index, 1); + } + } + } + } + } + + public logEvent(event: AbstractAnalyticsEvent, callback: (value: void) => void): void { + this.eventQueue.push({ event, callback }); + } +} diff --git a/src/snyk/common/analytics/itly.ts b/src/snyk/common/analytics/itly.ts deleted file mode 100644 index 90f7db690..000000000 --- a/src/snyk/common/analytics/itly.ts +++ /dev/null @@ -1,278 +0,0 @@ -import SegmentPlugin from '@itly/plugin-segment-node'; -import itly, { - AnalysisIsReadyProperties, - IssueHoverIsDisplayedProperties, - IssueInTreeIsClickedProperties, - ScanModeIsSelectedProperties, - TrackOptions, - AnalysisIsTriggeredProperties as _AnalysisIsTriggeredProperties, - QuickFixIsDisplayedProperties as _QuickFixIsDisplayedProperties, -} from '../../../ampli'; -import { Configuration } from '../configuration/configuration'; -import { SnykConfiguration } from '../configuration/snykConfiguration'; -import { IDE_NAME } from '../constants/general'; -import { ErrorHandler } from '../error/errorHandler'; -import { ILog } from '../logger/interfaces'; -import { User } from '../user'; -import { ItlyErrorPlugin } from './itlyErrorPlugin'; - -export type SupportedAnalysisProperties = - | 'Snyk Advisor' - | 'Snyk Code Quality' - | 'Snyk Code Security' - | 'Snyk Open Source'; -export type AnalysisIsTriggeredProperties = _AnalysisIsTriggeredProperties & { - analysisType: [SupportedAnalysisProperties, ...SupportedAnalysisProperties[]]; -}; - -export type SupportedQuickFixProperties = - | 'Show Suggestion' - | 'Ignore Suggestion In Line' - | 'Ignore Suggestion In File' - | 'Show Most Severe Vulnerability'; -export type QuickFixIsDisplayedProperties = _QuickFixIsDisplayedProperties & { - quickFixType: [SupportedQuickFixProperties, ...SupportedQuickFixProperties[]]; -}; - -export interface IAnalytics { - load(): Iteratively | null; - flush(): Promise; - setShouldReportEvents(shouldReportEvents: boolean): void; - identify(userId: string): Promise; - logIssueInTreeIsClicked(properties: IssueInTreeIsClickedProperties): void; - logAnalysisIsReady(properties: AnalysisIsReadyProperties): void; - logAnalysisIsTriggered(properties: AnalysisIsTriggeredProperties): void; - logWelcomeViewIsViewed(): void; - logAuthenticateButtonIsClicked(): void; - logWelcomeButtonIsClicked(): void; - logPluginIsInstalled(): void; - logQuickFixIsDisplayed(properties: QuickFixIsDisplayedProperties): void; - logIssueHoverIsDisplayed(properties: IssueHoverIsDisplayedProperties): void; - logScanModeIsSelected(properties: Omit): void; -} - -/** - * Do not have any dependencies on 'vscode' module to prevent uninstall hook from breaking. - * Import required dependencies dynamically, if needed. - */ -export class Iteratively implements IAnalytics { - private readonly ide = IDE_NAME; - - private loaded = false; - - constructor( - private readonly user: User, - private logger: ILog, - private shouldReportEvents: boolean, - private isFedramp: boolean, - private isDevelopment: boolean, - private snykConfiguration?: SnykConfiguration, - ) {} - - setShouldReportEvents(shouldReportEvents: boolean): void { - this.shouldReportEvents = shouldReportEvents; - this.load(); - } - - load(): Iteratively | null { - if (!this.shouldReportEvents || this.isFedramp) { - this.logger.debug(`Analytics are disabled. No analytics will be collected.`); - return null; - } - this.logger.debug(`Analytics are enabled. Analytics will be collected.`); - - const segmentWriteKey = this.snykConfiguration?.segmentWriteKey; - if (!segmentWriteKey) { - this.logger.debug('Segment analytics write key is empty. No analytics will be collected.'); - return this; - } - - const segment = new SegmentPlugin(segmentWriteKey); - const isDevelopment = this.isDevelopment; - - if (!this.loaded) { - try { - itly.load({ - disabled: !this.shouldReportEvents, - environment: isDevelopment ? 'development' : 'production', - plugins: [segment, new ItlyErrorPlugin(this.logger)], - }); - } catch (err) { - this.logger.warn(`Failed to load analytics: ${err}`); - } - - this.loaded = true; - } - - return this; - } - - public flush = (): Promise => itly.flush(); - - async identify(): Promise { - if (!this.canReportEvents()) { - return; - } - - if (!this.user.authenticatedId) { - this.logger.error('Tried to identify non-authenticated user'); - return; - } - - // Calling identify is the preferred way to merge authenticated user with anonymous one, - // see https://snyk.slack.com/archives/C01U2SPRB3Q/p1624276750134700?thread_ts=1624030602.128900&cid=C01U2SPRB3Q - itly.identify(this.user.authenticatedId, undefined, { - segment: { - options: { - anonymousId: this.user.anonymousId, - context: { - app: { - name: this.ide, - version: await Configuration.getVersion(), - }, - }, - }, - }, - }); - } - - public logIssueInTreeIsClicked(properties: IssueInTreeIsClickedProperties): void { - this.enqueueEvent(() => { - itly.issueInTreeIsClicked(this.getAuthenticatedUserId(), properties); - }); - } - - public logAnalysisIsReady(properties: AnalysisIsReadyProperties): void { - this.enqueueEvent(() => { - itly.analysisIsReady(this.getAuthenticatedUserId(), properties); - }); - } - - public logAnalysisIsTriggered(properties: AnalysisIsTriggeredProperties): void { - this.enqueueEvent(() => { - itly.analysisIsTriggered(this.getAuthenticatedUserId(), properties); - }); - } - - public logWelcomeViewIsViewed(): void { - this.enqueueEvent(() => { - itly.welcomeIsViewed( - '', - { - ide: this.ide, - }, - this.getAnonymousSegmentOptions(), - ); - }, false); - } - - public logAuthenticateButtonIsClicked(): void { - this.enqueueEvent(() => { - itly.authenticateButtonIsClicked( - '', - { - ide: this.ide, - eventSource: 'IDE', - }, - this.getAnonymousSegmentOptions(), - ); - }, false); - } - - public logWelcomeButtonIsClicked(): void { - this.enqueueEvent(() => { - itly.welcomeButtonIsClicked( - this.user.authenticatedId ?? '', - { - ide: this.ide, - eventSource: 'IDE', - }, - this.getAnonymousSegmentOptions(), - ); - }, false); - } - - public logPluginIsInstalled(): void { - this.enqueueEvent(() => { - itly.pluginIsInstalled( - '', - { - ide: this.ide, - }, - { - segment: { - options: { - anonymousId: this.user.anonymousId, - }, - }, - }, - ); - }); - } - - public logQuickFixIsDisplayed(properties: QuickFixIsDisplayedProperties): void { - this.enqueueEvent(() => { - itly.quickFixIsDisplayed(this.getAuthenticatedUserId(), properties); - }); - } - - public logIssueHoverIsDisplayed(properties: IssueHoverIsDisplayedProperties): void { - this.enqueueEvent(() => { - itly.issueHoverIsDisplayed(this.getAuthenticatedUserId(), properties); - }); - } - - public logScanModeIsSelected(properties: Omit): void { - this.enqueueEvent(() => { - itly.scanModeIsSelected(this.getAuthenticatedUserId(), { - ...properties, - ide: this.ide, - eventSource: 'IDE', - }); - }); - } - - private enqueueEvent(eventFunction: () => void, mustBeAuthenticated = true): void { - if (!this.canReportEvents()) { - return; - } - if (mustBeAuthenticated && !this.user.authenticatedId) { - return; - } - - eventFunction(); - } - - private canReportEvents(): boolean { - if (!this.loaded) { - this.logger.debug('Cannot report events because Iteratively not loaded.'); - return false; - } - - if (!this.shouldReportEvents) { - return false; - } - - return true; - } - - private getAnonymousSegmentOptions(): TrackOptions { - return { - segment: { - options: { - anonymousId: this.user.anonymousId, - }, - }, - }; - } - - private getAuthenticatedUserId(): string { - if (!this.user.authenticatedId) { - const err = new Error('User must be authenticated for analytics'); - ErrorHandler.handle(err, this.logger); - throw err; - } - - return this.user.authenticatedId; - } -} diff --git a/src/snyk/common/analytics/itlyErrorPlugin.ts b/src/snyk/common/analytics/itlyErrorPlugin.ts deleted file mode 100644 index 76519e886..000000000 --- a/src/snyk/common/analytics/itlyErrorPlugin.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { ILog } from '../logger/interfaces'; -import { Event, Plugin, Properties, ValidationResponse } from '../../../ampli'; - -export class ItlyErrorPlugin extends Plugin { - constructor(private logger: ILog) { - super('snyk-itly-error-plugin'); - } - - postIdentify( - _userId: string | undefined, - _properties: Properties | undefined, - validationResponses: ValidationResponse[], - ): void { - this.reportError(validationResponses); - } - - postGroup( - _userId: string | undefined, - _groupId: string, - _properties: Properties | undefined, - validationResponses: ValidationResponse[], - ): void { - this.reportError(validationResponses); - } - - postPage( - _userId: string | undefined, - _category: string | undefined, - _name: string | undefined, - _properties: Properties | undefined, - validationResponses: ValidationResponse[], - ): void { - this.reportError(validationResponses); - } - - postTrack(_userId: string | undefined, _event: Event, validationResponses: ValidationResponse[]): void { - this.reportError(validationResponses); - } - - reportError(validationResponses: ValidationResponse[]): void { - const errorMessage = validationResponses - .filter(r => !r.valid) - .map(r => r.message) - .join('\n'); - if (errorMessage) { - // deepcode ignore ExceptionIsNotThrown: - const err = new Error(errorMessage); - this.logger.debug(`Iteratively validation error: ${err}`); - } - } -} diff --git "a/src/snyk/common/api/api\320\241lient.ts" "b/src/snyk/common/api/api\320\241lient.ts" deleted file mode 100644 index d866a5ecd..000000000 --- "a/src/snyk/common/api/api\320\241lient.ts" +++ /dev/null @@ -1,71 +0,0 @@ -import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; -import { IConfiguration } from '../configuration/configuration'; -import { configuration } from '../configuration/instance'; -import { ILog } from '../logger/interfaces'; -import { getAxiosConfig } from '../proxy'; -import { IVSCodeWorkspace } from '../vscode/workspace'; -import { DEFAULT_API_HEADERS } from './headers'; - -export interface ISnykApiClient { - get>(url: string, config?: AxiosRequestConfig): Promise; -} - -export class SnykApiClient implements ISnykApiClient { - private instance: Promise | null = null; - - constructor( - private readonly configuration: IConfiguration, - private readonly workspace: IVSCodeWorkspace, - private readonly logger: ILog, - ) {} - - private get http(): Promise { - return this.instance != null ? this.instance : this.initHttp(); - } - - async initHttp(): Promise { - const axiosRequestConfig: AxiosRequestConfig = { - headers: DEFAULT_API_HEADERS, - responseType: 'json', - ...(await getAxiosConfig(this.workspace, this.configuration, this.logger)), - }; - - const http = axios.create(axiosRequestConfig); - - http.interceptors.response.use( - response => response, - async (error: AxiosError) => { - if (error.response?.status === 401) { - await configuration.clearToken(); - this.logger.warn('Call to Snyk API failed - Invalid token'); - return; - } - this.logger.error(`Call to Snyk API failed: ${error}`); - return Promise.reject(error); - }, - ); - - this.instance = Promise.resolve(http); - return http; - } - - async get>(url: string, config?: AxiosRequestConfig): Promise { - return (await this.http).get(url, await this.getRequestConfigWithAuth(config)); - } - - async post>(url: string, data: unknown, config?: AxiosRequestConfig): Promise { - return (await this.http).post(url, data, await this.getRequestConfigWithAuth(config)); - } - - private async getRequestConfigWithAuth(config?: AxiosRequestConfig) { - const token = await this.configuration.getToken(); - return { - ...config, - baseURL: `${this.configuration.authHost}/api/`, - headers: { - ...config?.headers, - Authorization: `token ${token}`, - } as { [header: string]: string }, - }; - } -} diff --git a/src/snyk/common/api/headers.ts b/src/snyk/common/api/headers.ts deleted file mode 100644 index 9b9bec6f0..000000000 --- a/src/snyk/common/api/headers.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const DEFAULT_API_HEADERS: Readonly> = { - Accept: 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'Accept-Encoding': 'gzip', -}; diff --git a/src/snyk/common/commands/commandController.ts b/src/snyk/common/commands/commandController.ts index cb2f31a28..596976f03 100644 --- a/src/snyk/common/commands/commandController.ts +++ b/src/snyk/common/commands/commandController.ts @@ -2,14 +2,10 @@ import _ from 'lodash'; import { IAuthenticationService } from '../../base/services/authenticationService'; import { ScanModeService } from '../../base/services/scanModeService'; -import { createDCIgnore } from '../../snykCode/utils/ignoreFileUtils'; -import { IssueUtils } from '../../snykCode/utils/issueUtils'; +import { createDCIgnore as createDCIgnoreUtil } from '../../snykCode/utils/ignoreFileUtils'; import { CodeIssueCommandArg } from '../../snykCode/views/interfaces'; import { IacIssueCommandArg } from '../../snykIac/views/interfaces'; -import { capitalizeOssSeverity } from '../../snykOss/ossResult'; -import { OssService } from '../../snykOss/services/ossService'; -import { OssIssueCommandArg } from '../../snykOss/views/ossVulnerabilityTreeProvider'; -import { IAnalytics } from '../analytics/itly'; +import { OssService } from '../../snykOss/ossService'; import { SNYK_INITIATE_LOGIN_COMMAND, SNYK_LOGIN_COMMAND, @@ -18,7 +14,7 @@ import { SNYK_TRUST_WORKSPACE_FOLDERS_COMMAND, VSCODE_GO_TO_SETTINGS_COMMAND, } from '../constants/commands'; -import { COMMAND_DEBOUNCE_INTERVAL, IDE_NAME, SNYK_NAME_EXTENSION, SNYK_PUBLISHER } from '../constants/general'; +import { COMMAND_DEBOUNCE_INTERVAL } from '../constants/general'; import { ErrorHandler } from '../error/errorHandler'; import { ILanguageServer } from '../languageServer/languageServer'; import { CodeIssueData, IacIssueData } from '../languageServer/types'; @@ -31,6 +27,8 @@ import { IUriAdapter } from '../vscode/uri'; import { IVSCodeWindow } from '../vscode/window'; import { IVSCodeWorkspace } from '../vscode/workspace'; import { OpenCommandIssueType, OpenIssueCommandArg } from './types'; +import { IFolderConfigs } from '../configuration/folderConfigs'; +import { IConfiguration } from '../configuration/configuration'; export class CommandController { private debouncedCommands: Record Promise>> = {}; @@ -47,7 +45,8 @@ export class CommandController { private window: IVSCodeWindow, private languageServer: ILanguageServer, private logger: ILog, - private analytics: IAnalytics, + private configuration: IConfiguration, + private folderConfigs: IFolderConfigs, ) {} openBrowser(url: string): unknown { @@ -81,8 +80,12 @@ export class CommandController { } } + async setBaseBranch(folderPath: string): Promise { + await this.folderConfigs.setBranch(this.window, this.configuration, folderPath); + } + openSettings(): void { - void this.commands.executeCommand(VSCODE_GO_TO_SETTINGS_COMMAND, `@ext:${SNYK_PUBLISHER}.${SNYK_NAME_EXTENSION}`); + void this.commands.executeCommand(VSCODE_GO_TO_SETTINGS_COMMAND, `@ext:${this.configuration.getExtensionId()}`); } async createDCIgnore(custom = false, uriAdapter: IUriAdapter, path?: string): Promise { @@ -90,11 +93,11 @@ export class CommandController { const paths = this.workspace.getWorkspaceFolders(); const promises = []; for (const p of paths) { - promises.push(createDCIgnore(p, custom, this.workspace, this.window, uriAdapter)); + promises.push(createDCIgnoreUtil(p, custom, this.workspace, this.window, uriAdapter)); } await Promise.all(promises); } else { - await createDCIgnore(path, custom, this.workspace, this.window, uriAdapter); + await createDCIgnoreUtil(path, custom, this.workspace, this.window, uriAdapter); } } @@ -114,23 +117,23 @@ export class CommandController { } catch (e) { ErrorHandler.handle(e, this.logger); } - - this.analytics.logIssueInTreeIsClicked({ - ide: IDE_NAME, - issueId: decodeURIComponent(issue.id), - issueType: IssueUtils.getIssueType(issue.additionalData.isSecurityType), - severity: IssueUtils.issueSeverityAsText(issue.severity), - }); } else if (arg.issueType == OpenCommandIssueType.OssVulnerability) { - const issue = arg.issue as OssIssueCommandArg; - void this.ossService.showSuggestionProvider(issue); - - this.analytics.logIssueInTreeIsClicked({ - ide: IDE_NAME, - issueId: issue.id, - issueType: 'Open Source Vulnerability', - severity: capitalizeOssSeverity(issue.severity), - }); + const issueArgs = arg.issue as CodeIssueCommandArg; + const folderPath = issueArgs.folderPath; + const issue = this.ossService.getIssue(folderPath, issueArgs.id); + + if (!issue) { + this.logger.warn(`Failed to find the issue ${issueArgs.id}.`); + return; + } + + await this.openLocalFile(issue.filePath, issueArgs.range); + + try { + await this.ossService.showSuggestionProvider(folderPath, issueArgs.id); + } catch (e) { + ErrorHandler.handle(e, this.logger); + } } else if (arg.issueType == OpenCommandIssueType.IacIssue) { const issueArgs = arg.issue as IacIssueCommandArg; const issue = this.iacService.getIssue(issueArgs.folderPath, issueArgs.id); @@ -146,13 +149,6 @@ export class CommandController { } catch (e) { ErrorHandler.handle(e, this.logger); } - - this.analytics.logIssueInTreeIsClicked({ - ide: IDE_NAME, - issueId: issue.id, - issueType: 'Infrastructure as Code Issue', - severity: IssueUtils.issueSeverityAsText(issue.severity), - }); } } diff --git a/src/snyk/common/commands/types.ts b/src/snyk/common/commands/types.ts index 5c61f0596..66df6f6aa 100644 --- a/src/snyk/common/commands/types.ts +++ b/src/snyk/common/commands/types.ts @@ -1,8 +1,6 @@ -import { completeFileSuggestionType } from '../../snykCode/interfaces'; import { CodeIssueCommandArg } from '../../snykCode/views/interfaces'; import { IacIssueCommandArg } from '../../snykIac/views/interfaces'; -import { OssIssueCommandArg } from '../../snykOss/views/ossVulnerabilityTreeProvider'; -import { CodeIssueData, Issue } from '../languageServer/types'; +import { OssIssueCommandArg } from '../../snykOss/interfaces'; export enum OpenCommandIssueType { CodeIssue, @@ -11,20 +9,6 @@ export enum OpenCommandIssueType { } export type OpenIssueCommandArg = { - issue: CodeIssueCommandArg | OssIssueCommandArg | IacIssueCommandArg; + issue: CodeIssueCommandArg | IacIssueCommandArg | OssIssueCommandArg; issueType: OpenCommandIssueType; }; - -export const isCodeIssue = ( - _issue: completeFileSuggestionType | Issue | OssIssueCommandArg, - issueType: OpenCommandIssueType, -): _issue is Issue => { - return issueType === OpenCommandIssueType.CodeIssue; -}; - -export const isOssIssue = ( - _issue: completeFileSuggestionType | Issue | OssIssueCommandArg, - issueType: OpenCommandIssueType, -): _issue is OssIssueCommandArg => { - return issueType === OpenCommandIssueType.OssVulnerability; -}; diff --git a/src/snyk/common/configuration/configuration.ts b/src/snyk/common/configuration/configuration.ts index 602f3ba40..187d8e68b 100644 --- a/src/snyk/common/configuration/configuration.ts +++ b/src/snyk/common/configuration/configuration.ts @@ -1,32 +1,40 @@ import _ from 'lodash'; import path from 'path'; import { URL } from 'url'; -import { IDE_NAME_SHORT, SNYK_TOKEN_KEY } from '../constants/general'; +import { SNYK_TOKEN_KEY } from '../constants/general'; import { ADVANCED_ADDITIONAL_PARAMETERS_SETTING, ADVANCED_ADVANCED_MODE_SETTING, + ADVANCED_AUTHENTICATION_METHOD, ADVANCED_AUTOMATIC_DEPENDENCY_MANAGEMENT, ADVANCED_AUTOSCAN_OSS_SETTING, + ADVANCED_CLI_BASE_DOWNLOAD_URL, ADVANCED_CLI_PATH, + ADVANCED_CLI_RELEASE_CHANNEL, ADVANCED_CUSTOM_ENDPOINT, ADVANCED_CUSTOM_LS_PATH, ADVANCED_ORGANIZATION, CODE_QUALITY_ENABLED_SETTING, CODE_SECURITY_ENABLED_SETTING, CONFIGURATION_IDENTIFIER, + DELTA_FINDINGS, FEATURES_PREVIEW_SETTING, + FOLDER_CONFIGS, IAC_ENABLED_SETTING, + ISSUE_VIEW_OPTIONS_SETTING, OSS_ENABLED_SETTING, SCANNING_MODE, SEVERITY_FILTER_SETTING, TRUSTED_FOLDERS, YES_BACKGROUND_OSS_NOTIFICATION_SETTING, YES_CRASH_REPORT_SETTING, - YES_TELEMETRY_SETTING, YES_WELCOME_NOTIFICATION_SETTING, } from '../constants/settings'; import SecretStorageAdapter from '../vscode/secretStorage'; import { IVSCodeWorkspace } from '../vscode/workspace'; +import { CliExecutable } from '../../cli/cliExecutable'; + +const NEWISSUES = 'Net new issues'; export type FeaturesConfiguration = { ossEnabled: boolean | undefined; @@ -35,6 +43,19 @@ export type FeaturesConfiguration = { iacEnabled: boolean | undefined; }; +export type FolderConfig = { + folderPath: string; + baseBranch: string; + localBranches: string[] | undefined; +}; + +export interface IssueViewOptions { + ignoredIssues: boolean; + openIssues: boolean; + + [option: string]: boolean; +} + export interface SeverityFilter { critical: boolean; high: boolean; @@ -46,33 +67,41 @@ export interface SeverityFilter { export type PreviewFeatures = { advisor: boolean | undefined; + ossQuickfixes: boolean | undefined; }; export interface IConfiguration { shouldShowAdvancedView: boolean; isDevelopment: boolean; - source: string; authHost: string; - baseApiUrl: string; + + getExtensionId(): string; + setExtensionId(extensionId: string): void; + getFeatureFlag(flagName: string): boolean; + + setFeatureFlag(flagName: string, value: boolean): void; getToken(): Promise; setToken(token: string | undefined): Promise; + getAuthenticationMethod(): string; + setCliPath(cliPath: string): Promise; + setCliReleaseChannel(releaseChannel: string): Promise; + setCliBaseDownloadUrl(baseDownloadUrl: string): Promise; + clearToken(): Promise; - snykCodeToken: Promise; - snykCodeBaseURL: string; snykCodeUrl: string; organization: string | undefined; getAdditionalCliParameters(): string | undefined; - snykOssApiEndpoint: string; + snykApiEndpoint: string; shouldShowOssBackgroundScanNotification: boolean; hideOssBackgroundScanNotification(): Promise; @@ -80,7 +109,6 @@ export interface IConfiguration { shouldAutoScanOss: boolean; shouldReportErrors: boolean; - shouldReportEvents: boolean; shouldShowWelcomeNotification: boolean; hideWelcomeNotification(): Promise; @@ -93,36 +121,111 @@ export interface IConfiguration { isAutomaticDependencyManagementEnabled(): boolean; - getCliPath(): string | undefined; - + getCliPath(): Promise; + getCliReleaseChannel(): Promise; + getCliBaseDownloadUrl(): string; getInsecure(): boolean; isFedramp: boolean; + issueViewOptions: IssueViewOptions; + severityFilter: SeverityFilter; scanningMode: string | undefined; getSnykLanguageServerPath(): string | undefined; - setShouldReportEvents(b: boolean): Promise; - getTrustedFolders(): string[]; setTrustedFolders(trustedFolders: string[]): Promise; setEndpoint(endpoint: string): Promise; + + getDeltaFindingsEnabled(): boolean; + + getOssQuickFixCodeActionsEnabled(): boolean; + + getFolderConfigs(): FolderConfig[]; + + setFolderConfigs(folderConfig: FolderConfig[]): Promise; } export class Configuration implements IConfiguration { - // These attributes are used in tests - private readonly defaultSnykCodeBaseURL = 'https://deeproxy.snyk.io'; - private readonly defaultAuthHost = 'https://snyk.io'; - private readonly defaultOssApiEndpoint = `${this.defaultAuthHost}/api/v1`; - private readonly defaultBaseApiHost = 'https://api.snyk.io'; + private readonly defaultAuthHost = 'https://app.snyk.io'; + private readonly defaultApiEndpoint = 'https://api.snyk.io'; + private readonly defaultCliBaseDownloadUrl = 'https://downloads.snyk.io'; + private readonly defaultCliReleaseChannel = 'stable'; + + private featureFlag: { [key: string]: boolean } = {}; + private extensionId: string; constructor(private processEnv: NodeJS.ProcessEnv = process.env, private workspace: IVSCodeWorkspace) {} + getExtensionId(): string { + return this.extensionId; + } + + setExtensionId(extensionId: string): void { + this.extensionId = extensionId; + } + + async setCliReleaseChannel(releaseChannel: string): Promise { + if (!releaseChannel) return; + return this.workspace.updateConfiguration( + CONFIGURATION_IDENTIFIER, + this.getConfigName(ADVANCED_CLI_RELEASE_CHANNEL), + releaseChannel, + true, + ); + } + + async setCliBaseDownloadUrl(baseDownloadUrl: string): Promise { + if (!baseDownloadUrl) return; + return this.workspace.updateConfiguration( + CONFIGURATION_IDENTIFIER, + this.getConfigName(ADVANCED_CLI_BASE_DOWNLOAD_URL), + baseDownloadUrl, + true, + ); + } + + async getCliReleaseChannel(): Promise { + let releaseChannel = this.workspace.getConfiguration( + CONFIGURATION_IDENTIFIER, + this.getConfigName(ADVANCED_CLI_RELEASE_CHANNEL), + ); + const extensionId = this.getExtensionId(); + // If Extension is preview and has default value of release Channel we override it to preview. + if (extensionId && extensionId.includes('preview') && releaseChannel === this.defaultCliReleaseChannel) { + await this.setCliReleaseChannel('preview'); + releaseChannel = 'preview'; + } else if (!releaseChannel) { + releaseChannel = this.defaultCliReleaseChannel; + } + return releaseChannel; + } + + getCliBaseDownloadUrl(): string { + return ( + this.workspace.getConfiguration( + CONFIGURATION_IDENTIFIER, + this.getConfigName(ADVANCED_CLI_BASE_DOWNLOAD_URL), + ) ?? this.defaultCliBaseDownloadUrl + ); + } + + getOssQuickFixCodeActionsEnabled(): boolean { + return this.getPreviewFeatures().ossQuickfixes ?? false; + } + + getSnykLanguageServerPath(): string | undefined { + return this.workspace.getConfiguration( + CONFIGURATION_IDENTIFIER, + this.getConfigName(ADVANCED_CUSTOM_LS_PATH), + ); + } + getInsecure(): boolean { const strictSSL = this.workspace.getConfiguration('http', 'proxyStrictSSL') ?? true; return !strictSSL; @@ -140,6 +243,14 @@ export class Configuration implements IConfiguration { return preview; } + getFeatureFlag(flagName: string): boolean { + return this.featureFlag[flagName] ?? false; + } + + setFeatureFlag(flagName: string, value: boolean): void { + this.featureFlag[flagName] = value; + } + private static async getPackageJsonConfig(): Promise<{ version: string; preview: boolean }> { return (await import(path.join('../../../..', 'package.json'))) as { version: string; preview: boolean }; } @@ -148,25 +259,6 @@ export class Configuration implements IConfiguration { return !!this.processEnv.SNYK_VSCE_DEVELOPMENT; } - get snykCodeBaseURL(): string { - if (this.processEnv.SNYK_VSCE_DEVELOPMENT_SNYKCODE_BASE_URL) { - return this.processEnv.SNYK_VSCE_DEVELOPMENT_SNYKCODE_BASE_URL; - } else if (this.customEndpoint) { - const url = new URL(this.customEndpoint); - - if (Configuration.isSingleTenant(url)) { - url.host = url.host.replace('app', 'deeproxy'); - } else { - url.host = `deeproxy.${url.host}`; - } - url.pathname = url.pathname.replace('api', ''); - - return this.removeTrailingSlash(url.toString()); - } - - return this.defaultSnykCodeBaseURL; - } - private get customEndpoint(): string | undefined { return this.workspace.getConfiguration( CONFIGURATION_IDENTIFIER, @@ -177,6 +269,7 @@ export class Configuration implements IConfiguration { get authHost(): string { if (this.customEndpoint) { const url = new URL(this.customEndpoint); + url.host = url.host.replace('api', 'app'); return `${url.protocol}//${url.host}`; } @@ -202,35 +295,40 @@ export class Configuration implements IConfiguration { const hostnameParts = endpoint.hostname.split('.'); if (hostnameParts.length < 3) return false; - const isFedrampDomain = `${hostnameParts[2]}.${hostnameParts[3]}`.includes('snykgov.io'); - return isFedrampDomain; + return `${hostnameParts[2]}.${hostnameParts[3]}`.includes('snykgov.io'); } - get snykOssApiEndpoint(): string { + get snykApiEndpoint(): string { if (this.customEndpoint) { - return this.customEndpoint; // E.g. https://app.eu.snyk.io/api + return this.customEndpoint; } - return this.defaultOssApiEndpoint; + return this.defaultApiEndpoint; } get snykCodeUrl(): string { const authUrl = new URL(this.authHost); - - if (Configuration.isSingleTenant(authUrl)) { - authUrl.pathname = authUrl.pathname.replace('api', ''); - } else { - authUrl.host = `app.${authUrl.host}`; - } - return `${authUrl.toString()}manage/snyk-code?from=vscode`; } - getSnykLanguageServerPath(): string | undefined { - return this.workspace.getConfiguration( + getDeltaFindingsEnabled(): boolean { + const selectionValue = this.workspace.getConfiguration( CONFIGURATION_IDENTIFIER, - this.getConfigName(ADVANCED_CUSTOM_LS_PATH), + this.getConfigName(DELTA_FINDINGS), ); + return selectionValue === NEWISSUES; + } + + getAuthenticationMethod(): string { + const setting = this.workspace.getConfiguration( + CONFIGURATION_IDENTIFIER, + this.getConfigName(ADVANCED_AUTHENTICATION_METHOD), + ); + if (setting?.toLowerCase() != 'token authentication') { + return 'oauth'; + } else { + return 'token'; + } } async getToken(): Promise { @@ -246,20 +344,15 @@ export class Configuration implements IConfiguration { }); } - get snykCodeToken(): Promise { - if (this.isDevelopment && this.processEnv.SNYK_VSCE_DEVELOPMENT_SNYKCODE_TOKEN) { - return Promise.resolve(this.processEnv.SNYK_VSCE_DEVELOPMENT_SNYKCODE_TOKEN); - } - return this.getToken(); - } - async setToken(token: string | undefined): Promise { if (!token) return; return await SecretStorageAdapter.instance.store(SNYK_TOKEN_KEY, token); } async setCliPath(cliPath: string | undefined): Promise { - if (!cliPath) return; + if (!cliPath) { + cliPath = await CliExecutable.getPath(); + } return this.workspace.updateConfiguration( CONFIGURATION_IDENTIFIER, this.getConfigName(ADVANCED_CLI_PATH), @@ -279,18 +372,6 @@ export class Configuration implements IConfiguration { }); } - static get source(): string { - return IDE_NAME_SHORT; - } - - get source(): string { - return Configuration.source; - } - - get baseApiUrl(): string { - return this.defaultBaseApiHost; - } - getFeaturesConfiguration(): FeaturesConfiguration { const ossEnabled = this.workspace.getConfiguration( CONFIGURATION_IDENTIFIER, @@ -328,6 +409,12 @@ export class Configuration implements IConfiguration { } async setFeaturesConfiguration(config: FeaturesConfiguration | undefined): Promise { + await this.workspace.updateConfiguration( + CONFIGURATION_IDENTIFIER, + this.getConfigName(OSS_ENABLED_SETTING), + config?.ossEnabled, + true, + ); await this.workspace.updateConfiguration( CONFIGURATION_IDENTIFIER, this.getConfigName(CODE_SECURITY_ENABLED_SETTING), @@ -340,28 +427,18 @@ export class Configuration implements IConfiguration { config?.codeQualityEnabled, true, ); - } - - get shouldReportErrors(): boolean { - return !!this.workspace.getConfiguration( + await this.workspace.updateConfiguration( CONFIGURATION_IDENTIFIER, - this.getConfigName(YES_CRASH_REPORT_SETTING), + this.getConfigName(IAC_ENABLED_SETTING), + config?.iacEnabled, + true, ); } - get shouldReportEvents(): boolean { + get shouldReportErrors(): boolean { return !!this.workspace.getConfiguration( CONFIGURATION_IDENTIFIER, - this.getConfigName(YES_TELEMETRY_SETTING), - ); - } - - async setShouldReportEvents(yesTelemetry: boolean): Promise { - await this.workspace.updateConfiguration( - CONFIGURATION_IDENTIFIER, - this.getConfigName(YES_TELEMETRY_SETTING), - yesTelemetry, - true, + this.getConfigName(YES_CRASH_REPORT_SETTING), ); } @@ -411,6 +488,20 @@ export class Configuration implements IConfiguration { ); } + get issueViewOptions(): IssueViewOptions { + const config = this.workspace.getConfiguration( + CONFIGURATION_IDENTIFIER, + this.getConfigName(ISSUE_VIEW_OPTIONS_SETTING), + ); + + return ( + config ?? { + openIssues: true, + ignoredIssues: true, + } + ); + } + get severityFilter(): SeverityFilter { const config = this.workspace.getConfiguration( CONFIGURATION_IDENTIFIER, @@ -434,6 +525,7 @@ export class Configuration implements IConfiguration { getPreviewFeatures(): PreviewFeatures { const defaultSetting: PreviewFeatures = { advisor: false, + ossQuickfixes: false, }; const userSetting = @@ -462,16 +554,41 @@ export class Configuration implements IConfiguration { ); } - getCliPath(): string | undefined { - return this.workspace.getConfiguration(CONFIGURATION_IDENTIFIER, this.getConfigName(ADVANCED_CLI_PATH)); + async getCliPath(): Promise { + let cliPath = this.workspace.getConfiguration( + CONFIGURATION_IDENTIFIER, + this.getConfigName(ADVANCED_CLI_PATH), + ); + if (!cliPath) { + cliPath = await this.determineCliPath(); + await this.setCliPath(cliPath); + } + return cliPath; } + async determineCliPath(): Promise { + // if CLI Path is empty and Automatic Dependency management is disabled + // But Snyk-LS path is set, we will set CLI Path to Snyk LS path. + // This is a workaround that should be removed after the release of v2.20.0 + const isAutomaticDependencyManagementEnabled = this.isAutomaticDependencyManagementEnabled(); + const snykLsPath = this.getSnykLanguageServerPath(); + if (!isAutomaticDependencyManagementEnabled && snykLsPath) return snykLsPath; + const defaultPath = await CliExecutable.getPath(); + return defaultPath; + } getTrustedFolders(): string[] { return ( this.workspace.getConfiguration(CONFIGURATION_IDENTIFIER, this.getConfigName(TRUSTED_FOLDERS)) || [] ); } + getFolderConfigs(): FolderConfig[] { + return ( + this.workspace.getConfiguration(CONFIGURATION_IDENTIFIER, this.getConfigName(FOLDER_CONFIGS)) || + [] + ); + } + get scanningMode(): string | undefined { return this.workspace.getConfiguration(CONFIGURATION_IDENTIFIER, this.getConfigName(SCANNING_MODE)); } @@ -484,13 +601,15 @@ export class Configuration implements IConfiguration { true, ); } - private getConfigName = (setting: string) => setting.replace(`${CONFIGURATION_IDENTIFIER}.`, ''); - private static isSingleTenant(url: URL): boolean { - return url.host.startsWith('app') && url.host.endsWith('snyk.io'); + async setFolderConfigs(folderConfigs: FolderConfig[]): Promise { + await this.workspace.updateConfiguration( + CONFIGURATION_IDENTIFIER, + this.getConfigName(FOLDER_CONFIGS), + folderConfigs, + true, + ); } - private removeTrailingSlash(str: string) { - return str.replace(/\/$/, ''); - } + private getConfigName = (setting: string) => setting.replace(`${CONFIGURATION_IDENTIFIER}.`, ''); } diff --git a/src/snyk/common/configuration/folderConfigs.ts b/src/snyk/common/configuration/folderConfigs.ts new file mode 100644 index 000000000..94da2dc19 --- /dev/null +++ b/src/snyk/common/configuration/folderConfigs.ts @@ -0,0 +1,69 @@ +import { IVSCodeWindow } from '../vscode/window'; +import { FolderConfig, IConfiguration } from './configuration'; + +export interface IFolderConfigs { + getFolderConfigs(config: IConfiguration): ReadonlyArray; + getFolderConfig(config: IConfiguration, folderPath: string): FolderConfig | undefined; + setFolderConfig(config: IConfiguration, folderConfig: FolderConfig): Promise; + setBranch(window: IVSCodeWindow, config: IConfiguration, folderPath: string): Promise; + resetFolderConfigsCache(): void; +} + +export class FolderConfigs implements IFolderConfigs { + private folderConfigsCache?: ReadonlyArray; + + getFolderConfig(config: IConfiguration, folderPath: string): FolderConfig | undefined { + const folderConfigs = this.getFolderConfigs(config); + return folderConfigs.find(i => i.folderPath === folderPath); + } + + getFolderConfigs(config: IConfiguration): ReadonlyArray { + if (this.folderConfigsCache !== undefined) { + return this.folderConfigsCache; + } + const folderConfigs = config.getFolderConfigs(); + this.folderConfigsCache = folderConfigs; + + return folderConfigs; + } + + async setBranch(window: IVSCodeWindow, config: IConfiguration, folderPath: string): Promise { + const folderConfig = this.getFolderConfig(config, folderPath); + + if (!folderConfig) { + return; + } + + const branchName = await window.showInputBox({ + placeHolder: '', + validateInput: input => { + const valid = this.validateBranchName(input, folderConfig.localBranches ?? []); + if (!valid) { + return "The chosen branch name doesn't exist."; + } + }, + }); + if (!branchName) { + return; + } + + folderConfig.baseBranch = branchName; + await this.setFolderConfig(config, folderConfig); + } + + private validateBranchName(branchName: string, branchList: string[]): boolean { + return branchList.includes(branchName); + } + + async setFolderConfig(config: IConfiguration, folderConfig: FolderConfig): Promise { + const currentFolderConfigs = this.getFolderConfigs(config); + const finalFolderConfigs = currentFolderConfigs.map(i => + i.folderPath === folderConfig.folderPath ? folderConfig : i, + ); + await config.setFolderConfigs(finalFolderConfigs); + } + + resetFolderConfigsCache() { + this.folderConfigsCache = undefined; + } +} diff --git a/src/snyk/common/configuration/snykConfiguration.ts b/src/snyk/common/configuration/snykConfiguration.ts index 635941bcd..9f4c7a8c8 100644 --- a/src/snyk/common/configuration/snykConfiguration.ts +++ b/src/snyk/common/configuration/snykConfiguration.ts @@ -4,12 +4,10 @@ export class SnykConfiguration { private static readonly configFileName = 'snyk.config.json'; private static readonly localConfigFileName = 'snyk.config.local.json'; - readonly segmentWriteKey: string; readonly amplitudeExperimentApiKey: string; readonly sentryKey: string; - constructor(segmentWriteKey: string, amplitudeExperimentApiKey: string, sentryKey: string) { - this.segmentWriteKey = segmentWriteKey; + constructor(amplitudeExperimentApiKey: string, sentryKey: string) { this.amplitudeExperimentApiKey = amplitudeExperimentApiKey; this.sentryKey = sentryKey; } diff --git a/src/snyk/common/constants/commands.ts b/src/snyk/common/constants/commands.ts index 7dbbb9c19..b49959089 100644 --- a/src/snyk/common/constants/commands.ts +++ b/src/snyk/common/constants/commands.ts @@ -2,7 +2,6 @@ export const VSCODE_GO_TO_SETTINGS_COMMAND = 'workbench.action.openSettings'; export const VSCODE_VIEW_CONTAINER_COMMAND = 'workbench.view.extension.snyk'; export const VSCODE_ADD_COMMENT_COMMAND = 'editor.action.addCommentLine'; -export const VSCODE_VIEW_OSS_VIEW_COMMAND = 'snyk.views.analysis.oss.focus'; // custom Snyk commands export const SNYK_START_COMMAND = 'snyk.start'; @@ -17,13 +16,21 @@ export const SNYK_OPEN_ISSUE_COMMAND = 'snyk.showissue'; export const SNYK_IGNORE_ISSUE_COMMAND = 'snyk.ignoreissue'; export const SNYK_SHOW_OUTPUT_COMMAND = 'snyk.showOutputChannel'; export const SNYK_SHOW_LS_OUTPUT_COMMAND = 'snyk.showLsOutputChannel'; +export const SNYK_SHOW_ERROR_FROM_CONTEXT_COMMAND = 'snyk.showErrorFromContext'; export const SNYK_GET_LESSON_COMMAND = 'snyk.getLearnLesson'; export const SNYK_GET_SETTINGS_SAST_ENABLED = 'snyk.getSettingsSastEnabled'; -// commands +export const SNYK_SET_BASE_BRANCH_COMMAND = 'snyk.setBaseBranch'; export const SNYK_LOGIN_COMMAND = 'snyk.login'; export const SNYK_WORKSPACE_SCAN_COMMAND = 'snyk.workspace.scan'; export const SNYK_TRUST_WORKSPACE_FOLDERS_COMMAND = 'snyk.trustWorkspaceFolders'; export const SNYK_GET_ACTIVE_USER = 'snyk.getActiveUser'; +export const SNYK_CODE_FIX_DIFFS_COMMAND = 'snyk.code.fixDiffs'; +export const SNYK_CODE_SUBMIT_FIX_FEEDBACK = 'snyk.code.submitFixFeedback'; +export const SNYK_FEATURE_FLAG_COMMAND = 'snyk.getFeatureFlagStatus'; +export const SNYK_CLEAR_CACHE_COMMAND = 'snyk.clearCache'; +export const SNYK_CLEAR_PERSISTED_CACHE_COMMAND = 'snyk.clearPersistedCache'; +export const SNYK_GENERATE_ISSUE_DESCRIPTION = 'snyk.generateIssueDescription'; +export const SNYK_REPORT_ANALYTICS = 'snyk.reportAnalytics'; // custom Snyk constants used in commands export const SNYK_CONTEXT_PREFIX = 'snyk:'; diff --git a/src/snyk/common/constants/errors.ts b/src/snyk/common/constants/errors.ts new file mode 100644 index 000000000..32f9f6f20 --- /dev/null +++ b/src/snyk/common/constants/errors.ts @@ -0,0 +1,3 @@ +export const ERRORS = { + DOWNLOAD_FAILED: `Unable to download the Snyk CLI. This could be caused by connectivity issues or the CLI not being available on the selected release channel.`, +}; diff --git a/src/snyk/common/constants/featureFlags.ts b/src/snyk/common/constants/featureFlags.ts new file mode 100644 index 000000000..14dfd7326 --- /dev/null +++ b/src/snyk/common/constants/featureFlags.ts @@ -0,0 +1,4 @@ +export const FEATURE_FLAGS = { + consistentIgnores: 'snykCodeConsistentIgnores', + snykCodeInlineIgnore: 'snykCodeInlineIgnore', +}; diff --git a/src/snyk/common/constants/general.ts b/src/snyk/common/constants/general.ts index d6e685c4e..8a1b06cf8 100644 --- a/src/snyk/common/constants/general.ts +++ b/src/snyk/common/constants/general.ts @@ -1,20 +1,13 @@ // Changing this requires changing display name in package.json. -export const SNYK_NAME = 'Snyk Security - Code, Open Source Dependencies, IaC Configurations'; +export const SNYK_NAME = 'Snyk Security'; export const SNYK_TOKEN_KEY = 'snyk.token'; -export const SNYK_UNIQUE_EXTENSION_NAME = 'Snyk Vulnerability Scanner'; +const SNYK_UNIQUE_EXTENSION_NAME = 'Snyk Vulnerability Scanner'; export const SNYK_PUBLISHER = 'snyk-security'; export const SNYK_NAME_EXTENSION = SNYK_UNIQUE_EXTENSION_NAME.toLowerCase().replace(/[()]/g, '').replace(/\s/g, '-'); -export const MAX_CONNECTION_RETRIES = 5; // max number of automatic retries before showing an error -export const IDE_NAME = 'Visual Studio Code'; export const IDE_NAME_SHORT = 'vscode'; export const COMMAND_DEBOUNCE_INTERVAL = 200; // 200 milliseconds export const DEFAULT_SCAN_DEBOUNCE_INTERVAL = 1000; // 1 second export const DEFAULT_LS_DEBOUNCE_INTERVAL = 1000; // 1 second -export const OSS_SCAN_DEBOUNCE_INTERVAL = 10000; // 10 seconds -export const EXECUTION_THROTTLING_INTERVAL = 1000 * 10; // * 60 * 30; // 30 minutes -export const EXECUTION_PAUSE_INTERVAL = 1000 * 60 * 30; // 30 minutes export const REFRESH_VIEW_DEBOUNCE_INTERVAL = 200; // 200 milliseconds -// If CONNECTION_ERROR_RETRY_INTERVAL is smaller than EXECUTION_DEBOUNCE_INTERVAL it might get swallowed by the debouncer -export const CONNECTION_ERROR_RETRY_INTERVAL = DEFAULT_SCAN_DEBOUNCE_INTERVAL * 2 + 1000 * 3; - -export const SNYK_LEARN_API_CACHE_DURATION_IN_MS = 1000 * 60 * 60 * 24; // 1 day +export const InMemory = 'inMemory'; +export const Persisted = 'persisted'; diff --git a/src/snyk/common/constants/globalState.ts b/src/snyk/common/constants/globalState.ts index cb62ac2eb..4d8add9da 100644 --- a/src/snyk/common/constants/globalState.ts +++ b/src/snyk/common/constants/globalState.ts @@ -1,5 +1,5 @@ -export const MEMENTO_FIRST_INSTALL_DATE_KEY = 'snyk.firstInstallDate'; export const MEMENTO_ANONYMOUS_ID = 'snyk.anonymousId'; -export const MEMENTO_LS_LAST_UPDATE_DATE = 'snyk.lsLastUpdateDate'; +export const MEMENTO_CLI_VERSION = 'snyk.cliVersion'; +export const MEMENTO_CLI_CHECKSUM = 'snyk.cliChecksum'; export const MEMENTO_LS_PROTOCOL_VERSION = 'snyk.lsProtocolVersion'; -export const MEMENTO_LS_CHECKSUM = 'snyk.lsChecksum'; +export const MEMENTO_ANALYTICS_PLUGIN_INSTALLED_SENT = 'snyk.pluginInstalledSent'; diff --git a/src/snyk/common/constants/languageConsts.ts b/src/snyk/common/constants/languageConsts.ts index 45d5b3ea9..e0f1bef36 100644 --- a/src/snyk/common/constants/languageConsts.ts +++ b/src/snyk/common/constants/languageConsts.ts @@ -7,5 +7,3 @@ export const JAVASCRIPT = 'javascript'; export const JAVASCRIPT_REACT = 'javascriptreact'; export const HTML = 'html'; export const PJSON = 'json'; - -export const SupportedLanguageIds = [TYPESCRIPT, TYPESCRIPT_REACT, JAVASCRIPT, JAVASCRIPT_REACT, HTML, PJSON]; diff --git a/src/snyk/common/constants/languageServer.ts b/src/snyk/common/constants/languageServer.ts index 94230e378..4ab1e3e12 100644 --- a/src/snyk/common/constants/languageServer.ts +++ b/src/snyk/common/constants/languageServer.ts @@ -2,13 +2,13 @@ // Language Server name, used e.g. for the output channel export const SNYK_LANGUAGE_SERVER_NAME = 'Snyk Language Server'; // The internal language server protocol version for custom messages and configuration -export const PROTOCOL_VERSION = 10; +export const PROTOCOL_VERSION = 17; // LS protocol methods (needed for not having to rely on vscode dependencies in testing) export const DID_CHANGE_CONFIGURATION_METHOD = 'workspace/didChangeConfiguration'; // custom methods export const SNYK_HAS_AUTHENTICATED = '$/snyk.hasAuthenticated'; -export const SNYK_CLI_PATH = '$/snyk.isAvailableCli'; export const SNYK_ADD_TRUSTED_FOLDERS = '$/snyk.addTrustedFolders'; export const SNYK_SCAN = '$/snyk.scan'; +export const SNYK_FOLDERCONFIG = '$/snyk.folderConfigs'; diff --git a/src/snyk/common/constants/settings.ts b/src/snyk/common/constants/settings.ts index 4e831c765..f2f9e2d28 100644 --- a/src/snyk/common/constants/settings.ts +++ b/src/snyk/common/constants/settings.ts @@ -9,7 +9,6 @@ export const IAC_ENABLED_SETTING = `${CONFIGURATION_IDENTIFIER}.features.infrast export const FEATURES_PREVIEW_SETTING = `${CONFIGURATION_IDENTIFIER}.features.preview`; export const YES_CRASH_REPORT_SETTING = `${CONFIGURATION_IDENTIFIER}.yesCrashReport`; -export const YES_TELEMETRY_SETTING = `${CONFIGURATION_IDENTIFIER}.yesTelemetry`; export const YES_WELCOME_NOTIFICATION_SETTING = `${CONFIGURATION_IDENTIFIER}.yesWelcomeNotification`; export const YES_BACKGROUND_OSS_NOTIFICATION_SETTING = `${CONFIGURATION_IDENTIFIER}.yesBackgroundOssNotification`; @@ -21,7 +20,14 @@ export const ADVANCED_ORGANIZATION = `${CONFIGURATION_IDENTIFIER}.advanced.organ export const ADVANCED_AUTOMATIC_DEPENDENCY_MANAGEMENT = `${CONFIGURATION_IDENTIFIER}.advanced.automaticDependencyManagement`; export const ADVANCED_CLI_PATH = `${CONFIGURATION_IDENTIFIER}.advanced.cliPath`; export const ADVANCED_CUSTOM_LS_PATH = `${CONFIGURATION_IDENTIFIER}.advanced.languageServerPath`; +export const ADVANCED_CLI_BASE_DOWNLOAD_URL = `${CONFIGURATION_IDENTIFIER}.advanced.cliBaseDownloadUrl`; +export const ADVANCED_CLI_RELEASE_CHANNEL = `${CONFIGURATION_IDENTIFIER}.advanced.cliReleaseChannel`; +export const ADVANCED_AUTHENTICATION_METHOD = `${CONFIGURATION_IDENTIFIER}.advanced.authenticationMethod`; +export const ISSUE_VIEW_OPTIONS_SETTING = `${CONFIGURATION_IDENTIFIER}.issueViewOptions`; export const SEVERITY_FILTER_SETTING = `${CONFIGURATION_IDENTIFIER}.severity`; export const TRUSTED_FOLDERS = `${CONFIGURATION_IDENTIFIER}.trustedFolders`; +export const FOLDER_CONFIGS = `${CONFIGURATION_IDENTIFIER}.folderConfigs`; export const SCANNING_MODE = `${CONFIGURATION_IDENTIFIER}.scanningMode`; + +export const DELTA_FINDINGS = `${CONFIGURATION_IDENTIFIER}.allIssuesVsNetNewIssues`; diff --git a/src/snyk/common/constants/views.ts b/src/snyk/common/constants/views.ts index 6616a1ef5..438827751 100644 --- a/src/snyk/common/constants/views.ts +++ b/src/snyk/common/constants/views.ts @@ -1,5 +1,6 @@ +// see https://code.visualstudio.com/api/references/contribution-points#contributes.viewsWelcome + export const SNYK_VIEW_WELCOME = 'snyk.views.welcome'; -export const SNYK_VIEW_FEATURES = 'snyk.views.features'; export const SNYK_VIEW_ANALYSIS_CODE_ENABLEMENT = 'snyk.views.analysis.code.enablement'; export const SNYK_VIEW_ANALYSIS_CODE_SECURITY = 'snyk.views.analysis.code.security'; export const SNYK_VIEW_ANALYSIS_CODE_QUALITY = 'snyk.views.analysis.code.quality'; @@ -15,6 +16,7 @@ export const SNYK_VIEW_ANALYSIS_IAC = 'snyk.views.analysis.configuration'; export const SNYK_CONTEXT = { INITIALIZED: 'initialized', // default to loading state (notLoading = false when boolean is initialized) LOGGEDIN: 'loggedIn', + AUTHENTICATION_METHOD_CHANGED: 'authMethodChanged', AUTHENTICATING: 'authenticating', CODE_ENABLED: 'codeEnabled', CODE_LOCAL_ENGINE_ENABLED: 'codeLocalEngineEnabled', @@ -22,10 +24,7 @@ export const SNYK_CONTEXT = { ERROR: 'error', MODE: 'mode', ADVANCED: 'advanced', -}; - -export const SNYK_ERROR_CODES = { - BLOCKING: 'blocking', + DELTA_FINDINGS_ENABLED: 'deltaFindingsEnabled', }; export const SNYK_ANALYSIS_STATUS = { diff --git a/src/snyk/common/download/downloader.ts b/src/snyk/common/download/downloader.ts index 0d02fe5e8..11542e9cc 100644 --- a/src/snyk/common/download/downloader.ts +++ b/src/snyk/common/download/downloader.ts @@ -1,53 +1,60 @@ import axios, { CancelTokenSource } from 'axios'; import * as fs from 'fs'; -import { mkdirSync } from 'fs'; +import * as path from 'path'; import * as fsPromises from 'fs/promises'; -import path from 'path'; import * as stream from 'stream'; +import { mkdirSync } from 'fs'; import { Progress } from 'vscode'; import { Checksum } from '../../cli/checksum'; -import { CliExecutable } from '../../cli/cliExecutable'; import { messages } from '../../cli/messages/messages'; import { IConfiguration } from '../configuration/configuration'; -import { LsExecutable } from '../languageServer/lsExecutable'; -import { IStaticLsApi } from '../languageServer/staticLsApi'; -import { LsSupportedPlatform } from '../languageServer/supportedPlatforms'; +import { IStaticCliApi } from '../../cli/staticCliApi'; +import { CliExecutable } from '../../cli/cliExecutable'; import { ILog } from '../logger/interfaces'; import { CancellationToken } from '../vscode/types'; import { IVSCodeWindow } from '../vscode/window'; +import { CliSupportedPlatform } from '../../cli/supportedPlatforms'; +import { ExtensionContext } from '../vscode/extensionContext'; +import { ERRORS } from '../constants/errors'; export type DownloadAxiosResponse = { data: stream.Readable; headers: { [header: string]: unknown } }; export class Downloader { constructor( private readonly configuration: IConfiguration, - private readonly lsApi: IStaticLsApi, + private readonly cliApi: IStaticCliApi, private readonly window: IVSCodeWindow, private readonly logger: ILog, + private readonly extensionContext: ExtensionContext, ) {} - /** - * Downloads LS. Existing executable is deleted. + * Downloads CLI. Existing executable is deleted. */ - async download(): Promise { - const lsPlatform = LsExecutable.getCurrentWithArch(); - if (lsPlatform === null) { - return Promise.reject(!messages.notSupported); + async download(): Promise { + try { + const platform = await CliExecutable.getCurrentWithArch(); + if (platform === null) { + return Promise.reject(!messages.notSupported); + } + return await this.getCliExecutable(platform); + } catch (e) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + this.logger.error(e); + throw new Error(ERRORS.DOWNLOAD_FAILED); } - return await this.getLsExecutable(lsPlatform); } - private async getLsExecutable(lsPlatform: LsSupportedPlatform): Promise { - const lsPath = LsExecutable.getPath(this.configuration.getSnykLanguageServerPath()); - const lsDir = path.dirname(lsPath); - mkdirSync(lsDir, { recursive: true }); - if (await this.binaryExists(lsPath)) { - await this.deleteFileAtPath(lsPath); + private async getCliExecutable(platform: CliSupportedPlatform): Promise { + const cliPath = await this.configuration.getCliPath(); + const cliDir = path.dirname(cliPath); + mkdirSync(cliDir, { recursive: true }); + if (await this.binaryExists(cliPath)) { + await this.deleteFileAtPath(cliPath); } - - const lsVersion = (await this.lsApi.getMetadata()).version; - const sha256 = await this.lsApi.getSha256Checksum(lsPlatform); - const checksum = await this.downloadLs(lsPath, lsPlatform, sha256); + const cliReleaseChannel = await this.configuration.getCliReleaseChannel(); + const cliVersion = await this.cliApi.getLatestCliVersion(cliReleaseChannel); + const sha256 = await this.cliApi.getSha256Checksum(cliVersion, platform); + const checksum = await this.downloadCli(cliPath, platform, sha256); if (!checksum) { return null; @@ -58,7 +65,7 @@ export class Downloader { return Promise.reject(messages.integrityCheckFailed); } - return new LsExecutable(lsVersion, checksum); + return new CliExecutable(cliVersion, checksum); } private async binaryExists(filePath: string): Promise { @@ -78,25 +85,25 @@ export class Downloader { } } - public async downloadLs( - lsPath: string, - platform: LsSupportedPlatform, + public async downloadCli( + cliPath: string, + platform: CliSupportedPlatform, expectedChecksum: string, ): Promise { const hash = new Checksum(expectedChecksum); return this.window.withProgress(messages.progressTitle, async (progress, token) => { const [request, requestToken]: [response: Promise, cancelToken: CancelTokenSource] = - await this.lsApi.downloadBinary(platform); + await this.cliApi.downloadBinary(platform); token.onCancellationRequested(async () => { requestToken.cancel(); this.logger.info(messages.downloadCanceled); - await this.deleteFileAtPath(lsPath); + await this.deleteFileAtPath(cliPath); }); progress.report({ increment: 0 }); - return await this.doDownload(requestToken, token, lsPath, request, hash, progress); + return await this.doDownload(requestToken, token, cliPath, request, hash, progress); }); } diff --git a/src/snyk/common/editor/codeActionsProvider.ts b/src/snyk/common/editor/codeActionsProvider.ts index 74a38b4b9..68b1f394d 100644 --- a/src/snyk/common/editor/codeActionsProvider.ts +++ b/src/snyk/common/editor/codeActionsProvider.ts @@ -1,38 +1,30 @@ -import { IAnalytics, SupportedQuickFixProperties } from '../../common/analytics/itly'; -import { IDE_NAME } from '../../common/constants/general'; -import { Issue } from '../../common/languageServer/types'; -import { ICodeActionKindAdapter } from '../../common/vscode/codeAction'; -import { CodeAction, CodeActionKind, CodeActionProvider, Range, TextDocument } from '../../common/vscode/types'; +import { Issue } from '../languageServer/types'; +import { ICodeActionKindAdapter } from '../vscode/codeAction'; +import { CodeAction, CodeActionContext, CodeActionProvider, Range, TextDocument } from '../vscode/types'; import { ProductResult } from '../services/productService'; export abstract class CodeActionsProvider implements CodeActionProvider { protected readonly providedCodeActionKinds = [this.codeActionKindAdapter.getQuickFix()]; constructor( - private readonly issues: ProductResult, + protected readonly issues: ProductResult, private readonly codeActionKindAdapter: ICodeActionKindAdapter, - private readonly analytics: IAnalytics, ) {} - abstract getActions(folderPath: string, document: TextDocument, issue: Issue, issueRange: Range): CodeAction[]; - - abstract getAnalyticsActionTypes(): [string, ...string[]] & - [SupportedQuickFixProperties, ...SupportedQuickFixProperties[]]; + abstract getActions(folderPath: string, document: TextDocument, issue: Issue, issueRange?: Range): CodeAction[]; abstract getIssueRange(issue: Issue): Range; - getProvidedCodeActionKinds(): CodeActionKind[] { - return this.providedCodeActionKinds; - } - - public provideCodeActions(document: TextDocument, clickedRange: Range): CodeAction[] | undefined { + public provideCodeActions( + document: TextDocument, + clickedRange: Range, + _context: CodeActionContext, + ): CodeAction[] | undefined { if (this.issues.size === 0) { return undefined; } - for (const result of this.issues.entries()) { - const folderPath = result[0]; - const issues = result[1]; + for (const [folderPath, issues] of this.issues.entries()) { if (issues instanceof Error || !issues) { continue; } @@ -42,22 +34,15 @@ export abstract class CodeActionsProvider implements CodeActionProvider { continue; } - const codeActions = this.getActions(folderPath, document, issue, range); - const analyticsType = this.getAnalyticsActionTypes(); - - this.analytics.logQuickFixIsDisplayed({ - quickFixType: analyticsType, - ide: IDE_NAME, - }); - - // returns list of actions, all new actions should be added to this list - return codeActions; + // If an issue is found, return the actions + return this.getActions(folderPath, document, issue, range); } + // If no issues were found after checking all entries, return undefined return undefined; } - private findIssueWithRange( + protected findIssueWithRange( result: Issue[], document: TextDocument, clickedRange: Range, diff --git a/src/snyk/common/error/errorHandler.ts b/src/snyk/common/error/errorHandler.ts index 835abb015..9bfae6218 100644 --- a/src/snyk/common/error/errorHandler.ts +++ b/src/snyk/common/error/errorHandler.ts @@ -1,8 +1,7 @@ import { ILoadingBadge } from '../../base/views/loadingBadge'; -import { SNYK_CONTEXT, SNYK_ERROR_CODES } from '../constants/views'; +import { SNYK_CONTEXT } from '../constants/views'; import { ILog } from '../logger/interfaces'; import { IContextService } from '../services/contextService'; -import { ErrorReporter, Tags } from './errorReporter'; /** * General error handler. @@ -17,7 +16,7 @@ export class ErrorHandler { contextService: IContextService, loadingBadge: ILoadingBadge, ): Promise { - await contextService.setContext(SNYK_CONTEXT.ERROR, SNYK_ERROR_CODES.BLOCKING); + await contextService.setContext(SNYK_CONTEXT.ERROR, error); loadingBadge.setLoadingBadge(true); ErrorHandler.handle(error, logger); } @@ -25,10 +24,9 @@ export class ErrorHandler { /** * Should be used to log locally and report error event remotely. */ - static handle(error: Error | unknown, logger: ILog, message?: string, tags?: Tags): void { + static handle(error: Error | unknown, logger: ILog, message?: string): void { const errorStr = ErrorHandler.stringifyError(error); logger.error(message ? `${message}. ${errorStr}` : errorStr); - ErrorReporter.capture(error, tags); } static stringifyError(error: Error | unknown): string { diff --git a/src/snyk/common/error/errorReporter.ts b/src/snyk/common/error/errorReporter.ts deleted file mode 100644 index 906d3e2ad..000000000 --- a/src/snyk/common/error/errorReporter.ts +++ /dev/null @@ -1,128 +0,0 @@ -import * as Sentry from '@sentry/node'; -import { Contexts, Transport, TransportClass } from '@sentry/types'; -import { Configuration, IConfiguration } from '../configuration/configuration'; -import { SnykConfiguration } from '../configuration/snykConfiguration'; -import { ILog } from '../logger/interfaces'; -import { Platform } from '../platform'; -import { User } from '../user'; -import { IVSCodeEnv } from '../vscode/env'; -import { OnUncaughtException } from './integrations/onUncaughtException'; - -type SentryEnvironment = 'development' | 'preview' | 'production'; - -export enum TagKeys { - CodeRequestId = 'code_request_id', -} -export type Tags = { [key in TagKeys]?: string }; - -export class ErrorReporter { - private static readonly eventQueueTimeoutMs = 1000; - - /** - * 'OnUncaughException' integration must be ignored since it causes Sentry to permanently fail during runtime. Default Sentry behaviour is to call process.exit() for uncaught errors. - * This is being prevented by VS Code and is logged as: - * --- "An extension called process.exit() and this was prevented.". - * As a result, Sentry shuts down and doesn't log any caught errors: - * --- "Sentry Logger [Warn]: uncaught exception after calling fatal error shutdown callback - this is bad! forcing shutdown". - * - * 'OnUnhandledRejection' must be ignored as well, since it captures unhandled rejections from other extensions running in the extension host and there's no way to determine which extension does the unhandled rejection belong to. - * - * Integrations reference: https://docs.sentry.io/platforms/node/configuration/integrations/default-integrations/ - */ - private static readonly nonValidIntegrations = [ - Sentry.Integrations.OnUncaughtException.id, - Sentry.Integrations.OnUnhandledRejection.id, - ]; - - static async init( - userConfig: IConfiguration, - snykConfig: SnykConfiguration, - extensionPath: string, - vscodeEnv: IVSCodeEnv, - logger: ILog, - transport?: TransportClass, - ): Promise { - if (!snykConfig.sentryKey) { - logger.warn('Error reporting not initialized - key not provided.'); - return; - } - - Sentry.init({ - dsn: snykConfig.sentryKey, - maxBreadcrumbs: 50, - debug: userConfig.isDevelopment, - environment: await ErrorReporter.getEnvironment(userConfig), - release: await Configuration.getVersion(), - transport, - integrations(integrations) { - return [ - ...integrations.filter( - integration => - !ErrorReporter.nonValidIntegrations.map(i => i.toLowerCase()).includes(integration.name.toLowerCase()), - ), - new OnUncaughtException({ extensionPath }), // custom integration for uncaught exceptions - ]; - }, - beforeSend(event) { - // drop reporting, if user doesn't want to report events here - // https://github.com/getsentry/sentry-javascript/issues/2039 - if (!userConfig.shouldReportErrors || userConfig.isFedramp) { - return null; - } - - event.contexts = ErrorReporter.getContexts(vscodeEnv, event.contexts); - return event; - }, - }); - } - - static capture(e: Error | unknown, tags?: Tags): string | undefined { - const isInitialized = Sentry.getCurrentHub().getClient(); - if (isInitialized) { - if (tags && Object.keys(tags).length > 0) { - Sentry.withScope(scope => { - Object.keys(tags).forEach(tag => scope.setTag(tag, tags[tag] as string)); - return Sentry.captureException(e); - }); - } else { - return Sentry.captureException(e); - } - } - } - - static identify(user: User): void { - Sentry.setUser({ - id: user.hashedAuthenticatedId, - }); - } - - static flush(): Promise { - return Sentry.close(this.eventQueueTimeoutMs); - } - - private static getContexts(vscodeEnv: IVSCodeEnv, contexts?: Contexts): Contexts { - return { - ...contexts, - os: { - name: Platform.getCurrent(), - version: Platform.getVersion(), - }, - vscode: { - appName: vscodeEnv.getAppName(), - appHost: vscodeEnv.getAppHost(), - uiKind: vscodeEnv.getUiKind(), - remoteName: vscodeEnv.getRemoteName(), - }, - }; - } - - private static async getEnvironment(userConfig: IConfiguration): Promise { - if (userConfig.isDevelopment) { - return 'development'; - } else if (await Configuration.isPreview()) { - return 'preview'; - } - - return 'production'; - } -} diff --git a/src/snyk/common/error/integrations/onUncaughtException.ts b/src/snyk/common/error/integrations/onUncaughtException.ts deleted file mode 100644 index 03597508a..000000000 --- a/src/snyk/common/error/integrations/onUncaughtException.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { getCurrentHub, Scope } from '@sentry/core'; -import { Integration, Severity } from '@sentry/types'; - -/** Uncaught exception handler based on the Sentry Node.js global handler: - * https://github.dev/getsentry/sentry-javascript/blob/a565aaaeff6ede4bf2ca75b55f919df2c059415b/packages/node/src/integrations/onuncaughtexception.ts#L1-L129. - * The handler tracks uncaught errors and captures only the ones that have extension path as part of the error stacktrace, since VS Code extensions are running in separate folders on the file system. - */ -export class OnUncaughtException implements Integration { - /** - * @inheritDoc - */ - static id = 'OnSnykUncaughtException'; - - /** - * @inheritDoc - */ - name: string = OnUncaughtException.id; - - /** - * @inheritDoc - */ - readonly handler: (error: Error) => void = this.makeErrorHandler(); - - /** - * @inheritDoc - */ - constructor( - private readonly options: { - /** - * Extension path where stack traces should originate from. - */ - extensionPath: string; - }, - ) {} - - /** - * @inheritDoc - */ - setupOnce(): void { - global.process.on('uncaughtException', (error: Error) => this.handler(error)); - } - - isExtensionOriginError(error: Error): boolean { - const extensionTraceRegex = new RegExp(this.options.extensionPath, 'gi'); - - if (error && error instanceof Error && error.stack && extensionTraceRegex.exec(error.stack)) { - // The error doesn't belong to Snyk extension, ignore it - return true; - } - - return false; - } - - /** - * @hidden - */ - private makeErrorHandler(): (error: Error) => void { - return (error: Error): void => { - if (!this.isExtensionOriginError(error)) { - return; - } - - const hub = getCurrentHub(); - if (hub.getIntegration(OnUncaughtException)) { - hub.withScope((scope: Scope) => { - scope.setLevel(Severity.fromString('fatal')); - hub.captureException(error, { - originalException: error, - data: { mechanism: { handled: false, type: 'onuncaughtexception' } }, - }); - }); - } - }; - } -} diff --git a/src/snyk/common/experiment/services/experimentService.ts b/src/snyk/common/experiment/services/experimentService.ts index 0edceb5e4..1cde157aa 100644 --- a/src/snyk/common/experiment/services/experimentService.ts +++ b/src/snyk/common/experiment/services/experimentService.ts @@ -42,11 +42,7 @@ export class ExperimentService { const variants = await this.fetchVariants(forceFetchVariants); const variant = variants[variantFlag]; - if (variant?.value === 'on') { - return true; - } - - return false; + return variant?.value === 'on'; } private async fetchVariants(forceFetchVariants: boolean): Promise { @@ -67,5 +63,5 @@ export class ExperimentService { return this.variants; } - private canExperiment = this.configuration.shouldReportEvents; + private canExperiment = true; } diff --git a/src/snyk/common/git.ts b/src/snyk/common/git.ts new file mode 100644 index 000000000..b1c847979 --- /dev/null +++ b/src/snyk/common/git.ts @@ -0,0 +1,23 @@ +import * as vscode from 'vscode'; + +export interface GitExtension { + getAPI(version: number): GitAPI; +} + +export interface GitAPI { + repositories: Repository[]; +} + +export interface Repository { + rootUri: vscode.Uri; + state: RepositoryState; +} + +export interface RepositoryState { + HEAD: Branch | undefined; + onDidChange: vscode.Event; +} + +export interface Branch { + name?: string; +} diff --git a/src/snyk/common/languageServer/languageServer.ts b/src/snyk/common/languageServer/languageServer.ts index 10be6c636..11ee70504 100644 --- a/src/snyk/common/languageServer/languageServer.ts +++ b/src/snyk/common/languageServer/languageServer.ts @@ -1,10 +1,10 @@ import _ from 'lodash'; import { firstValueFrom, ReplaySubject, Subject } from 'rxjs'; import { IAuthenticationService } from '../../base/services/authenticationService'; -import { IConfiguration } from '../configuration/configuration'; +import { FolderConfig, IConfiguration } from '../configuration/configuration'; import { SNYK_ADD_TRUSTED_FOLDERS, - SNYK_CLI_PATH, + SNYK_FOLDERCONFIG, SNYK_HAS_AUTHENTICATED, SNYK_LANGUAGE_SERVER_NAME, SNYK_SCAN, @@ -19,10 +19,11 @@ import { ILanguageClientAdapter } from '../vscode/languageClient'; import { LanguageClient, LanguageClientOptions, ServerOptions } from '../vscode/types'; import { IVSCodeWindow } from '../vscode/window'; import { IVSCodeWorkspace } from '../vscode/workspace'; -import { LsExecutable } from './lsExecutable'; +import { CliExecutable } from '../../cli/cliExecutable'; import { LanguageClientMiddleware } from './middleware'; import { LanguageServerSettings, ServerSettings } from './settings'; import { CodeIssueData, IacIssueData, OssIssueData, Scan } from './types'; +import { ExtensionContext } from '../vscode/extensionContext'; export interface ILanguageServer { start(): Promise; @@ -49,6 +50,7 @@ export class LanguageServer implements ILanguageServer { private authenticationService: IAuthenticationService, private readonly logger: ILog, private downloadService: DownloadService, + private extensionContext: ExtensionContext, ) { this.downloadService = downloadService; } @@ -76,7 +78,7 @@ export class LanguageServer implements ILanguageServer { }; } - const lsBinaryPath = LsExecutable.getPath(this.configuration.getSnykLanguageServerPath()); + const cliBinaryPath = await this.configuration.getCliPath(); // log level is set to info by default let logLevel = 'info'; @@ -91,10 +93,10 @@ export class LanguageServer implements ILanguageServer { logLevel = process.env.SNYK_LOG_LEVEL ?? logLevel; const args = ['language-server', '-l', logLevel]; - this.logger.info(`Snyk Language Server - path: ${lsBinaryPath}`); + this.logger.info(`Snyk Language Server - path: ${cliBinaryPath}`); this.logger.info(`Snyk Language Server - args: ${args}`); const serverOptions: ServerOptions = { - command: lsBinaryPath, + command: cliBinaryPath, args: args, options: { env: processEnv, @@ -109,7 +111,7 @@ export class LanguageServer implements ILanguageServer { synchronize: { configurationSection: CONFIGURATION_IDENTIFIER, }, - middleware: new LanguageClientMiddleware(this.configuration, this.user), + middleware: new LanguageClientMiddleware(this.configuration, this.user, this.extensionContext), /** * We reuse the output channel here as it's not properly disposed of by the language client (vscode-languageclient@8.0.0-next.2) * See: https://github.com/microsoft/vscode-languageserver-node/blob/cdf4d6fdaefe329ce417621cf0f8b14e0b9bb39d/client/src/common/client.ts#L2789 @@ -118,7 +120,7 @@ export class LanguageServer implements ILanguageServer { }; // Create the language client and start the client. - this.client = this.languageClientAdapter.create('Snyk LS', SNYK_LANGUAGE_SERVER_NAME, serverOptions, clientOptions); + this.client = this.languageClientAdapter.create('SnykLS', SNYK_LANGUAGE_SERVER_NAME, serverOptions, clientOptions); try { // Start the client. This will also launch the server @@ -132,34 +134,16 @@ export class LanguageServer implements ILanguageServer { } private registerListeners(client: LanguageClient): void { - client.onNotification(SNYK_HAS_AUTHENTICATED, ({ token }: { token: string }) => { - this.authenticationService.updateToken(token).catch((error: Error) => { + client.onNotification(SNYK_HAS_AUTHENTICATED, ({ token, apiUrl }: { token: string; apiUrl: string }) => { + this.authenticationService.updateTokenAndEndpoint(token, apiUrl).catch((error: Error) => { ErrorHandler.handle(error, this.logger, error.message); }); }); - client.onNotification(SNYK_CLI_PATH, ({ cliPath }: { cliPath: string }) => { - if (!cliPath) { - ErrorHandler.handle( - new Error("CLI path wasn't provided by language server on $/snyk.isAvailableCli notification " + cliPath), - this.logger, - "CLI path wasn't provided by language server on notification", - ); - return; - } - - const currentCliPath = this.configuration.getCliPath(); - if (currentCliPath != cliPath) { - this.logger.info('Setting Snyk CLI path to: ' + cliPath); - void this.configuration - .setCliPath(cliPath) - .then(() => { - this.cliReady$.next(cliPath); - }) - .catch((error: Error) => { - ErrorHandler.handle(error, this.logger, error.message); - }); - } + client.onNotification(SNYK_FOLDERCONFIG, ({ folderConfigs }: { folderConfigs: FolderConfig[] }) => { + this.configuration.setFolderConfigs(folderConfigs).catch((error: Error) => { + ErrorHandler.handle(error, this.logger, error.message); + }); }); client.onNotification(SNYK_ADD_TRUSTED_FOLDERS, ({ trustedFolders }: { trustedFolders: string[] }) => { diff --git a/src/snyk/common/languageServer/lsExecutable.ts b/src/snyk/common/languageServer/lsExecutable.ts deleted file mode 100644 index 8a7c0ca8e..000000000 --- a/src/snyk/common/languageServer/lsExecutable.ts +++ /dev/null @@ -1,80 +0,0 @@ -import os from 'os'; -import path from 'path'; -import { Checksum } from '../../cli/checksum'; -import { Platform } from '../platform'; -import { LsSupportedPlatform, SupportedLsPlatformsList } from './supportedPlatforms'; -import fs from 'fs/promises'; -import { IConfiguration } from '../configuration/configuration'; - -export class LsExecutable { - private static filenamePrefix = 'snyk-ls'; - public static filenameSuffixes: Record = { - linux386: 'linux_386', - linuxAmd64: 'linux_amd64', - linuxArm64: 'linux_arm64', - windows386: 'windows_386.exe', - windowsAmd64: 'windows_amd64.exe', - darwinAmd64: 'darwin_amd64', - darwinArm64: 'darwin_arm64', - }; - - public static defaultPaths: Record = { - linux386: process.env.XDG_DATA_HOME ?? '/.local/share/', - linuxAmd64: process.env.XDG_DATA_HOME ?? '/.local/share/', - linuxArm64: process.env.XDG_DATA_HOME ?? '/.local/share/', - windows386: process.env.XDG_DATA_HOME ?? '\\AppData\\Local\\', - windowsAmd64: process.env.XDG_DATA_HOME ?? '\\AppData\\Local\\', - darwinAmd64: process.env.XDG_DATA_HOME ?? '/Library/Application Support/', - darwinArm64: process.env.XDG_DATA_HOME ?? '/Library/Application Support/', - }; - - constructor(public readonly version: string, public readonly checksum: Checksum) {} - - static getFilename(platform: LsSupportedPlatform): string { - return `${this.filenamePrefix}_${this.filenameSuffixes[platform]}`; - } - - static getVersionedFilename(platform: LsSupportedPlatform, version: string) { - return `${this.filenamePrefix}_${version}_${this.filenameSuffixes[platform]}`; - } - - static getPath(customPath?: string): string { - if (customPath) { - return customPath; - } - - const platform = this.getCurrentWithArch(); - - const homeDir = Platform.getHomeDir(); - const lsFilename = this.getFilename(platform); - const defaultPath = this.defaultPaths[platform]; - const lsDir = path.join(homeDir, defaultPath, 'snyk-ls'); - return path.join(lsDir, lsFilename); - } - - static getCurrentWithArch(): LsSupportedPlatform { - let opSys = os.platform().toString(); - if (opSys === 'win32') { - opSys = 'windows'; - } - let opArch = os.arch(); - if (opArch === 'x64') { - opArch = 'amd64'; - } - if (opArch === 'ia32') { - opArch = '386'; - } - const supportPlatform = `${opSys}${opArch.charAt(0).toUpperCase()}${opArch.slice(1)}`; - if (SupportedLsPlatformsList.find(p => p === supportPlatform) !== undefined) { - return supportPlatform as LsSupportedPlatform; - } - throw new Error(`Unsupported platform: ${supportPlatform}`); - } - - static exists(configuration: IConfiguration): Promise { - return fs - .access(LsExecutable.getPath(configuration.getSnykLanguageServerPath())) - .then(() => true) - .catch(() => false); - } -} diff --git a/src/snyk/common/languageServer/middleware.ts b/src/snyk/common/languageServer/middleware.ts index 1b695dc38..3f920fb23 100644 --- a/src/snyk/common/languageServer/middleware.ts +++ b/src/snyk/common/languageServer/middleware.ts @@ -1,5 +1,6 @@ import { IConfiguration } from '../../common/configuration/configuration'; import { User } from '../user'; +import { ExtensionContext } from '../vscode/extensionContext'; import type { CancellationToken, ConfigurationParams, @@ -10,7 +11,7 @@ import type { } from '../vscode/types'; import { LanguageServerSettings, ServerSettings } from './settings'; -export type LanguageClientWorkspaceMiddleware = Partial & { +type LanguageClientWorkspaceMiddleware = Partial & { configuration: ( params: ConfigurationParams, token: CancellationToken, @@ -19,7 +20,7 @@ export type LanguageClientWorkspaceMiddleware = Partial & { }; export class LanguageClientMiddleware implements Middleware { - constructor(private configuration: IConfiguration, private user: User) {} + constructor(private configuration: IConfiguration, private user: User, private extensionContext: ExtensionContext) {} workspace: LanguageClientWorkspaceMiddleware = { configuration: async ( diff --git a/src/snyk/common/languageServer/settings.ts b/src/snyk/common/languageServer/settings.ts index 7fbe9024b..e1351d348 100644 --- a/src/snyk/common/languageServer/settings.ts +++ b/src/snyk/common/languageServer/settings.ts @@ -1,6 +1,8 @@ +import _ from 'lodash'; import { CLI_INTEGRATION_NAME } from '../../cli/contants/integration'; -import { Configuration, IConfiguration, SeverityFilter } from '../configuration/configuration'; +import { Configuration, FolderConfig, IConfiguration, SeverityFilter } from '../configuration/configuration'; import { User } from '../user'; +import { PROTOCOL_VERSION } from '../constants/languageServer'; export type ServerSettings = { // Feature toggles @@ -18,12 +20,12 @@ export type ServerSettings = { // Authentication and parameters token?: string; automaticAuthentication?: string; + authenticationMethod?: string; additionalParams?: string; manageBinariesAutomatically?: string; // Reporting and telemetry sendErrorReports?: string; - enableTelemetry?: string; // Security and scanning settings filterSeverity?: SeverityFilter; @@ -38,57 +40,54 @@ export type ServerSettings = { integrationName?: string; integrationVersion?: string; deviceId?: string; -}; - -/** - * Transforms a boolean or undefined value into a string representation. - * It guarantees that undefined values are represented as 'true'. - * This utility is used to ensure feature flags are enabled by default - * when not explicitly set to false. - * - * @param {boolean | undefined} value - The value to transform. - * @returns {string} - The string 'true' if the value is undefined or truthy, 'false' if the value is false. - */ -export const defaultToTrue = (value: boolean | undefined): string => { - return `${value !== undefined ? value : true}`; + requiredProtocolVersion?: string; + enableDeltaFindings?: string; + folderConfigs: FolderConfig[]; + enableSnykOSSQuickFixCodeActions: string; + hoverVerbosity: number; }; export class LanguageServerSettings { static async fromConfiguration(configuration: IConfiguration, user: User): Promise { const featuresConfiguration = configuration.getFeaturesConfiguration(); - const iacEnabled = defaultToTrue(featuresConfiguration.iacEnabled); - const codeSecurityEnabled = defaultToTrue(featuresConfiguration.codeSecurityEnabled); - const codeQualityEnabled = defaultToTrue(featuresConfiguration.codeQualityEnabled); + const ossEnabled = _.isUndefined(featuresConfiguration.ossEnabled) ? true : featuresConfiguration.ossEnabled; - return { - activateSnykCodeSecurity: codeSecurityEnabled, - activateSnykCodeQuality: codeQualityEnabled, - activateSnykOpenSource: 'false', - activateSnykIac: iacEnabled, + const iacEnabled = _.isUndefined(featuresConfiguration.iacEnabled) ? true : featuresConfiguration.iacEnabled; + const codeSecurityEnabled = _.isUndefined(featuresConfiguration.codeSecurityEnabled) + ? true + : featuresConfiguration.codeSecurityEnabled; + const codeQualityEnabled = _.isUndefined(featuresConfiguration.codeQualityEnabled) + ? true + : featuresConfiguration.codeQualityEnabled; - cliPath: configuration.getCliPath(), - endpoint: configuration.snykOssApiEndpoint, + return { + activateSnykCodeSecurity: `${codeSecurityEnabled}`, + activateSnykCodeQuality: `${codeQualityEnabled}`, + activateSnykOpenSource: `${ossEnabled}`, + activateSnykIac: `${iacEnabled}`, + enableDeltaFindings: `${configuration.getDeltaFindingsEnabled()}`, + sendErrorReports: `${configuration.shouldReportErrors}`, + cliPath: await configuration.getCliPath(), + endpoint: configuration.snykApiEndpoint, organization: configuration.organization, - token: await configuration.getToken(), automaticAuthentication: 'false', + authenticationMethod: configuration.getAuthenticationMethod(), additionalParams: configuration.getAdditionalCliParameters(), manageBinariesAutomatically: `${configuration.isAutomaticDependencyManagementEnabled()}`, - - sendErrorReports: `${configuration.shouldReportErrors}`, - enableTelemetry: `${configuration.shouldReportEvents}`, - filterSeverity: configuration.severityFilter, scanningMode: configuration.scanningMode, insecure: `${configuration.getInsecure()}`, - enableTrustedFoldersFeature: 'true', trustedFolders: configuration.getTrustedFolders(), - integrationName: CLI_INTEGRATION_NAME, integrationVersion: await Configuration.getVersion(), deviceId: user.anonymousId, + requiredProtocolVersion: `${PROTOCOL_VERSION}`, + folderConfigs: configuration.getFolderConfigs(), + enableSnykOSSQuickFixCodeActions: `${configuration.getPreviewFeatures().ossQuickfixes}`, + hoverVerbosity: 1, }; } } diff --git a/src/snyk/common/languageServer/staticLsApi.ts b/src/snyk/common/languageServer/staticLsApi.ts deleted file mode 100644 index 70d08b30d..000000000 --- a/src/snyk/common/languageServer/staticLsApi.ts +++ /dev/null @@ -1,90 +0,0 @@ -import axios, { CancelTokenSource } from 'axios'; -import { PROTOCOL_VERSION } from '../constants/languageServer'; -import { LsExecutable } from './lsExecutable'; -import { LsSupportedPlatform } from './supportedPlatforms'; -import { getAxiosConfig } from '../proxy'; -import { IVSCodeWorkspace } from '../vscode/workspace'; -import { DownloadAxiosResponse } from '../download/downloader'; -import { IConfiguration } from '../configuration/configuration'; -import { ILog } from '../logger/interfaces'; - -export type LsMetadata = { - tag: string; - version: string; - commit: string; - date: string; - previous_tag: string; - project_name: string; - runtime: string; -}; - -export interface IStaticLsApi { - getDownloadUrl(platform: LsSupportedPlatform): Promise; - - downloadBinary(platform: LsSupportedPlatform): Promise<[Promise, CancelTokenSource]>; - - getMetadata(): Promise; - - getSha256Checksum(platform: LsSupportedPlatform): Promise; -} - -export class StaticLsApi implements IStaticLsApi { - private readonly baseUrl = `https://static.snyk.io/snyk-ls/${PROTOCOL_VERSION}`; - - constructor( - private readonly workspace: IVSCodeWorkspace, - private readonly configuration: IConfiguration, - private readonly logger: ILog, - ) {} - - async getDownloadUrl(platform: LsSupportedPlatform): Promise { - return `${this.baseUrl}/${await this.getFileName(platform)}`; - } - - async getFileName(platform: LsSupportedPlatform): Promise { - return LsExecutable.getVersionedFilename(platform, await this.getLatestVersion()); - } - - async downloadBinary(platform: LsSupportedPlatform): Promise<[Promise, CancelTokenSource]> { - const axiosCancelToken = axios.CancelToken.source(); - const downloadUrl = await this.getDownloadUrl(platform); - - const response = axios.get(downloadUrl, { - responseType: 'stream', - cancelToken: axiosCancelToken.token, - ...(await getAxiosConfig(this.workspace, this.configuration, this.logger)), - }); - - return [response as Promise, axiosCancelToken]; - } - - async getLatestVersion(): Promise { - return Promise.resolve(this.getMetadata().then(metadata => metadata.version)); - } - - async getSha256Checksum(platform: LsSupportedPlatform): Promise { - const fileName = await this.getFileName(platform); - const { data } = await axios.get( - `${this.baseUrl}/snyk-ls_${await this.getLatestVersion()}_SHA256SUMS`, - await getAxiosConfig(this.workspace, this.configuration, this.logger), - ); - - let checksum = ''; - data.split('\n').forEach(line => { - if (line.includes(fileName)) { - checksum = line.split(' ')[0].trim().toLowerCase(); - } - }); - if (checksum == '') return Promise.reject(new Error('Checksum not found')); - - return checksum; - } - - async getMetadata(): Promise { - const response = await axios.get( - `${this.baseUrl}/metadata.json`, - await getAxiosConfig(this.workspace, this.configuration, this.logger), - ); - return response.data; - } -} diff --git a/src/snyk/common/languageServer/supportedPlatforms.ts b/src/snyk/common/languageServer/supportedPlatforms.ts deleted file mode 100644 index 8bc66a87a..000000000 --- a/src/snyk/common/languageServer/supportedPlatforms.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const SupportedLsPlatformsList = [ - 'darwinAmd64', - 'darwinArm64', - 'linux386', - 'linuxAmd64', - 'linuxArm64', - 'windows386', - 'windowsAmd64', -] as const; - -export function isPlatformSupported(platform: string): boolean { - return SupportedLsPlatformsList.find(p => p === platform) !== undefined; -} - -export type LsSupportedPlatform = typeof SupportedLsPlatformsList[number]; diff --git a/src/snyk/common/languageServer/types.ts b/src/snyk/common/languageServer/types.ts index 9dbe9a125..cc53c2f9e 100644 --- a/src/snyk/common/languageServer/types.ts +++ b/src/snyk/common/languageServer/types.ts @@ -4,18 +4,29 @@ export enum ScanProduct { InfrastructureAsCode = 'iac', } -export type InProgress = 'inProgress'; +export enum LsScanProduct { + Code = 'Snyk Code', + OpenSource = 'Snyk Open Source', + InfrastructureAsCode = 'Snyk IaC', + Unknown = '', +} + export enum ScanStatus { InProgress = 'inProgress', Success = 'success', Error = 'error', } +export enum LsErrorMessage { + repositoryInvalidError = 'repository does not exist', +} + export type Scan = { folderPath: string; product: ScanProduct; status: ScanStatus; issues: Issue[]; + errorMessage: string; }; export type Issue = { @@ -24,6 +35,7 @@ export type Issue = { severity: IssueSeverity; filePath: string; additionalData: T; + isIgnored: boolean; }; export enum IssueSeverity { @@ -43,11 +55,13 @@ export type CodeIssueData = { exampleCommitFixes: ExampleCommitFix[]; cwe: string[]; text: string; - markers?: Marker[]; cols: Point; rows: Point; isSecurityType: boolean; + priorityScore: number; + hasAIFix: boolean; + details: string; // HTML from the LSP }; export type ExampleCommitFix = { @@ -58,6 +72,7 @@ type CommitChangeLine = { line: string; lineNumber: number; lineChange: 'removed' | 'added' | 'none'; + isExampleLineEncoded?: boolean; }; export type Marker = { msg: Point; @@ -95,8 +110,10 @@ export type OssIssueData = { projectName: string; displayTargetFile: string; + + details: string; }; -export type Identifiers = { +type Identifiers = { CWE: string[]; CVE: string[]; }; @@ -111,4 +128,10 @@ export type IacIssueData = { path?: string[]; resolve?: string; references?: string[]; + customUIContent: string; +}; + +export type AutofixUnifiedDiffSuggestion = { + fixId: string; + unifiedDiffsPerFile: { [key: string]: string }; }; diff --git a/src/snyk/common/messages/analysisMessages.ts b/src/snyk/common/messages/analysisMessages.ts index b54d200f8..63f555ae5 100644 --- a/src/snyk/common/messages/analysisMessages.ts +++ b/src/snyk/common/messages/analysisMessages.ts @@ -4,6 +4,9 @@ export const messages = { clickToProblem: 'Click here to see the problem.', scanRunning: 'Scanning...', allSeverityFiltersDisabled: 'Please enable severity filters to see the results.', + allIssueViewOptionsDisabled: 'Adjust your Issue View Options to see all issues.', + openIssueViewOptionDisabled: 'Adjust your Issue View Options to see open issues.', + ignoredIssueViewOptionDisabled: 'Adjust your Issue View Options to see ignored issues.', duration: (time: string, day: string): string => `Analysis finished at ${time}, ${day}`, noWorkspaceTrustDescription: 'None of workspace folders were trusted. If you trust the workspace, you can add it to the list of trusted folders in the extension settings, or when prompted by the extension next time.', diff --git a/src/snyk/common/messages/learn.ts b/src/snyk/common/messages/learn.ts index 863829227..8ef2430de 100644 --- a/src/snyk/common/messages/learn.ts +++ b/src/snyk/common/messages/learn.ts @@ -1,4 +1,4 @@ export const messages = { getLessonError: 'Failed to get Snyk Learn lesson', - lessonButtonTitle: 'Learn about this vulnerability', + lessonButtonTitle: 'Learn about this issue', }; diff --git a/src/snyk/common/platform.ts b/src/snyk/common/platform.ts index ecb9a09ca..8475f00c1 100644 --- a/src/snyk/common/platform.ts +++ b/src/snyk/common/platform.ts @@ -5,6 +5,10 @@ export class Platform { return os.platform(); } + static getArch(): string { + return os.arch(); + } + static getVersion(): string { return `${os.release()}-${os.arch}`; } diff --git a/src/snyk/common/proxy.ts b/src/snyk/common/proxy.ts index 1d54078f7..76bf22b0e 100644 --- a/src/snyk/common/proxy.ts +++ b/src/snyk/common/proxy.ts @@ -3,9 +3,9 @@ import fs from 'fs/promises'; import { Agent, AgentOptions, globalAgent } from 'https'; import { HttpsProxyAgent, HttpsProxyAgentOptions } from 'https-proxy-agent'; import * as url from 'url'; -import { IVSCodeWorkspace } from './vscode/workspace'; import { IConfiguration } from './configuration/configuration'; import { ILog } from './logger/interfaces'; +import { IVSCodeWorkspace } from './vscode/workspace'; export async function getHttpsProxyAgent( workspace: IVSCodeWorkspace, @@ -62,7 +62,7 @@ export async function getProxyOptions( }; } -export function getVsCodeProxy(workspace: IVSCodeWorkspace): string | undefined { +function getVsCodeProxy(workspace: IVSCodeWorkspace): string | undefined { return workspace.getConfiguration('http', 'proxy'); } diff --git a/src/snyk/common/services/CacheService.ts b/src/snyk/common/services/CacheService.ts new file mode 100644 index 000000000..27f4b749c --- /dev/null +++ b/src/snyk/common/services/CacheService.ts @@ -0,0 +1,20 @@ +import { IVSCodeCommands } from '../vscode/commands'; +import { SNYK_CLEAR_CACHE_COMMAND } from '../constants/commands'; + +export interface IClearCacheService { + clearCache(folderUri?: string, cacheType?: string): Promise; +} + +export class ClearCacheService implements IClearCacheService { + constructor(private commandExecutor: IVSCodeCommands) {} + + async clearCache(folderUri?: string, cacheType?: string): Promise { + try { + const uri = folderUri || ''; + const type = cacheType || ''; + await this.commandExecutor.executeCommand(SNYK_CLEAR_CACHE_COMMAND, uri, type); + } catch (error) { + console.warn(`[ClearCacheService] Failed to clear cache`); + } + } +} diff --git a/src/snyk/common/services/diagnosticsService.ts b/src/snyk/common/services/diagnosticsService.ts new file mode 100644 index 000000000..a4631ca5c --- /dev/null +++ b/src/snyk/common/services/diagnosticsService.ts @@ -0,0 +1,44 @@ +import * as vscode from 'vscode'; +import { Issue, LsScanProduct, ScanProduct } from '../languageServer/types'; + +// This is a workaround until the LanguageClient package adds data to the Diagnostic type +// according to https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic +// Since 3.16 the property data was introduced +class Diagnostic316 extends vscode.Diagnostic { + data: Issue; +} + +export interface IDiagnosticsIssueProvider { + getIssuesFromDiagnostics(product: ScanProduct): Issue[]; +} + +export class DiagnosticsIssueProvider implements IDiagnosticsIssueProvider { + getIssuesFromDiagnostics(product: ScanProduct): Issue[] { + const allDiagnostics = vscode.languages.getDiagnostics(); + const diagnosticsSource = this.productToLsProduct(product); + + // Filter and flatten the diagnostics list + // Also filter only when diagnostic.data exists + const filteredDiagnostics = allDiagnostics.flatMap(([_, diagnostics]) => { + return diagnostics.filter( + (diagnostic): diagnostic is Diagnostic316 => + diagnostic.source === diagnosticsSource && diagnostic.hasOwnProperty('data'), + ); + }); + const issues = filteredDiagnostics.map(diagnostic => diagnostic.data); + return issues; + } + + private productToLsProduct(product: ScanProduct): LsScanProduct { + switch (product) { + case ScanProduct.Code: + return LsScanProduct.Code; + case ScanProduct.InfrastructureAsCode: + return LsScanProduct.InfrastructureAsCode; + case ScanProduct.OpenSource: + return LsScanProduct.OpenSource; + default: + return LsScanProduct.Unknown; + } + } +} diff --git a/src/snyk/common/services/downloadService.ts b/src/snyk/common/services/downloadService.ts index 8cf86d0cc..b7e547a3b 100644 --- a/src/snyk/common/services/downloadService.ts +++ b/src/snyk/common/services/downloadService.ts @@ -1,46 +1,41 @@ import { ReplaySubject } from 'rxjs'; +import * as fsPromises from 'fs/promises'; import { Checksum } from '../../cli/checksum'; import { messages } from '../../cli/messages/messages'; import { IConfiguration } from '../configuration/configuration'; -import { - MEMENTO_LS_CHECKSUM, - MEMENTO_LS_LAST_UPDATE_DATE, - MEMENTO_LS_PROTOCOL_VERSION, -} from '../constants/globalState'; -import { PROTOCOL_VERSION } from '../constants/languageServer'; +import { MEMENTO_CLI_CHECKSUM, MEMENTO_CLI_VERSION, MEMENTO_LS_PROTOCOL_VERSION } from '../constants/globalState'; import { Downloader } from '../download/downloader'; -import { LsExecutable } from '../languageServer/lsExecutable'; -import { IStaticLsApi } from '../languageServer/staticLsApi'; -import { LsSupportedPlatform } from '../languageServer/supportedPlatforms'; +import { CliExecutable } from '../../cli/cliExecutable'; +import { IStaticCliApi } from '../../cli/staticCliApi'; import { ILog } from '../logger/interfaces'; import { ExtensionContext } from '../vscode/extensionContext'; import { IVSCodeWindow } from '../vscode/window'; +import { CliSupportedPlatform } from '../../cli/supportedPlatforms'; +import { PROTOCOL_VERSION } from '../constants/languageServer'; export class DownloadService { - readonly fourDaysInMs = 4 * 24 * 3600 * 1000; readonly downloadReady$ = new ReplaySubject(1); - private readonly downloader: Downloader; constructor( private readonly extensionContext: ExtensionContext, private readonly configuration: IConfiguration, - private readonly lsApi: IStaticLsApi, + private readonly cliApi: IStaticCliApi, readonly window: IVSCodeWindow, private readonly logger: ILog, downloader?: Downloader, ) { - this.downloader = downloader ?? new Downloader(configuration, lsApi, window, logger); + this.downloader = downloader ?? new Downloader(configuration, cliApi, window, logger, this.extensionContext); } async downloadOrUpdate(): Promise { - const lsInstalled = await this.isLsInstalled(); + const cliInstalled = await this.isCliInstalled(); if (!this.configuration.isAutomaticDependencyManagementEnabled()) { this.downloadReady$.next(); return false; } - if (!lsInstalled) { + if (!cliInstalled) { const downloaded = await this.download(); this.downloadReady$.next(); return downloaded; @@ -59,20 +54,24 @@ export class DownloadService { return false; } - await this.setLastLsUpdateDateAndChecksum(executable.checksum); - await this.setCurrentLspVersion(); + await this.setCliChecksum(executable.checksum); + await this.setCliVersion(executable.version); this.logger.info(messages.downloadFinished(executable.version)); return true; } async update(): Promise { - // let language server manage CLI downloads, but download LS here - const platform = LsExecutable.getCurrentWithArch(); - const lsInstalled = await this.isLsInstalled(); - const lspVersionHasUpdated = this.hasLspVersionUpdated(); - const needsUpdate = this.isFourDaysPassedSinceLastLsUpdate() || lspVersionHasUpdated; - if (!lsInstalled || needsUpdate) { - const updateAvailable = await this.isLsUpdateAvailable(platform); + const platform = await CliExecutable.getCurrentWithArch(); + const cliReleaseChannel = await this.configuration.getCliReleaseChannel(); + const version = await this.cliApi.getLatestCliVersion(cliReleaseChannel); + if (!version) { + return false; + } + const cliInstalled = await this.isCliInstalled(); + const cliVersionHasUpdated = this.hasCliVersionUpdated(version); + const needsUpdate = cliVersionHasUpdated || this.hasLspVersionUpdated(); + if (!cliInstalled || needsUpdate) { + const updateAvailable = await this.isCliUpdateAvailable(platform); if (!updateAvailable) { return false; } @@ -81,7 +80,8 @@ export class DownloadService { return false; } - await this.setLastLsUpdateDateAndChecksum(executable.checksum); + await this.setCliChecksum(executable.checksum); + await this.setCliVersion(executable.version); await this.setCurrentLspVersion(); this.logger.info(messages.downloadFinished(executable.version)); return true; @@ -89,43 +89,52 @@ export class DownloadService { return false; } - async isLsInstalled() { - const lsExecutableExists = await LsExecutable.exists(this.configuration); - const lastUpdateDateWritten = !!this.getLastLsUpdateDate(); - const lsChecksumWritten = !!this.getLsChecksum(); + async isCliInstalled() { + const cliExecutableExists = await CliExecutable.exists(this.extensionContext.extensionPath); + const cliChecksumWritten = !!this.getCliChecksum(); - return lsExecutableExists && lastUpdateDateWritten && lsChecksumWritten; + return cliExecutableExists && cliChecksumWritten; } - private async isLsUpdateAvailable(platform: LsSupportedPlatform): Promise { - const latestChecksum = await this.lsApi.getSha256Checksum(platform); - const path = LsExecutable.getPath(this.configuration.getSnykLanguageServerPath()); - - // Update is available if fetched checksum not matching the current one - const checksum = await Checksum.getChecksumOf(path, latestChecksum); - if (checksum.verify()) { - this.logger.info(messages.isLatest); + private async isCliUpdateAvailable(platform: CliSupportedPlatform): Promise { + const cliReleaseChannel = await this.configuration.getCliReleaseChannel(); + const version = await this.cliApi.getLatestCliVersion(cliReleaseChannel); + if (!version) { return false; } + const latestChecksum = await this.cliApi.getSha256Checksum(version, platform); + const path = await this.configuration.getCliPath(); + // migration for moving from default extension path to xdg dirs. + if (CliExecutable.isPathInExtensionDirectory(this.extensionContext.extensionPath, path)) { + try { + await fsPromises.unlink(path); + } catch { + // eslint-disable-next-line no-empty + } + await this.configuration.setCliPath(await CliExecutable.getPath()); + return true; + } + // Update is available if fetched checksum not matching the current one + try { + const checksum = await Checksum.getChecksumOf(path, latestChecksum); + if (checksum.verify()) { + this.logger.info(messages.isLatest); + return false; + } + } catch { + // if checksum check fails; force an update + return true; + } return true; } - private async setLastLsUpdateDateAndChecksum(checksum: Checksum): Promise { - await this.extensionContext.updateGlobalStateValue(MEMENTO_LS_LAST_UPDATE_DATE, Date.now()); - await this.extensionContext.updateGlobalStateValue(MEMENTO_LS_CHECKSUM, checksum.checksum); + private async setCliChecksum(checksum: Checksum): Promise { + await this.extensionContext.updateGlobalStateValue(MEMENTO_CLI_CHECKSUM, checksum.checksum); } - private async setCurrentLspVersion(): Promise { - await this.extensionContext.updateGlobalStateValue(MEMENTO_LS_PROTOCOL_VERSION, PROTOCOL_VERSION); - } - - private isFourDaysPassedSinceLastLsUpdate(): boolean { - const lastUpdateDate = this.getLastLsUpdateDate(); - if (!lastUpdateDate) { - throw new Error('Last update date is not known.'); - } - return Date.now() - lastUpdateDate > this.fourDaysInMs; + private async setCliVersion(cliVersion: string): Promise { + await this.extensionContext.updateGlobalStateValue(MEMENTO_CLI_VERSION, cliVersion); } private hasLspVersionUpdated(): boolean { @@ -133,15 +142,24 @@ export class DownloadService { return currentProtoclVersion != PROTOCOL_VERSION; } - private getLastLsUpdateDate() { - return this.extensionContext.getGlobalStateValue(MEMENTO_LS_LAST_UPDATE_DATE); + private async setCurrentLspVersion(): Promise { + await this.extensionContext.updateGlobalStateValue(MEMENTO_LS_PROTOCOL_VERSION, PROTOCOL_VERSION); } private getLsProtocolVersion() { return this.extensionContext.getGlobalStateValue(MEMENTO_LS_PROTOCOL_VERSION); } - private getLsChecksum(): number | undefined { - return this.extensionContext.getGlobalStateValue(MEMENTO_LS_CHECKSUM); + private hasCliVersionUpdated(cliVersion: string): boolean { + const currentVersion = this.getCliVersion(); + return currentVersion != cliVersion; + } + + private getCliVersion(): string | undefined { + return this.extensionContext.getGlobalStateValue(MEMENTO_CLI_VERSION); + } + + private getCliChecksum(): string | undefined { + return this.extensionContext.getGlobalStateValue(MEMENTO_CLI_CHECKSUM); } } diff --git a/src/snyk/common/services/featureFlagService.ts b/src/snyk/common/services/featureFlagService.ts new file mode 100644 index 000000000..bf8496e70 --- /dev/null +++ b/src/snyk/common/services/featureFlagService.ts @@ -0,0 +1,21 @@ +import { IVSCodeCommands } from '../vscode/commands'; +import { FeatureFlagStatus } from '../types'; +import { SNYK_FEATURE_FLAG_COMMAND } from '../constants/commands'; + +export class FeatureFlagService { + constructor(private commandExecutor: IVSCodeCommands) {} + + async fetchFeatureFlag(flagName: string, fallbackValue = false): Promise { + try { + const ffStatus = await this.commandExecutor.executeCommand( + SNYK_FEATURE_FLAG_COMMAND, + flagName, + ); + console.log(`[FeatureFlagService] ${flagName} is ${ffStatus?.ok ? 'enabled' : 'disabled'}`); + return ffStatus?.ok ?? false; + } catch (error) { + console.warn(`[FeatureFlagService] Failed to fetch feature flag ${flagName}: ${error}`); + return fallbackValue; + } + } +} diff --git a/src/snyk/common/services/learnService.ts b/src/snyk/common/services/learnService.ts index df3bd9964..647449b8e 100644 --- a/src/snyk/common/services/learnService.ts +++ b/src/snyk/common/services/learnService.ts @@ -1,4 +1,3 @@ -import { OssIssueCommandArg } from '../../snykOss/views/ossVulnerabilityTreeProvider'; import { SNYK_GET_LESSON_COMMAND } from '../constants/commands'; import { CodeIssueData, Issue } from '../languageServer/types'; import { IVSCodeCommands } from '../vscode/commands'; @@ -11,35 +10,13 @@ export type Lesson = { export class LearnService { constructor(private commandExecutor: IVSCodeCommands) {} - async getOssLesson(vulnerability: OssIssueCommandArg): Promise { - const cwe = vulnerability.identifiers?.CWE; - let cweElement = ''; - if (cwe && cwe.length > 0) { - cweElement = cwe[0]; - } - - const cve = vulnerability.identifiers?.CWE; - let cveElement = ''; - if (cve && cve.length > 0) { - cveElement = cve[0]; - } - return this.commandExecutor.executeCommand( - SNYK_GET_LESSON_COMMAND, - vulnerability.id, - vulnerability.packageManager, - cweElement, - cveElement, - 4, - ); - } - async getCodeLesson(issue: Issue): Promise { const ruleSplit = issue.additionalData.ruleId.split('/'); const rule = ruleSplit[ruleSplit.length - 1]; const ecosystem = ruleSplit[0]; const additionalData = issue.additionalData; let cwe = ''; - if (additionalData.cwe.length > 0) { + if (additionalData?.cwe?.length) { cwe = additionalData.cwe[0]; } diff --git a/src/snyk/common/services/notificationService.ts b/src/snyk/common/services/notificationService.ts index 4eed79d39..6052db94c 100644 --- a/src/snyk/common/services/notificationService.ts +++ b/src/snyk/common/services/notificationService.ts @@ -1,7 +1,6 @@ import { snykMessages } from '../../base/messages/snykMessages'; -import { IAnalytics } from '../analytics/itly'; import { IConfiguration } from '../configuration/configuration'; -import { VSCODE_VIEW_CONTAINER_COMMAND } from '../constants/commands'; +import { SNYK_OPEN_BROWSER_COMMAND, VSCODE_VIEW_CONTAINER_COMMAND } from '../constants/commands'; import { ErrorHandler } from '../error/errorHandler'; import { ILog } from '../logger/interfaces'; import { errorsLogs } from '../messages/errors'; @@ -10,7 +9,10 @@ import { IVSCodeWindow } from '../vscode/window'; export interface INotificationService { init(): Promise; + showErrorNotification(message: string): Promise; + + showErrorNotificationWithLinkAction(message: string, actionText: string, actionLink: string): Promise; } export class NotificationService implements INotificationService { @@ -18,7 +20,6 @@ export class NotificationService implements INotificationService { private readonly window: IVSCodeWindow, private readonly commands: IVSCodeCommands, private readonly configuration: IConfiguration, - private readonly analytics: IAnalytics, private readonly logger: ILog, ) {} @@ -40,13 +41,27 @@ export class NotificationService implements INotificationService { if (pressedButton === snykMessages.welcome.button) { await this.commands.executeCommand(VSCODE_VIEW_CONTAINER_COMMAND); - this.analytics.logWelcomeButtonIsClicked(); } await this.configuration.hideWelcomeNotification(); } async showErrorNotification(message: string): Promise { - await this.window.showErrorMessage(message); + await this.showErrorNotificationWithLinkAction( + message, + 'Show Documentation', + 'https://docs.snyk.io/scm-ide-and-ci-cd-integrations/snyk-ide-plugins-and-extensions/visual-studio-code-extension/troubleshooting-for-visual-studio-code-extension', + ); + } + + async showErrorNotificationWithLinkAction(message: string, actionText: string, actionLink: string): Promise { + await this.window + .showErrorMessage(message, actionText) + .then(async selectedAction => { + if (selectedAction == actionText) { + await this.commands.executeCommand(SNYK_OPEN_BROWSER_COMMAND, actionLink); + } + }) + .catch(err => ErrorHandler.handle(err, this.logger, 'error occurred during error handling')); } } diff --git a/src/snyk/common/services/openerService.ts b/src/snyk/common/services/openerService.ts index 14a4f00dd..5882f0b02 100644 --- a/src/snyk/common/services/openerService.ts +++ b/src/snyk/common/services/openerService.ts @@ -6,7 +6,6 @@ export interface IOpenerService { openBrowserUrl(url: string): Promise; } -// TODO: use Language Server to open browser urls export class OpenerService { async openBrowserUrl(url: string): Promise { try { diff --git a/src/snyk/common/services/productService.ts b/src/snyk/common/services/productService.ts index 62b6c69b3..374142682 100644 --- a/src/snyk/common/services/productService.ts +++ b/src/snyk/common/services/productService.ts @@ -1,17 +1,18 @@ -import { Subscription } from 'rxjs'; +import { Subject, Subscription } from 'rxjs'; import { AnalysisStatusProvider } from '../analysis/statusProvider'; import { IConfiguration } from '../configuration/configuration'; import { IWorkspaceTrust } from '../configuration/trustedFolders'; import { CodeActionsProvider } from '../editor/codeActionsProvider'; import { ILanguageServer } from '../languageServer/languageServer'; -import { Issue, Scan, ScanStatus } from '../languageServer/types'; +import { Issue, Scan, ScanProduct, ScanStatus } from '../languageServer/types'; import { ILog } from '../logger/interfaces'; -import { IViewManagerService } from '../services/viewManagerService'; +import { IViewManagerService } from './viewManagerService'; import { IProductWebviewProvider } from '../views/webviewProvider'; import { ExtensionContext } from '../vscode/extensionContext'; import { IVSCodeLanguages } from '../vscode/languages'; import { Disposable } from '../vscode/types'; import { IVSCodeWorkspace } from '../vscode/workspace'; +import { IDiagnosticsIssueProvider } from './diagnosticsService'; export type WorkspaceFolderResult = Issue[] | Error; export type ProductResult = Map>; // map of a workspace folder to results array or an error occurred in this folder @@ -29,7 +30,10 @@ export interface IProductService extends AnalysisStatusProvider, Disposable { } export abstract class ProductService extends AnalysisStatusProvider implements IProductService { + abstract readonly productType: ScanProduct; + private _result: ProductResult; + readonly newResultAvailable$ = new Subject(); // Track running scan count. Assumption: server sends N success/error messages for N scans in progress. private runningScanCount = 0; @@ -47,6 +51,7 @@ export abstract class ProductService extends AnalysisStatusProvider implement private readonly workspaceTrust: IWorkspaceTrust, readonly languageServer: ILanguageServer, readonly languages: IVSCodeLanguages, + readonly diagnosticsIssueProvider: IDiagnosticsIssueProvider, private readonly logger: ILog, ) { super(); @@ -58,6 +63,10 @@ export abstract class ProductService extends AnalysisStatusProvider implement abstract refreshTreeView(): void; + public getSnykProductType(): ScanProduct { + return this.productType; + } + registerCodeActionsProvider(provider: CodeActionsProvider) { this.languages.registerCodeActionsProvider({ scheme: 'file', language: '*' }, provider); } @@ -159,15 +168,17 @@ export abstract class ProductService extends AnalysisStatusProvider implement this.runningScanCount--; if (scanMsg.status == ScanStatus.Success) { - this._result.set(scanMsg.folderPath, scanMsg.issues); + const issues = this.diagnosticsIssueProvider.getIssuesFromDiagnostics(scanMsg.product); + this._result.set(scanMsg.folderPath, issues); } else { - this._result.set(scanMsg.folderPath, new Error('Failed to analyze.')); + this._result.set(scanMsg.folderPath, new Error(scanMsg.errorMessage)); } if (this.runningScanCount <= 0) { this.analysisFinished(); this.runningScanCount = 0; + this.newResultAvailable$.next(); this.refreshTreeView(); } } diff --git a/src/snyk/common/services/viewManagerService.ts b/src/snyk/common/services/viewManagerService.ts index c1706b149..e003d109d 100644 --- a/src/snyk/common/services/viewManagerService.ts +++ b/src/snyk/common/services/viewManagerService.ts @@ -5,9 +5,9 @@ import { configuration } from '../configuration/instance'; import { REFRESH_VIEW_DEBOUNCE_INTERVAL } from '../constants/general'; import { TreeNode } from '../views/treeNode'; -export type ViewType = TreeView; +type ViewType = TreeView; -export class ViewContainer { +class ViewContainer { private container = new Map(); get(key: string): T | undefined { diff --git a/src/snyk/common/types.ts b/src/snyk/common/types.ts index 6b3fd99e6..0e39872f2 100644 --- a/src/snyk/common/types.ts +++ b/src/snyk/common/types.ts @@ -1,3 +1,5 @@ +import { JAVASCRIPT, TYPESCRIPT, HTML, PJSON } from './constants/languageConsts'; + export enum Language { TypeScript, JavaScript, @@ -22,3 +24,21 @@ export type ImportedModule = { string: string; version?: string; }; + +export function languageToString(language: Language): string { + switch (language) { + case Language.TypeScript: + return TYPESCRIPT; + case Language.JavaScript: + return JAVASCRIPT; + case Language.HTML: + return HTML; + case Language.PJSON: + return PJSON; + } +} + +export type FeatureFlagStatus = { + ok: boolean; + userMessage?: string; +}; diff --git a/src/snyk/common/user.ts b/src/snyk/common/user.ts index e6b49a5c8..143145a2f 100644 --- a/src/snyk/common/user.ts +++ b/src/snyk/common/user.ts @@ -1,9 +1,7 @@ import * as crypto from 'crypto'; import { v4 as uuidv4 } from 'uuid'; -import { IAnalytics } from './analytics/itly'; import { SNYK_GET_ACTIVE_USER } from './constants/commands'; import { MEMENTO_ANONYMOUS_ID } from './constants/globalState'; -import { ErrorReporter } from './error/errorReporter'; import { IVSCodeCommands } from './vscode/commands'; import { ExtensionContext } from './vscode/extensionContext'; import { ILog } from './logger/interfaces'; @@ -15,7 +13,7 @@ export type UserDto = { export class User { private _authenticatedId?: string; - private logger?: ILog; + private readonly logger?: ILog; readonly anonymousId: string; @@ -47,13 +45,10 @@ export class User { return crypto.createHash('sha256').update(this._authenticatedId).digest('hex'); } - async identify(commandExecutor: IVSCodeCommands, analytics: IAnalytics): Promise { + async identify(commandExecutor: IVSCodeCommands): Promise { const user = await this.userMe(commandExecutor); if (user && user.id) { this._authenticatedId = user.id; - - await analytics.identify(this._authenticatedId); // map the anonymousId onto authenticatedId - ErrorReporter.identify(this); } } diff --git a/src/snyk/common/views/analysisTreeNodeProvider.ts b/src/snyk/common/views/analysisTreeNodeProvider.ts index 990602efa..314bb5fe3 100644 --- a/src/snyk/common/views/analysisTreeNodeProvider.ts +++ b/src/snyk/common/views/analysisTreeNodeProvider.ts @@ -2,10 +2,13 @@ import _ from 'lodash'; import * as path from 'path'; import { AnalysisStatusProvider } from '../analysis/statusProvider'; import { IConfiguration } from '../configuration/configuration'; -import { SNYK_SHOW_LS_OUTPUT_COMMAND } from '../constants/commands'; +import { SNYK_SHOW_LS_OUTPUT_COMMAND, VSCODE_GO_TO_SETTINGS_COMMAND } from '../constants/commands'; import { messages } from '../messages/analysisMessages'; import { NODE_ICONS, TreeNode } from './treeNode'; import { TreeNodeProvider } from './treeNodeProvider'; +import { SNYK_NAME_EXTENSION, SNYK_PUBLISHER } from '../constants/general'; +import { configuration } from '../configuration/instance'; +import { FEATURE_FLAGS } from '../constants/featureFlags'; export abstract class AnalysisTreeNodeProvider extends TreeNodeProvider { constructor(protected readonly configuration: IConfiguration, private statusProvider: AnalysisStatusProvider) { @@ -36,16 +39,6 @@ export abstract class AnalysisTreeNodeProvider extends TreeNodeProvider { return 0; }; - protected getDurationTreeNode(): TreeNode { - const ts = new Date(this.statusProvider.lastAnalysisTimestamp); - const time = ts.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); - const day = ts.toLocaleDateString([], { year: '2-digit', month: '2-digit', day: '2-digit' }); - - return new TreeNode({ - text: messages.duration(time, day), - }); - } - protected getNoSeverityFiltersSelectedTreeNode(): TreeNode | null { const anyFilterEnabled = Object.values(this.configuration.severityFilter).find(enabled => !!enabled); if (anyFilterEnabled) { @@ -57,6 +50,51 @@ export abstract class AnalysisTreeNodeProvider extends TreeNodeProvider { }); } + protected getNoIssueViewOptionsSelectedTreeNode(numIssues: number, ignoredIssueCount: number): TreeNode | null { + const isIgnoresEnabled = configuration.getFeatureFlag(FEATURE_FLAGS.consistentIgnores); + if (!isIgnoresEnabled) { + return null; + } + + const anyOptionEnabled = Object.values(this.configuration.issueViewOptions).find(enabled => !!enabled); + if (!anyOptionEnabled) { + return new TreeNode({ + text: messages.allIssueViewOptionsDisabled, + }); + } + + if (numIssues === 0) { + return null; + } + + // if only ignored issues are enabled, then let the customer know to adjust their settings + if (numIssues === ignoredIssueCount && !this.configuration.issueViewOptions.ignoredIssues) { + return new TreeNode({ + text: messages.ignoredIssueViewOptionDisabled, + command: { + command: VSCODE_GO_TO_SETTINGS_COMMAND, + title: '', + arguments: [`@ext:${SNYK_PUBLISHER}.${SNYK_NAME_EXTENSION}`], + }, + }); + } + + // if only open issues are enabled, then let the customer know to adjust their settings + if (ignoredIssueCount === 0 && !this.configuration.issueViewOptions.openIssues) { + return new TreeNode({ + text: messages.openIssueViewOptionDisabled, + command: { + command: VSCODE_GO_TO_SETTINGS_COMMAND, + title: '', + arguments: [`@ext:${SNYK_PUBLISHER}.${SNYK_NAME_EXTENSION}`], + }, + }); + } + + // if all options are enabled we don't want to show a warning + return null; + } + protected getErrorEncounteredTreeNode(scanPath?: string): TreeNode { return new TreeNode({ icon: NODE_ICONS.error, @@ -72,6 +110,21 @@ export abstract class AnalysisTreeNodeProvider extends TreeNodeProvider { }); } + protected getFaultyRepositoryErrorTreeNode(scanPath?: string, errorMessage?: string): TreeNode { + return new TreeNode({ + icon: NODE_ICONS.error, + text: scanPath ? path.basename(scanPath) : messages.scanFailed, + description: errorMessage, + internal: { + isError: true, + }, + command: { + command: SNYK_SHOW_LS_OUTPUT_COMMAND, + title: 'errorMessage', + }, + }); + } + protected getNoWorkspaceTrustTreeNode(): TreeNode { return new TreeNode({ text: messages.noWorkspaceTrust, @@ -81,6 +134,4 @@ export abstract class AnalysisTreeNodeProvider extends TreeNodeProvider { }, }); } - - protected abstract getFilteredIssues(issues: readonly unknown[]): readonly unknown[]; } diff --git a/src/snyk/common/views/issueTreeProvider.ts b/src/snyk/common/views/issueTreeProvider.ts index 122f94966..0eb42114b 100644 --- a/src/snyk/common/views/issueTreeProvider.ts +++ b/src/snyk/common/views/issueTreeProvider.ts @@ -1,7 +1,7 @@ -import _ from 'lodash'; +import _, { flatten } from 'lodash'; import * as vscode from 'vscode'; // todo: invert dependency -import { IConfiguration } from '../../common/configuration/configuration'; -import { Issue, IssueSeverity } from '../../common/languageServer/types'; +import { IConfiguration, IssueViewOptions } from '../../common/configuration/configuration'; +import { Issue, IssueSeverity, LsErrorMessage } from '../../common/languageServer/types'; import { messages as commonMessages } from '../../common/messages/analysisMessages'; import { IContextService } from '../../common/services/contextService'; import { IProductService } from '../../common/services/productService'; @@ -9,6 +9,8 @@ import { AnalysisTreeNodeProvider } from '../../common/views/analysisTreeNodePro import { INodeIcon, InternalType, NODE_ICONS, TreeNode } from '../../common/views/treeNode'; import { IVSCodeLanguages } from '../../common/vscode/languages'; import { Command, Range } from '../../common/vscode/types'; +import { IFolderConfigs } from '../configuration/folderConfigs'; +import { SNYK_SET_BASE_BRANCH_COMMAND } from '../constants/commands'; interface ISeverityCounts { [severity: string]: number; @@ -20,6 +22,7 @@ export abstract class ProductIssueTreeProvider extends AnalysisTreeNodeProvid protected readonly productService: IProductService, protected readonly configuration: IConfiguration, protected readonly languages: IVSCodeLanguages, + protected readonly folderConfigs: IFolderConfigs, ) { super(configuration, productService); } @@ -36,13 +39,21 @@ export abstract class ProductIssueTreeProvider extends AnalysisTreeNodeProvid } abstract shouldShowTree(): boolean; + abstract filterIssues(issues: Issue[]): Issue[]; abstract getRunTestMessage(): string; + abstract getIssueTitle(issue: Issue): string; - abstract getIssueRange(issue: Issue): Range; - abstract getOpenIssueCommand(issue: Issue, folderPath: string, filePath: string): Command; + abstract getIssueRange(issue?: Issue): Range | undefined; + + abstract getOpenIssueCommand( + issue: Issue, + folderPath: string, + filePath: string, + filteredIssues?: Issue[], + ): Command; getRootChildren(): TreeNode[] { const nodes: TreeNode[] = []; @@ -70,31 +81,123 @@ export abstract class ProductIssueTreeProvider extends AnalysisTreeNodeProvid ]; } - const [resultNodes, nIssues] = this.getResultNodes(); - nodes.push(...resultNodes); + nodes.push(...this.getResultNodes()); const folderResults = Array.from(this.productService.result.values()); const allFailed = folderResults.every(folderResult => folderResult instanceof Error); if (allFailed) { return nodes; } - nodes.sort(this.compareNodes); - const topNodes = [ + const totalIssueCount = this.getTotalIssueCount(); + const ignoredIssueCount = this.getIgnoredCount(); + + const topNodes: (TreeNode | null)[] = [ new TreeNode({ - text: this.getIssueFoundText(nIssues), + text: this.getIssueFoundText(totalIssueCount, ignoredIssueCount), }), - this.getDurationTreeNode(), - this.getNoSeverityFiltersSelectedTreeNode(), ]; - nodes.unshift(...topNodes.filter((n): n is TreeNode => n !== null)); + + if (totalIssueCount > 0) { + topNodes.push(this.getFixableIssuesNode(this.getFixableCount())); + } + + const noSeverityFiltersSelectedWarning = this.getNoSeverityFiltersSelectedTreeNode(); + if (noSeverityFiltersSelectedWarning !== null) { + topNodes.push(noSeverityFiltersSelectedWarning); + } else { + const noIssueViewOptionSelectedWarning = this.getNoIssueViewOptionsSelectedTreeNode( + totalIssueCount, + ignoredIssueCount, + ); + topNodes.push(noIssueViewOptionSelectedWarning); + } + const validTopNodes = topNodes.filter((n): n is TreeNode => n !== null); + + const baseBranchNodeIndex = nodes.findIndex(node => { + const label = node.label as string; + return label?.toLowerCase().indexOf('base branch') !== -1; + }); + + if (baseBranchNodeIndex > -1) { + nodes.splice(baseBranchNodeIndex + 1, 0, ...validTopNodes); + } else { + nodes.unshift(...validTopNodes); + } return nodes; } - getResultNodes(): [TreeNode[], number] { + getFixableIssuesNode(_fixableIssueCount: number): TreeNode | null { + return null; // optionally overridden by products + } + + getFilteredIssues(): Issue[] { + const folderResults = Array.from(this.productService.result.values()); + const successfulResults = flatten>( + folderResults.filter((result): result is Issue[] => Array.isArray(result)), + ); + return this.filterIssues(successfulResults); + } + + getTotalIssueCount(): number { + return this.getFilteredIssues().length; + } + + getFixableCount(): number { + return this.getFilteredIssues().filter(issue => this.isFixableIssue(issue)).length; + } + + getIgnoredCount(): number { + const ignoredIssues = this.getFilteredIssues().filter(issue => issue.isIgnored); + return ignoredIssues.length; + } + + isFixableIssue(_issue: Issue) { + return false; // optionally overridden by products + } + + filterVisibleIssues(issues: Issue[]): Issue[] { + return issues.filter(issue => this.isVisibleIssue(issue, this.configuration.issueViewOptions)); + } + + protected isVisibleIssue(issue: Issue, issueViewOptions: IssueViewOptions) { + const { ignoredIssues: includeIgnoredIssues, openIssues: includeOpenIssues } = issueViewOptions; + + // Show all issues + if (includeIgnoredIssues && includeOpenIssues) { + return true; + } + + // Show issues based on options + if (includeIgnoredIssues) { + return issue.isIgnored; + } + if (includeOpenIssues) { + return !issue.isIgnored; + } + return false; + } + + getBaseBranch(folderPath: string): TreeNode | undefined { + const deltaFindingsEnabled = this.configuration.getDeltaFindingsEnabled(); + const config = this.folderConfigs.getFolderConfig(this.configuration, folderPath); + + if (deltaFindingsEnabled && config) { + return new TreeNode({ + text: 'Base branch: ' + config.baseBranch, + icon: NODE_ICONS.branch, + command: { + command: SNYK_SET_BASE_BRANCH_COMMAND, + title: 'Choose Base Branch', + arguments: [folderPath], + }, + }); + } + } + + getResultNodes(): TreeNode[] { const nodes: TreeNode[] = []; - let totalVulnCount = 0; for (const result of this.productService.result.entries()) { const folderPath = result[0]; @@ -102,9 +205,15 @@ export abstract class ProductIssueTreeProvider extends AnalysisTreeNodeProvid const uri = vscode.Uri.file(folderPath); const shortFolderPath = uri.path.split('/'); + // TODO: this might need to be changed to uri.fspath const folderName = shortFolderPath.pop() || uri.path; let folderVulnCount = 0; + if (folderResult instanceof Error && folderResult.message === LsErrorMessage.repositoryInvalidError) { + nodes.push(this.getFaultyRepositoryErrorTreeNode(folderName, folderResult.toString())); + continue; + } + if (folderResult instanceof Error) { nodes.push(this.getErrorEncounteredTreeNode(folderName)); continue; @@ -125,10 +234,10 @@ export abstract class ProductIssueTreeProvider extends AnalysisTreeNodeProvid const fileSeverityCounts = this.initSeverityCounts(); const filteredIssues = this.filterIssues(fileIssues); + const visibleIssues = this.filterVisibleIssues(filteredIssues); - const issueNodes = filteredIssues.map(issue => { + const issueNodes = visibleIssues.map(issue => { fileSeverityCounts[issue.severity] += 1; - totalVulnCount++; folderVulnCount++; const issueRange = this.getIssueRange(issue); @@ -182,12 +291,14 @@ export abstract class ProductIssueTreeProvider extends AnalysisTreeNodeProvid const folderSeverity = ProductIssueTreeProvider.getHighestSeverity(folderSeverityCounts); + const baseBranchNode = this.getBaseBranch(uri.fsPath); if (folderVulnCount == 0) { + this.addBaseBranchNode(baseBranchNode, nodes); continue; } - // flatten results if single workspace folder - if (this.productService.result.size == 1) { + if (this.productService.result.size === 1) { + this.addBaseBranchNode(baseBranchNode, nodes); nodes.push(...fileNodes); } else { const folderNode = new TreeNode({ @@ -200,27 +311,32 @@ export abstract class ProductIssueTreeProvider extends AnalysisTreeNodeProvid severity: ProductIssueTreeProvider.getSeverityComparatorIndex(folderSeverity), }, }); + this.addBaseBranchNode(baseBranchNode, fileNodes); nodes.push(folderNode); } } - return [nodes, totalVulnCount]; + return nodes; + } + + addBaseBranchNode(baseBranchNode: TreeNode | undefined, nodes: TreeNode[]) { + if (!baseBranchNode) { + return; + } + nodes.unshift(baseBranchNode); } - protected getIssueFoundText(nIssues: number): string { - return `Snyk found ${!nIssues ? 'no issues! ✅' : `${nIssues} issue${nIssues === 1 ? '' : 's'}`}`; + protected getIssueFoundText(nIssues: number, _: number): string { + if (!nIssues) { + return '✅ Congrats! No issues found!'; + } + return `Snyk found ${nIssues} issue${nIssues === 1 ? '' : 's'}`; } protected getIssueDescriptionText(dir: string | undefined, issueCount: number): string | undefined { return `${dir} - ${issueCount} issue${issueCount === 1 ? '' : 's'}`; } - // todo: Obsolete. Remove after OSS scans migration to LS - protected getFilteredIssues(diagnostics: readonly unknown[]): readonly unknown[] { - // Diagnostics are already filtered by the analyzer - return diagnostics; - } - static getHighestSeverity(counts: ISeverityCounts): IssueSeverity { for (const s of [IssueSeverity.Critical, IssueSeverity.High, IssueSeverity.Medium, IssueSeverity.Low]) { if (counts[s]) return s; @@ -229,7 +345,7 @@ export abstract class ProductIssueTreeProvider extends AnalysisTreeNodeProvid return IssueSeverity.Low; } - private initSeverityCounts(): ISeverityCounts { + protected initSeverityCounts(): ISeverityCounts { return { [IssueSeverity.Critical]: 0, [IssueSeverity.High]: 0, diff --git a/src/snyk/common/views/treeNode.ts b/src/snyk/common/views/treeNode.ts index d46e0a58d..53241b7dc 100644 --- a/src/snyk/common/views/treeNode.ts +++ b/src/snyk/common/views/treeNode.ts @@ -7,7 +7,7 @@ export interface INodeIcon { ['dark']: string; } -type NODE_ICON_TYPE = 'critical' | 'high' | 'medium' | 'low' | 'error'; +type NODE_ICON_TYPE = 'critical' | 'high' | 'medium' | 'low' | 'error' | 'branch' | 'pencil'; export const NODE_ICONS: { [key in NODE_ICON_TYPE]: INodeIcon } = { critical: { @@ -30,6 +30,14 @@ export const NODE_ICONS: { [key in NODE_ICON_TYPE]: INodeIcon } = { light: path.join(__filename, '..', '..', '..', '..', '..', 'media', 'images', 'warning.svg'), dark: path.join(__filename, '..', '..', '..', '..', '..', 'media', 'images', 'warning.svg'), }, + branch: { + light: path.join(__filename, '..', '..', '..', '..', '..', 'media', 'images', 'branch-light.svg'), + dark: path.join(__filename, '..', '..', '..', '..', '..', 'media', 'images', 'branch-dark.svg'), + }, + pencil: { + light: path.join(__filename, '..', '..', '..', '..', '..', 'media', 'images', 'pencil-light.svg'), + dark: path.join(__filename, '..', '..', '..', '..', '..', 'media', 'images', 'pencil-dark.svg'), + }, }; export type InternalType = { @@ -38,7 +46,7 @@ export type InternalType = { isError?: boolean; }; -export interface INodeOptions { +interface INodeOptions { text: string; description?: string; descriptionTail?: string; @@ -56,7 +64,7 @@ export interface INodeOptions { internal?: InternalType; } -export type INode = TreeItem & { +type INode = TreeItem & { readonly internal: InternalType; }; diff --git a/src/snyk/common/views/webviewProvider.ts b/src/snyk/common/views/webviewProvider.ts index f999aa54c..c9420955a 100644 --- a/src/snyk/common/views/webviewProvider.ts +++ b/src/snyk/common/views/webviewProvider.ts @@ -30,7 +30,6 @@ export abstract class WebviewProvider implements IWebViewProvider; @@ -76,6 +75,5 @@ export abstract class WebviewProvider implements IWebViewProvider(command: string, ...rest: unknown[]): Thenable; } -export class VSCodeCommands implements IVSCodeCommands { +class VSCodeCommands implements IVSCodeCommands { executeCommand(command: string, ...rest: unknown[]): Thenable { return vscode.commands.executeCommand(command, ...rest); } diff --git a/src/snyk/common/vscode/env.ts b/src/snyk/common/vscode/env.ts index 736f95328..00f111f0a 100644 --- a/src/snyk/common/vscode/env.ts +++ b/src/snyk/common/vscode/env.ts @@ -7,7 +7,7 @@ export interface IVSCodeEnv { getAppHost(): string | undefined; } -export class VSCodeEnv implements IVSCodeEnv { +class VSCodeEnv implements IVSCodeEnv { getUiKind(): string { return vscode.UIKind[vscode.env.uiKind]; } diff --git a/src/snyk/common/vscode/hover.ts b/src/snyk/common/vscode/hover.ts deleted file mode 100644 index 4518ecc66..000000000 --- a/src/snyk/common/vscode/hover.ts +++ /dev/null @@ -1,12 +0,0 @@ -import * as vscode from 'vscode'; -import { Hover, MarkdownString, Range } from './types'; - -export interface IHoverAdapter { - create(contents: MarkdownString | MarkdownString[], range?: Range): Hover; -} - -export class HoverAdapter implements IHoverAdapter { - create(contents: vscode.MarkdownString | MarkdownString[], range?: Range): Hover { - return new vscode.Hover(contents, range); - } -} diff --git a/src/snyk/common/vscode/languages.ts b/src/snyk/common/vscode/languages.ts index 3deb382e0..7200ee976 100644 --- a/src/snyk/common/vscode/languages.ts +++ b/src/snyk/common/vscode/languages.ts @@ -31,7 +31,7 @@ export interface IVSCodeLanguages { ): Disposable; } -export class VSCodeLanguages implements IVSCodeLanguages { +class VSCodeLanguages implements IVSCodeLanguages { registerHoverProvider(selector: DocumentSelector, provider: HoverProvider): Disposable { return vscode.languages.registerHoverProvider(selector, provider); } diff --git a/src/snyk/common/vscode/secretStorage.ts b/src/snyk/common/vscode/secretStorage.ts index d9c81d003..5725b3e7e 100644 --- a/src/snyk/common/vscode/secretStorage.ts +++ b/src/snyk/common/vscode/secretStorage.ts @@ -1,6 +1,6 @@ import { ExtensionContext, Event, SecretStorage, SecretStorageChangeEvent } from './types'; -export interface ISecretStorageAdapter { +interface ISecretStorageAdapter { get(key: string): Promise; store(key: string, value: string): Promise; delete(key: string): Promise; diff --git a/src/snyk/common/vscode/types.ts b/src/snyk/common/vscode/types.ts index 0ce5f0664..c8564f23d 100644 --- a/src/snyk/common/vscode/types.ts +++ b/src/snyk/common/vscode/types.ts @@ -16,23 +16,18 @@ export enum DiagnosticSeverity { // map of vscode.DiagnosticSeverity } export type DocumentSelector = vscode.DocumentSelector; -export type DocumentFilter = vscode.DocumentFilter; export type HoverProvider = vscode.HoverProvider; -export type ProviderResult = vscode.ProviderResult; export type TextEditor = vscode.TextEditor; export type TextDocument = vscode.TextDocument; export type TextDocumentShowOptions = vscode.TextDocumentShowOptions; export type ViewColumn = vscode.ViewColumn; export type Position = vscode.Position; export type Range = vscode.Range; -export type Selection = vscode.Selection; export type SecretStorage = vscode.SecretStorage; export type SecretStorageChangeEvent = vscode.SecretStorageChangeEvent; export type Event = vscode.Event; export type Uri = vscode.Uri; -export type MarkedString = vscode.MarkedString; export type MarkdownString = vscode.MarkdownString; -export type Hover = vscode.Hover; export type CodeAction = vscode.CodeAction; export type CodeActionKind = vscode.CodeActionKind; export type CodeActionProvider = vscode.CodeActionProvider; @@ -58,6 +53,5 @@ export type ConfigurationParams = lsc.ConfigurationParams; export type CancellationToken = lsc.CancellationToken; export type ConfigurationRequestHandlerSignature = lsc.ConfigurationRequest.HandlerSignature; export type ResponseError = lsc.ResponseError; -export type InlineValueContext = lsc.InlineValueContext; export type InlineValueText = lsc.InlineValueText; export type LSPTextDocument = lst.TextDocument; diff --git a/src/snyk/common/vscode/window.ts b/src/snyk/common/vscode/window.ts index 7b63aa7e8..c38ae9104 100644 --- a/src/snyk/common/vscode/window.ts +++ b/src/snyk/common/vscode/window.ts @@ -38,7 +38,7 @@ export interface IVSCodeWindow { /** * A wrapper class for the vscode.window to provide centralised access to dealing with the current window of the editor. */ -export class VSCodeWindow implements IVSCodeWindow { +class VSCodeWindow implements IVSCodeWindow { getActiveTextEditor(): vscode.TextEditor | undefined { return vscode.window.activeTextEditor; } diff --git a/src/snyk/common/watchers/configurationWatcher.ts b/src/snyk/common/watchers/configurationWatcher.ts index 5b3a74440..c3846daaa 100644 --- a/src/snyk/common/watchers/configurationWatcher.ts +++ b/src/snyk/common/watchers/configurationWatcher.ts @@ -1,49 +1,66 @@ import * as _ from 'lodash'; import * as vscode from 'vscode'; import { IExtension } from '../../base/modules/interfaces'; -import { IAnalytics } from '../analytics/itly'; import { configuration } from '../configuration/instance'; import { DEFAULT_LS_DEBOUNCE_INTERVAL, SNYK_TOKEN_KEY } from '../constants/general'; import { ADVANCED_ADVANCED_MODE_SETTING, ADVANCED_AUTOSCAN_OSS_SETTING, ADVANCED_CUSTOM_ENDPOINT, - ADVANCED_CUSTOM_LS_PATH, CODE_QUALITY_ENABLED_SETTING, CODE_SECURITY_ENABLED_SETTING, IAC_ENABLED_SETTING, + ADVANCED_ORGANIZATION, + ISSUE_VIEW_OPTIONS_SETTING, OSS_ENABLED_SETTING, SEVERITY_FILTER_SETTING, TRUSTED_FOLDERS, - YES_TELEMETRY_SETTING, + DELTA_FINDINGS, + FOLDER_CONFIGS, + ADVANCED_AUTHENTICATION_METHOD, + ADVANCED_CLI_PATH, + ADVANCED_CLI_RELEASE_CHANNEL, } from '../constants/settings'; import { ErrorHandler } from '../error/errorHandler'; import { ILog } from '../logger/interfaces'; import { errorsLogs } from '../messages/errors'; import SecretStorageAdapter from '../vscode/secretStorage'; import { IWatcher } from './interfaces'; +import { SNYK_CONTEXT } from '../constants/views'; class ConfigurationWatcher implements IWatcher { - constructor(private readonly analytics: IAnalytics, private readonly logger: ILog) {} + constructor(private readonly logger: ILog) {} private async onChangeConfiguration(extension: IExtension, key: string): Promise { - if (key === ADVANCED_ADVANCED_MODE_SETTING) { + if (key === ADVANCED_ORGANIZATION) { + return extension.setupFeatureFlags(); + } else if (key === ADVANCED_ADVANCED_MODE_SETTING) { return extension.checkAdvancedMode(); - } else if (key === YES_TELEMETRY_SETTING) { - return this.analytics.setShouldReportEvents(configuration.shouldReportEvents); } else if (key === OSS_ENABLED_SETTING) { extension.viewManagerService.refreshOssView(); } else if (key === CODE_SECURITY_ENABLED_SETTING || key === CODE_QUALITY_ENABLED_SETTING) { return extension.viewManagerService.refreshAllCodeAnalysisViews(); } else if (key === IAC_ENABLED_SETTING) { return extension.viewManagerService.refreshIacView(); + } else if (key === ISSUE_VIEW_OPTIONS_SETTING) { + extension.viewManagerService.refreshAllViews(); } else if (key === SEVERITY_FILTER_SETTING) { return extension.viewManagerService.refreshAllViews(); } else if (key === ADVANCED_CUSTOM_ENDPOINT) { return configuration.clearToken(); - } else if (key === ADVANCED_CUSTOM_LS_PATH) { + } else if (key === ADVANCED_AUTHENTICATION_METHOD) { + await extension.contextService.setContext(SNYK_CONTEXT.LOGGEDIN, false); + await extension.contextService.setContext(SNYK_CONTEXT.AUTHENTICATION_METHOD_CHANGED, true); + return extension.viewManagerService.refreshAllViews(); + } else if (key === ADVANCED_CLI_PATH) { // Language Server client must sync config changes before we can restart return _.debounce(() => extension.restartLanguageServer(), DEFAULT_LS_DEBOUNCE_INTERVAL)(); + } else if (key === ADVANCED_CLI_RELEASE_CHANNEL) { + await extension.stopLanguageServer(); + extension.initDependencyDownload(); + return; + } else if (key === FOLDER_CONFIGS || key == DELTA_FINDINGS) { + extension.viewManagerService.refreshAllViews(); } else if (key === TRUSTED_FOLDERS) { extension.workspaceTrust.resetTrustedFoldersCache(); extension.viewManagerService.refreshAllViews(); @@ -67,15 +84,20 @@ class ConfigurationWatcher implements IWatcher { const change = [ ADVANCED_ADVANCED_MODE_SETTING, ADVANCED_AUTOSCAN_OSS_SETTING, - YES_TELEMETRY_SETTING, + ADVANCED_ORGANIZATION, OSS_ENABLED_SETTING, CODE_SECURITY_ENABLED_SETTING, CODE_QUALITY_ENABLED_SETTING, IAC_ENABLED_SETTING, SEVERITY_FILTER_SETTING, ADVANCED_CUSTOM_ENDPOINT, - ADVANCED_CUSTOM_LS_PATH, + ADVANCED_CLI_PATH, + ADVANCED_CLI_RELEASE_CHANNEL, + ADVANCED_AUTHENTICATION_METHOD, TRUSTED_FOLDERS, + ISSUE_VIEW_OPTIONS_SETTING, + DELTA_FINDINGS, + FOLDER_CONFIGS, ].find(config => event.affectsConfiguration(config)); if (change) { diff --git a/src/snyk/extension.ts b/src/snyk/extension.ts index a3688f750..cb455a315 100644 --- a/src/snyk/extension.ts +++ b/src/snyk/extension.ts @@ -1,19 +1,16 @@ import * as vscode from 'vscode'; -import AdvisorProvider from './advisor/services/advisorProvider'; -import { AdvisorService } from './advisor/services/advisorService'; import { IExtension } from './base/modules/interfaces'; import SnykLib from './base/modules/snykLib'; import { AuthenticationService } from './base/services/authenticationService'; import { ScanModeService } from './base/services/scanModeService'; import { EmptyTreeDataProvider } from './base/views/emptyTreeDataProvider'; import { SupportProvider } from './base/views/supportProvider'; -import { messages } from './cli/messages/messages'; -import { Iteratively } from './common/analytics/itly'; import { CommandController } from './common/commands/commandController'; import { OpenIssueCommandArg } from './common/commands/types'; import { configuration } from './common/configuration/instance'; import { SnykConfiguration } from './common/configuration/snykConfiguration'; import { + SNYK_CLEAR_PERSISTED_CACHE_COMMAND, SNYK_DCIGNORE_COMMAND, SNYK_ENABLE_CODE_COMMAND, SNYK_IGNORE_ISSUE_COMMAND, @@ -21,14 +18,15 @@ import { SNYK_OPEN_BROWSER_COMMAND, SNYK_OPEN_ISSUE_COMMAND, SNYK_OPEN_LOCAL_COMMAND, + SNYK_SET_BASE_BRANCH_COMMAND, SNYK_SET_TOKEN_COMMAND, SNYK_SETTINGS_COMMAND, + SNYK_SHOW_ERROR_FROM_CONTEXT_COMMAND, SNYK_SHOW_LS_OUTPUT_COMMAND, SNYK_SHOW_OUTPUT_COMMAND, SNYK_START_COMMAND, SNYK_WORKSPACE_SCAN_COMMAND, } from './common/constants/commands'; -import { MEMENTO_FIRST_INSTALL_DATE_KEY } from './common/constants/globalState'; import { SNYK_CONTEXT, SNYK_VIEW_ANALYSIS_CODE_ENABLEMENT, @@ -40,20 +38,17 @@ import { SNYK_VIEW_WELCOME, } from './common/constants/views'; import { ErrorHandler } from './common/error/errorHandler'; -import { ErrorReporter } from './common/error/errorReporter'; import { ExperimentService } from './common/experiment/services/experimentService'; import { LanguageServer } from './common/languageServer/languageServer'; -import { StaticLsApi } from './common/languageServer/staticLsApi'; +import { StaticCliApi } from './cli/staticCliApi'; import { Logger } from './common/logger/logger'; import { DownloadService } from './common/services/downloadService'; import { LearnService } from './common/services/learnService'; import { NotificationService } from './common/services/notificationService'; import { User } from './common/user'; -import { CodeActionAdapter, CodeActionKindAdapter } from './common/vscode/codeAction'; +import { CodeActionAdapter } from './common/vscode/codeAction'; import { vsCodeCommands } from './common/vscode/commands'; -import { vsCodeEnv } from './common/vscode/env'; import { extensionContext } from './common/vscode/extensionContext'; -import { HoverAdapter } from './common/vscode/hover'; import { LanguageClientAdapter } from './common/vscode/languageClient'; import { vsCodeLanguages } from './common/vscode/languages'; import SecretStorageAdapter from './common/vscode/secretStorage'; @@ -74,30 +69,67 @@ import { IacService } from './snykIac/iacService'; import IacIssueTreeProvider from './snykIac/views/iacIssueTreeProvider'; import { IacSuggestionWebviewProvider } from './snykIac/views/suggestion/iacSuggestionWebviewProvider'; import { EditorDecorator } from './snykOss/editor/editorDecorator'; -import { OssService } from './snykOss/services/ossService'; +import { OssService } from './snykOss/ossService'; +import { OssDetailPanelProvider } from './snykOss/providers/ossDetailPanelProvider'; +import { OssVulnerabilityCountProvider } from './snykOss/providers/ossVulnerabilityCountProvider'; +import OssIssueTreeProvider from './snykOss/providers/ossVulnerabilityTreeProvider'; import { OssVulnerabilityCountService } from './snykOss/services/vulnerabilityCount/ossVulnerabilityCountService'; -import { ModuleVulnerabilityCountProvider } from './snykOss/services/vulnerabilityCount/vulnerabilityCountProvider'; -import { OssVulnerabilityTreeProvider } from './snykOss/views/ossVulnerabilityTreeProvider'; -import { OssSuggestionWebviewProvider } from './snykOss/views/suggestion/ossSuggestionWebviewProvider'; -import { DailyScanJob } from './snykOss/watchers/dailyScanJob'; +import { FeatureFlagService } from './common/services/featureFlagService'; +import { DiagnosticsIssueProvider } from './common/services/diagnosticsService'; +import { CodeIssueData, IacIssueData, OssIssueData } from './common/languageServer/types'; +import { ClearCacheService } from './common/services/CacheService'; +import { InMemory, Persisted } from './common/constants/general'; +import { GitAPI, GitExtension, Repository } from './common/git'; +import { AnalyticsSender } from './common/analytics/AnalyticsSender'; +import { MEMENTO_ANALYTICS_PLUGIN_INSTALLED_SENT } from './common/constants/globalState'; +import { AnalyticsEvent } from './common/analytics/AnalyticsEvent'; class SnykExtension extends SnykLib implements IExtension { public async activate(vscodeContext: vscode.ExtensionContext): Promise { extensionContext.setContext(vscodeContext); this.context = extensionContext; - const snykConfiguration = await this.getSnykConfiguration(); - if (snykConfiguration) { - await ErrorReporter.init(configuration, snykConfiguration, extensionContext.extensionPath, vsCodeEnv, Logger); - } try { await this.initializeExtension(vscodeContext, snykConfiguration); + this.configureGitHandlers(); } catch (e) { ErrorHandler.handle(e, Logger); } } + private configureGitHandlers(): void { + // Get the Git extension + const gitExtension = vscode.extensions.getExtension('vscode.git')?.exports; + + if (!gitExtension) { + return; + } + + // Get the API from the Git extension + const git: GitAPI = gitExtension.getAPI(1); + + // Check if there are any repositories + const repositories: Repository[] = git?.repositories; + if (!repositories || repositories.length === 0) { + return; + } + const previousBranches = new Map(); + // Register event listener for changes in each repository + repositories.forEach((repo: Repository) => { + const previousBranch = repo.state.HEAD?.name; + previousBranches.set(repo, previousBranch); + repo.state.onDidChange(async () => { + const currentBranch = repo.state.HEAD?.name; + const storedPreviousBranch = previousBranches.get(repo); + if (currentBranch !== storedPreviousBranch) { + await this.cacheService.clearCache(repo.rootUri.toString(), InMemory); + previousBranches.set(repo, currentBranch); + } + }); + }); + } + private async getSnykConfiguration(): Promise { try { return await SnykConfiguration.get(extensionContext.extensionPath, configuration.isDevelopment); @@ -122,25 +154,10 @@ class SnykExtension extends SnykLib implements IExtension { this.user = await User.getAnonymous(this.context, Logger); - this.analytics = new Iteratively( - this.user, - Logger, - configuration.shouldReportEvents, - configuration.isFedramp, - configuration.isDevelopment, - snykConfiguration, - ); - SecretStorageAdapter.init(vscodeContext); - - this.configurationWatcher = new ConfigurationWatcher(this.analytics, Logger); - this.notificationService = new NotificationService( - vsCodeWindow, - vsCodeCommands, - configuration, - this.analytics, - Logger, - ); + configuration.setExtensionId(vscodeContext.extension.id); + this.configurationWatcher = new ConfigurationWatcher(Logger); + this.notificationService = new NotificationService(vsCodeWindow, vsCodeCommands, configuration, Logger); this.statusBarItem.show(); @@ -150,23 +167,22 @@ class SnykExtension extends SnykLib implements IExtension { this, configuration, vsCodeWindow, - this.analytics, Logger, languageClientAdapter, vsCodeCommands, ); this.learnService = new LearnService(vsCodeCommands); + this.cacheService = new ClearCacheService(vsCodeCommands); this.codeSettings = new CodeSettings(this.contextService, configuration, this.openerService, vsCodeCommands); - this.scanModeService = new ScanModeService(this.contextService, configuration, this.analytics); + this.scanModeService = new ScanModeService(this.contextService, configuration); - this.advisorService = new AdvisorProvider(this.advisorApiClient, Logger); this.downloadService = new DownloadService( this.context, configuration, - new StaticLsApi(vsCodeWorkspace, configuration, Logger), + new StaticCliApi(vsCodeWorkspace, configuration, Logger), vsCodeWindow, Logger, ); @@ -182,6 +198,7 @@ class SnykExtension extends SnykLib implements IExtension { this.authService, Logger, this.downloadService, + this.context, ); const codeSuggestionProvider = new CodeSuggestionWebviewProvider( @@ -191,6 +208,7 @@ class SnykExtension extends SnykLib implements IExtension { vsCodeLanguages, vsCodeWorkspace, this.learnService, + vsCodeCommands, ); this.snykCode = new SnykCodeService( @@ -204,23 +222,32 @@ class SnykExtension extends SnykLib implements IExtension { this.workspaceTrust, this.languageServer, vsCodeLanguages, + new DiagnosticsIssueProvider(), Logger, - this.analytics, ); - this.ossService = new OssService( - this.context, + const ossSuggestionProvider = new OssDetailPanelProvider( + vsCodeWindow, + extensionContext, Logger, - configuration, - new OssSuggestionWebviewProvider(this.context, vsCodeWindow, Logger, this.learnService), + vsCodeLanguages, vsCodeWorkspace, + vsCodeCommands, + ); + + this.ossService = new OssService( + extensionContext, + configuration, + ossSuggestionProvider, + new CodeActionAdapter(), + this.codeActionKindAdapter, this.viewManagerService, - this.downloadService, - new DailyScanJob(this), - this.notificationService, - this.analytics, - this.languageServer, + vsCodeWorkspace, this.workspaceTrust, + this.languageServer, + vsCodeLanguages, + new DiagnosticsIssueProvider(), + Logger, ); const iacSuggestionProvider = new IacSuggestionWebviewProvider( @@ -229,6 +256,7 @@ class SnykExtension extends SnykLib implements IExtension { Logger, vsCodeLanguages, vsCodeWorkspace, + vsCodeCommands, ); this.iacService = new IacService( @@ -242,8 +270,8 @@ class SnykExtension extends SnykLib implements IExtension { this.workspaceTrust, this.languageServer, vsCodeLanguages, + new DiagnosticsIssueProvider(), Logger, - this.analytics, ); this.commandController = new CommandController( @@ -258,50 +286,48 @@ class SnykExtension extends SnykLib implements IExtension { vsCodeWindow, this.languageServer, Logger, - this.analytics, + configuration, + this.folderConfigs, ); this.registerCommands(vscodeContext); const codeSecurityIssueProvider = new CodeSecurityIssueTreeProvider( - this.viewManagerService, - this.contextService, - this.snykCode, - configuration, - vsCodeLanguages, - ), - codeQualityIssueProvider = new CodeQualityIssueTreeProvider( - this.viewManagerService, - this.contextService, - this.snykCode, - configuration, - vsCodeLanguages, - ); - - const codeSecurityTree = vscode.window.createTreeView(SNYK_VIEW_ANALYSIS_CODE_SECURITY, { + this.viewManagerService, + this.contextService, + this.snykCode, + configuration, + vsCodeLanguages, + this.folderConfigs, + ); + + const codeQualityIssueProvider = new CodeQualityIssueTreeProvider( + this.viewManagerService, + this.contextService, + this.snykCode, + configuration, + vsCodeLanguages, + this.folderConfigs, + ); + + const securityCodeView = SNYK_VIEW_ANALYSIS_CODE_SECURITY; + const codeQualityView = SNYK_VIEW_ANALYSIS_CODE_QUALITY; + + const codeSecurityTree = vscode.window.createTreeView(securityCodeView, { treeDataProvider: codeSecurityIssueProvider, }); - const codeQualityTree = vscode.window.createTreeView(SNYK_VIEW_ANALYSIS_CODE_QUALITY, { + + const codeQualityTree = vscode.window.createTreeView(codeQualityView, { treeDataProvider: codeQualityIssueProvider, }); vscodeContext.subscriptions.push( - vscode.window.registerTreeDataProvider(SNYK_VIEW_ANALYSIS_CODE_SECURITY, codeSecurityIssueProvider), - vscode.window.registerTreeDataProvider(SNYK_VIEW_ANALYSIS_CODE_QUALITY, codeQualityIssueProvider), + vscode.window.registerTreeDataProvider(securityCodeView, codeSecurityIssueProvider), + vscode.window.registerTreeDataProvider(codeQualityView, codeQualityIssueProvider), codeSecurityTree, codeQualityTree, ); - const ossVulnerabilityProvider = new OssVulnerabilityTreeProvider( - this.viewManagerService, - this.contextService, - this.ossService, - configuration, - ); - - vscodeContext.subscriptions.push( - vscode.window.registerTreeDataProvider(SNYK_VIEW_ANALYSIS_OSS, ossVulnerabilityProvider), - vscode.window.registerTreeDataProvider(SNYK_VIEW_SUPPORT, new SupportProvider()), - ); + vscodeContext.subscriptions.push(vscode.window.registerTreeDataProvider(SNYK_VIEW_SUPPORT, new SupportProvider())); const welcomeTree = vscode.window.createTreeView(SNYK_VIEW_WELCOME, { treeDataProvider: new EmptyTreeDataProvider(), @@ -310,14 +336,24 @@ class SnykExtension extends SnykLib implements IExtension { treeDataProvider: new EmptyTreeDataProvider(), }); - const ossTree = vscode.window.createTreeView(SNYK_VIEW_ANALYSIS_OSS, { - treeDataProvider: ossVulnerabilityProvider, + vscodeContext.subscriptions.push(codeEnablementTree); + + const ossIssueProvider = new OssIssueTreeProvider( + this.viewManagerService, + this.contextService, + this.ossService, + configuration, + vsCodeLanguages, + this.folderConfigs, + ); + + const ossSecurityTree = vscode.window.createTreeView(SNYK_VIEW_ANALYSIS_OSS, { + treeDataProvider: ossIssueProvider, }); vscodeContext.subscriptions.push( - ossTree.onDidChangeVisibility(e => this.onDidChangeOssTreeVisibility(e.visible)), - welcomeTree.onDidChangeVisibility(e => this.onDidChangeWelcomeViewVisibility(e.visible)), - codeEnablementTree, + vscode.window.registerTreeDataProvider(SNYK_VIEW_ANALYSIS_OSS, ossIssueProvider), + ossSecurityTree, ); const iacIssueProvider = new IacIssueTreeProvider( @@ -326,6 +362,7 @@ class SnykExtension extends SnykLib implements IExtension { this.iacService, configuration, vsCodeLanguages, + this.folderConfigs, ); const iacSecurityTree = vscode.window.createTreeView(SNYK_VIEW_ANALYSIS_IAC, { @@ -344,35 +381,31 @@ class SnykExtension extends SnykLib implements IExtension { vscode.workspace.onDidChangeWorkspaceFolders(e => { this.workspaceTrust.resetTrustedFoldersCache(); e.removed.forEach(folder => { - this.snykCode.resetResult(folder.uri.path); + this.snykCode.resetResult(folder.uri.fsPath); }); - this.runScan(false); + this.runScan(); }); this.editorsWatcher.activate(this); this.configurationWatcher.activate(this); this.snykCode.activateWebviewProviders(); - this.ossService.activateSuggestionProvider(); - this.ossService.activateManifestFileWatcher(this); this.iacService.activateWebviewProviders(); + this.ossService.activateWebviewProviders(); // noinspection ES6MissingAwait void this.notificationService.init(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + this.checkAdvancedMode().catch(err => Logger.error(err)); - this.checkAdvancedMode().catch(err => ErrorReporter.capture(err)); - - this.analytics.load(); this.experimentService.load(); - this.logPluginIsInstalled(); - this.initDependencyDownload(); this.ossVulnerabilityCountService = new OssVulnerabilityCountService( vsCodeWorkspace, vsCodeWindow, vsCodeLanguages, - new ModuleVulnerabilityCountProvider( + new OssVulnerabilityCountProvider( this.ossService, languageClientAdapter, new UriAdapter(), @@ -381,28 +414,10 @@ class SnykExtension extends SnykLib implements IExtension { this.ossService, Logger, new EditorDecorator(vsCodeWindow, vsCodeLanguages, new ThemeColorAdapter()), - new CodeActionKindAdapter(), - this.analytics, configuration, ); this.ossVulnerabilityCountService.activate(); - this.advisorScoreDisposable = new AdvisorService( - vsCodeWindow, - vsCodeLanguages, - this.advisorService, - Logger, - vsCodeWorkspace, - this.advisorApiClient, - new ThemeColorAdapter(), - new HoverAdapter(), - this.markdownStringAdapter, - configuration, - ); - - // noinspection ES6MissingAwait - void this.advisorScoreDisposable.activate(); - // Wait for LS startup to finish before updating the codeEnabled context // The codeEnabled context depends on an LS command await this.languageServer.start(); @@ -410,37 +425,57 @@ class SnykExtension extends SnykLib implements IExtension { // initialize contexts await this.contextService.setContext(SNYK_CONTEXT.INITIALIZED, true); + // Fetch feature flag to determine whether to use the new LSP-based rendering. + // feature flags depend on the language server + this.featureFlagService = new FeatureFlagService(vsCodeCommands); + await this.setupFeatureFlags(); + + // Fetch feature flag to determine whether to use the new LSP-based rendering. + + // initialize contexts + await this.contextService.setContext(SNYK_CONTEXT.INITIALIZED, true); + this.sendPluginInstalledEvent(); + // Actually start analysis this.runScan(); } + private sendPluginInstalledEvent() { + // start analytics sender and send plugin installed event + const analyticsSender = AnalyticsSender.getInstance(Logger, configuration, vsCodeCommands, this.contextService); + + const pluginInstalledSent = + extensionContext.getGlobalStateValue(MEMENTO_ANALYTICS_PLUGIN_INSTALLED_SENT) ?? false; + + if (!pluginInstalledSent) { + const category = []; + category.push('install'); + const pluginInstalleEvent = new AnalyticsEvent(this.user.anonymousId, 'plugin installed', category); + analyticsSender.logEvent(pluginInstalleEvent, () => { + void extensionContext.updateGlobalStateValue(MEMENTO_ANALYTICS_PLUGIN_INSTALLED_SENT, true); + }); + } + } + public async deactivate(): Promise { this.ossVulnerabilityCountService.dispose(); await this.languageServer.stop(); - await this.analytics.flush(); - await ErrorReporter.flush(); } - public async restartLanguageServer(): Promise { + public async stopLanguageServer(): Promise { await this.languageServer.stop(); - await this.languageServer.start(); } - private logPluginIsInstalled(): void { - // Use memento until lifecycle hooks are implemented - // https://github.com/microsoft/vscode/issues/98732 - if (!this.context.getGlobalStateValue(MEMENTO_FIRST_INSTALL_DATE_KEY)) { - this.analytics.logPluginIsInstalled(); - void this.context.updateGlobalStateValue(MEMENTO_FIRST_INSTALL_DATE_KEY, Date.now()); - } + public async restartLanguageServer(): Promise { + await this.languageServer.stop(); + await this.languageServer.start(); } - private initDependencyDownload(): DownloadService { + public initDependencyDownload(): DownloadService { this.downloadService.downloadOrUpdate().catch(err => { - Logger.error(`${messages.lsDownloadFailed} ${ErrorHandler.stringifyError(err)}`); - this.ossService?.handleLsDownloadFailure(); + void ErrorHandler.handleGlobal(err, Logger, this.contextService, this.loadingBadge); + void this.notificationService.showErrorNotification((err as Error).message); }); - return this.downloadService; } @@ -454,13 +489,15 @@ class SnykExtension extends SnykLib implements IExtension { ), vscode.commands.registerCommand(SNYK_INITIATE_LOGIN_COMMAND, () => this.commandController.initiateLogin()), vscode.commands.registerCommand(SNYK_SET_TOKEN_COMMAND, () => this.commandController.setToken()), + vscode.commands.registerCommand( + SNYK_CLEAR_PERSISTED_CACHE_COMMAND, + async () => await this.cacheService.clearCache('', Persisted), + ), vscode.commands.registerCommand(SNYK_ENABLE_CODE_COMMAND, () => this.commandController.executeCommand(SNYK_ENABLE_CODE_COMMAND, () => this.enableCode()), ), vscode.commands.registerCommand(SNYK_START_COMMAND, async () => { await vscode.commands.executeCommand(SNYK_WORKSPACE_SCAN_COMMAND); - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - await this.commandController.executeCommand(SNYK_START_COMMAND, () => this.runScan(true)); // todo: remove once OSS scans replaced with LS }), vscode.commands.registerCommand(SNYK_SETTINGS_COMMAND, () => this.commandController.openSettings()), vscode.commands.registerCommand(SNYK_DCIGNORE_COMMAND, (custom: boolean, path?: string) => @@ -472,6 +509,13 @@ class SnykExtension extends SnykLib implements IExtension { vscode.commands.registerCommand(SNYK_SHOW_OUTPUT_COMMAND, () => this.commandController.showOutputChannel()), vscode.commands.registerCommand(SNYK_SHOW_LS_OUTPUT_COMMAND, () => this.commandController.showLsOutputChannel()), vscode.commands.registerCommand(SNYK_IGNORE_ISSUE_COMMAND, IgnoreCommand.ignoreIssues), + vscode.commands.registerCommand(SNYK_SET_BASE_BRANCH_COMMAND, (folderPath: string) => + this.commandController.setBaseBranch(folderPath), + ), + vscode.commands.registerCommand(SNYK_SHOW_ERROR_FROM_CONTEXT_COMMAND, () => { + const err = this.contextService.viewContext[SNYK_CONTEXT.ERROR] as Error; + void this.notificationService.showErrorNotification(err.message); + }), ); } } diff --git a/src/snyk/snykCode/codeActions/codeIssuesActionsProvider.ts b/src/snyk/snykCode/codeActions/codeIssuesActionsProvider.ts index 7a6c52d93..a47f924ea 100644 --- a/src/snyk/snykCode/codeActions/codeIssuesActionsProvider.ts +++ b/src/snyk/snykCode/codeActions/codeIssuesActionsProvider.ts @@ -1,5 +1,4 @@ import { CodeAction, Range, TextDocument } from 'vscode'; -import { IAnalytics, SupportedQuickFixProperties } from '../../common/analytics/itly'; import { OpenCommandIssueType, OpenIssueCommandArg } from '../../common/commands/types'; import { SNYK_IGNORE_ISSUE_COMMAND, SNYK_OPEN_ISSUE_COMMAND } from '../../common/constants/commands'; import { CodeActionsProvider } from '../../common/editor/codeActionsProvider'; @@ -11,6 +10,8 @@ import { IVSCodeLanguages } from '../../common/vscode/languages'; import { FILE_IGNORE_ACTION_NAME, IGNORE_ISSUE_ACTION_NAME } from '../constants/analysis'; import { IssueUtils } from '../utils/issueUtils'; import { CodeIssueCommandArg } from '../views/interfaces'; +import { IConfiguration } from '../../common/configuration/configuration'; +import { FEATURE_FLAGS } from '../../common/constants/featureFlags'; export class SnykCodeActionsProvider extends CodeActionsProvider { constructor( @@ -18,9 +19,9 @@ export class SnykCodeActionsProvider extends CodeActionsProvider private readonly codeActionAdapter: ICodeActionAdapter, codeActionKindAdapter: ICodeActionKindAdapter, private readonly languages: IVSCodeLanguages, - analytics: IAnalytics, + private readonly configuration: IConfiguration, ) { - super(issues, codeActionKindAdapter, analytics); + super(issues, codeActionKindAdapter); } getActions(folderPath: string, document: TextDocument, issue: Issue, range: Range): CodeAction[] { @@ -28,12 +29,15 @@ export class SnykCodeActionsProvider extends CodeActionsProvider const ignoreIssueAction = this.createIgnoreIssueAction(document, issue, range, false); const fileIgnoreIssueAction = this.createIgnoreIssueAction(document, issue, range, true); - // returns list of actions, all new actions should be added to this list - return [openIssueAction, ignoreIssueAction, fileIgnoreIssueAction]; - } + const actions = [openIssueAction]; - getAnalyticsActionTypes(): [string, ...string[]] & [SupportedQuickFixProperties, ...SupportedQuickFixProperties[]] { - return ['Show Suggestion', 'Ignore Suggestion In Line', 'Ignore Suggestion In File']; + if (this.configuration.getFeatureFlag(FEATURE_FLAGS.snykCodeInlineIgnore)) { + actions.push(fileIgnoreIssueAction); + actions.push(ignoreIssueAction); + } + + // returns list of actions, all new actions should be added to this list + return actions; } getIssueRange(issue: Issue): Range { diff --git a/src/snyk/snykCode/codeService.ts b/src/snyk/snykCode/codeService.ts index ec4174f44..bb7284a8a 100644 --- a/src/snyk/snykCode/codeService.ts +++ b/src/snyk/snykCode/codeService.ts @@ -1,5 +1,4 @@ import { Subscription } from 'rxjs'; -import { IAnalytics } from '../common/analytics/itly'; import { IConfiguration } from '../common/configuration/configuration'; import { IWorkspaceTrust } from '../common/configuration/trustedFolders'; import { ILanguageServer } from '../common/languageServer/languageServer'; @@ -13,8 +12,11 @@ import { IVSCodeLanguages } from '../common/vscode/languages'; import { IVSCodeWorkspace } from '../common/vscode/workspace'; import { SnykCodeActionsProvider } from './codeActions/codeIssuesActionsProvider'; import { ICodeSuggestionWebviewProvider } from './views/interfaces'; +import { IDiagnosticsIssueProvider } from '../common/services/diagnosticsService'; export class SnykCodeService extends ProductService { + public readonly productType = ScanProduct.Code; + constructor( extensionContext: ExtensionContext, config: IConfiguration, @@ -26,8 +28,8 @@ export class SnykCodeService extends ProductService { workspaceTrust: IWorkspaceTrust, languageServer: ILanguageServer, languages: IVSCodeLanguages, + readonly diagnosticsIssueProvider: IDiagnosticsIssueProvider, logger: ILog, - readonly analytics: IAnalytics, ) { super( extensionContext, @@ -38,11 +40,12 @@ export class SnykCodeService extends ProductService { workspaceTrust, languageServer, languages, + diagnosticsIssueProvider, logger, ); this.registerCodeActionsProvider( - new SnykCodeActionsProvider(this.result, codeActionAdapter, codeActionKindAdapter, languages, analytics), + new SnykCodeActionsProvider(this.result, codeActionAdapter, codeActionKindAdapter, languages, config), ); } diff --git a/src/snyk/snykCode/codeSettings.ts b/src/snyk/snykCode/codeSettings.ts index face46032..096a7cf95 100644 --- a/src/snyk/snykCode/codeSettings.ts +++ b/src/snyk/snykCode/codeSettings.ts @@ -13,7 +13,7 @@ export interface ICodeSettings { getSastSettings(): Promise; } -export type SastSettings = { +type SastSettings = { sastEnabled: boolean; localCodeEngine: { enabled: boolean; @@ -43,6 +43,7 @@ export class CodeSettings implements ICodeSettings { } await this.contextService.setContext(SNYK_CONTEXT.CODE_ENABLED, codeEnabled); await this.contextService.setContext(SNYK_CONTEXT.CODE_LOCAL_ENGINE_ENABLED, localCodeEngineEnabled); + return codeEnabled; } diff --git a/src/snyk/snykCode/constants/analysis.ts b/src/snyk/snykCode/constants/analysis.ts index a9dc2baf4..34c606b2d 100644 --- a/src/snyk/snykCode/constants/analysis.ts +++ b/src/snyk/snykCode/constants/analysis.ts @@ -1,29 +1,13 @@ -export const SNYK_SEVERITIES: { [key: string]: number } = { - information: 1, - warning: 2, - error: 3, -}; - export const IGNORE_ISSUE_BASE_COMMENT_TEXT = 'deepcode ignore'; export const FILE_IGNORE_ISSUE_BASE_COMMENT_TEXT = `file ${IGNORE_ISSUE_BASE_COMMENT_TEXT}`; export const IGNORE_ISSUE_REASON_TIP = ''; -export const SHOW_ISSUE_ACTION_NAME = 'Show this suggestion (Snyk)'; export const IGNORE_ISSUE_ACTION_NAME = 'Ignore this particular suggestion (Snyk)'; export const FILE_IGNORE_ACTION_NAME = 'Ignore this suggestion in current file (Snyk)'; -export const IGNORE_TIP_FOR_USER = "To ignore this issue for Snyk choose 'Ignore this issue' in QuickFix dropdown"; - -export const ISSUES_MARKERS_DECORATION_TYPE: { [key: string]: string } = { - border: '1px', - borderColor: 'green', - borderStyle: 'none none dashed none', -}; -export const DIAGNOSTICS_CODE_SECURITY_COLLECTION_NAME = 'Snyk Code Security'; -export const DIAGNOSTICS_CODE_QUALITY_COLLECTION_NAME = 'Snyk Code Quality'; export const DIAGNOSTICS_OSS_COLLECTION_NAME = 'Snyk Open Source Security'; +export const DIAGNOSTICS_OSS_COLLECTION_NAME_LS = 'Snyk Open Source'; -export const WEBVIEW_PANEL_SECURITY_TITLE = 'Snyk Code Vulnerability'; -export const WEBVIEW_PANEL_QUALITY_TITLE = 'Snyk Code Issue'; +export const WEBVIEW_PANEL_SECURITY_TITLE = 'Snyk Code Issue'; diff --git a/src/snyk/snykCode/constants/dcignore.ts b/src/snyk/snykCode/constants/dcignore.ts new file mode 100644 index 000000000..0af79e6f4 --- /dev/null +++ b/src/snyk/snykCode/constants/dcignore.ts @@ -0,0 +1,74 @@ +import { CustomDCIgnore, DefaultDCIgnore } from '@deepcode/dcignore'; + +export const MAX_PAYLOAD = 4 * 1024 * 1024; +export const MAX_FILE_SIZE = 1024 * 1024; +export const HASH_ALGORITHM = 'sha256'; +export const ENCODE_TYPE = 'hex'; +export const GIT_FILENAME = '.git'; +export const GITIGNORE_FILENAME = '.gitignore'; +export const DCIGNORE_FILENAME = '.dcignore'; +export const DOTSNYK_FILENAME = '.snyk'; +export const EXCLUDED_NAMES = [GITIGNORE_FILENAME, DCIGNORE_FILENAME]; +export const CACHE_KEY = '.dccache'; +export const MAX_UPLOAD_ATTEMPTS = 10; +export const UPLOAD_CONCURRENCY = 2; +export const POLLING_INTERVAL = 500; +export const MAX_RETRY_ATTEMPTS = 10; // Request retries on network errors +export const REQUEST_RETRY_DELAY = 5 * 1000; // delay between retries in milliseconds +export const ORG_ID_REGEXP = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; + +export const IGNORES_DEFAULT = [`**/${GIT_FILENAME}/**`]; + +export const IGNORE_FILES_NAMES = [GITIGNORE_FILENAME, DCIGNORE_FILENAME, DOTSNYK_FILENAME]; + +export const DCIGNORE_DRAFTS = { + custom: CustomDCIgnore, + default: DefaultDCIgnore, +}; + +// eslint-disable-next-line no-shadow +export enum ErrorCodes { + loginInProgress = 304, + badRequest = 400, + unauthorizedUser = 401, + unauthorizedBundleAccess = 403, + notFound = 404, + bigPayload = 413, + connectionRefused = 421, + dnsNotFound = 452, + serverError = 500, + badGateway = 502, + serviceUnavailable = 503, + timeout = 504, +} + +export const NETWORK_ERRORS = { + ETIMEDOUT: ErrorCodes.timeout, + ECONNREFUSED: ErrorCodes.connectionRefused, + ECONNRESET: ErrorCodes.connectionRefused, + ENETUNREACH: ErrorCodes.connectionRefused, + ENOTFOUND: ErrorCodes.dnsNotFound, +}; + +export const DEFAULT_ERROR_MESSAGES: { [P in ErrorCodes]: string } = { + [ErrorCodes.serverError]: 'Unexpected server error', // 500 + [ErrorCodes.badGateway]: 'Bad gateway', // 502 + [ErrorCodes.serviceUnavailable]: 'Service unavailable', // 503 + [ErrorCodes.timeout]: 'Timeout occured. Try again later.', // 504 + [ErrorCodes.dnsNotFound]: '[Connection issue] Could not resolve domain', // 452 + [ErrorCodes.connectionRefused]: '[Connection issue] Connection refused', // 421 + [ErrorCodes.loginInProgress]: 'Login has not been confirmed yet', + [ErrorCodes.badRequest]: 'Bad request', + [ErrorCodes.unauthorizedUser]: 'Missing, revoked or inactive token', + [ErrorCodes.unauthorizedBundleAccess]: 'Unauthorized access to requested bundle analysis', + [ErrorCodes.notFound]: 'Not found', + [ErrorCodes.bigPayload]: `Payload too large (max is ${MAX_PAYLOAD}b)`, +}; + +export type GenericErrorTypes = + | ErrorCodes.serverError + | ErrorCodes.badGateway + | ErrorCodes.serviceUnavailable + | ErrorCodes.timeout + | ErrorCodes.connectionRefused + | ErrorCodes.dnsNotFound; diff --git a/src/snyk/snykCode/hoverProvider/hoverProvider.ts b/src/snyk/snykCode/hoverProvider/hoverProvider.ts deleted file mode 100644 index cafb460e9..000000000 --- a/src/snyk/snykCode/hoverProvider/hoverProvider.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { IAnalytics } from '../../common/analytics/itly'; -import { IDE_NAME } from '../../common/constants/general'; -import { ILog } from '../../common/logger/interfaces'; -import { IHoverAdapter } from '../../common/vscode/hover'; -import { IVSCodeLanguages } from '../../common/vscode/languages'; -import { IMarkdownStringAdapter } from '../../common/vscode/markdownString'; -import { Diagnostic, DiagnosticCollection, Disposable, Hover, Position, TextDocument } from '../../common/vscode/types'; -import { IGNORE_TIP_FOR_USER } from '../constants/analysis'; -import { ISnykCodeAnalyzer } from '../interfaces'; -import { IssueUtils } from '../utils/issueUtils'; - -export class DisposableHoverProvider implements Disposable { - private hoverProvider: Disposable | undefined; - - constructor( - private readonly analyzer: ISnykCodeAnalyzer, - private readonly logger: ILog, - private readonly vscodeLanguages: IVSCodeLanguages, - private readonly analytics: IAnalytics, - private readonly markdownStringAdapter: IMarkdownStringAdapter, - ) {} - - register(snykReview: DiagnosticCollection | undefined, hoverAdapter: IHoverAdapter): Disposable { - this.hoverProvider = this.vscodeLanguages.registerHoverProvider( - { scheme: 'file', language: '*' }, - { - provideHover: this.getHover(snykReview, hoverAdapter), - }, - ); - return this; - } - - getHover(snykReview: DiagnosticCollection | undefined, hoverAdapter: IHoverAdapter) { - return (document: TextDocument, position: Position): Hover | undefined => { - if (!snykReview || !snykReview.has(document.uri)) { - return undefined; - } - const currentFileReviewIssues = snykReview.get(document.uri); - const issue = IssueUtils.findIssueWithRange(position, currentFileReviewIssues); - if (issue) { - this.logIssueHoverIsDisplayed(issue); - const ignoreMarkdown = this.markdownStringAdapter.get(IGNORE_TIP_FOR_USER); - return hoverAdapter.create(ignoreMarkdown); - } - }; - } - - private logIssueHoverIsDisplayed(issue: Diagnostic): void { - const suggestion = this.analyzer.findSuggestion(issue); - if (!suggestion) { - this.logger.debug('Failed to log hover displayed analytical event.'); - return; - } - - this.analytics.logIssueHoverIsDisplayed({ - issueId: suggestion.id, - issueType: IssueUtils.getIssueType(suggestion.isSecurityType), - severity: IssueUtils.severityAsText(suggestion.severity), - ide: IDE_NAME, - }); - } - - dispose(): void { - if (this.hoverProvider) { - this.hoverProvider.dispose(); - } - } -} diff --git a/src/snyk/snykCode/interfaces.ts b/src/snyk/snykCode/interfaces.ts index 482a99ca2..e8dcc8fae 100644 --- a/src/snyk/snykCode/interfaces.ts +++ b/src/snyk/snykCode/interfaces.ts @@ -1,16 +1,4 @@ -import { AnalysisResultLegacy, FilePath, FileSuggestion, Suggestion } from '@snyk/code-client'; -import * as vscode from 'vscode'; -import { DiagnosticCollection, TextDocument } from 'vscode'; -import { IExtension } from '../base/modules/interfaces'; -import { IHoverAdapter } from '../common/vscode/hover'; -import { IMarkdownStringAdapter } from '../common/vscode/markdownString'; -import { Disposable } from '../common/vscode/types'; - -// TODO: remove after Code move to LS. -export type completeFileSuggestionType = ICodeSuggestion & - FileSuggestion & { - uri: string; - }; +import { TextDocument } from 'vscode'; export type openedTextEditorType = { fullPath: string; @@ -22,49 +10,3 @@ export type openedTextEditorType = { contentChanges: any[]; document: TextDocument; }; - -export interface IIssuesListOptions { - fileIssuesList: FilePath; - suggestions: Readonly; - fileUri: vscode.Uri; -} - -export type ICodeSuggestion = Suggestion & { - isSecurityType: boolean; -}; - -interface ICodeSuggestions { - [suggestionIndex: string]: Readonly; -} - -export interface ISnykCodeResult extends AnalysisResultLegacy { - suggestions: Readonly; -} - -export interface ISnykCodeAnalyzer extends Disposable { - codeSecurityReview: DiagnosticCollection | undefined; - codeQualityReview: DiagnosticCollection | undefined; - - registerHoverProviders( - codeSecurityHoverAdapter: IHoverAdapter, - codeQualityHoverAdapter: IHoverAdapter, - markdownStringAdapter: IMarkdownStringAdapter, - ): void; - registerCodeActionProviders( - codeSecurityCodeActionsProvider: Disposable, - codeQualityCodeActionsProvider: Disposable, - ): void; - - setAnalysisResults(results: AnalysisResultLegacy): void; - getAnalysisResults(): Readonly; - findSuggestion(diagnostic: vscode.Diagnostic): Readonly; - getFullSuggestion( - suggestionId: string, - uri: vscode.Uri, - position: vscode.Range, - ): Readonly; - checkFullSuggestion(suggestion: completeFileSuggestionType): boolean; - createReviewResults(): void; - updateReviewResultsPositions(extension: IExtension, updatedFile: openedTextEditorType): Promise; - refreshDiagnostics(): void; -} diff --git a/src/snyk/snykCode/utils/analysisUtils.ts b/src/snyk/snykCode/utils/analysisUtils.ts index f311ce96a..8c5e02cfd 100644 --- a/src/snyk/snykCode/utils/analysisUtils.ts +++ b/src/snyk/snykCode/utils/analysisUtils.ts @@ -2,297 +2,19 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { AnalysisResultLegacy, FilePath, FileSuggestion, Marker, Suggestion } from '@snyk/code-client'; import path from 'path'; -import { IVSCodeLanguages } from '../../common/vscode/languages'; -import { - DecorationOptions, - Diagnostic, - DiagnosticRelatedInformation, - DiagnosticSeverity, - Range, - Uri, -} from '../../common/vscode/types'; -import { IUriAdapter } from '../../common/vscode/uri'; import { IVSCodeWorkspace } from '../../common/vscode/workspace'; import { FILE_IGNORE_ISSUE_BASE_COMMENT_TEXT, IGNORE_ISSUE_BASE_COMMENT_TEXT, IGNORE_ISSUE_REASON_TIP, - SNYK_SEVERITIES, } from '../constants/analysis'; -import { completeFileSuggestionType, ICodeSuggestion, ISnykCodeResult, openedTextEditorType } from '../interfaces'; -import { IssuePlacementPosition, IssueUtils } from './issueUtils'; - -export const createSnykSeveritiesMap = (): { [x: number]: { name: DiagnosticSeverity } } => { - const { information, error, warning } = SNYK_SEVERITIES; - - return { - [information]: { - name: DiagnosticSeverity.Information, - }, - [warning]: { name: DiagnosticSeverity.Warning }, - [error]: { name: DiagnosticSeverity.Error }, - }; -}; - -export const getVSCodeSeverity = (snykSeverity: number): DiagnosticSeverity => { - const { information, error, warning } = SNYK_SEVERITIES; - return ( - { - [information]: DiagnosticSeverity.Information, - [warning]: DiagnosticSeverity.Warning, - [error]: DiagnosticSeverity.Error, - }[snykSeverity] || DiagnosticSeverity.Information - ); -}; - -export const getSnykSeverity = (vscodeSeverity: DiagnosticSeverity): number => { - const { information, error, warning } = SNYK_SEVERITIES; - return { - [DiagnosticSeverity.Information]: information, - [DiagnosticSeverity.Warning]: warning, - [DiagnosticSeverity.Error]: error, - [DiagnosticSeverity.Hint]: information, - }[vscodeSeverity]; -}; - -export const createSnykProgress = (progress: number): number => { - const progressOffset = 100; - return Math.round(progress * progressOffset); -}; - -export const createIssueRange = (position: IssuePlacementPosition, languages: IVSCodeLanguages): Range => { - return languages.createRange( - Math.max(0, position.rows.start), - Math.max(0, position.cols.start), - Math.max(0, position.rows.end), - Math.max(0, position.cols.end), - ); -}; - -// todo: remove when Snyk Code uses LS. -export const createIssueCorrectRange = (issuePosition: FileSuggestion, languages: IVSCodeLanguages): Range => { - return createIssueRange( - { - ...IssueUtils.createCorrectIssuePlacement(issuePosition), - }, - languages, - ); -}; - -export const updateFileReviewResultsPositions = ( - analysisResults: AnalysisResultLegacy, - updatedFile: openedTextEditorType, -): FilePath => { - const changesRange = updatedFile.contentChanges[0].range; - const changesText = updatedFile.contentChanges[0].text; - const goToNewLine = '\n'; - // eslint-disable-next-line @typescript-eslint/restrict-plus-operands - const offsetedline = changesRange.start.line + 1; - const charOffset = 1; - - const fileIssuesList = { - ...analysisResults.files[updatedFile.fullPath], - }; - for (const issue in fileIssuesList) { - if (!Object.prototype.hasOwnProperty.call(fileIssuesList, issue)) { - continue; - } - - for (const [index, position] of fileIssuesList[issue].entries()) { - const currentLineIsOnEdgeOfIssueRange = offsetedline === position.rows[0] || offsetedline === position.rows[1]; - - for (const row in position.rows) { - if (offsetedline < position.rows[row]) { - position.rows[row] += updatedFile.lineCount.prevOffset; - } else if (offsetedline === position.rows[row]) { - if (changesRange.start.character < position.rows[row]) { - position.rows[row] += updatedFile.lineCount.prevOffset; - } - } - } - - if (currentLineIsOnEdgeOfIssueRange || (offsetedline > position.rows[0] && offsetedline < position.rows[1])) { - // when chars are added - if (changesText.length && changesText !== goToNewLine && currentLineIsOnEdgeOfIssueRange) { - if (changesRange.start.character < position.cols[0] && !changesText.includes(goToNewLine)) { - for (const col in position.cols) { - if (!Object.prototype.hasOwnProperty.call(position.cols, col)) continue; - position.cols[col] += changesText.length; - } - } - // if char is inside issue range - if (changesRange.start.character >= position.cols[0] && changesRange.start.character <= position.cols[1]) { - position.cols[1] += changesText.length; - } - } - // when chars are deleted - if (updatedFile.contentChanges[0].rangeLength && currentLineIsOnEdgeOfIssueRange) { - if (updatedFile.lineCount.prevOffset < 0 && !changesText) { - continue; - } - if (changesRange.start.character < position.cols[0] && !changesText.includes(goToNewLine)) { - for (const char in position.cols) { - if (!Object.prototype.hasOwnProperty.call(position.cols, char)) continue; - position.cols[char] = - position.cols[char] > 0 ? position.cols[char] - updatedFile.contentChanges[0].rangeLength : 0; - } - } - // if char is in issue range - if (changesRange.start.character >= position.cols[0] && changesRange.start.character <= position.cols[1]) { - position.cols[1] = position.cols[1] > 0 ? position.cols[1] - updatedFile.contentChanges[0].rangeLength : 0; - } - } - // hide issue - if (position.cols[0] - charOffset === position.cols[1]) { - fileIssuesList[issue].splice(index, 1); - } - position.cols[0] = position.cols[0] > 0 ? position.cols[0] : 0; - position.cols[1] = position.cols[1] > 0 ? position.cols[1] : 0; - } - } - } - return fileIssuesList; -}; - -export const createIssueMarkerMsg = (originalMsg: string, [markerStartIdx, markerEndIdx]: number[]): string => { - return originalMsg.substring(markerStartIdx, markerEndIdx + 1); -}; - -export const createIssuesMarkersDecorationOptions = ( - currentFileReviewIssues: readonly Diagnostic[] | undefined, -): DecorationOptions[] => { - if (!currentFileReviewIssues) { - return []; - } - const issueMarkersDecorationOptions = currentFileReviewIssues.reduce((markersRanges, issue) => { - if (issue.relatedInformation) { - for (const markerInfo of issue.relatedInformation) { - markersRanges.push({ - range: markerInfo.location.range, - hoverMessage: markerInfo.message, - }); - } - } - return markersRanges; - }, Array()); - return issueMarkersDecorationOptions; -}; - -export const createIssueRelatedInformation = ( - markersList: Marker[], - fileUriPath: string, - message: string, - languages: IVSCodeLanguages, - workspace: IVSCodeWorkspace, - uriAdapter: IUriAdapter, -): DiagnosticRelatedInformation[] => { - return markersList.reduce((res, marker) => { - const { msg: markerMsgIdxs, pos: positions } = marker; - - positions.forEach(position => { - const positionUri = getAbsoluteMarkerFilePath(workspace, position.file, fileUriPath); - const relatedInfo = languages.createDiagnosticRelatedInformation( - uriAdapter.file(positionUri), - createIssueCorrectRange(position, languages), - createIssueMarkerMsg(message, markerMsgIdxs), - ); - res.push(relatedInfo); - }); - - return res; - }, Array()); -}; - -export const findCompleteSuggestion = ( - analysisResults: ISnykCodeResult, - suggestionId: string, - uri: Uri, - position: Range, - languages: IVSCodeLanguages, -): completeFileSuggestionType | undefined => { - const filePath = uri.fsPath; - if (!analysisResults.files[filePath]) return; - const file: FilePath = analysisResults.files[filePath]; - let fileSuggestion: FileSuggestion | undefined; - let suggestionIndex: string | number | undefined = Object.keys(file).find(i => { - const index = parseInt(i, 10); - if (analysisResults.suggestions[index].id !== suggestionId) return false; - const pos = file[index].find(fs => { - const r = createIssueCorrectRange(fs, languages); - return ( - r.start.character === position.start.character && - r.start.line === position.start.line && - r.end.character === position.end.character && - r.end.line === position.end.line - ); - }); - if (pos) { - fileSuggestion = pos; - return true; - } - return false; - }); - if (!fileSuggestion || !suggestionIndex) return; - suggestionIndex = parseInt(suggestionIndex, 10); - const suggestion = analysisResults.suggestions[suggestionIndex]; - if (!suggestion) return; - // eslint-disable-next-line consistent-return - return { - uri: uri.toString(), - ...suggestion, - ...fileSuggestion, - }; -}; - -export const checkCompleteSuggestion = ( - analysisResults: AnalysisResultLegacy, - suggestion: completeFileSuggestionType, - uriAdapter: IUriAdapter, -): boolean => { - const filePath = uriAdapter.parse(suggestion.uri).fsPath; - if (!analysisResults.files[filePath]) return false; - const file: FilePath = analysisResults.files[filePath]; - const suggestionIndex: string | undefined = Object.keys(file).find(i => { - const index = parseInt(i, 10); - if ( - analysisResults.suggestions[index].id !== suggestion.id || - analysisResults.suggestions[index].message !== suggestion.message - ) - return false; - const found = file[index].find(fs => { - let equal = true; - for (const dir of ['cols', 'rows']) { - for (const ind of [0, 1]) { - equal = equal && fs[dir][ind] === suggestion[dir][ind]; - } - } - return equal; - }); - return !!found; - }); - return !!suggestionIndex; -}; - -export const findSuggestionByMessage = ( - analysisResults: ISnykCodeResult, - suggestionName: string, -): ICodeSuggestion | undefined => { - return Object.values(analysisResults.suggestions).find( - (suggestion: ICodeSuggestion) => suggestion.message === suggestionName, - ); -}; export const ignoreIssueCommentText = (issueId: string, isFileIgnore?: boolean): string => { const snykComment = isFileIgnore ? FILE_IGNORE_ISSUE_BASE_COMMENT_TEXT : IGNORE_ISSUE_BASE_COMMENT_TEXT; return `${snykComment} ${issueId}: ${IGNORE_ISSUE_REASON_TIP}`; }; -export const isSecurityTypeSuggestion = (suggestion: Suggestion): boolean => { - return suggestion.categories.includes('Security'); -}; - export const getAbsoluteMarkerFilePath = ( workspace: IVSCodeWorkspace, markerFilePath: string, diff --git a/src/snyk/snykCode/utils/htmlEncoder.ts b/src/snyk/snykCode/utils/htmlEncoder.ts new file mode 100644 index 000000000..046d7f499 --- /dev/null +++ b/src/snyk/snykCode/utils/htmlEncoder.ts @@ -0,0 +1,21 @@ +import he from 'he'; +import { ExampleCommitFix } from '../../common/languageServer/types'; + +export const encodeExampleCommitFixes = (exampleCommitFixes: ExampleCommitFix[]): ExampleCommitFix[] => { + return exampleCommitFixes.map(example => { + return { + ...example, + lines: example.lines.map(commitLine => { + if (!commitLine.isExampleLineEncoded) { + return { + ...commitLine, + line: he.encode(commitLine.line), + isExampleLineEncoded: true, + }; + } + + return commitLine; + }), + }; + }); +}; diff --git a/src/snyk/snykCode/utils/ignoreFileUtils.ts b/src/snyk/snykCode/utils/ignoreFileUtils.ts index 96cf5e0e2..810b28ec6 100644 --- a/src/snyk/snykCode/utils/ignoreFileUtils.ts +++ b/src/snyk/snykCode/utils/ignoreFileUtils.ts @@ -1,4 +1,4 @@ -import { constants } from '@snyk/code-client'; +import * as dcIgnoreConstant from '../../snykCode/constants/dcignore'; import { Buffer } from 'buffer'; import * as fs from 'fs'; import { IUriAdapter } from '../../common/vscode/uri'; @@ -12,8 +12,10 @@ export const createDCIgnore = async ( window: IVSCodeWindow, uriAdapter: IUriAdapter, ): Promise => { - const content: Buffer = Buffer.from(custom ? constants.DCIGNORE_DRAFTS.custom : constants.DCIGNORE_DRAFTS.default); - const filePath = `${path}/${constants.DCIGNORE_FILENAME}`; + const content: Buffer = Buffer.from( + custom ? dcIgnoreConstant.DCIGNORE_DRAFTS.custom : dcIgnoreConstant.DCIGNORE_DRAFTS.default, + ); + const filePath = `${path}/${dcIgnoreConstant.DCIGNORE_FILENAME}`; const openPath = uriAdapter.file(filePath); // We don't want to override the dcignore file with an empty one. if (!custom || !fs.existsSync(filePath)) await workspace.fs.writeFile(openPath, content); diff --git a/src/snyk/snykCode/utils/issueUtils.ts b/src/snyk/snykCode/utils/issueUtils.ts index 34f8f46dd..2a6e8bd50 100644 --- a/src/snyk/snykCode/utils/issueUtils.ts +++ b/src/snyk/snykCode/utils/issueUtils.ts @@ -1,70 +1,9 @@ -import { FileSuggestion } from '@snyk/code-client'; import _ from 'lodash'; -import { CodeIssueData, IssueSeverity } from '../../common/languageServer/types'; +import { CodeIssueData } from '../../common/languageServer/types'; import { IVSCodeLanguages } from '../../common/vscode/languages'; -import { Diagnostic, Position, Range } from '../../common/vscode/types'; - -export type IssuePlacementPosition = { - cols: { - start: number; - end: number; - }; - rows: { - start: number; - end: number; - }; -}; +import { Range } from '../../common/vscode/types'; export class IssueUtils { - static findIssueWithRange = ( - matchingRange: Range | Position, - issuesList: readonly Diagnostic[] | undefined, - ): Diagnostic | undefined => { - return ( - issuesList && - issuesList.find((issue: Diagnostic) => { - return issue.range.contains(matchingRange); - }) - ); - }; - - static issueSeverityAsText = (severity: IssueSeverity): 'Low' | 'Medium' | 'High' | 'Critical' => { - return _.startCase(severity) as 'Low' | 'Medium' | 'High' | 'Critical'; - }; - - // todo: remove with OSS integration - static severityAsText = (severity: 1 | 2 | 3 | 4): 'Low' | 'Medium' | 'High' | 'Critical' => { - switch (severity) { - case 1: - return 'Low'; - case 2: - return 'Medium'; - case 3: - return 'High'; - case 4: - return 'Critical'; - } - }; - - static getIssueType = (isSecurityType: boolean): 'Code Security Vulnerability' | 'Code Quality Issue' => { - return isSecurityType ? 'Code Security Vulnerability' : 'Code Quality Issue'; - }; - - static createCorrectIssuePlacement = (item: FileSuggestion): IssuePlacementPosition => { - const rowOffset = 1; - const createPosition = (i: number): number => (i - rowOffset < 0 ? 0 : i - rowOffset); - return { - cols: { - start: createPosition(item.cols[0]), - end: item.cols[1], - }, - rows: { - start: createPosition(item.rows[0]), - end: createPosition(item.rows[1]), - }, - }; - }; - // Creates zero-based range static createVsCodeRange = (issueData: CodeIssueData, languages: IVSCodeLanguages): Range => { return IssueUtils.createVsCodeRangeFromRange(issueData.rows, issueData.cols, languages); diff --git a/src/snyk/snykCode/utils/patchUtils.ts b/src/snyk/snykCode/utils/patchUtils.ts new file mode 100644 index 000000000..e798f54e4 --- /dev/null +++ b/src/snyk/snykCode/utils/patchUtils.ts @@ -0,0 +1,42 @@ +import { IVSCodeLanguages } from '../../common/vscode/languages'; +import { DecorationOptions } from '../../common/vscode/types'; + +// Supports Unified Diff Format +export function generateDecorationOptions(patch: string, languages: IVSCodeLanguages): DecorationOptions[] { + const codeLines = patch.split('\n'); + + // the first two lines are the file names + codeLines.shift(); + codeLines.shift(); + + const decorationOptions: DecorationOptions[] = []; + let currentLine = -1; + + for (const line of codeLines) { + if (line.startsWith('@@ ')) { + // format is -original, +new + // @@ -start,count +start,count @@ + // counts are considered optional + // we only care about the start line for the new file + const [, , added] = line.split(' '); + const [startLineValue] = added.split(','); + + // unified diff line numbers start from 1 not 0 + // vscode.Range starts from 0 not 1 + currentLine = parseInt(startLineValue) - 1; + } else { + if (line.startsWith('+')) { + const range = languages.createRange(currentLine, 0, currentLine, line.length - 1); + + decorationOptions.push({ range }); + currentLine++; + } else if (line.startsWith('-')) { + continue; + } else { + currentLine++; + } + } + } + + return decorationOptions; +} diff --git a/src/snyk/snykCode/views/issueTreeProvider.ts b/src/snyk/snykCode/views/issueTreeProvider.ts index acc96239f..4cb055f40 100644 --- a/src/snyk/snykCode/views/issueTreeProvider.ts +++ b/src/snyk/snykCode/views/issueTreeProvider.ts @@ -10,6 +10,8 @@ import { IVSCodeLanguages } from '../../common/vscode/languages'; import { messages } from '../messages/analysis'; import { IssueUtils } from '../utils/issueUtils'; import { CodeIssueCommandArg } from './interfaces'; +import { TreeNode } from '../../common/views/treeNode'; +import { IFolderConfigs } from '../../common/configuration/folderConfigs'; export class IssueTreeProvider extends ProductIssueTreeProvider { constructor( @@ -18,8 +20,9 @@ export class IssueTreeProvider extends ProductIssueTreeProvider { protected configuration: IConfiguration, protected languages: IVSCodeLanguages, protected readonly isSecurityType: boolean, + protected readonly folderConfigs: IFolderConfigs, ) { - super(contextService, codeService, configuration, languages); + super(contextService, codeService, configuration, languages, folderConfigs); } shouldShowTree(): boolean { @@ -33,8 +36,19 @@ export class IssueTreeProvider extends ProductIssueTreeProvider { getRunTestMessage = () => messages.runTest; // The title in the tree is taken from the title for vulnerabilities and from the message for quality rules - getIssueTitle = (issue: Issue) => - issue.additionalData.isSecurityType ? issue.title.split(':')[0] : issue.additionalData.message.split('.')[0]; + getIssueTitle(issue: Issue): string { + const fixIcon = issue.additionalData.hasAIFix ? '⚡️' : ''; + const issueTitle = issue.additionalData.isSecurityType + ? issue.title.split(':')[0] + : issue.additionalData.message.split('.')[0]; + + let prefixIgnored = ''; + if (issue.isIgnored) { + prefixIgnored = '[ Ignored ] '; + } + + return fixIcon + prefixIgnored + issueTitle; + } getIssueRange(issue: Issue): Range { return IssueUtils.createVsCodeRange(issue.additionalData, this.languages); @@ -57,4 +71,20 @@ export class IssueTreeProvider extends ProductIssueTreeProvider { ], }; } + + isFixableIssue(issue: Issue): boolean { + return issue.additionalData.hasAIFix; + } + + getFixableIssuesNode(fixableIssueCount: number): TreeNode { + return new TreeNode({ + text: this.getAIFixableIssuesText(fixableIssueCount), + }); + } + + private getAIFixableIssuesText(issuesCount: number): string { + return issuesCount > 0 + ? `⚡️ ${issuesCount} ${issuesCount === 1 ? 'issue' : 'issues'} can be fixed by Snyk DeepCode AI` + : 'There are no issues fixable by Snyk DeepCode AI'; + } } diff --git a/src/snyk/snykCode/views/qualityIssueTreeProvider.ts b/src/snyk/snykCode/views/qualityIssueTreeProvider.ts index 5cd70e2d1..e4c70b3d8 100644 --- a/src/snyk/snykCode/views/qualityIssueTreeProvider.ts +++ b/src/snyk/snykCode/views/qualityIssueTreeProvider.ts @@ -1,4 +1,5 @@ import { IConfiguration } from '../../common/configuration/configuration'; +import { IFolderConfigs } from '../../common/configuration/folderConfigs'; import { configuration } from '../../common/configuration/instance'; import { SNYK_ANALYSIS_STATUS } from '../../common/constants/views'; import { CodeIssueData } from '../../common/languageServer/types'; @@ -16,8 +17,9 @@ export class CodeQualityIssueTreeProvider extends IssueTreeProvider { protected codeService: IProductService, protected configuration: IConfiguration, protected languages: IVSCodeLanguages, + protected readonly folderConfigs: IFolderConfigs, ) { - super(contextService, codeService, configuration, languages, false); + super(contextService, codeService, configuration, languages, false, folderConfigs); } getRootChildren(): TreeNode[] { diff --git a/src/snyk/snykCode/views/securityIssueTreeProvider.ts b/src/snyk/snykCode/views/securityIssueTreeProvider.ts index cfec68524..643214e5a 100644 --- a/src/snyk/snykCode/views/securityIssueTreeProvider.ts +++ b/src/snyk/snykCode/views/securityIssueTreeProvider.ts @@ -8,6 +8,8 @@ import { IViewManagerService } from '../../common/services/viewManagerService'; import { TreeNode } from '../../common/views/treeNode'; import { IVSCodeLanguages } from '../../common/vscode/languages'; import { IssueTreeProvider } from './issueTreeProvider'; +import { FEATURE_FLAGS } from '../../common/constants/featureFlags'; +import { IFolderConfigs } from '../../common/configuration/folderConfigs'; export default class CodeSecurityIssueTreeProvider extends IssueTreeProvider { constructor( @@ -16,8 +18,9 @@ export default class CodeSecurityIssueTreeProvider extends IssueTreeProvider { protected codeService: IProductService, protected configuration: IConfiguration, protected languages: IVSCodeLanguages, + protected readonly folderConfigs: IFolderConfigs, ) { - super(contextService, codeService, configuration, languages, true); + super(contextService, codeService, configuration, languages, true, folderConfigs); } getRootChildren(): TreeNode[] { @@ -35,12 +38,26 @@ export default class CodeSecurityIssueTreeProvider extends IssueTreeProvider { onDidChangeTreeData = this.viewManagerService.refreshCodeSecurityViewEmitter.event; protected getIssueDescriptionText(dir: string | undefined, issueCount: number): string | undefined { - return `${dir} - ${issueCount} ${issueCount === 1 ? 'vulnerability' : 'vulnerabilities'}`; + return `${dir} - ${issueCount} ${issueCount === 1 ? 'issue' : 'issues'}`; } - protected getIssueFoundText(nIssues: number): string { - return `Snyk found ${ - !nIssues ? 'no vulnerabilities! ✅' : `${nIssues} ${nIssues === 1 ? 'vulnerability' : 'vulnerabilities'}` - }`; + protected getIssueFoundText(nIssues: number, ignoredIssueCount: number): string { + if (nIssues > 0) { + let text; + + if (nIssues === 1) { + text = `${nIssues} issue found by Snyk`; + } else { + text = `✋ ${nIssues} issues found by Snyk`; + } + + const isIgnoresEnabled = configuration.getFeatureFlag(FEATURE_FLAGS.consistentIgnores); + if (isIgnoresEnabled) { + text += `, ${ignoredIssueCount} ignored`; + } + return text; + } else { + return '✅ Congrats! No issues found!'; + } } } diff --git a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts index f12f5b37a..08e470f52 100644 --- a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts +++ b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts @@ -1,46 +1,41 @@ import _ from 'lodash'; +import { relative } from 'path'; +import { applyPatch } from 'diff'; +import { marked } from 'marked'; import * as vscode from 'vscode'; import { + SNYK_CODE_FIX_DIFFS_COMMAND, + SNYK_GENERATE_ISSUE_DESCRIPTION, + SNYK_CODE_SUBMIT_FIX_FEEDBACK, SNYK_IGNORE_ISSUE_COMMAND, SNYK_OPEN_BROWSER_COMMAND, SNYK_OPEN_LOCAL_COMMAND, } from '../../../common/constants/commands'; import { SNYK_VIEW_SUGGESTION_CODE } from '../../../common/constants/views'; import { ErrorHandler } from '../../../common/error/errorHandler'; -import { CodeIssueData, ExampleCommitFix, Issue, Marker, Point } from '../../../common/languageServer/types'; +import { AutofixUnifiedDiffSuggestion, CodeIssueData, Issue } from '../../../common/languageServer/types'; import { ILog } from '../../../common/logger/interfaces'; import { messages as learnMessages } from '../../../common/messages/learn'; import { LearnService } from '../../../common/services/learnService'; import { getNonce } from '../../../common/views/nonce'; -import { WebviewPanelSerializer } from '../../../common/views/webviewPanelSerializer'; import { WebviewProvider } from '../../../common/views/webviewProvider'; import { ExtensionContext } from '../../../common/vscode/extensionContext'; import { IVSCodeLanguages } from '../../../common/vscode/languages'; import { IVSCodeWindow } from '../../../common/vscode/window'; import { IVSCodeWorkspace } from '../../../common/vscode/workspace'; -import { WEBVIEW_PANEL_QUALITY_TITLE, WEBVIEW_PANEL_SECURITY_TITLE } from '../../constants/analysis'; +import { WEBVIEW_PANEL_SECURITY_TITLE } from '../../constants/analysis'; import { messages as errorMessages } from '../../messages/error'; import { getAbsoluteMarkerFilePath } from '../../utils/analysisUtils'; +import { generateDecorationOptions } from '../../utils/patchUtils'; import { IssueUtils } from '../../utils/issueUtils'; import { ICodeSuggestionWebviewProvider } from '../interfaces'; - -type Suggestion = { - id: string; - message: string; - severity: string; - leadURL?: string; - rule: string; - repoDatasetSize: number; - exampleCommitFixes: ExampleCommitFix[]; - cwe: string[]; - title: string; - text: string; - isSecurityType: boolean; - uri: string; - markers?: Marker[]; - cols: Point; - rows: Point; -}; +import { readFileSync } from 'fs'; +import { TextDocument } from '../../../common/vscode/types'; +import { Suggestion, SuggestionMessage } from './types'; +import { WebviewPanelSerializer } from '../../../snykCode/views/webviewPanelSerializer'; +import { configuration } from '../../../common/configuration/instance'; +import { FEATURE_FLAGS } from '../../../common/constants/featureFlags'; +import { IVSCodeCommands } from '../../../common/vscode/commands'; export class CodeSuggestionWebviewProvider extends WebviewProvider> @@ -57,6 +52,7 @@ export class CodeSuggestionWebviewProvider private readonly languages: IVSCodeLanguages, private readonly workspace: IVSCodeWorkspace, private readonly learnService: LearnService, + private commandExecutor: IVSCodeCommands, ) { super(context, logger); } @@ -71,17 +67,21 @@ export class CodeSuggestionWebviewProvider return this.issue?.id; } + private async postSuggestMessage(message: SuggestionMessage): Promise { + await this.panel?.webview.postMessage(message); + } + async postLearnLessonMessage(issue: Issue): Promise { try { if (this.panel) { const lesson = await this.learnService.getCodeLesson(issue); if (lesson) { - void this.panel.webview.postMessage({ + void this.postSuggestMessage({ type: 'setLesson', args: { url: lesson.url, title: learnMessages.lessonButtonTitle }, }); } else { - void this.panel.webview.postMessage({ + void this.postSuggestMessage({ type: 'setLesson', args: null, }); @@ -95,14 +95,13 @@ export class CodeSuggestionWebviewProvider async showPanel(issue: Issue): Promise { try { await this.focusSecondEditorGroup(); - if (this.panel) { - this.panel.title = this.getTitle(issue); + this.panel.title = this.getTitle(); this.panel.reveal(vscode.ViewColumn.Two, true); } else { this.panel = vscode.window.createWebviewPanel( SNYK_VIEW_SUGGESTION_CODE, - this.getTitle(issue), + this.getTitle(), { viewColumn: vscode.ViewColumn.Two, preserveFocus: true, @@ -111,15 +110,46 @@ export class CodeSuggestionWebviewProvider ); this.registerListeners(); } - this.panel.webview.html = this.getHtmlForWebview(this.panel.webview); + this.panel.iconPath = vscode.Uri.joinPath( vscode.Uri.file(this.context.extensionPath), 'media', 'images', 'snyk-code.svg', ); - - void this.panel.webview.postMessage({ type: 'set', args: this.mapToModel(issue) }); + // TODO: delete this when SNYK_GENERATE_ISSUE_DESCRIPTION command is in stable CLI. + let html: string; + if (issue.additionalData.details) { + html = issue.additionalData.details; + } else { + html = (await this.commandExecutor.executeCommand(SNYK_GENERATE_ISSUE_DESCRIPTION, issue.id)) ?? ''; + } + const ideStylePath = vscode.Uri.joinPath( + vscode.Uri.file(this.context.extensionPath), + 'media', + 'views', + 'snykCode', + 'suggestion', + 'suggestionLS.css', + ); + const ideStyle = readFileSync(ideStylePath.fsPath, 'utf8'); + const ideScriptPath = vscode.Uri.joinPath( + vscode.Uri.file(this.context.extensionPath), + 'out', + 'snyk', + 'snykCode', + 'views', + 'suggestion', + 'codeSuggestionWebviewScriptLS.js', + ); + const ideScript = readFileSync(ideScriptPath.fsPath, 'utf8'); + html = html.replace('${ideStyle}', ''); + html = html.replace('${ideScript}', ''); + const nonce = getNonce(); + html = html.replaceAll('${nonce}', nonce); + html = html.replace('--default-font: ', '--default-font: var(--vscode-font-family) ,'); + this.panel.webview.html = html; + void this.postSuggestMessage({ type: 'set', args: this.mapToModel(issue) }); void this.postLearnLessonMessage(issue); this.issue = issue; @@ -134,7 +164,11 @@ export class CodeSuggestionWebviewProvider this.panel.onDidDispose(() => this.onPanelDispose(), null, this.disposables); this.panel.onDidChangeViewState(() => this.checkVisibility(), undefined, this.disposables); // Handle messages from the webview - this.panel.webview.onDidReceiveMessage(msg => this.handleMessage(msg), undefined, this.disposables); + this.panel.webview.onDidReceiveMessage( + (msg: SuggestionMessage) => this.handleMessage(msg), + undefined, + this.disposables, + ); } disposePanel(): void { @@ -145,58 +179,132 @@ export class CodeSuggestionWebviewProvider super.onPanelDispose(); } + private getWorkspaceFolderPath(filePath: string) { + // get the workspace folders + // look at the filepath and identify the folder that contains the filepath + for (const folderPath of this.workspace.getWorkspaceFolders()) { + if (filePath.startsWith(folderPath)) { + return folderPath; + } + } + throw new Error(`Unable to find workspace for: ${filePath}`); + } + private mapToModel(issue: Issue): Suggestion { + const parsedDetails = marked.parse(issue.additionalData.text) as string; + const showInlineIgnoresButton = configuration.getFeatureFlag(FEATURE_FLAGS.snykCodeInlineIgnore); + return { id: issue.id, title: issue.title, - uri: issue.filePath, severity: _.capitalize(issue.severity), ...issue.additionalData, + text: parsedDetails, + hasAIFix: issue.additionalData.hasAIFix, + filePath: issue.filePath, + showInlineIgnoresButton, }; } - private async handleMessage(message: any) { + private async handleMessage(message: SuggestionMessage) { try { - const { type, args } = message; - switch (type) { + switch (message.type) { case 'openLocal': { - const { uri, cols, rows, suggestionUri } = args as { - uri: string; - cols: [number, number]; - rows: [number, number]; - suggestionUri: string; - }; + const { uri, cols, rows, suggestionUri } = message.args; const localUriPath = getAbsoluteMarkerFilePath(this.workspace, uri, suggestionUri); const localUri = vscode.Uri.file(localUriPath); const range = IssueUtils.createVsCodeRangeFromRange(rows, cols, this.languages); await vscode.commands.executeCommand(SNYK_OPEN_LOCAL_COMMAND, localUri, range); break; } + case 'openBrowser': { - const { url } = args as { url: string }; + const { url } = message.args; await vscode.commands.executeCommand(SNYK_OPEN_BROWSER_COMMAND, url); break; } + case 'ignoreIssue': { - const { lineOnly, message, rule, uri, cols, rows } = args as { - lineOnly: boolean; - message: string; - rule: string; - uri: string; - cols: [number, number]; - rows: [number, number]; - }; + const { lineOnly, rule, uri, cols, rows } = message.args; const vscodeUri = vscode.Uri.file(uri); const range = IssueUtils.createVsCodeRangeFromRange(rows, cols, this.languages); await vscode.commands.executeCommand(SNYK_IGNORE_ISSUE_COMMAND, { uri: vscodeUri, - matchedIssue: { message, range }, + matchedIssue: { + message: message.args.message, + range, + }, ruleId: rule, isFileIgnore: !lineOnly, }); this.panel?.dispose(); break; } + + case 'getAutofixDiffs': { + this.logger.info('Generating fixes'); + + const { suggestion } = message.args; + try { + const filePath = suggestion.filePath; + const folderPath = this.getWorkspaceFolderPath(filePath); + const relativePath = relative(folderPath, filePath); + + const issueId = suggestion.id; + + const diffs: AutofixUnifiedDiffSuggestion[] = await vscode.commands.executeCommand( + SNYK_CODE_FIX_DIFFS_COMMAND, + folderPath, + relativePath, + issueId, + ); + // todo(berkay.berabi): Here if suggestions are empty, we should post a different type of message that + // will show the user correct information, namely: we tried but no fixes available for now. + + void this.postSuggestMessage({ type: 'setAutofixDiffs', args: { suggestion, diffs } }); + } catch (error) { + void this.postSuggestMessage({ type: 'setAutofixError', args: { suggestion } }); + } + + break; + } + + case 'applyGitDiff': { + const { patch, filePath, fixId } = message.args; + + const fileContent = readFileSync(filePath, 'utf8'); + const patchedContent = applyPatch(fileContent, patch); + + if (!patchedContent) { + throw Error('Failed to apply patch'); + } + const edit = new vscode.WorkspaceEdit(); + + const editor = vscode.window.visibleTextEditors.find(editor => editor.document.uri.fsPath === filePath); + + if (!editor) { + throw Error(`Editor with file not found: ${filePath}`); + } + + const editorEndLine = editor.document.lineCount; + edit.replace(vscode.Uri.file(filePath), new vscode.Range(0, 0, editorEndLine, 0), patchedContent); + + const success = await vscode.workspace.applyEdit(edit); + if (!success) { + throw Error('Failed to apply edit to workspace'); + } + + this.highlightAddedCode(filePath, patch); + this.setupCloseOnSave(filePath); + + try { + await vscode.commands.executeCommand(SNYK_CODE_SUBMIT_FIX_FEEDBACK, fixId, 'FIX_APPLIED'); + } catch (e) { + throw new Error('Error in submit fix feedback'); + } + break; + } + default: { throw new Error('Unknown message type'); } @@ -206,122 +314,66 @@ export class CodeSuggestionWebviewProvider } } - private getTitle(issue: Issue): string { - return issue.additionalData.isSecurityType ? WEBVIEW_PANEL_SECURITY_TITLE : WEBVIEW_PANEL_QUALITY_TITLE; + private setupCloseOnSave(filePath: string) { + vscode.workspace.onDidSaveTextDocument((e: TextDocument) => { + if (e.uri.fsPath == filePath) { + this.panel?.dispose(); + } + }); } - protected getHtmlForWebview(webview: vscode.Webview): string { - const images: Record = [ - ['icon-external', 'svg'], - ['icon-code', 'svg'], - ['icon-github', 'svg'], - ['icon-like', 'svg'], - ['dark-low-severity', 'svg'], - ['dark-medium-severity', 'svg'], - ['dark-high-severity', 'svg'], - ['light-icon-critical', 'svg'], - ['arrow-left-dark', 'svg'], - ['arrow-right-dark', 'svg'], - ['arrow-left-light', 'svg'], - ['arrow-right-light', 'svg'], - ['learn-icon', 'svg'], - ].reduce>((accumulator: Record, [name, ext]) => { - const uri = this.getWebViewUri('media', 'images', `${name}.${ext}`); - if (!uri) throw new Error('Image missing.'); - accumulator[name] = uri.toString(); - return accumulator; - }, {}); - - const scriptUri = this.getWebViewUri( - 'out', - 'snyk', - 'snykCode', - 'views', - 'suggestion', - 'codeSuggestionWebviewScript.js', - ); - const styleVSCodeUri = this.getWebViewUri('media', 'views', 'common', 'vscode.css'); - const styleUri = this.getWebViewUri('media', 'views', 'snykCode', 'suggestion', 'suggestion.css'); - const learnStyleUri = this.getWebViewUri('media', 'views', 'common', 'learn.css'); - - const nonce = getNonce(); - return ` - - - - - - - - - - - - -
-
-
- - - - -
-
-
- -
-
- - -
-
-
-
- -
-
-
- This issue was fixed by projects. Here are examples: -
-
- There are no fix examples for this issue. -
-
-
- - -
-
- - - - - - Example 1/ - - - - - -
-
-
-
-
-
-
- - -
-
-
-
- - - `; + private highlightAddedCode(filePath: string, diffData: string) { + const highlightDecoration = vscode.window.createTextEditorDecorationType({ + // seems to work well with both dark and light backgrounds + backgroundColor: 'rgba(0,255,0,0.3)', + }); + + const editor = vscode.window.visibleTextEditors.find(editor => editor.document.uri.fsPath === filePath); + if (!editor) { + return; // No open editor found with the target file + } + + const decorationOptions = generateDecorationOptions(diffData, this.languages); + if (decorationOptions.length === 0) { + return; + } + + editor.setDecorations(highlightDecoration, decorationOptions); + + const firstLine = decorationOptions[0].range.start.line; + + // scroll to first added line + const line = editor.document.lineAt(firstLine); + const range = line.range; + editor.revealRange(range, vscode.TextEditorRevealType.InCenter); + + // remove highlight on any of: + // - user types + // - saves the doc + // - after an amount of time + + const removeHighlights = () => { + editor.setDecorations(highlightDecoration, []); + listeners.forEach(listener => { + if (listener instanceof vscode.Disposable) listener.dispose(); + else clearTimeout(listener); + }); + }; + + const documentEventHandler = (document: TextDocument) => { + if (document.uri.fsPath == filePath) { + removeHighlights(); + } + }; + + const listeners = [ + setTimeout(removeHighlights, 30000), + vscode.workspace.onDidSaveTextDocument(documentEventHandler), + vscode.workspace.onDidChangeTextDocument(e => documentEventHandler(e.document)), + ]; + } + + private getTitle(): string { + return WEBVIEW_PANEL_SECURITY_TITLE; } } diff --git a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScript.ts b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScript.ts deleted file mode 100644 index 843da0291..000000000 --- a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScript.ts +++ /dev/null @@ -1,372 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/// - -// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-explicit-any -declare const acquireVsCodeApi: any; - -// This script will be run within the webview itself -// It cannot access the main VS Code APIs directly. -(function () { - // TODO: Redefine types until bundling is introduced into extension - // https://stackoverflow.com/a/56938089/1713082 - type Lesson = { - url: string; - title: string; - }; - - type ExampleCommitFix = { - commitURL: string; - lines: CommitChangeLine[]; - }; - type CommitChangeLine = { - line: string; - lineNumber: number; - lineChange: 'removed' | 'added' | 'none'; - }; - type Marker = { - msg: Point; - pos: MarkerPosition[]; - }; - type MarkerPosition = { - cols: Point; - rows: Point; - file: string; - }; - type Point = [number, number]; - type Suggestion = { - id: string; - message: string; - severity: string; - leadURL?: string; - rule: string; - repoDatasetSize: number; - exampleCommitFixes: ExampleCommitFix[]; - cwe: string[]; - title: string; - text: string; - isSecurityType: boolean; - uri: string; - markers?: Marker[]; - cols: Point; - rows: Point; - }; - - const vscode = acquireVsCodeApi(); - - function navigateToUrl(url: string) { - sendMessage({ - type: 'openBrowser', - args: { url }, - }); - } - - let exampleCount = 0; - - // Try to restore the previous state - let lesson: Lesson | null = vscode.getState()?.lesson || null; - fillLearnLink(); - let suggestion: Suggestion | null = vscode.getState()?.suggestion || null; - showCurrentSuggestion(); - - function navigateToLeadURL() { - if (!suggestion?.leadURL) return; - navigateToUrl(suggestion.leadURL); - } - function navigateToIssue(_e: any, range: any) { - if (!suggestion) return; - sendMessage({ - type: 'openLocal', - args: getSuggestionPosition(suggestion, range), - }); - } - function navigateToCurrentExample() { - if (!suggestion?.exampleCommitFixes) return; - - const url = suggestion.exampleCommitFixes[exampleCount].commitURL; - sendMessage({ - type: 'openBrowser', - args: { url }, - }); - } - function ignoreIssue(lineOnly: boolean) { - if (!suggestion) return; - - sendMessage({ - type: 'ignoreIssue', - args: { - ...getSuggestionPosition(suggestion), - message: suggestion.message, - rule: suggestion.rule, - id: suggestion.id, - severity: suggestion.severity, - lineOnly: lineOnly, - }, - }); - } - function getSuggestionPosition(suggestionParam: Suggestion, position?: { file: string; rows: any; cols: any }) { - return { - uri: position?.file ?? suggestionParam.uri, - rows: position ? position.rows : suggestionParam.rows, - cols: position ? position.cols : suggestionParam.cols, - suggestionUri: suggestionParam.uri, - }; - } - function previousExample() { - if (!suggestion || !suggestion.exampleCommitFixes || exampleCount <= 0) return; - --exampleCount; - showCurrentExample(); - } - function nextExample() { - if (!suggestion || !suggestion.exampleCommitFixes || exampleCount >= suggestion.exampleCommitFixes.length - 1) - return; - ++exampleCount; - showCurrentExample(); - } - function showCurrentExample() { - if ( - !suggestion?.exampleCommitFixes?.length || - exampleCount < 0 || - exampleCount >= suggestion.exampleCommitFixes.length - ) - return; - const counter = document.getElementById('example-counter')!; - counter.innerHTML = (exampleCount + 1).toString(); - const url = suggestion.exampleCommitFixes[exampleCount].commitURL; - const repo = url.match(/https?:\/\/[^\\/]+\/([^\\/]+\/[^\\/]+)/); - if (repo && repo[1]) { - const exLink = document.getElementById('example-link')!; - exLink.innerHTML = repo[1]; - } - const example = document.getElementById('example')!; - example.querySelectorAll('*').forEach(n => n.remove()); - for (const l of suggestion.exampleCommitFixes[exampleCount].lines) { - const line = document.createElement('div'); - line.className = `example-line ${l.lineChange}`; - example.appendChild(line); - const code = document.createElement('code'); - code.innerHTML = l.line; - line.appendChild(code); - } - } - function getCurrentSeverity() { - const stringMap = { - Low: 1, - Medium: 2, - High: 3, - }; - return suggestion - ? { - value: stringMap[suggestion.severity], - text: suggestion.severity, - } - : undefined; - } - - function fillLearnLink() { - const learnWrapper = document.querySelector('.learn')!; - learnWrapper.className = 'learn learn__code'; - - if (lesson) { - const learnLink = document.querySelector('.learn--link')!; - learnLink.innerText = lesson.title; - const lessonUrl = lesson.url; - learnLink.onclick = () => navigateToUrl(lessonUrl); - learnWrapper.className = 'learn learn__code show'; - } - } - - function showCurrentSuggestion() { - if (!suggestion) { - return; - } - - exampleCount = 0; - const currentSeverity = getCurrentSeverity(); - const severity = document.getElementById('severity')!; - const title = document.getElementById('title')!; - const description = document.getElementById('description')!; - const meta = document.getElementById('meta')!; - let type = ''; - - // Set issue type: vulnerability or issue - type = suggestion.isSecurityType ? 'vulnerability' : 'issue'; - - // Remove existing meta - const metas = meta.querySelectorAll('.suggestion-meta'); - metas.forEach(element => { - element.remove(); - }); - - // Append CWEs - if (suggestion.cwe !== null && suggestion.cwe.length) { - // add the new CWEs - suggestion.cwe.forEach(cwe => { - meta.insertAdjacentHTML( - 'afterbegin', - '' + - cwe + - '', - ); - }); - } - - // Append issue type in the meta section - meta.insertAdjacentHTML('afterbegin', '' + type + ''); - - // Append line number - const issuePosition = document.getElementById('navigateToIssue')!; - issuePosition.innerHTML = ''; - issuePosition.insertAdjacentHTML( - 'afterbegin', - 'Position: line ' + (Number(suggestion.rows[0]) + 1).toString() + '', - ); - - if (currentSeverity && currentSeverity.text) { - severity.querySelectorAll('img').forEach(n => { - if (n.id.includes(currentSeverity.value)) { - n.className = 'icon'; - severity.setAttribute('title', currentSeverity.text); - } else { - n.className = 'icon hidden'; - } - }); - } else { - severity.querySelectorAll('img').forEach(n => (n.className = 'icon hidden')); - } - - title.innerText = suggestion.title.split(':')[0]; - - description.querySelectorAll('*').forEach(n => n.remove()); - description.innerHTML = ''; - if (suggestion.markers && suggestion.markers.length) { - let i = 0; - for (const m of suggestion.markers) { - const preText = suggestion.message.substring(i, m.msg[0]); - const preMark = document.createTextNode(preText); - description.appendChild(preMark); - const mark = document.createElement('a'); - mark.className = 'mark-message clickable'; - mark.onclick = function () { - navigateToIssue(undefined, m.pos[0]); - }; - description.appendChild(mark); - const markMsg = document.createElement('span'); - markMsg.className = 'mark-string'; - markMsg.innerHTML = suggestion.message.substring(m.msg[0], m.msg[1] + 1); - mark.appendChild(markMsg); - let markLineText = '['; - let first = true; - for (const p of m.pos) { - const rowStart = Number(p.rows[0]) + 1; // editors are 1-based - markLineText += (first ? '' : ', ') + ':' + rowStart.toString(); - first = false; - } - markLineText += ']'; - const markLine = document.createElement('span'); - markLine.innerHTML = markLineText; - markLine.className = 'mark-position'; - mark.appendChild(markLine); - i = m.msg[1] + 1; - } - const postText = suggestion.message.substring(i); - const postMark = document.createTextNode(postText); - description.appendChild(postMark); - } else { - description.innerHTML = suggestion.message; - } - - const moreInfo = document.getElementById('lead-url')!; - moreInfo.className = suggestion.leadURL ? 'clickable' : 'clickable hidden'; - - const suggestionPosition2 = document.getElementById('line-position2')!; - suggestionPosition2.innerHTML = (Number(suggestion.rows[0]) + 1).toString(); - - const dataset = document.getElementById('dataset-number')!; - const infoTop = document.getElementById('info-top')!; - if (suggestion.repoDatasetSize) { - dataset.innerHTML = suggestion.repoDatasetSize.toString(); - infoTop.className = 'font-light'; - } else { - infoTop.className = 'font-light hidden'; - } - - const exampleTop = document.getElementById('example-top')!; - const example = document.getElementById('example')!; - const noExamples = document.getElementById('info-no-examples')!; - if (suggestion?.exampleCommitFixes?.length) { - exampleTop.className = 'row between'; - example.className = ''; - const exNum = document.getElementById('example-number')!; - exNum.innerHTML = suggestion.exampleCommitFixes.length.toString(); - const exNum2 = document.getElementById('example-number2')!; - exNum2.innerHTML = suggestion.exampleCommitFixes.length.toString(); - noExamples.className = 'hidden'; - showCurrentExample(); - } else { - exampleTop.className = 'row between hidden'; - example.className = 'hidden'; - noExamples.className = 'font-light'; - } - } - - function sendMessage(message: { - type: string; - args: - | { uri: any; rows: any; cols: any } - | { url: any } - | { url: any } - | { url: string } - | { message: any; rule: any; id: any; severity: any; lineOnly: boolean; uri: any; rows: any; cols: any } - | { suggestion: any }; - }) { - vscode.postMessage(message); - } - - document.getElementById('navigateToIssue')!.addEventListener('click', navigateToIssue.bind(undefined)); - document.getElementById('lead-url')!.addEventListener('click', navigateToLeadURL); - document.getElementById('current-example')!.addEventListener('click', navigateToCurrentExample); - document.getElementById('previous-example')!.addEventListener('click', previousExample); - document.getElementById('next-example')!.addEventListener('click', nextExample); - document.getElementById('ignore-line-issue')!.addEventListener('click', () => { - ignoreIssue(true); - }); - document.getElementById('ignore-file-issue')!.addEventListener('click', () => { - ignoreIssue(false); - }); - - // deepcode ignore InsufficientValidation: Content Security Policy applied in provider - window.addEventListener('message', event => { - const { type, args } = event.data; - switch (type) { - case 'set': { - suggestion = args; - vscode.setState({ ...vscode.getState(), suggestion }); - showCurrentSuggestion(); - break; - } - case 'get': { - suggestion = vscode.getState()?.suggestion || {}; - showCurrentSuggestion(); - break; - } - case 'setLesson': { - lesson = args; - vscode.setState({ ...vscode.getState(), lesson }); - fillLearnLink(); - break; - } - case 'getLesson': { - lesson = vscode.getState()?.lesson || null; - fillLearnLink(); - break; - } - } - }); -})(); diff --git a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScriptLS.ts b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScriptLS.ts new file mode 100644 index 000000000..8d1aceaf0 --- /dev/null +++ b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScriptLS.ts @@ -0,0 +1,418 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ + +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/// +declare const acquireVsCodeApi: any; + +// This script will be run within the webview itself +// It cannot access the main VS Code APIs directly. +(function () { + // TODO: Redefine types until bundling is introduced into extension + // https://stackoverflow.com/a/56938089/1713082 + type Marker = { + msg: Point; + pos: MarkerPosition[]; + }; + type MarkerPosition = { + cols: Point; + rows: Point; + file: string; + }; + type Point = [number, number]; + type AutofixUnifiedDiffSuggestion = { + fixId: string; + unifiedDiffsPerFile: { [key: string]: string }; + }; + type Suggestion = { + id: string; + message: string; + severity: 'Low' | 'Medium' | 'High'; + rule: string; + cwe: string[]; + title: string; + text: string; + markers?: Marker[]; + cols: Point; + rows: Point; + filePath: string; + hasAIFix: boolean; + diffs: AutofixUnifiedDiffSuggestion[]; + showInlineIgnoresButton: boolean; + }; + + type OpenLocalMessage = { + type: 'openLocal'; + args: { + uri: string; + cols: [number, number]; + rows: [number, number]; + suggestionUri: string; + }; + }; + + type IgnoreIssueMessage = { + type: 'ignoreIssue'; + args: { + id: string; + severity: 'Low' | 'Medium' | 'High'; + lineOnly: boolean; + message: string; + rule: string; + uri: string; + cols: [number, number]; + rows: [number, number]; + }; + }; + + type SetSuggestionMessage = { + type: 'set'; + args: Suggestion; + }; + + type GetSuggestionMessage = { + type: 'get'; + }; + + type GetAutofixDiffsMesssage = { + type: 'getAutofixDiffs'; + args: { + suggestion: Suggestion; + }; + }; + + type ApplyGitDiffMessage = { + type: 'applyGitDiff'; + args: { + patch: string; + filePath: string; + fixId: string; + }; + }; + + type SetAutofixDiffsMessage = { + type: 'setAutofixDiffs'; + args: { + suggestion: Suggestion; + diffs: AutofixUnifiedDiffSuggestion[]; + }; + }; + + type SetAutofixErrorMessage = { + type: 'setAutofixError'; + args: { + suggestion: Suggestion; + }; + }; + + type SuggestionMessage = + | OpenLocalMessage + | IgnoreIssueMessage + | SetSuggestionMessage + | GetSuggestionMessage + | GetAutofixDiffsMesssage + | ApplyGitDiffMessage + | SetAutofixDiffsMessage + | SetAutofixErrorMessage; + + const vscode = acquireVsCodeApi(); + + function sendMessage(message: SuggestionMessage) { + vscode.postMessage(message); + } + + function navigateToIssue(position?: MarkerPosition) { + if (!suggestion) { + return; + } + + const message: OpenLocalMessage = { + type: 'openLocal', + args: { + ...getSuggestionPosition(suggestion, position), + suggestionUri: suggestion.filePath, + }, + }; + + sendMessage(message); + } + let suggestion: Suggestion | null = vscode.getState()?.suggestion || null; + + function ignoreIssue(lineOnly: boolean) { + if (!suggestion) return; + + const message: IgnoreIssueMessage = { + type: 'ignoreIssue', + args: { + ...getSuggestionPosition(suggestion), + message: suggestion.message, + rule: suggestion.rule, + id: suggestion.id, + severity: suggestion.severity, + lineOnly: lineOnly, + }, + }; + sendMessage(message); + } + + function getSuggestionPosition(suggestionParam: Suggestion, position?: MarkerPosition) { + return { + uri: position?.file ?? suggestionParam.filePath, + rows: position ? position.rows : suggestionParam.rows, + cols: position ? position.cols : suggestionParam.cols, + }; + } + + const dataFlows = document.getElementsByClassName('data-flow-clickable-row'); + for (let i = 0; i < dataFlows.length; i++) { + dataFlows[i].addEventListener('click', () => { + const rows: Point = [ + parseInt(dataFlows[i].getAttribute('start-line')!), + parseInt(dataFlows[i].getAttribute('end-line')!), + ]; + const cols: Point = [ + parseInt(dataFlows[i].getAttribute('start-character')!), + parseInt(dataFlows[i].getAttribute('end-character')!), + ]; + const position = { + file: dataFlows[i].getAttribute('file-path')!, + rows: rows, + cols: cols, + }; + navigateToIssue(position); + }); + } + document.getElementById('ignore-line-issue')?.addEventListener('click', () => { + ignoreIssue(true); + }); + document.getElementById('ignore-file-issue')?.addEventListener('click', () => { + ignoreIssue(false); + }); + document.getElementById('position-line')!.addEventListener('click', () => { + navigateToIssue(); + }); + + function toggleElement(element: Element | null, toggle: 'hide' | 'show') { + if (!element) { + return; + } + + if (toggle === 'show') { + element.classList.remove('hidden'); + } else if (toggle === 'hide') { + element.classList.add('hidden'); + } else { + console.error('Unexpected toggle value', toggle); + } + } + + // different AI fix buttons + const applyFixButton = document.getElementById('apply-fix') as HTMLButtonElement; + const retryGenerateFixButton = document.getElementById('retry-generate-fix') as HTMLElement; + const generateAIFixButton = document.getElementById('generate-ai-fix') as HTMLElement; + + const ignoreContainerElements = document.getElementsByClassName('ignore-action-container'); + if (ignoreContainerElements) { + toggleElement(ignoreContainerElements[0] as HTMLElement, 'show'); + (ignoreContainerElements[0] as HTMLElement).style.display = suggestion?.showInlineIgnoresButton ? 'block' : 'none'; + } + + function generateAIFix() { + if (!suggestion) { + return; + } + + toggleElement(generateAIFixButton, 'hide'); + toggleElement(fixLoadingIndicatorElem, 'show'); + const message: GetAutofixDiffsMesssage = { + type: 'getAutofixDiffs', + args: { suggestion }, + }; + sendMessage(message); + } + + function retryGenerateAIFix() { + console.log('retrying generate AI Fix'); + + toggleElement(fixWrapperElem, 'show'); + toggleElement(fixErrorSectionElem, 'hide'); + + generateAIFix(); + } + + function applyFix() { + if (!suggestion) return; + const diffSuggestion = suggestion.diffs[diffSelectedIndex]; + const filePath = suggestion.filePath; + const patch = diffSuggestion.unifiedDiffsPerFile[filePath]; + const fixId = diffSuggestion.fixId; + lastAppliedFix = diffSelectedIndex; + applyFixButton.disabled = true; + const message: ApplyGitDiffMessage = { + type: 'applyGitDiff', + args: { filePath, patch, fixId }, + }; + sendMessage(message); + } + + generateAIFixButton?.addEventListener('click', generateAIFix); + retryGenerateFixButton?.addEventListener('click', retryGenerateAIFix); + applyFixButton?.addEventListener('click', applyFix); + + // different AI fix states + const fixLoadingIndicatorElem = document.getElementById('fix-loading-indicator') as HTMLElement; + const fixWrapperElem = document.getElementById('fix-wrapper') as HTMLElement; + const fixSectionElem = document.getElementById('fixes-section') as HTMLElement; + const fixErrorSectionElem = document.getElementById('fixes-error-section') as HTMLElement; + + // generated AI fix diffs + const nextDiffElem = document.getElementById('next-diff') as HTMLElement; + const previousDiffElem = document.getElementById('previous-diff') as HTMLElement; + const diffSelectedIndexElem = document.getElementById('diff-counter') as HTMLElement; + + const diffTopElem = document.getElementById('diff-top') as HTMLElement; + const diffElem = document.getElementById('diff') as HTMLElement; + const noDiffsElem = document.getElementById('info-no-diffs') as HTMLElement; + if (noDiffsElem) { + noDiffsElem.innerText = "We couldn't determine any fixes for this issue."; + } + const diffNumElem = document.getElementById('diff-number') as HTMLElement; + const diffNum2Elem = document.getElementById('diff-number2') as HTMLElement; + + let diffSelectedIndex = 0; + let lastAppliedFix = -1; + function nextDiff() { + if (!suggestion || !suggestion.diffs || diffSelectedIndex >= suggestion.diffs.length - 1) return; + ++diffSelectedIndex; + applyFixButton.disabled = diffSelectedIndex == lastAppliedFix; + showCurrentDiff(); + } + + function previousDiff() { + if (!suggestion || !suggestion.diffs || diffSelectedIndex <= 0) return; + --diffSelectedIndex; + applyFixButton.disabled = diffSelectedIndex == lastAppliedFix; + showCurrentDiff(); + } + + function showCurrentDiff() { + if (!suggestion?.diffs?.length) { + toggleElement(noDiffsElem, 'show'); + toggleElement(diffTopElem, 'hide'); + toggleElement(diffElem, 'hide'); + toggleElement(applyFixButton, 'hide'); + return; + } + + if (!suggestion?.diffs?.length || diffSelectedIndex < 0 || diffSelectedIndex >= suggestion.diffs.length) return; + + toggleElement(noDiffsElem, 'hide'); + toggleElement(diffTopElem, 'show'); + toggleElement(diffElem, 'show'); + toggleElement(applyFixButton, 'show'); + + diffNumElem.innerText = suggestion.diffs.length.toString(); + diffNum2Elem.innerText = suggestion.diffs.length.toString(); + + diffSelectedIndexElem.innerText = (diffSelectedIndex + 1).toString(); + + const diffSuggestion = suggestion.diffs[diffSelectedIndex]; + + const filePath = suggestion.filePath; + const patch = diffSuggestion.unifiedDiffsPerFile[filePath]; + + // clear all elements + while (diffElem.firstChild) { + diffElem.removeChild(diffElem.firstChild); + } + diffElem.appendChild(generateDiffHtml(patch)); + } + + function generateDiffHtml(patch: string): HTMLElement { + const codeLines = patch.split('\n'); + + // the first two lines are the file names + codeLines.shift(); + codeLines.shift(); + + const diffHtml = document.createElement('div'); + let blockDiv: HTMLElement | null = null; + + for (const line of codeLines) { + if (line.startsWith('@@ ')) { + blockDiv = document.createElement('div'); + blockDiv.className = 'example'; + + if (blockDiv) { + diffHtml.appendChild(blockDiv); + } + } else { + const lineDiv = document.createElement('div'); + lineDiv.className = 'example-line'; + + if (line.startsWith('+')) { + lineDiv.classList.add('added'); + } else if (line.startsWith('-')) { + lineDiv.classList.add('removed'); + } + + const lineCode = document.createElement('code'); + // if line is empty, we need to fallback to ' ' + // to make sure it displays in the diff + lineCode.innerText = line.slice(1, line.length) || ' '; + + lineDiv.appendChild(lineCode); + blockDiv?.appendChild(lineDiv); + } + } + + return diffHtml; + } + + nextDiffElem.addEventListener('click', nextDiff); + previousDiffElem.addEventListener('click', previousDiff); + + window.addEventListener('message', event => { + const message = event.data as SuggestionMessage; + switch (message.type) { + case 'set': { + suggestion = message.args; + vscode.setState({ ...vscode.getState(), suggestion }); + break; + } + case 'get': { + const newSuggestion = vscode.getState()?.suggestion || {}; + if (newSuggestion != suggestion) { + suggestion = newSuggestion; + } + break; + } + case 'setAutofixDiffs': { + if (suggestion?.id === message.args.suggestion.id) { + toggleElement(fixSectionElem, 'show'); + toggleElement(fixLoadingIndicatorElem, 'hide'); + toggleElement(fixWrapperElem, 'hide'); + + const { diffs } = message.args; + suggestion.diffs = diffs; + + vscode.setState({ ...vscode.getState(), suggestion }); + showCurrentDiff(); + } + break; + } + case 'setAutofixError': { + const errorSuggestion = message.args.suggestion; + + if (errorSuggestion.id != suggestion?.id) { + console.log('Got an error for a previously generated suggestion: ignoring'); + break; + } + toggleElement(fixWrapperElem, 'hide'); + toggleElement(fixErrorSectionElem, 'show'); + } + } + }); +})(); diff --git a/src/snyk/snykCode/views/suggestion/types.ts b/src/snyk/snykCode/views/suggestion/types.ts new file mode 100644 index 000000000..6c89d6379 --- /dev/null +++ b/src/snyk/snykCode/views/suggestion/types.ts @@ -0,0 +1,115 @@ +import { AutofixUnifiedDiffSuggestion, ExampleCommitFix, Marker, Point } from '../../../common/languageServer/types'; +import { Lesson } from '../../../common/services/learnService'; + +export type Suggestion = { + id: string; + message: string; + severity: string; + leadURL?: string; + rule: string; + repoDatasetSize: number; + exampleCommitFixes: ExampleCommitFix[]; + cwe: string[]; + title: string; + text: string; + isSecurityType: boolean; + markers?: Marker[]; + cols: Point; + rows: Point; + hasAIFix?: boolean; + filePath: string; + showInlineIgnoresButton: boolean; +}; + +export type OpenLocalMessage = { + type: 'openLocal'; + args: { + uri: string; + cols: [number, number]; + rows: [number, number]; + suggestionUri: string; + }; +}; + +export type IgnoreIssueMessage = { + type: 'ignoreIssue'; + args: { + id: string; + severity: 'Low' | 'Medium' | 'High'; + lineOnly: boolean; + message: string; + rule: string; + uri: string; + cols: [number, number]; + rows: [number, number]; + }; +}; + +export type OpenBrowserMessage = { + type: 'openBrowser'; + args: { + url: string; + }; +}; + +export type GetAutofixDiffsMesssage = { + type: 'getAutofixDiffs'; + args: { + suggestion: Suggestion; + }; +}; + +export type ApplyGitDiffMessage = { + type: 'applyGitDiff'; + args: { + patch: string; + filePath: string; + fixId: string; + }; +}; + +export type SetSuggestionMessage = { + type: 'set'; + args: Suggestion; +}; + +export type GetSuggestionMessage = { + type: 'get'; +}; + +export type SetLessonMessage = { + type: 'setLesson'; + args: Lesson | null; +}; + +export type GetLessonMessage = { + type: 'getLesson'; +}; + +export type SetAutofixDiffsMessage = { + type: 'setAutofixDiffs'; + args: { + suggestion: Suggestion; + diffs: AutofixUnifiedDiffSuggestion[]; + }; +}; + +export type SetAutofixErrorMessage = { + type: 'setAutofixError'; + args: { + suggestion: Suggestion; + }; +}; + +export type SuggestionMessage = + | OpenLocalMessage + | OpenBrowserMessage + | IgnoreIssueMessage + | GetAutofixDiffsMesssage + | ApplyGitDiffMessage + | SetSuggestionMessage + | GetSuggestionMessage + | SetLessonMessage + | GetLessonMessage + | SetAutofixDiffsMessage + | SetAutofixErrorMessage; diff --git a/src/snyk/snykCode/views/webviewPanelSerializer.ts b/src/snyk/snykCode/views/webviewPanelSerializer.ts new file mode 100644 index 000000000..fca27e31a --- /dev/null +++ b/src/snyk/snykCode/views/webviewPanelSerializer.ts @@ -0,0 +1,13 @@ +import * as vscode from 'vscode'; +import { WebviewProvider } from '../../../snyk/common/views/webviewProvider'; + +export class WebviewPanelSerializer, State> + implements vscode.WebviewPanelSerializer +{ + constructor(private readonly provider: Provider) {} + async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel): Promise { + // we want to make sure the panel is closed on startup + webviewPanel.dispose(); + return Promise.resolve(); + } +} diff --git a/src/snyk/snykIac/codeActions/iacCodeActionsProvider.ts b/src/snyk/snykIac/codeActions/iacCodeActionsProvider.ts index ea3bfda5b..a3d731e13 100644 --- a/src/snyk/snykIac/codeActions/iacCodeActionsProvider.ts +++ b/src/snyk/snykIac/codeActions/iacCodeActionsProvider.ts @@ -1,5 +1,4 @@ import { CodeAction, Range, TextDocument } from 'vscode'; -import { IAnalytics, SupportedQuickFixProperties } from '../../common/analytics/itly'; import { OpenCommandIssueType, OpenIssueCommandArg } from '../../common/commands/types'; import { SNYK_OPEN_ISSUE_COMMAND } from '../../common/constants/commands'; import { CodeActionsProvider } from '../../common/editor/codeActionsProvider'; @@ -17,9 +16,8 @@ export class IacCodeActionsProvider extends CodeActionsProvider { private readonly codeActionAdapter: ICodeActionAdapter, codeActionKindAdapter: ICodeActionKindAdapter, private readonly languages: IVSCodeLanguages, - analytics: IAnalytics, ) { - super(issues, codeActionKindAdapter, analytics); + super(issues, codeActionKindAdapter); } getActions(folderPath: string, _: TextDocument, issue: Issue, range: Range): CodeAction[] { @@ -29,10 +27,6 @@ export class IacCodeActionsProvider extends CodeActionsProvider { return [openIssueAction]; } - getAnalyticsActionTypes(): [string, ...string[]] & [SupportedQuickFixProperties, ...SupportedQuickFixProperties[]] { - return ['Show Suggestion']; - } - getIssueRange(issue: Issue): Range { return IacIssue.getRange(issue, this.languages); } diff --git a/src/snyk/snykIac/iacService.ts b/src/snyk/snykIac/iacService.ts index 9c640c59c..423cf3288 100644 --- a/src/snyk/snykIac/iacService.ts +++ b/src/snyk/snykIac/iacService.ts @@ -1,5 +1,4 @@ import { Subscription } from 'rxjs'; -import { IAnalytics } from '../common/analytics/itly'; import { IConfiguration } from '../common/configuration/configuration'; import { IWorkspaceTrust } from '../common/configuration/trustedFolders'; import { ILanguageServer } from '../common/languageServer/languageServer'; @@ -13,8 +12,11 @@ import { IVSCodeLanguages } from '../common/vscode/languages'; import { IVSCodeWorkspace } from '../common/vscode/workspace'; import { IacCodeActionsProvider } from './codeActions/iacCodeActionsProvider'; import { IIacSuggestionWebviewProvider } from './views/interfaces'; +import { IDiagnosticsIssueProvider } from '../common/services/diagnosticsService'; export class IacService extends ProductService { + public readonly productType = ScanProduct.InfrastructureAsCode; + constructor( extensionContext: ExtensionContext, config: IConfiguration, @@ -26,8 +28,8 @@ export class IacService extends ProductService { workspaceTrust: IWorkspaceTrust, languageServer: ILanguageServer, languages: IVSCodeLanguages, + readonly diagnosticsIssueProvider: IDiagnosticsIssueProvider, logger: ILog, - readonly analytics: IAnalytics, ) { super( extensionContext, @@ -38,11 +40,12 @@ export class IacService extends ProductService { workspaceTrust, languageServer, languages, + diagnosticsIssueProvider, logger, ); this.registerCodeActionsProvider( - new IacCodeActionsProvider(this.result, codeActionAdapter, codeActionKindAdapter, languages, analytics), + new IacCodeActionsProvider(this.result, codeActionAdapter, codeActionKindAdapter, languages), ); } diff --git a/src/snyk/snykIac/views/iacIssueTreeProvider.ts b/src/snyk/snykIac/views/iacIssueTreeProvider.ts index b34c02663..73f31579a 100644 --- a/src/snyk/snykIac/views/iacIssueTreeProvider.ts +++ b/src/snyk/snykIac/views/iacIssueTreeProvider.ts @@ -14,6 +14,7 @@ import { IVSCodeLanguages } from '../../common/vscode/languages'; import { IacIssue } from '../issue'; import { messages } from '../messages/analysis'; import { IacIssueCommandArg } from './interfaces'; +import { IFolderConfigs } from '../../common/configuration/folderConfigs'; export default class IacIssueTreeProvider extends ProductIssueTreeProvider { constructor( @@ -22,8 +23,9 @@ export default class IacIssueTreeProvider extends ProductIssueTreeProvider, protected configuration: IConfiguration, protected languages: IVSCodeLanguages, + protected readonly folderConfigs: IFolderConfigs, ) { - super(contextService, iacService, configuration, languages); + super(contextService, iacService, configuration, languages, folderConfigs); } getRootChildren(): TreeNode[] { @@ -48,8 +50,11 @@ export default class IacIssueTreeProvider extends ProductIssueTreeProvider[]): Issue[] { diff --git a/src/snyk/snykIac/views/suggestion/iacSuggestionWebviewProvider.ts b/src/snyk/snykIac/views/suggestion/iacSuggestionWebviewProvider.ts index 80cbab77d..51e153f4c 100644 --- a/src/snyk/snykIac/views/suggestion/iacSuggestionWebviewProvider.ts +++ b/src/snyk/snykIac/views/suggestion/iacSuggestionWebviewProvider.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import { SNYK_OPEN_BROWSER_COMMAND } from '../../../common/constants/commands'; +import { SNYK_GENERATE_ISSUE_DESCRIPTION, SNYK_OPEN_BROWSER_COMMAND } from '../../../common/constants/commands'; import { SNYK_VIEW_SUGGESTION_IAC } from '../../../common/constants/views'; import { ErrorHandler } from '../../../common/error/errorHandler'; import { IacIssueData, Issue } from '../../../common/languageServer/types'; @@ -12,6 +12,8 @@ import { IVSCodeLanguages } from '../../../common/vscode/languages'; import { IVSCodeWindow } from '../../../common/vscode/window'; import { IVSCodeWorkspace } from '../../../common/vscode/workspace'; import { messages as errorMessages } from '../../messages/error'; +import { readFileSync } from 'fs'; +import { IVSCodeCommands } from '../../../common/vscode/commands'; // import { getAbsoluteMarkerFilePath } from '../../utils/analysisUtils'; // import { IssueUtils } from '../../utils/issueUtils'; // import { ICodeSuggestionWebviewProvider } from '../interfaces'; @@ -30,6 +32,7 @@ export class IacSuggestionWebviewProvider protected readonly logger: ILog, private readonly languages: IVSCodeLanguages, private readonly workspace: IVSCodeWorkspace, + private commandExecutor: IVSCodeCommands, ) { super(context, logger); } @@ -62,8 +65,15 @@ export class IacSuggestionWebviewProvider ); this.registerListeners(); } + // TODO: delete this when SNYK_GENERATE_ISSUE_DESCRIPTION command is in stable CLI. + let html: string = ''; + if (issue.additionalData.customUIContent) { + html = issue.additionalData.customUIContent; + } else { + html = (await this.commandExecutor.executeCommand(SNYK_GENERATE_ISSUE_DESCRIPTION, issue.id)) ?? ''; + } + this.panel.webview.html = this.getHtmlFromLanguageServer(html); - this.panel.webview.html = this.getHtmlForWebview(this.panel.webview); this.panel.iconPath = vscode.Uri.joinPath( vscode.Uri.file(this.context.extensionPath), 'media', @@ -79,6 +89,28 @@ export class IacSuggestionWebviewProvider } } + private getHtmlFromLanguageServer(html: string): string { + const nonce = getNonce(); + const ideStylePath = vscode.Uri.joinPath( + vscode.Uri.file(this.context.extensionPath), + 'media', + 'views', + 'snykCode', // TODO: check with design + 'suggestion', + 'suggestionLS.css', + ); + + const ideStyle = readFileSync(ideStylePath.fsPath, 'utf8'); + // nonce-ideNonce is a placeholder defined in the Language Server + // to be replaced with the local nonce in the tag. + html = html.replace(/nonce-ideNonce/g, `nonce-${nonce}`); + // data-ide-style is a placeholder defined in the Language Server + // to be replaced with the custom IDE styles. + html = html.replace('${ideStyle}', ``); + html = html.replace('${ideScript}', ''); + return html; + } + protected registerListeners(): void { if (!this.panel) return; @@ -112,91 +144,4 @@ export class IacSuggestionWebviewProvider ErrorHandler.handle(e, this.logger, errorMessages.suggestionViewShowFailed); } } - - protected getHtmlForWebview(webview: vscode.Webview): string { - const images: Record = [ - ['dark-critical-severity', 'svg'], - ['dark-high-severity', 'svg'], - ['dark-medium-severity', 'svg'], - ['dark-low-severity', 'svg'], - ].reduce((accumulator: Record, [name, ext]) => { - const uri = this.getWebViewUri('media', 'images', `${name}.${ext}`); - if (!uri) throw new Error('Image missing.'); - accumulator[name] = uri.toString(); - return accumulator; - }, {}); - - const scriptUri = this.getWebViewUri( - 'out', - 'snyk', - 'snykIac', - 'views', - 'suggestion', - 'iacSuggestionWebviewScript.js', - ); - const styleUri = this.getWebViewUri('media', 'views', 'oss', 'suggestion', 'suggestion.css'); // make it common - - const nonce = getNonce(); - - return ` - - - - - - - - - - - -
-
-
- - - - - - - - - -
-
-
-
-
-
-
Description
-
-
-
-
Impact
-
-
-
-
Path
-
- -
-
-
-
-
-

Remediation

-
-
- - - - - `; - } } diff --git a/src/snyk/snykIac/views/suggestion/iacSuggestionWebviewScript.ts b/src/snyk/snykIac/views/suggestion/iacSuggestionWebviewScript.ts deleted file mode 100644 index bcab7587e..000000000 --- a/src/snyk/snykIac/views/suggestion/iacSuggestionWebviewScript.ts +++ /dev/null @@ -1,181 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/// -// This script will be run within the webview itself - -// It cannot access the main VS Code APIs directly. -(function () { - // TODO: Redefine types until bundling is introduced into extension - // https://stackoverflow.com/a/56938089/1713082 - type ConfigurationIssue = { - id: string; - title: string; - severity: string; - filePath: string; - additionalData: IacIssueData; - }; - type IacIssueData = { - publicId: string; - documentation: string; - lineNumber: number; - issue: string; - impact: string; - path?: string[]; - resolve?: string; - references?: string[]; - }; - - let issue = {} as ConfigurationIssue; - - const vscode = acquireVsCodeApi(); - - function navigateToUrl(url: string) { - vscode.postMessage({ - type: 'openBrowser', - value: url, - }); - } - - function showCurrentSuggestion() { - const severity = document.querySelector('.severity')!; - const title = document.querySelector('.suggestion .suggestion-text')!; - - // Set title - title.innerHTML = issue.title; - - // Set severity icon - setSeverityIcon(); - - // Fill identifiers line - fillIdentifiers(); - - // Fill description - fillDescription(); - - // Fill impact - fillImpact(); - - // Fill path - fillPath(); - - // Fill remediation - fillRemediation(); - - // Fill references - fillReferences(); - - function setSeverityIcon() { - if (issue.severity) { - severity.querySelectorAll('img').forEach(n => { - if (n.id.slice(-1) === 'l') { - if (n.id.includes(issue.severity)) n.className = 'icon light-only'; - else n.className = 'icon light-only hidden'; - } else { - if (n.id.includes(issue.severity)) n.className = 'icon dark-only'; - else n.className = 'icon dark-only hidden'; - } - }); - } else { - severity.querySelectorAll('img').forEach(n => (n.className = 'icon hidden')); - } - } - - function fillIdentifiers() { - const identifiers = document.querySelector('.identifiers')!; - identifiers.innerHTML = ''; // reset node - const typeNode = document.createTextNode('Issue'); - identifiers.appendChild(typeNode); - - appendIdentifierSpan( - identifiers, - issue.additionalData.publicId.toUpperCase(), - issue.additionalData.documentation, - ); - } - - function fillDescription() { - const module = document.querySelector('.description > .content')!; - module.textContent = issue.additionalData.issue; - } - - function fillImpact() { - const module = document.querySelector('.impact > .content')!; - module.textContent = issue.additionalData.impact; - } - - function fillPath() { - const module = document.querySelector('.path > .content code')!; - if (issue.additionalData.path) { - module.textContent = issue.additionalData.path.join(' > '); - } else { - module.textContent = 'No path available.'; - } - } - - function fillRemediation() { - const module = document.querySelector('.remediation')!; - if (issue.additionalData.resolve) { - module.textContent = issue.additionalData.resolve; - } else { - module.textContent = 'No remediation available.'; - } - } - - function fillReferences() { - const section = document.querySelector('.references')!; - if (issue.additionalData.references) { - section.classList.remove('hidden'); - const module = document.querySelector('.references > .reference-links')!; - for (const reference of issue.additionalData.references) { - const paragraph = document.createElement('p'); - const referenceLink = document.createElement('a'); - const linkText = document.createTextNode(reference); - referenceLink.appendChild(linkText); - referenceLink.title = reference; - referenceLink.onclick = () => navigateToUrl(reference); - paragraph.appendChild(referenceLink); - module.appendChild(paragraph); - } - } - } - } - - window.addEventListener('message', event => { - const { type, args } = event.data; - switch (type) { - case 'set': { - issue = args; - vscode.setState({ ...vscode.getState(), issue }); - showCurrentSuggestion(); - break; - } - case 'get': { - issue = vscode.getState()?.issue || {}; - showCurrentSuggestion(); - break; - } - } - }); - - function appendIdentifierSpan(identifiers: Element, id: string, link?: string) { - const delimiter = document.createElement('span'); - delimiter.innerText = ' | '; - delimiter.className = 'delimiter'; - identifiers.appendChild(delimiter); - - let cveNode: HTMLElement; - if (link) { - cveNode = document.createElement('a'); - cveNode.onclick = () => navigateToUrl(link); - } else { - cveNode = document.createElement('span'); - } - - cveNode.innerText = id; - - identifiers.appendChild(cveNode); - } -})(); diff --git a/src/snyk/snykOss/codeActions/vulnerabilityCodeActionProvider.ts b/src/snyk/snykOss/codeActions/vulnerabilityCodeActionProvider.ts deleted file mode 100644 index 68b1b3535..000000000 --- a/src/snyk/snykOss/codeActions/vulnerabilityCodeActionProvider.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { IAnalytics } from '../../common/analytics/itly'; -import { OpenCommandIssueType, OpenIssueCommandArg } from '../../common/commands/types'; -import { SNYK_OPEN_ISSUE_COMMAND } from '../../common/constants/commands'; -import { IDE_NAME } from '../../common/constants/general'; -import { ICodeActionKindAdapter } from '../../common/vscode/codeAction'; -import { - CodeAction, - CodeActionContext, - CodeActionKind, - CodeActionProvider, - Command, - ProviderResult, - Range, - Selection, - TextDocument, -} from '../../common/vscode/types'; -import { DIAGNOSTICS_OSS_COLLECTION_NAME } from '../../snykCode/constants/analysis'; -import { messages } from '../messages/vulnerabilityCount'; -import { isResultCliError } from '../ossResult'; -import { OssService } from '../services/ossService'; -import { ModuleVulnerabilityCountProvider } from '../services/vulnerabilityCount/vulnerabilityCountProvider'; - -export class VulnerabilityCodeActionProvider implements CodeActionProvider { - public codeActionKinds: ReadonlyArray = [this.codeActionKindProvider.getQuickFix()]; - - constructor( - private readonly ossService: OssService, - private readonly vulnerabilityCountProvider: ModuleVulnerabilityCountProvider, - private readonly codeActionKindProvider: ICodeActionKindAdapter, - private readonly analytics: IAnalytics, - ) {} - - async provideCodeActions( - document: TextDocument, - _: Range | Selection, - context: CodeActionContext, - ): Promise> { - const ossDiagnostics = context.diagnostics.filter(d => d.source === DIAGNOSTICS_OSS_COLLECTION_NAME); - if (!ossDiagnostics.length) { - return; - } - - const ossResult = this.ossService.getResultArray(); - if (!ossResult) { - return; - } - - const fileResult = ossResult.find( - res => !isResultCliError(res) && this.vulnerabilityCountProvider.isFilePartOfOssTest(document.fileName, res), - ); - - if (!fileResult || isResultCliError(fileResult)) { - return; - } - - for (const diagnostic of ossDiagnostics) { - const vulnerability = fileResult.vulnerabilities.find(vuln => vuln.id === diagnostic.code); - if (!vulnerability) { - continue; - } - - const command: Command = { - command: SNYK_OPEN_ISSUE_COMMAND, - title: messages.showMostSevereVulnerability, - arguments: [ - { - issueType: OpenCommandIssueType.OssVulnerability, - issue: await this.ossService.getOssIssueCommandArg(vulnerability, fileResult.vulnerabilities), - } as OpenIssueCommandArg, - ], - }; - - this.analytics.logQuickFixIsDisplayed({ - quickFixType: ['Show Most Severe Vulnerability'], - ide: IDE_NAME, - }); - - return [command]; - } - } -} diff --git a/src/snyk/snykOss/constants/messages.ts b/src/snyk/snykOss/constants/messages.ts new file mode 100644 index 000000000..5c8f7f63f --- /dev/null +++ b/src/snyk/snykOss/constants/messages.ts @@ -0,0 +1,32 @@ +export const messages = { + analysis: { + scanFailed: 'Scan failed', + noWorkspaceTrust: 'No workspace folder was granted trust', + clickToProblem: 'Click here to see the problem.', + scanRunning: 'Scanning...', + allSeverityFiltersDisabled: 'Please enable severity filters to see the results.', + duration: (time: string, day: string): string => `Analysis finished at ${time}, ${day}`, + noWorkspaceTrustDescription: + 'None of workspace folders were trusted. If you trust the workspace, you can add it to the list of trusted folders in the extension settings, or when prompted by the extension next time.', + }, + errors: { + suggestionViewShowFailed: 'Failed to show Snyk OSS suggestion view', + }, + test: { + testFailed: 'Open Source Security test failed.', + testStarted: 'Open Source Security test started.', + viewResults: 'View results', + hide: "Don't show again", + testFailedForPath: (path: string): string => `Open Source Security test failed for "${path}".`, + testFinished: (projectName: string): string => `Open Source Security test finished for "${projectName}".`, + }, + treeView: { + cookingDependencies: 'Scanning...', + runTest: 'Run scan for Open Source security issues.', + noVulnerabilitiesFound: ' ✅ Congrats! No issues found!', + issue: 'issue', + issues: 'issues', + singleVulnerabilityFound: 'Snyk found 1 issue', + multipleVulnerabilitiesFound: (issueCount: number): string => `Snyk found ${issueCount} issues`, + }, +}; diff --git a/src/snyk/snykOss/editor/editorDecorator.ts b/src/snyk/snykOss/editor/editorDecorator.ts index 398a5d888..3fd9e4850 100644 --- a/src/snyk/snykOss/editor/editorDecorator.ts +++ b/src/snyk/snykOss/editor/editorDecorator.ts @@ -4,7 +4,6 @@ import { IVSCodeLanguages } from '../../common/vscode/languages'; import { IThemeColorAdapter } from '../../common/vscode/theme'; import { TextEditorDecorationType } from '../../common/vscode/types'; import { IVSCodeWindow } from '../../common/vscode/window'; -import { messages } from '../messages/vulnerabilityCount'; import { ImportedModule, ModuleVulnerabilityCount } from '../services/vulnerabilityCount/importedModule'; export class EditorDecorator { @@ -12,7 +11,7 @@ export class EditorDecorator { private readonly fileDecorationMap: Map; private readonly editorLastCharacterIndex = Number.MAX_SAFE_INTEGER; - private updateTimeout: NodeJS.Timer | undefined = undefined; + private updateTimeout: NodeJS.Timeout | undefined = undefined; constructor( private readonly window: IVSCodeWindow, @@ -58,7 +57,7 @@ export class EditorDecorator { module.line - 1, this.editorLastCharacterIndex, ), - renderOptions: getRenderOptions(messages.fetchingVulnerabilities, this.themeColorAdapter), + renderOptions: getRenderOptions('Fetching issues...', this.themeColorAdapter), }; } @@ -92,16 +91,16 @@ export class EditorDecorator { this.fileDecorationMap.set(filePath, lineDecorations); // set map, if no decoration was set before } - const text = vulnerabilityCount.count ? messages.decoratorMessage(vulnerabilityCount.count) : ''; + const vulnerabilityCountMessage = vulnerabilityCount.count ?? ''; lineDecorations[vulnerabilityCount.line] = { range: this.languages.createRange( - vulnerabilityCount.line - 1, + vulnerabilityCount.line - 1, // start line, index is 0 based this.editorLastCharacterIndex, - vulnerabilityCount.line - 1, + vulnerabilityCount.line - 1, // end line, index is 0 based this.editorLastCharacterIndex, ), - renderOptions: getRenderOptions(text, this.themeColorAdapter), + renderOptions: getRenderOptions(vulnerabilityCountMessage, this.themeColorAdapter), }; if (triggerUpdate) { diff --git a/src/snyk/snykOss/hoverProvider/vulnerabilityCountHoverProvider.ts b/src/snyk/snykOss/hoverProvider/vulnerabilityCountHoverProvider.ts deleted file mode 100644 index 8fc56f11d..000000000 --- a/src/snyk/snykOss/hoverProvider/vulnerabilityCountHoverProvider.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { IAnalytics } from '../../common/analytics/itly'; -import { IDE_NAME } from '../../common/constants/general'; -import { SupportedLanguageIds } from '../../common/constants/languageConsts'; -import { IVSCodeLanguages } from '../../common/vscode/languages'; -import { DiagnosticCollection, Disposable, Hover, Position, TextDocument } from '../../common/vscode/types'; -import { IssueUtils } from '../../snykCode/utils/issueUtils'; - -export class VulnerabilityCountHoverProvider implements Disposable { - private hoverProvider: Disposable | undefined; - - constructor(private readonly vscodeLanguages: IVSCodeLanguages, private readonly analytics: IAnalytics) {} - - register(diagnostics: DiagnosticCollection | undefined): Disposable { - const documentFilter = SupportedLanguageIds.map(id => ({ scheme: 'file', language: id })); - - this.hoverProvider = this.vscodeLanguages.registerHoverProvider(documentFilter, { - provideHover: this.getHover(diagnostics), - }); - - return this; - } - - getHover(diagnostics: DiagnosticCollection | undefined) { - return (document: TextDocument, position: Position): Hover | undefined => { - if (!diagnostics || !diagnostics.has(document.uri)) { - return undefined; - } - - const currentFileReviewIssues = diagnostics.get(document.uri); - const issue = IssueUtils.findIssueWithRange(position, currentFileReviewIssues); - if (issue) { - this.logIssueHoverIsDisplayed(); - } - }; - } - - private logIssueHoverIsDisplayed(): void { - this.analytics.logIssueHoverIsDisplayed({ - issueType: 'Open Source Vulnerability', - ide: IDE_NAME, - }); - } - - dispose(): void { - if (this.hoverProvider) { - this.hoverProvider.dispose(); - } - } -} diff --git a/src/snyk/snykOss/interfaces.ts b/src/snyk/snykOss/interfaces.ts new file mode 100644 index 000000000..793165d52 --- /dev/null +++ b/src/snyk/snykOss/interfaces.ts @@ -0,0 +1,108 @@ +import _ from 'lodash'; +import { Issue, IssueSeverity, OssIssueData } from '../common/languageServer/types'; +import { IWebViewProvider } from '../common/views/webviewProvider'; +import { CliError } from '../cli/services/cliService'; + +export interface IOssSuggestionWebviewProvider extends IWebViewProvider> { + openIssueId: string | undefined; +} + +export type OssIssueCommandArg = Issue & { + matchingIdVulnerabilities: Issue[]; + overviewHtml: string; + folderPath: string; +}; + +export type OssFileResult = OssResultBody | CliError; + +export type OssResultBody = { + vulnerabilities: OssVulnerability[]; + projectName: string; + displayTargetFile: string; + packageManager: string; + path: string; +}; + +export type OssVulnerability = { + id: string; + license?: string; + identifiers?: Identifiers; + title: string; + description: string; + language: string; + packageManager: string; + packageName: string; + severity: OssSeverity; + name: string; + version: string; + exploit?: string; + + CVSSv3?: string; + cvssScore?: string; + + fixedIn?: Array; + from: Array; + upgradePath: Array; + isPatchable: boolean; + isUpgradable: boolean; +}; + +type Identifiers = { + CWE: string[]; + CVE: string[]; +}; + +enum OssSeverity { + Low = 'low', + Medium = 'medium', + High = 'high', + Critical = 'critical', +} + +export function isResultCliError(fileResult: OssFileResult): fileResult is CliError { + return (fileResult as CliError).error !== undefined; +} + +function convertSeverity(severity: IssueSeverity): OssSeverity { + switch (severity) { + case IssueSeverity.Low: + return OssSeverity.Low; + case IssueSeverity.Medium: + return OssSeverity.Medium; + case IssueSeverity.High: + return OssSeverity.High; + default: + return OssSeverity.Critical; + } +} + +export function convertIssue(issue: Issue): OssVulnerability { + const tempVuln: OssVulnerability = { + id: issue.id, + identifiers: issue.additionalData.identifiers, + title: issue.title, + description: issue.additionalData.description, + language: issue.additionalData.language, + packageManager: issue.additionalData.packageManager, + packageName: issue.additionalData.packageName, + severity: convertSeverity(issue.severity), + name: issue.additionalData.name, + version: issue.additionalData.version, + exploit: issue.additionalData.exploit, + + CVSSv3: issue.additionalData.CVSSv3, + cvssScore: issue.additionalData.cvssScore, + + fixedIn: issue.additionalData.fixedIn === undefined ? [] : issue.additionalData.fixedIn, + from: issue.additionalData.from, + upgradePath: issue.additionalData.upgradePath, + isPatchable: issue.additionalData.isPatchable, + isUpgradable: issue.additionalData.isUpgradable, + }; + + if (issue.additionalData.license !== undefined) { + tempVuln.license = issue.additionalData.license; + } + + return tempVuln; +} diff --git a/src/snyk/snykOss/messages/error.ts b/src/snyk/snykOss/messages/error.ts deleted file mode 100644 index f8f215e17..000000000 --- a/src/snyk/snykOss/messages/error.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const messages = { - suggestionViewShowFailed: 'Failed to show Snyk OSS suggestion view', -}; diff --git a/src/snyk/snykOss/messages/test.ts b/src/snyk/snykOss/messages/test.ts deleted file mode 100644 index d41d6d05e..000000000 --- a/src/snyk/snykOss/messages/test.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const messages = { - testFailed: 'Open Source Security test failed.', - testStarted: 'Open Source Security test started.', - viewResults: 'View results', - hide: "Don't show again", - - testFailedForPath: (path: string): string => `Open Source Security test failed for "${path}".`, - testFinished: (projectName: string): string => `Open Source Security test finished for "${projectName}".`, -}; diff --git a/src/snyk/snykOss/messages/treeView.ts b/src/snyk/snykOss/messages/treeView.ts deleted file mode 100644 index e01a041bc..000000000 --- a/src/snyk/snykOss/messages/treeView.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const messages = { - cookingDependencies: 'Scanning...', - - runTest: 'Run scan for Open Source security vulnerabilities.', - noVulnerabilitiesFound: ' ✅ Congrats! Snyk found no vulnerabilities.', - singleVulnerabilityFound: 'Snyk found 1 vulnerability', - vulnerability: 'vulnerability', - vulnerabilities: 'vulnerabilities', - - multipleVulnerabilitiesFound: (issueCount: number): string => `Snyk found ${issueCount} vulnerabilities`, -}; diff --git a/src/snyk/snykOss/messages/vulnerabilityCount.ts b/src/snyk/snykOss/messages/vulnerabilityCount.ts deleted file mode 100644 index f328ebd22..000000000 --- a/src/snyk/snykOss/messages/vulnerabilityCount.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ModuleVulnerabilityCount } from '../services/vulnerabilityCount/importedModule'; - -export const messages = { - fetchingVulnerabilities: 'Fetching vulnerabilities...', - vulnerability: 'vulnerability', - vulnerabilities: 'vulnerabilities', - showMostSevereVulnerability: 'Show the most severe vulnerability (Snyk)', - - decoratorMessage: (vulnerabilityCount: string): string => { - const vulnerabilityCountNumber = Number.parseInt(vulnerabilityCount, 10); - if (isNaN(vulnerabilityCountNumber)) { - return vulnerabilityCount; - } - return `${vulnerabilityCountNumber} ${vulnerabilityCountNumber > 1 ? 'vulnerabilities' : 'vulnerability'}`; - }, - - diagnosticMessagePrefix: (module: ModuleVulnerabilityCount): string => - `Dependency ${module.name}${module.version ? `@${module.version}` : ''} has `, -}; diff --git a/src/snyk/snykOss/ossResult.ts b/src/snyk/snykOss/ossResult.ts deleted file mode 100644 index 625019a49..000000000 --- a/src/snyk/snykOss/ossResult.ts +++ /dev/null @@ -1,58 +0,0 @@ -import _ from 'lodash'; -import { CliError } from '../cli/services/cliService'; - -export type OssResult = OssFileResult[] | OssFileResult; - -export type OssFileResult = OssResultBody | CliError; - -export type OssResultBody = { - vulnerabilities: OssVulnerability[]; - projectName: string; - displayTargetFile: string; - packageManager: string; - path: string; -}; - -export type OssVulnerability = { - id: string; - license?: string; - identifiers?: Identifiers; - title: string; - description: string; - language: string; - packageManager: string; - packageName: string; - severity: OssSeverity; - name: string; - version: string; - exploit?: string; - - CVSSv3?: string; - cvssScore?: string; - - fixedIn?: Array; - from: Array; - upgradePath: Array; - isPatchable: boolean; - isUpgradable: boolean; -}; - -export type Identifiers = { - CWE: string[]; - CVE: string[]; -}; - -export enum OssSeverity { - Low = 'low', - Medium = 'medium', - High = 'high', - Critical = 'critical', -} - -export function capitalizeOssSeverity(ossSeverity: OssSeverity): Capitalize { - return _.capitalize(ossSeverity) as Capitalize; -} - -export function isResultCliError(fileResult: OssFileResult): fileResult is CliError { - return (fileResult as CliError).error !== undefined; -} diff --git a/src/snyk/snykOss/ossService.ts b/src/snyk/snykOss/ossService.ts new file mode 100644 index 000000000..271fd3449 --- /dev/null +++ b/src/snyk/snykOss/ossService.ts @@ -0,0 +1,65 @@ +import { Subscription } from 'rxjs'; +import { IConfiguration } from '../common/configuration/configuration'; +import { IWorkspaceTrust } from '../common/configuration/trustedFolders'; +import { ILanguageServer } from '../common/languageServer/languageServer'; +import { OssIssueData, Scan, ScanProduct } from '../common/languageServer/types'; +import { ILog } from '../common/logger/interfaces'; +import { ProductService } from '../common/services/productService'; +import { IViewManagerService } from '../common/services/viewManagerService'; +import { ICodeActionAdapter, ICodeActionKindAdapter } from '../common/vscode/codeAction'; +import { ExtensionContext } from '../common/vscode/extensionContext'; +import { IVSCodeLanguages } from '../common/vscode/languages'; +import { IVSCodeWorkspace } from '../common/vscode/workspace'; +import { IOssSuggestionWebviewProvider } from './interfaces'; +import { OssCodeActionsProvider } from './providers/ossCodeActionsProvider'; +import { IDiagnosticsIssueProvider } from '../common/services/diagnosticsService'; + +export class OssService extends ProductService { + public readonly productType = ScanProduct.OpenSource; + + constructor( + extensionContext: ExtensionContext, + config: IConfiguration, + suggestionProvider: IOssSuggestionWebviewProvider, + codeActionAdapter: ICodeActionAdapter, + codeActionKindAdapter: ICodeActionKindAdapter, + viewManagerService: IViewManagerService, + workspace: IVSCodeWorkspace, + workspaceTrust: IWorkspaceTrust, + languageServer: ILanguageServer, + languages: IVSCodeLanguages, + readonly diagnosticsIssueProvider: IDiagnosticsIssueProvider, + logger: ILog, + ) { + super( + extensionContext, + config, + suggestionProvider, + viewManagerService, + workspace, + workspaceTrust, + languageServer, + languages, + diagnosticsIssueProvider, + logger, + ); + + this.registerCodeActionsProvider( + new OssCodeActionsProvider(languages, codeActionAdapter, codeActionKindAdapter, this.result), + ); + } + + subscribeToLsScanMessages(): Subscription { + return this.languageServer.scan$.subscribe((scan: Scan) => { + if (scan.product !== ScanProduct.OpenSource) { + return; + } + + super.handleLsScanMessage(scan); + }); + } + + refreshTreeView() { + this.viewManagerService.refreshOssView(); + } +} diff --git a/src/snyk/snykOss/providers/ossCodeActionsProvider.ts b/src/snyk/snykOss/providers/ossCodeActionsProvider.ts new file mode 100644 index 000000000..6201425f2 --- /dev/null +++ b/src/snyk/snykOss/providers/ossCodeActionsProvider.ts @@ -0,0 +1,148 @@ +import { CodeAction, Range, TextDocument, Uri } from 'vscode'; +import { OpenCommandIssueType, OpenIssueCommandArg } from '../../common/commands/types'; +import { SNYK_OPEN_ISSUE_COMMAND } from '../../common/constants/commands'; +import { CodeActionsProvider } from '../../common/editor/codeActionsProvider'; +import { Issue, IssueSeverity, OssIssueData } from '../../common/languageServer/types'; +import { ProductResult } from '../../common/services/productService'; +import { ICodeActionAdapter, ICodeActionKindAdapter } from '../../common/vscode/codeAction'; +import { IVSCodeLanguages } from '../../common/vscode/languages'; +import { CodeActionContext } from '../../common/vscode/types'; +import { DIAGNOSTICS_OSS_COLLECTION_NAME_LS } from '../../snykCode/constants/analysis'; +import { getOssIssueCommandArg } from './ossIssueCommandHelper'; + +export class OssCodeActionsProvider extends CodeActionsProvider { + constructor( + private readonly languages: IVSCodeLanguages, + private readonly codeActionAdapter: ICodeActionAdapter, + codeActionKindAdapter: ICodeActionKindAdapter, + issues: Readonly>, + ) { + super(issues, codeActionKindAdapter); + } + + override provideCodeActions( + document: TextDocument, + _clickedRange: Range, + context: CodeActionContext, + ): CodeAction[] | undefined { + // is there a better way to get the folder path? + const folderPath = document.uri.fsPath.split('/').slice(0, -1).join('/'); + if (!folderPath) { + return; + } + + const vulnerabilities = this.getVulnerabilities(folderPath, context); + if (!vulnerabilities) { + return; + } + + const mostSevereVulnerability = this.getMostSevereVulnerability(vulnerabilities, folderPath); + if (!mostSevereVulnerability) { + return; + } + + return this.getActions(folderPath, document, mostSevereVulnerability, this.getIssueRange(mostSevereVulnerability)); + } + + getActions( + _folderPath: string, + _document: TextDocument, + mostSevereVulnerability: Issue, + _issueRange?: Range, + ): CodeAction[] { + const openIssueAction = this.createMostSevereVulnerabilityAction(mostSevereVulnerability); + + // returns list of actions, all new actions should be added to this list + return [openIssueAction]; + } + + // noop + getIssueRange(_issue: Issue): Range { + return this.languages.createRange(0, 0, 0, 0); + } + + private createMostSevereVulnerabilityAction(mostSevereVulnerability: Issue): CodeAction { + // create the CodeAction + const openIssueAction = this.codeActionAdapter.create( + `Show the most severe vulnerability [${mostSevereVulnerability.id}] (Snyk)`, + this.providedCodeActionKinds[0], + ); + + openIssueAction.command = { + command: SNYK_OPEN_ISSUE_COMMAND, + title: SNYK_OPEN_ISSUE_COMMAND, + arguments: [ + { + issueType: OpenCommandIssueType.OssVulnerability, + issue: mostSevereVulnerability, + } as OpenIssueCommandArg, + ], + }; + + return openIssueAction; + } + + private issueSeverityToRanking(severity: IssueSeverity): number { + switch (severity) { + case IssueSeverity.Critical: + return 3; + case IssueSeverity.High: + return 2; + case IssueSeverity.Medium: + return 1; + default: + return 0; + } + } + + private getVulnerabilities(folderPath: string, context: CodeActionContext): Issue[] | undefined { + // get all OSS vulnerabilities for the folder + const ossResult = this.issues.get(folderPath); + if (!ossResult || ossResult instanceof Error) { + return; + } + + // get all OSS diagnostics; these contain the relevant vulnerabilities + const ossDiagnostics = context.diagnostics.filter(d => d.source === DIAGNOSTICS_OSS_COLLECTION_NAME_LS); + if (!ossDiagnostics.length) { + return; + } + + // find the corresponding Issue objects from ossDiagnostics + const vulnerabilities: Issue[] = []; + for (const diagnostic of ossDiagnostics) { + const vulnerability = ossResult.find( + ossIssue => ossIssue.id === (diagnostic.code as { value: string | number; target: Uri }).value, + ); + if (!vulnerability) { + continue; + } + vulnerabilities.push(vulnerability); + } + + return vulnerabilities; + } + + private getMostSevereVulnerability( + vulnerabilities: Issue[], + folderPath: string, + ): Issue | undefined { + // iterate vulnerabilities and get the most severe one + // if there are multiple of the same severity, get the first one + let highestSeverity = this.issueSeverityToRanking(IssueSeverity.Low); + let mostSevereVulnerability: Issue | undefined; + + for (const vulnerability of vulnerabilities) { + if (this.issueSeverityToRanking(vulnerability.severity) > highestSeverity) { + highestSeverity = this.issueSeverityToRanking(vulnerability.severity); + mostSevereVulnerability = vulnerability; + } + } + + if (!mostSevereVulnerability) { + return; + } + + return getOssIssueCommandArg(mostSevereVulnerability, folderPath, vulnerabilities); + } +} diff --git a/src/snyk/snykOss/providers/ossDetailPanelProvider.ts b/src/snyk/snykOss/providers/ossDetailPanelProvider.ts new file mode 100644 index 000000000..659a50fbf --- /dev/null +++ b/src/snyk/snykOss/providers/ossDetailPanelProvider.ts @@ -0,0 +1,129 @@ +import * as vscode from 'vscode'; +import { SNYK_VIEW_SUGGESTION_OSS } from '../../common/constants/views'; +import { ErrorHandler } from '../../common/error/errorHandler'; +import { Issue, OssIssueData } from '../../common/languageServer/types'; +import { ILog } from '../../common/logger/interfaces'; +import { getNonce } from '../../common/views/nonce'; +import { WebviewPanelSerializer } from '../../common/views/webviewPanelSerializer'; +import { IWebViewProvider, WebviewProvider } from '../../common/views/webviewProvider'; +import { ExtensionContext } from '../../common/vscode/extensionContext'; +import { IVSCodeLanguages } from '../../common/vscode/languages'; +import { IVSCodeWindow } from '../../common/vscode/window'; +import { IVSCodeWorkspace } from '../../common/vscode/workspace'; +import { messages } from '../constants/messages'; +import { readFileSync } from 'fs'; +import { SNYK_GENERATE_ISSUE_DESCRIPTION } from '../../common/constants/commands'; +import { IVSCodeCommands } from '../../common/vscode/commands'; + +export class OssDetailPanelProvider + extends WebviewProvider> + implements IWebViewProvider> +{ + // For consistency reasons, the single source of truth for the current suggestion is the + // panel state. The following field is only used in + private issue: Issue | undefined; + + constructor( + private readonly window: IVSCodeWindow, + protected readonly context: ExtensionContext, + protected readonly logger: ILog, + private readonly languages: IVSCodeLanguages, + private readonly workspace: IVSCodeWorkspace, + private commandExecutor: IVSCodeCommands, + ) { + super(context, logger); + } + + activate(): void { + this.context.addDisposables( + this.window.registerWebviewPanelSerializer(SNYK_VIEW_SUGGESTION_OSS, new WebviewPanelSerializer(this)), + ); + } + + get openIssueId(): string | undefined { + return this.issue?.id; + } + + async showPanel(issue: Issue): Promise { + try { + await this.focusSecondEditorGroup(); + + if (this.panel) { + this.panel.reveal(vscode.ViewColumn.Two, true); + } else { + this.panel = vscode.window.createWebviewPanel( + SNYK_VIEW_SUGGESTION_OSS, + 'Snyk OSS Issue', + { + viewColumn: vscode.ViewColumn.Two, + preserveFocus: true, + }, + this.getWebviewOptions(), + ); + this.registerListeners(); + } + [ + ['icon-code', 'svg'], + ['dark-critical-severity', 'svg'], + ['dark-high-severity', 'svg'], + ['dark-medium-severity', 'svg'], + ['dark-low-severity', 'svg'], + ['learn-icon', 'svg'], + ].reduce((accumulator: Record, [name, ext]) => { + const uri = this.getWebViewUri('media', 'images', `${name}.${ext}`); + if (!uri) throw new Error('Image missing.'); + accumulator[name] = uri.toString(); + return accumulator; + }, {}); + let html: string = ''; + // TODO: delete this when SNYK_GENERATE_ISSUE_DESCRIPTION command is in stable CLI. + if (issue.additionalData.details) { + html = issue.additionalData.details; + } else { + html = (await this.commandExecutor.executeCommand(SNYK_GENERATE_ISSUE_DESCRIPTION, issue.id)) ?? ''; + } + + // Add the style + const ideStylePath = vscode.Uri.joinPath( + vscode.Uri.file(this.context.extensionPath), + 'media', + 'views', + 'oss', + 'suggestion', + 'suggestion.css', + ); + const ideStyle = readFileSync(ideStylePath.fsPath, 'utf8'); + const nonce = getNonce(); + + html = html.replace('${ideStyle}', ''); + html = html.replaceAll('${nonce}', nonce); + html = html.replaceAll(/\$\{\w+\}/g, ''); + this.panel.webview.html = html; + this.panel.iconPath = vscode.Uri.joinPath( + vscode.Uri.file(this.context.extensionPath), + 'media', + 'images', + 'snyk-oss.svg', + ); + + this.issue = issue; + } catch (e) { + ErrorHandler.handle(e, this.logger, messages.errors.suggestionViewShowFailed); + } + } + + protected registerListeners(): void { + if (!this.panel) return; + + this.panel.onDidDispose(() => this.onPanelDispose(), null, this.disposables); + this.panel.onDidChangeViewState(() => this.checkVisibility(), undefined, this.disposables); + } + + disposePanel(): void { + super.disposePanel(); + } + + protected onPanelDispose(): void { + super.onPanelDispose(); + } +} diff --git a/src/snyk/snykOss/providers/ossIssueCommandHelper.ts b/src/snyk/snykOss/providers/ossIssueCommandHelper.ts new file mode 100644 index 000000000..e068c025e --- /dev/null +++ b/src/snyk/snykOss/providers/ossIssueCommandHelper.ts @@ -0,0 +1,26 @@ +import { marked } from 'marked'; +import { Issue, OssIssueData } from '../../common/languageServer/types'; +import { OssIssueCommandArg } from '../interfaces'; + +export function getOssIssueCommandArg( + vuln: Issue, + folderPath: string, + filteredVulns: Issue[], +): OssIssueCommandArg { + const matchingIdVulnerabilities = filteredVulns.filter(v => v.id === vuln.id); + let overviewHtml = ''; + + try { + // TODO: marked.parse does not sanitize the HTML. See: https://marked.js.org/#usage + overviewHtml = marked.parse(vuln.additionalData.description) as string; + } catch (error) { + overviewHtml = '

There was a problem rendering the issue overview

'; + } + + return { + ...vuln, + matchingIdVulnerabilities, + overviewHtml, + folderPath, + }; +} diff --git a/src/snyk/snykOss/providers/ossVulnerabilityCountProvider.ts b/src/snyk/snykOss/providers/ossVulnerabilityCountProvider.ts new file mode 100644 index 000000000..0ecd40aa7 --- /dev/null +++ b/src/snyk/snykOss/providers/ossVulnerabilityCountProvider.ts @@ -0,0 +1,132 @@ +import { CliError } from '../../cli/services/cliService'; +import { Language, languageToString } from '../../common/types'; +import { ILanguageClientAdapter } from '../../common/vscode/languageClient'; +import { ITextDocumentAdapter } from '../../common/vscode/textdocument'; +import { InlineValueText, LSPTextDocument } from '../../common/vscode/types'; +import { IUriAdapter } from '../../common/vscode/uri'; +import { convertIssue, isResultCliError, OssFileResult, OssResultBody } from '../interfaces'; +import { OssService } from '../ossService'; +import { ImportedModule, ModuleVulnerabilityCount } from '../services/vulnerabilityCount/importedModule'; +import { VulnerabilityCountEmitter } from '../services/vulnerabilityCount/vulnerabilityCountEmitter'; + +export class OssVulnerabilityCountProvider { + constructor( + private readonly ossService: OssService, + private readonly languageClientAdapter: ILanguageClientAdapter, + private readonly uriAdapter: IUriAdapter, + private readonly textDocumentAdapter: ITextDocumentAdapter, + ) {} + + async getVulnerabilityCount( + fileName: string, + module: ImportedModule, + language: Language, + emitter: VulnerabilityCountEmitter, + ): Promise { + let moduleVulnerabilityCount: ModuleVulnerabilityCount = { + name: module.name, + fileName: module.fileName, + line: module.line, + range: module.loc, + hasCount: false, + }; + + const processFile = [Language.TypeScript, Language.JavaScript, Language.PJSON, Language.HTML].includes(language); + if (processFile) { + const uri = this.uriAdapter.file(fileName).toString(); + const doc: LSPTextDocument = this.textDocumentAdapter.create(uri, languageToString(language), 1, ''); + + let firstLine = 0; + let lastLine = doc.lineCount; + let firstCharacter = 0; + let lastCharacter = Number.MAX_SAFE_INTEGER; + + if (module.loc) { + firstLine = module.loc.start.line - 1; + lastLine = module.loc.end.line - 1; + firstCharacter = module.loc.start.column; + lastCharacter = module.loc.end.column; + } + + const param = { + textDocument: { uri: doc.uri }, + range: { + start: { line: firstLine, character: firstCharacter }, + end: { line: lastLine, character: lastCharacter }, + }, + }; + + const inlineValues: InlineValueText[] = await this.languageClientAdapter + .getLanguageClient() + .sendRequest('textDocument/inlineValue', param); + + if (inlineValues?.length > 0) { + moduleVulnerabilityCount = { + name: module.name, + version: module.version, + fileName: module.fileName, + line: module.line, + range: module.loc, + count: inlineValues[0].text, + hasCount: true, + }; + } + } + + emitter?.scanned(moduleVulnerabilityCount); + return moduleVulnerabilityCount; + } + + isFilePartOfOssTest(filePath: string, ossFileResult: OssFileResult): boolean { + if (isResultCliError(ossFileResult)) { + return false; + } + + // File is considered to be part of OSS test if it has common root directory between OSS result path and filename path. + // This is since package.json always lies in the root directory folder of a project. + return filePath.startsWith(ossFileResult.path); + } + + public getResultArray = (): ReadonlyArray | undefined => { + if (!this.ossService.result) { + return undefined; + } + + const tempResultArray: OssFileResult[] = []; + const resultCache = new Map(); + + for (const [, value] of this.ossService.result) { + // value is Error + if (value instanceof Error) { + tempResultArray.push(new CliError(value)); + } + // value is Issue[] + else { + for (const issue of value) { + // try to access list of vulns for the current file + let res = resultCache.get(issue.filePath); + + // add list of vulns to local cache if not there yet + if (res === undefined) { + res = { + path: issue.filePath, + vulnerabilities: [], + projectName: issue.additionalData.projectName, + displayTargetFile: issue.additionalData.displayTargetFile, + packageManager: issue.additionalData.packageManager, + }; + resultCache.set(issue.filePath, res); + } + + const tempVuln = convertIssue(issue); + res.vulnerabilities.push(tempVuln); + } + } + } + + // copy cached results to final result array + resultCache.forEach(value => tempResultArray.push(value)); + + return tempResultArray; + }; +} diff --git a/src/snyk/snykOss/providers/ossVulnerabilityTreeProvider.ts b/src/snyk/snykOss/providers/ossVulnerabilityTreeProvider.ts new file mode 100644 index 000000000..66dd6d00e --- /dev/null +++ b/src/snyk/snykOss/providers/ossVulnerabilityTreeProvider.ts @@ -0,0 +1,214 @@ +import _ from 'lodash'; +import { Command, Uri } from 'vscode'; +import { OpenCommandIssueType, OpenIssueCommandArg } from '../../common/commands/types'; +import { IConfiguration } from '../../common/configuration/configuration'; +import { configuration } from '../../common/configuration/instance'; +import { SNYK_OPEN_ISSUE_COMMAND } from '../../common/constants/commands'; +import { SNYK_ANALYSIS_STATUS } from '../../common/constants/views'; +import { Issue, IssueSeverity, OssIssueData, LsErrorMessage } from '../../common/languageServer/types'; +import { IContextService } from '../../common/services/contextService'; +import { IProductService } from '../../common/services/productService'; +import { IViewManagerService } from '../../common/services/viewManagerService'; +import { ProductIssueTreeProvider } from '../../common/views/issueTreeProvider'; +import { TreeNode } from '../../common/views/treeNode'; +import { IVSCodeLanguages } from '../../common/vscode/languages'; +import { messages } from '../constants/messages'; +import { getOssIssueCommandArg } from './ossIssueCommandHelper'; +import { IFolderConfigs } from '../../common/configuration/folderConfigs'; + +export default class OssIssueTreeProvider extends ProductIssueTreeProvider { + constructor( + protected viewManagerService: IViewManagerService, + protected contextService: IContextService, + protected ossService: IProductService, + protected configuration: IConfiguration, + protected languages: IVSCodeLanguages, + protected readonly folderConfigs: IFolderConfigs, + ) { + super(contextService, ossService, configuration, languages, folderConfigs); + } + + getRootChildren(): TreeNode[] { + if (!configuration.getFeaturesConfiguration()?.ossEnabled) { + return [ + new TreeNode({ + text: SNYK_ANALYSIS_STATUS.OSS_DISABLED, + }), + ]; + } + + return super.getRootChildren(); + } + + override getResultNodes(): TreeNode[] { + const nodes: TreeNode[] = []; + + for (const result of this.productService.result.entries()) { + const folderPath = result[0]; + const folderResult = result[1]; + + const uri = Uri.file(folderPath); + const shortFolderPath = uri.path.split('/'); + const folderName = shortFolderPath.pop() || uri.path; + + let folderVulnCount = 0; + + if (folderResult instanceof Error && folderResult.message === LsErrorMessage.repositoryInvalidError.toString()) { + nodes.push(this.getFaultyRepositoryErrorTreeNode(folderName, folderResult.toString())); + continue; + } + + if (folderResult instanceof Error) { + nodes.push(this.getErrorEncounteredTreeNode(folderName)); + continue; + } + + const folderSeverityCounts = this.initSeverityCounts(); + const fileNodes: TreeNode[] = []; + + const fileVulns = _.groupBy(folderResult, v => v.filePath); + + for (const file in fileVulns) { + const fileIssues = fileVulns[file]; + const uri = Uri.file(file); + const filePath = uri.path.split('/'); + const filename = filePath.pop() || uri.path; + const dir = filePath.pop(); + + const fileSeverityCounts = this.initSeverityCounts(); + + const uniqueIssues = fileIssues.filter( + (issue, index, self) => index === self.findIndex(t => t.id === issue.id), + ); + + const filteredIssues = this.filterIssues(uniqueIssues); + + const vulnerabilityNodes: TreeNode[] = this.filterVisibleIssues(filteredIssues).map( + (issue: Issue) => { + fileSeverityCounts[issue.severity] += 1; + folderVulnCount++; + + return new TreeNode({ + text: `${issue.additionalData.packageName}@${issue.additionalData.version} - ${issue.title}`, + icon: ProductIssueTreeProvider.getSeverityIcon(issue.severity), + internal: { + severity: ProductIssueTreeProvider.getSeverityComparatorIndex(issue.severity), + }, + command: this.getOpenIssueCommand(issue, folderPath, '', filteredIssues), + }); + }, + ); + + if (vulnerabilityNodes.length === 0) { + continue; + } + + vulnerabilityNodes.sort(this.compareNodes); + + const fileSeverity = ProductIssueTreeProvider.getHighestSeverity(fileSeverityCounts); + folderSeverityCounts[fileSeverity] += 1; + + // append file node + const fileNode = new TreeNode({ + text: filename, + description: this.getIssueDescriptionText(dir, vulnerabilityNodes.length), + icon: ProductIssueTreeProvider.getSeverityIcon(fileSeverity), + children: vulnerabilityNodes, + internal: { + nIssues: vulnerabilityNodes.length, + severity: ProductIssueTreeProvider.getSeverityComparatorIndex(fileSeverity), + }, + }); + fileNodes.push(fileNode); + } + + fileNodes.sort(this.compareNodes); + + const folderSeverity = ProductIssueTreeProvider.getHighestSeverity(folderSeverityCounts); + + const baseBranchNode = this.getBaseBranch(uri.fsPath); + if (folderVulnCount == 0) { + this.addBaseBranchNode(baseBranchNode, nodes); + continue; + } + // flatten results if single workspace folder + if (this.productService.result.size === 1) { + this.addBaseBranchNode(baseBranchNode, nodes); + nodes.push(...fileNodes); + } else { + const folderNode = new TreeNode({ + text: folderName, + description: this.getIssueDescriptionText(folderName, folderVulnCount), + icon: ProductIssueTreeProvider.getSeverityIcon(folderSeverity), + children: fileNodes, + internal: { + nIssues: folderVulnCount, + severity: ProductIssueTreeProvider.getSeverityComparatorIndex(folderSeverity), + }, + }); + this.addBaseBranchNode(baseBranchNode, fileNodes); + nodes.push(folderNode); + } + } + + return nodes; + } + + onDidChangeTreeData = this.viewManagerService.refreshOssViewEmitter.event; + + shouldShowTree(): boolean { + return this.contextService.shouldShowOssAnalysis; + } + + getIssueDescriptionText(dir: string | undefined, issueCount: number): string | undefined { + return `${dir} - ${issueCount} ${issueCount === 1 ? 'vulnerability' : 'vulnerabilities'}`; + } + + getIssueFoundText(nIssues: number, _: number): string { + if (!nIssues) { + return '✅ Congrats! No issues found!'; + } + return `Snyk found ${nIssues} issue${nIssues === 1 ? '' : 's'}`; + } + + filterIssues(issues: Issue[]): Issue[] { + return issues.filter(vuln => { + switch (vuln.severity) { + case IssueSeverity.Critical: + return this.configuration.severityFilter.critical; + case IssueSeverity.High: + return this.configuration.severityFilter.high; + case IssueSeverity.Medium: + return this.configuration.severityFilter.medium; + case IssueSeverity.Low: + return this.configuration.severityFilter.low; + default: + return true; + } + }); + } + + getRunTestMessage = () => messages.treeView.runTest; + + getIssueTitle = (issue: Issue) => issue.title; + + getIssueRange = () => undefined; + + getOpenIssueCommand( + issue: Issue, + folderPath: string, + _filePath: string, + filteredIssues: Issue[], + ): Command { + return { + command: SNYK_OPEN_ISSUE_COMMAND, + title: '', + arguments: [ + { + issueType: OpenCommandIssueType.OssVulnerability, + issue: getOssIssueCommandArg(issue, folderPath, filteredIssues), + } as OpenIssueCommandArg, + ], + }; + } +} diff --git a/src/snyk/snykOss/services/ossService.ts b/src/snyk/snykOss/services/ossService.ts deleted file mode 100644 index 0a1cda3d7..000000000 --- a/src/snyk/snykOss/services/ossService.ts +++ /dev/null @@ -1,224 +0,0 @@ -import * as marked from 'marked'; -import { Subject } from 'rxjs'; -import { IExtension } from '../../base/modules/interfaces'; -import { CliError, CliService } from '../../cli/services/cliService'; -import { IAnalytics } from '../../common/analytics/itly'; -import { IConfiguration } from '../../common/configuration/configuration'; -import { IWorkspaceTrust } from '../../common/configuration/trustedFolders'; -import { IDE_NAME } from '../../common/constants/general'; -import { ILanguageServer } from '../../common/languageServer/languageServer'; -import { ILog } from '../../common/logger/interfaces'; -import { DownloadService } from '../../common/services/downloadService'; -import { INotificationService } from '../../common/services/notificationService'; -import { IViewManagerService } from '../../common/services/viewManagerService'; -import { IWebViewProvider } from '../../common/views/webviewProvider'; -import { ExtensionContext } from '../../common/vscode/extensionContext'; -import { IVSCodeWorkspace } from '../../common/vscode/workspace'; -import { messages } from '../messages/test'; -import { isResultCliError, OssFileResult, OssResult, OssSeverity, OssVulnerability } from '../ossResult'; -import { OssIssueCommandArg } from '../views/ossVulnerabilityTreeProvider'; -import { DailyScanJob } from '../watchers/dailyScanJob'; -import createManifestFileWatcher from '../watchers/manifestFileWatcher'; - -export class OssService extends CliService { - protected readonly command: string[] = ['test']; - - private isVulnerabilityTreeVisible = false; - - readonly scanFinished$ = new Subject(); - - constructor( - protected readonly extensionContext: ExtensionContext, - protected readonly logger: ILog, - protected readonly config: IConfiguration, - private readonly suggestionProvider: IWebViewProvider, - protected readonly workspace: IVSCodeWorkspace, - private readonly viewManagerService: IViewManagerService, - protected readonly downloadService: DownloadService, - private readonly dailyScanJob: DailyScanJob, - private readonly notificationService: INotificationService, - private readonly analytics: IAnalytics, - protected readonly languageServer: ILanguageServer, - protected readonly workspaceTrust: IWorkspaceTrust, - ) { - super(extensionContext, logger, config, workspace, downloadService, languageServer, workspaceTrust); - } - - public getResultArray = (): ReadonlyArray | undefined => { - if (!this.result) { - return undefined; - } - - return Array.isArray(this.result) ? this.result : [this.result]; - }; - - protected mapToResultType(rawCliResult: string): OssResult { - if (rawCliResult.length == 0) { - throw new Error('CLI returned empty output result.'); - } - - let result: OssResult; - try { - result = JSON.parse(rawCliResult) as OssResult; - } catch (err) { - throw new Error(`Failed to parse JSON result. Unparsed: ${rawCliResult}`); - } - - return result; - } - - protected ensureDependencies(): void { - this.viewManagerService.refreshOssView(); - this.logger.info('Waiting for Open Source scan CLI readiness'); - } - - protected beforeTest(manualTrigger: boolean, reportTriggeredEvent: boolean): void { - this.logger.info(messages.testStarted); - this.viewManagerService.refreshOssView(); - - if (reportTriggeredEvent) { - this.analytics.logAnalysisIsTriggered({ - analysisType: ['Snyk Open Source'], - ide: IDE_NAME, - triggeredByUser: manualTrigger, - }); - } - } - - protected afterTest(result: OssResult | CliError): void { - if (result instanceof CliError) { - this.logger.error(`${messages.testFailed} ${result.error}`); - this.logAnalysisIsReady('Error'); - } else { - this.logOssResult(result); - - if (this.config.shouldAutoScanOss) { - this.dailyScanJob.schedule(); - } - } - - this.scanFinished$.next(); - this.viewManagerService.refreshOssView(); - } - - override handleLsDownloadFailure(): void { - super.handleLsDownloadFailure(); - this.viewManagerService.refreshOssView(); - } - - override handleNoTrustedFolders(): void { - super.handleNoTrustedFolders(); - this.viewManagerService.refreshOssView(); - } - - activateSuggestionProvider(): void { - this.suggestionProvider.activate(); - } - - showSuggestionProvider(vulnerability: OssIssueCommandArg): Promise { - return this.suggestionProvider.showPanel(vulnerability); - } - - activateManifestFileWatcher(extension: IExtension): void { - const manifestWatcher = createManifestFileWatcher(extension, this.workspace, this.config); - this.extensionContext.addDisposables(manifestWatcher); - } - - setVulnerabilityTreeVisibility(visible: boolean): void { - this.isVulnerabilityTreeVisible = visible; - } - - getUniqueVulnerabilities(vulnerabilities: OssVulnerability[]): OssVulnerability[] { - return vulnerabilities.filter((val, i, arr) => arr.findIndex(el => el.id === val.id) == i); - } - - getNewCriticalVulnerabilitiesCount(currentResult: OssResult, otherResult: OssResult): number { - if (Array.isArray(currentResult) && Array.isArray(otherResult)) { - let newVulnerabilityCount = 0; - for (let i = 0; i < otherResult.length; i++) { - newVulnerabilityCount += this.getNewCriticalVulnerabilitiesCount(currentResult[i], otherResult[i]); - } - - return newVulnerabilityCount; - } - - // if only one of results is an array, no count possible - if (Array.isArray(currentResult) || Array.isArray(otherResult)) { - throw new Error('Result types mismatch for new vulnerabilities calculation.'); - } - - if (!currentResult || isResultCliError(currentResult)) { - return 0; - } - - const currentVulnSet = this.getUniqueVulnerabilities(currentResult.vulnerabilities).filter( - v => v.severity === OssSeverity.Critical, - ); - - if (isResultCliError(otherResult)) { - return currentVulnSet.length; - } - - const otherVulnSet = this.getUniqueVulnerabilities(otherResult.vulnerabilities).filter( - v => v.severity === OssSeverity.Critical, - ); - - if (currentVulnSet.length > otherVulnSet.length) { - return currentVulnSet.length - otherVulnSet.length; - } - - return 0; - } - - getOssIssueCommandArg( - vulnerability: OssVulnerability, - allVulnerabilities: OssVulnerability[], - ): Promise { - return new Promise((resolve, reject) => { - const matchingIdVulnerabilities = allVulnerabilities.filter(v => v.id === vulnerability.id); - marked.parse(vulnerability.description, (err, overviewHtml) => { - if (err) { - return reject(err); - } - - return resolve({ - ...vulnerability, - matchingIdVulnerabilities: matchingIdVulnerabilities, - overviewHtml, - }); - }); - }); - } - - private logOssResult(result: OssResult) { - const fileResults = Array.isArray(result) ? result : [result]; - - for (const fileResult of fileResults) { - if (isResultCliError(fileResult)) { - this.logger.error(this.getTestErrorMessage(fileResult)); - this.logAnalysisIsReady('Error'); - } else { - this.logger.info(messages.testFinished(fileResult.projectName)); - this.logAnalysisIsReady('Success'); - } - } - } - - private getTestErrorMessage(fileResult: CliError): string { - let errorMessage: string; - if (fileResult.path) { - errorMessage = `${messages.testFailedForPath(fileResult.path)} ${fileResult.error}`; - } else { - errorMessage = `${messages.testFailed} ${fileResult.error}`; - } - return errorMessage; - } - - private logAnalysisIsReady(result: 'Error' | 'Success'): void { - this.analytics.logAnalysisIsReady({ - ide: IDE_NAME, - analysisType: 'Snyk Open Source', - result, - }); - } -} diff --git a/src/snyk/snykOss/services/vulnerabilityCount/importedModule.ts b/src/snyk/snykOss/services/vulnerabilityCount/importedModule.ts index 0fe3843f2..809699fe6 100644 --- a/src/snyk/snykOss/services/vulnerabilityCount/importedModule.ts +++ b/src/snyk/snykOss/services/vulnerabilityCount/importedModule.ts @@ -24,7 +24,7 @@ export enum ModuleVulnerabilityCountSeverity { Critical = 'critical', } -export type SeverityCounts = { +type SeverityCounts = { [s in ModuleVulnerabilityCountSeverity]: number; }; diff --git a/src/snyk/snykOss/services/vulnerabilityCount/ossVulnerabilityCountService.ts b/src/snyk/snykOss/services/vulnerabilityCount/ossVulnerabilityCountService.ts index 787d0f36c..1c6f42b07 100644 --- a/src/snyk/snykOss/services/vulnerabilityCount/ossVulnerabilityCountService.ts +++ b/src/snyk/snykOss/services/vulnerabilityCount/ossVulnerabilityCountService.ts @@ -1,32 +1,26 @@ import { Subscription } from 'rxjs'; -import { IAnalytics } from '../../../common/analytics/itly'; import { IConfiguration } from '../../../common/configuration/configuration'; -import { HTML, JAVASCRIPT, PJSON, TYPESCRIPT } from '../../../common/constants/languageConsts'; import { ILog } from '../../../common/logger/interfaces'; import { getSupportedLanguage, isValidModuleName } from '../../../common/parsing'; import { ModuleParserProvider } from '../../../common/services/moduleParserProvider'; import { Language } from '../../../common/types'; -import { ICodeActionKindAdapter } from '../../../common/vscode/codeAction'; import { IVSCodeLanguages } from '../../../common/vscode/languages'; -import { Diagnostic, DiagnosticCollection, Disposable, TextDocument } from '../../../common/vscode/types'; +import { + Diagnostic, + DiagnosticCollection, + Disposable, + TextDocument, + TextDocumentChangeEvent, + TextEditor, +} from '../../../common/vscode/types'; import { IVSCodeWindow } from '../../../common/vscode/window'; import { IVSCodeWorkspace } from '../../../common/vscode/workspace'; import { DIAGNOSTICS_OSS_COLLECTION_NAME } from '../../../snykCode/constants/analysis'; -import { VulnerabilityCodeActionProvider } from '../../codeActions/vulnerabilityCodeActionProvider'; import { EditorDecorator } from '../../editor/editorDecorator'; -import { VulnerabilityCountHoverProvider } from '../../hoverProvider/vulnerabilityCountHoverProvider'; -import { messages } from '../../messages/vulnerabilityCount'; -import { VulnerabilityCountEmitter, VulnerabilityCountEvents } from '../../vulnerabilityCountEmitter'; -import { OssService } from '../ossService'; +import { OssService } from '../../ossService'; +import { OssVulnerabilityCountProvider } from '../../providers/ossVulnerabilityCountProvider'; import { ImportedModule, ModuleVulnerabilityCount, ModuleVulnerabilityCountSeverity } from './importedModule'; -import { ModuleVulnerabilityCountProvider } from './vulnerabilityCountProvider'; - -export enum SupportedLanguage { - TypeScript, - JavaScript, - HTML, - PJSON, -} +import { VulnerabilityCountEmitter, VulnerabilityCountEvents } from './vulnerabilityCountEmitter'; export class OssVulnerabilityCountService implements Disposable { protected disposables: Disposable[] = []; @@ -39,57 +33,38 @@ export class OssVulnerabilityCountService implements Disposable { private readonly workspace: IVSCodeWorkspace, private readonly window: IVSCodeWindow, private readonly languages: IVSCodeLanguages, - private readonly vulnerabilityCountProvider: ModuleVulnerabilityCountProvider, + private readonly vulnerabilityCountProvider: OssVulnerabilityCountProvider, private readonly ossService: OssService, private readonly logger: ILog, private readonly editorDecorator: EditorDecorator, - private readonly codeActionKindProvider: ICodeActionKindAdapter, - private readonly analytics: IAnalytics, private readonly configuration: IConfiguration, ) {} - activate(): boolean { this.disposables.push( (this.diagnostics = this.languages.createDiagnosticCollection(DIAGNOSTICS_OSS_COLLECTION_NAME)), - this.workspace.onDidChangeTextDocument(ev => { - if (ev.contentChanges.length) { - this.processFile(ev.document); + this.workspace.onDidChangeTextDocument((ev: TextDocumentChangeEvent) => { + if (ev?.contentChanges.length) { + // TODO: this feature is buggy if implemented; reset decorations instead as a compromise + // this.processFile(ev.document); + this.editorDecorator.resetDecorations(ev.document.fileName); } }), - this.window.onDidChangeActiveTextEditor(ev => { + this.window.onDidChangeActiveTextEditor((ev: TextEditor | undefined) => { if (ev) { this.processFile(ev.document); } }), - - // register hover provider - new VulnerabilityCountHoverProvider(this.languages, this.analytics).register(this.diagnostics), ); // Subscribe to OSS scan finished updates - this.ossScanFinishedSubscription = this.ossService.scanFinished$.subscribe(() => this.processActiveEditor()); - - [JAVASCRIPT, TYPESCRIPT, PJSON, HTML].forEach(language => { - const provider = new VulnerabilityCodeActionProvider( - this.ossService, - this.vulnerabilityCountProvider, - this.codeActionKindProvider, - this.analytics, - ); - this.disposables.push( - this.languages.registerCodeActionsProvider(language, provider, { - providedCodeActionKinds: provider.codeActionKinds, - }), - ); - }); - - this.processActiveEditor(); + this.ossScanFinishedSubscription = this.ossService.newResultAvailable$.subscribe(() => this.processActiveEditor()); return true; } processActiveEditor(): void { const activeEditor = this.window.getActiveTextEditor(); + if (activeEditor) { this.processFile(activeEditor.document); } @@ -131,20 +106,25 @@ export class OssVulnerabilityCountService implements Disposable { } emitter.on(VulnerabilityCountEvents.Error, e => { - this.logger.error(`Error counting module vulnerabilities: ${e}`); + this.logger.error(`Error counting module issues: ${e}`); this.editorDecorator.resetDecorations(fileName); }); emitter.on(VulnerabilityCountEvents.Start, (modules: ImportedModule[]) => { this.editorDecorator.setScanStartDecorations(fileName, modules); }); + emitter.on(VulnerabilityCountEvents.Scanned, (vulnerabilityCount: ModuleVulnerabilityCount) => { this.editorDecorator.setScannedDecoration(vulnerabilityCount, true); }); emitter.on(VulnerabilityCountEvents.Done, (modules: ModuleVulnerabilityCount[]) => { this.editorDecorator.setScanDoneDecorations(fileName, modules); - this.updateDiagnostics(document, modules); + // TODO: delete this and related code if we move HTML diagnostics to Language Server + // Update diagnostics only for HTML files; for other files, diagnostics are provided by Language Server + if (getSupportedLanguage(fileName, languageId) === Language.HTML) { + this.updateDiagnostics(document, modules); + } }); // Start @@ -188,7 +168,7 @@ export class OssVulnerabilityCountService implements Disposable { private shouldProcessFile(fileName: string, language: Language): boolean { if ([Language.TypeScript, Language.JavaScript, Language.PJSON].includes(language)) { - const ossResult = this.ossService.getResultArray(); + const ossResult = this.vulnerabilityCountProvider.getResultArray(); if (!ossResult) { return false; } @@ -215,16 +195,13 @@ export class OssVulnerabilityCountService implements Disposable { const modules = this.getModules(fileName, content, language).filter(isValidModuleName); emitter.startScanning(modules); - const promises = modules - .map(module => this.vulnerabilityCountProvider.getVulnerabilityCount(fileName, module, language)) - .map(promise => - promise.then(module => { - emitter.scanned(module); - return module; - }), - ); - const testedModules = await Promise.all(promises); - emitter.done(testedModules); + const vulnerabilityCountPromises = modules.map(module => + this.vulnerabilityCountProvider.getVulnerabilityCount(fileName, module, language, emitter), + ); + + const vulnerabilityCount = await Promise.all(vulnerabilityCountPromises); + + emitter.done(vulnerabilityCount); } catch (e) { emitter.error(e); } @@ -244,7 +221,7 @@ export class OssVulnerabilityCountService implements Disposable { return ''; } - let message = messages.diagnosticMessagePrefix(module); + let message = `Dependency ${module.name}${module.version ? `@${module.version}` : ''} has `; message += this.getSeverityCountMessage( [ ModuleVulnerabilityCountSeverity.Critical, @@ -254,7 +231,7 @@ export class OssVulnerabilityCountService implements Disposable { ], module, ); - message += messages.decoratorMessage(module.count); + return message; } diff --git a/src/snyk/snykOss/services/vulnerabilityCount/parsers/babelParser.ts b/src/snyk/snykOss/services/vulnerabilityCount/parsers/babelParser.ts index e898fbb78..f42023a36 100644 --- a/src/snyk/snykOss/services/vulnerabilityCount/parsers/babelParser.ts +++ b/src/snyk/snykOss/services/vulnerabilityCount/parsers/babelParser.ts @@ -2,7 +2,7 @@ import { parse as jsParse, ParserPlugin } from '@babel/parser'; import traverse, { TraverseOptions } from '@babel/traverse'; import * as t from '@babel/types'; import { Identifier, ImportDeclaration, V8IntrinsicIdentifier } from '@babel/types'; -import { glob } from 'glob'; +import { globSync } from 'glob'; import path from 'path'; import { JAVASCRIPT_FILE_REGEX, TYPESCRIPT_FILE_REGEX } from '../../../../common/constants/languageConsts'; import { ImportedModule, Language } from '../../../../common/types'; @@ -78,7 +78,7 @@ export class BabelParser extends ModuleParser { } private static isLocalFile(path: string): boolean { - const foundFiles = [...glob.sync(`${path}/index.*`), ...glob.sync(`${path}.*`)]; + const foundFiles = [...globSync(`${path}/index.*`), ...globSync(`${path}.*`)]; if (!foundFiles.length) { return false; } diff --git a/src/snyk/snykOss/services/vulnerabilityCount/parsers/packageJsonParser.ts b/src/snyk/snykOss/services/vulnerabilityCount/parsers/packageJsonParser.ts index 62be33178..f4142c5cd 100644 --- a/src/snyk/snykOss/services/vulnerabilityCount/parsers/packageJsonParser.ts +++ b/src/snyk/snykOss/services/vulnerabilityCount/parsers/packageJsonParser.ts @@ -2,16 +2,16 @@ import { ILog } from '../../../../common/logger/interfaces'; import { ImportedModule, OssRange } from '../../../../common/types'; import { ModuleParser } from './moduleParser'; -export type PackageJsonDependencies = { +type PackageJsonDependencies = { [dependency: string]: string; }; -export interface PackageJson { +interface PackageJson { dependencies: PackageJsonDependencies; devDependencies: PackageJsonDependencies; } -export interface DependencyLines { +interface DependencyLines { lines: string[]; offset: number; } diff --git a/src/snyk/snykOss/vulnerabilityCountEmitter.ts b/src/snyk/snykOss/services/vulnerabilityCount/vulnerabilityCountEmitter.ts similarity index 72% rename from src/snyk/snykOss/vulnerabilityCountEmitter.ts rename to src/snyk/snykOss/services/vulnerabilityCount/vulnerabilityCountEmitter.ts index 4564f0742..d2b66dc38 100644 --- a/src/snyk/snykOss/vulnerabilityCountEmitter.ts +++ b/src/snyk/snykOss/services/vulnerabilityCount/vulnerabilityCountEmitter.ts @@ -1,8 +1,7 @@ import EventEmitter from 'events'; -import { ImportedModule, ModuleVulnerabilityCount } from './services/vulnerabilityCount/importedModule'; +import { ImportedModule, ModuleVulnerabilityCount } from './importedModule'; export enum VulnerabilityCountEvents { - PackageJsonFound = 'packageJsonFound', Start = 'start', Scanned = 'scanned', Done = 'done', @@ -10,10 +9,6 @@ export enum VulnerabilityCountEvents { } export class VulnerabilityCountEmitter extends EventEmitter { - packageJsonFound(fileName: string): void { - this.emit(VulnerabilityCountEvents.PackageJsonFound, fileName); - } - startScanning(importedModules: ImportedModule[]): void { this.emit(VulnerabilityCountEvents.Start, importedModules); } @@ -26,6 +21,7 @@ export class VulnerabilityCountEmitter extends EventEmitter { this.emit(VulnerabilityCountEvents.Done, moduleInfos); } + // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents error(error: Error | unknown): void { this.emit(VulnerabilityCountEvents.Error, error); } diff --git a/src/snyk/snykOss/services/vulnerabilityCount/vulnerabilityCountProvider.ts b/src/snyk/snykOss/services/vulnerabilityCount/vulnerabilityCountProvider.ts deleted file mode 100644 index 3c852ae33..000000000 --- a/src/snyk/snykOss/services/vulnerabilityCount/vulnerabilityCountProvider.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { Language } from '../../../common/types'; -import { ILanguageClientAdapter } from '../../../common/vscode/languageClient'; -import { ITextDocumentAdapter } from '../../../common/vscode/textdocument'; -import { InlineValueText, LSPTextDocument } from '../../../common/vscode/types'; -import { IUriAdapter } from '../../../common/vscode/uri'; -import { OssFileResult, OssResultBody, OssVulnerability, isResultCliError } from '../../ossResult'; -import { OssService } from '../ossService'; -import { ImportedModule, ModuleVulnerabilityCount, SeverityCounts } from './importedModule'; - -export class ModuleVulnerabilityCountProvider { - constructor( - private readonly ossService: OssService, - private readonly lca: ILanguageClientAdapter, - private readonly uriAdapter: IUriAdapter, - private readonly textDocumentAdapter: ITextDocumentAdapter, - ) {} - - async getVulnerabilityCount( - fileName: string, - module: ImportedModule, - language: Language, - ): Promise { - const notCalculated = { - name: module.name, - fileName: module.fileName, - line: null, - range: null, - hasCount: false, - }; - - if ([Language.TypeScript, Language.JavaScript, Language.PJSON].includes(language)) { - // TODO use LS when OSS is moved to LS - const ossResult = this.ossService.getResultArray(); - if (!ossResult) { - return notCalculated; - } - - return this.mapOssResult(module, ossResult); - } else if (language == Language.HTML && module.loc) { - const uri = this.uriAdapter.file(fileName).toString(); - const doc: LSPTextDocument = this.textDocumentAdapter.create(uri, 'HTML', 1, ''); - const line = module.loc.start.line - 1; - const param = { - textDocument: { uri: doc.uri }, - range: { - start: { line: line, character: module.loc.start.column }, - end: { line: line, character: module.loc.end.column }, - }, - }; - const inlineValues: InlineValueText[] = await this.lca - .getLanguageClient() - .sendRequest('textDocument/inlineValue', param); - - if (inlineValues.length > 0) { - return { - name: module.name, - version: module.version, - fileName: module.fileName, - line: module.line, - range: module.loc, - count: inlineValues[0].text, - hasCount: true, - } as ModuleVulnerabilityCount; - } - } - - return notCalculated; - } - - isFilePartOfOssTest(filePath: string, ossFileResult: OssFileResult): boolean { - if (isResultCliError(ossFileResult)) { - return false; - } - - // File is considered to be part of OSS test if it has common root directory between OSS result path and filename path. - // This is since package.json always lies in the root directory folder of a project. - return filePath.startsWith(ossFileResult.path); - } - - private mapOssResult(module: ImportedModule, ossResult: ReadonlyArray): ModuleVulnerabilityCount { - const notCalculated = { - name: module.name, - fileName: module.fileName, - line: null, - hasCount: false, - range: null, - }; - - for (const fileResult of ossResult) { - if (!this.isFilePartOfOssTest(module.fileName, fileResult)) { - continue; - } - - const vulnerabilities = this.ossService.getUniqueVulnerabilities((fileResult as OssResultBody).vulnerabilities); - - // Sum up all vulnerabilities detected in first-level dependencies by OSS matching the imported module name. - // Ideally we want to use the same mechanism as NPM for determining the version used within users code. For now we stick with direct-vulnerability surfacing only. - const directVulnerabilities = vulnerabilities - .filter(v => v.name === module.name) - .filter(v => v.from.length == 2 && v.from[1].startsWith(module.name)); - const vulnerabilityCount = directVulnerabilities.length; - - // NPM allows declaration of the same direct dependency with multiple versions of it (e.g. {"dependencies": "webpack": "^4.44.1", "webpack": "^4.44.2",}). Thus, we should account for vulnerabilities that can be in different versions of the same package. - const hasSingleVersionVulnerability = directVulnerabilities.every( - vuln => vuln.version == directVulnerabilities[0].version, - ); - - let moduleVersion; - if (directVulnerabilities.length && hasSingleVersionVulnerability) { - moduleVersion = directVulnerabilities[0].version; - } - - const severityCounts = this.getSeverityCounts(directVulnerabilities); - const mostSevereVulnerability = this.getMostSevereVulnerability(directVulnerabilities); - - return { - name: module.name, - version: moduleVersion, - fileName: module.fileName, - count: `${vulnerabilityCount}`, - line: module.line, - range: module.loc, - hasCount: vulnerabilityCount > 0, - severityCounts, - mostSevereVulnerabilityId: mostSevereVulnerability?.id, - }; - } - - return notCalculated; - } - - private getSeverityCounts(directVulnerabilities: OssVulnerability[]): SeverityCounts { - return directVulnerabilities - .map(v => v.severity) - .reduce( - (arr, severity) => ({ - ...arr, - [severity]: directVulnerabilities.filter(v => v.severity == severity).length, - }), - {} as SeverityCounts, - ); - } - - private getMostSevereVulnerability(vulnerabilities: OssVulnerability[]): OssVulnerability | null { - return vulnerabilities.sort((a, b) => { - if (!a.cvssScore && !b.cvssScore) return 0; - if (!a.cvssScore) return 1; - if (!b.cvssScore) return -1; - - const cvssScore1 = parseFloat(a.cvssScore); - const cvssScore2 = parseFloat(b.cvssScore); - if (cvssScore1 > cvssScore2) { - return -1; - } else if (cvssScore1 < cvssScore2) { - return 1; - } - - return 0; - })?.[0]; - } -} diff --git a/src/snyk/snykOss/views/ossVulnerabilityTreeProvider.ts b/src/snyk/snykOss/views/ossVulnerabilityTreeProvider.ts deleted file mode 100644 index 17b9037b2..000000000 --- a/src/snyk/snykOss/views/ossVulnerabilityTreeProvider.ts +++ /dev/null @@ -1,230 +0,0 @@ -import { OpenCommandIssueType, OpenIssueCommandArg } from '../../common/commands/types'; -import { IConfiguration } from '../../common/configuration/configuration'; -import { SNYK_OPEN_ISSUE_COMMAND } from '../../common/constants/commands'; -import { SNYK_ANALYSIS_STATUS } from '../../common/constants/views'; -import { messages as commonMessages } from '../../common/messages/analysisMessages'; -import { IContextService } from '../../common/services/contextService'; -import { IViewManagerService } from '../../common/services/viewManagerService'; -import { AnalysisTreeNodeProvider } from '../../common/views/analysisTreeNodeProvider'; -import { INodeIcon, NODE_ICONS, TreeNode } from '../../common/views/treeNode'; -import { messages } from '../messages/treeView'; -import { isResultCliError, OssFileResult, OssSeverity, OssVulnerability } from '../ossResult'; -import { OssService } from '../services/ossService'; - -type ISeverityCounts = { - [key in OssSeverity]: number; -}; - -export type OssIssueCommandArg = OssVulnerability & { - matchingIdVulnerabilities: OssVulnerability[]; - overviewHtml: string; -}; - -export class OssVulnerabilityTreeProvider extends AnalysisTreeNodeProvider { - constructor( - protected readonly viewManagerService: IViewManagerService, - protected readonly contextService: IContextService, - protected readonly ossService: OssService, - protected readonly configuration: IConfiguration, - ) { - super(configuration, ossService); - } - - async getRootChildren(): Promise { - if (!this.configuration.getFeaturesConfiguration()?.ossEnabled) { - return [ - new TreeNode({ - text: SNYK_ANALYSIS_STATUS.OSS_DISABLED, - }), - ]; - } - - if (!this.contextService.shouldShowOssAnalysis) return []; - - if (!this.ossService.isLsDownloadSuccessful) { - return [this.getErrorEncounteredTreeNode()]; - } - - if (!this.ossService.isCliReady) { - return [ - new TreeNode({ - text: messages.cookingDependencies, - }), - ]; - } else if (!this.ossService.isAnyWorkspaceFolderTrusted) { - return [this.getNoWorkspaceTrustTreeNode()]; - } - - if (this.ossService.isAnalysisRunning) { - return [ - new TreeNode({ - text: commonMessages.scanRunning, - }), - ]; - } - - const ossResults = this.ossService.getResultArray(); - if (!ossResults) { - return [ - new TreeNode({ - text: messages.runTest, - }), - ]; - } - - const nodes: TreeNode[] = []; - const [resultNodes, totalVulnCount] = await this.getResultNodes(ossResults); - nodes.push(...resultNodes); - - if (ossResults.length == 1 && isResultCliError(ossResults[0])) { - return nodes; - } - - nodes.sort(this.compareNodes); - - const topNodes = [ - new TreeNode({ - text: this.getIssueFoundText(totalVulnCount), - }), - this.getDurationTreeNode(), - this.getNoSeverityFiltersSelectedTreeNode(), - ]; - nodes.unshift(...topNodes.filter((n): n is TreeNode => n !== null)); - - return nodes; - } - - protected getIssueFoundText(nIssues: number): string { - switch (nIssues) { - case 0: - return messages.noVulnerabilitiesFound; - case 1: - return messages.singleVulnerabilityFound; - default: - return messages.multipleVulnerabilitiesFound(nIssues); - } - } - - protected getIssueDescriptionText( - dir: string | undefined, - vulnerabilities: readonly OssVulnerability[], - ): string | undefined { - return `${dir} - ${vulnerabilities.length} ${ - vulnerabilities.length === 1 ? messages.vulnerability : messages.vulnerabilities - }`; - } - - static getSeverityIcon(severity: OssSeverity | string): INodeIcon { - return ( - { - [OssSeverity.Critical]: NODE_ICONS.critical, - [OssSeverity.High]: NODE_ICONS.high, - [OssSeverity.Medium]: NODE_ICONS.medium, - [OssSeverity.Low]: NODE_ICONS.low, - }[severity] || NODE_ICONS.low - ); - } - - static getFileSeverity(counts: ISeverityCounts): OssSeverity { - for (const s of [OssSeverity.Critical, OssSeverity.High, OssSeverity.Medium, OssSeverity.Low]) { - if (counts[s]) return s; - } - - return OssSeverity.Low; - } - - /** Returns severity significance index. The higher, the more significant severity is. */ - static getSeverityComparatorIndex(severity: OssSeverity): number { - return Object.values(OssSeverity).indexOf(severity); - } - - onDidChangeTreeData = this.viewManagerService.refreshOssViewEmitter.event; - - private initFileSeverityCounts(): ISeverityCounts { - return { - [OssSeverity.Critical]: 0, - [OssSeverity.High]: 0, - [OssSeverity.Medium]: 0, - [OssSeverity.Low]: 0, - }; - } - - protected getFilteredIssues(uniqueVulnerabilities: OssVulnerability[]): OssVulnerability[] { - return uniqueVulnerabilities.filter(vuln => { - switch (vuln.severity.toLowerCase()) { - case OssSeverity.Critical: - return this.configuration.severityFilter.critical; - case OssSeverity.High: - return this.configuration.severityFilter.high; - case OssSeverity.Medium: - return this.configuration.severityFilter.medium; - case OssSeverity.Low: - return this.configuration.severityFilter.low; - default: - return true; - } - }); - } - - private async getResultNodes(ossResults: ReadonlyArray): Promise<[TreeNode[], number]> { - const nodes: TreeNode[] = []; - let totalVulnCount = 0; - - for (const fileResult of ossResults) { - if (isResultCliError(fileResult)) { - nodes.push(this.getErrorEncounteredTreeNode(fileResult.path)); - continue; - } - - const counts: ISeverityCounts = this.initFileSeverityCounts(); - const vulnerabilityNodes: TreeNode[] = []; - - const uniqueVulns = this.ossService.getUniqueVulnerabilities(fileResult.vulnerabilities); - totalVulnCount += uniqueVulns.length; - - const fileVulnerabilities = this.getFilteredIssues(uniqueVulns); - if (fileVulnerabilities.length == 0) continue; - - for (const vuln of fileVulnerabilities) { - counts[vuln.severity]++; - vulnerabilityNodes.push( - new TreeNode({ - text: `${vuln.packageName}@${vuln.version} - ${vuln.title}`, - icon: OssVulnerabilityTreeProvider.getSeverityIcon(vuln.severity), - internal: { - severity: OssVulnerabilityTreeProvider.getSeverityComparatorIndex(vuln.severity), - }, - command: { - command: SNYK_OPEN_ISSUE_COMMAND, - title: '', - arguments: [ - { - issueType: OpenCommandIssueType.OssVulnerability, - // eslint-disable-next-line no-await-in-loop - issue: await this.ossService.getOssIssueCommandArg(vuln, fileResult.vulnerabilities), - } as OpenIssueCommandArg, - ], - }, - }), - ); - } - - vulnerabilityNodes.sort(this.compareNodes); - const fileSeverity = OssVulnerabilityTreeProvider.getFileSeverity(counts); - - const fileNode = new TreeNode({ - text: fileResult.displayTargetFile, - description: this.getIssueDescriptionText(fileResult.projectName, fileVulnerabilities), - icon: OssVulnerabilityTreeProvider.getSeverityIcon(fileSeverity), - children: vulnerabilityNodes, - internal: { - nIssues: vulnerabilityNodes.length, - severity: OssVulnerabilityTreeProvider.getSeverityComparatorIndex(fileSeverity), - }, - }); - nodes.push(fileNode); - } - - return [nodes, totalVulnCount]; - } -} diff --git a/src/snyk/snykOss/views/suggestion/ossSuggestionWebviewProvider.ts b/src/snyk/snykOss/views/suggestion/ossSuggestionWebviewProvider.ts deleted file mode 100644 index 8d9ad8b86..000000000 --- a/src/snyk/snykOss/views/suggestion/ossSuggestionWebviewProvider.ts +++ /dev/null @@ -1,210 +0,0 @@ -import * as vscode from 'vscode'; -import { SNYK_OPEN_BROWSER_COMMAND } from '../../../common/constants/commands'; -import { SNYK_VIEW_SUGGESTION_OSS } from '../../../common/constants/views'; -import { ErrorHandler } from '../../../common/error/errorHandler'; -import { ILog } from '../../../common/logger/interfaces'; -import { messages as learnMessages } from '../../../common/messages/learn'; -import { LearnService } from '../../../common/services/learnService'; -import { getNonce } from '../../../common/views/nonce'; -import { WebviewPanelSerializer } from '../../../common/views/webviewPanelSerializer'; -import { WebviewProvider } from '../../../common/views/webviewProvider'; -import { ExtensionContext } from '../../../common/vscode/extensionContext'; -import { IVSCodeWindow } from '../../../common/vscode/window'; -import { messages as errorMessages } from '../../messages/error'; -import { OssIssueCommandArg } from '../ossVulnerabilityTreeProvider'; - -enum OssSuggestionsViewEventMessageType { - OpenBrowser = 'openBrowser', -} - -type OssSuggestionViewEventMessage = { - type: OssSuggestionsViewEventMessageType; - value: unknown; -}; - -export class OssSuggestionWebviewProvider extends WebviewProvider { - constructor( - protected readonly context: ExtensionContext, - private readonly window: IVSCodeWindow, - protected readonly logger: ILog, - private readonly learnService: LearnService, - ) { - super(context, logger); - } - - activate(): void { - this.context.addDisposables( - this.window.registerWebviewPanelSerializer(SNYK_VIEW_SUGGESTION_OSS, new WebviewPanelSerializer(this)), - ); - } - - async postLearnLessonMessage(vulnerability: OssIssueCommandArg): Promise { - try { - if (this.panel) { - const lesson = await this.learnService.getOssLesson(vulnerability); - if (lesson) { - void this.panel.webview.postMessage({ - type: 'setLesson', - args: { url: lesson.url, title: learnMessages.lessonButtonTitle }, - }); - } else { - void this.panel.webview.postMessage({ - type: 'setLesson', - args: null, - }); - } - } - } catch (e) { - ErrorHandler.handle(e, this.logger, learnMessages.getLessonError); - } - } - - async showPanel(vulnerability: OssIssueCommandArg): Promise { - try { - await this.focusSecondEditorGroup(); - - if (this.panel) { - this.panel.reveal(vscode.ViewColumn.Two, true); - } else { - this.panel = vscode.window.createWebviewPanel( - SNYK_VIEW_SUGGESTION_OSS, - 'Snyk OSS Vulnerability', - { - viewColumn: vscode.ViewColumn.Two, - preserveFocus: true, - }, - this.getWebviewOptions(), - ); - this.registerListeners(); - } - - this.panel.webview.html = this.getHtmlForWebview(this.panel.webview); - this.panel.iconPath = vscode.Uri.joinPath( - vscode.Uri.file(this.context.extensionPath), - 'media', - 'images', - 'snyk-oss.svg', - ); - - void this.panel.webview.postMessage({ type: 'set', args: vulnerability }); - void this.postLearnLessonMessage(vulnerability); - } catch (e) { - ErrorHandler.handle(e, this.logger, errorMessages.suggestionViewShowFailed); - } - } - - protected registerListeners(): void { - if (!this.panel) return; - - this.panel.onDidDispose(() => this.onPanelDispose(), null, this.disposables); - this.panel.webview.onDidReceiveMessage( - (data: OssSuggestionViewEventMessage) => { - switch (data.type) { - case OssSuggestionsViewEventMessageType.OpenBrowser: - void vscode.commands.executeCommand(SNYK_OPEN_BROWSER_COMMAND, data.value); - break; - default: - break; - } - }, - null, - this.disposables, - ); - this.panel.onDidChangeViewState(() => this.checkVisibility(), null, this.disposables); - } - - protected getHtmlForWebview(webview: vscode.Webview): string { - const images: Record = [ - ['icon-code', 'svg'], - ['dark-critical-severity', 'svg'], - ['dark-high-severity', 'svg'], - ['dark-medium-severity', 'svg'], - ['dark-low-severity', 'svg'], - ['learn-icon', 'svg'], - ].reduce((accumulator: Record, [name, ext]) => { - const uri = this.getWebViewUri('media', 'images', `${name}.${ext}`); - if (!uri) throw new Error('Image missing.'); - accumulator[name] = uri.toString(); - return accumulator; - }, {}); - - const scriptUri = this.getWebViewUri( - 'out', - 'snyk', - 'snykOss', - 'views', - 'suggestion', - 'ossSuggestionWebviewScript.js', - ); - const styleUri = this.getWebViewUri('media', 'views', 'oss', 'suggestion', 'suggestion.css'); - const learnStyleUri = this.getWebViewUri('media', 'views', 'common', 'learn.css'); - - const nonce = getNonce(); - - return ` - - - - - - - - - - - - -
-
-
- - - - - - - - - -
-
-
-
- - -
-
-
-
-
Vulnerable module
-
-
-
-
Introduced through
-
-
-
-
Fixed in
-
-
-
-
Exploit maturity
-
-
-
-
-

Detailed paths

-
-
-
-
-
-
- - - `; - } -} diff --git a/src/snyk/snykOss/views/suggestion/ossSuggestionWebviewScript.ts b/src/snyk/snykOss/views/suggestion/ossSuggestionWebviewScript.ts deleted file mode 100644 index 5dce4e32d..000000000 --- a/src/snyk/snykOss/views/suggestion/ossSuggestionWebviewScript.ts +++ /dev/null @@ -1,293 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/// -// This script will be run within the webview itself -// It cannot access the main VS Code APIs directly. -(function () { - // TODO: Redefine types until bundling is introduced into extension - // https://stackoverflow.com/a/56938089/1713082 - type Vulnerability = { - id: string; - license?: string; - identifiers?: Identifiers; - title: string; - description: string; - language: string; - packageManager: string; - packageName: string; - severity: string; - name: string; - version: string; - exploit?: string; - - CVSSv3?: string; - cvssScore?: string; - - fixedIn?: Array; - from: Array; - upgradePath: Array; - isPatchable: boolean; - isUpgradable: boolean; - - matchingIdVulnerabilities: Vulnerability[]; - overviewHtml: string; - }; - - type Lesson = { - url: string; - title: string; - }; - - type Identifiers = { - CWE: string[]; - CVE: string[]; - }; - - const vscode = acquireVsCodeApi(); - let vulnerability = {} as Vulnerability; - - let lesson: Lesson | null; - - function navigateToUrl(url: string) { - vscode.postMessage({ - type: 'openBrowser', - value: url, - }); - } - - function fillLearnLink() { - const learnWrapper = document.querySelector('.learn')!; - learnWrapper.className = 'learn'; - - if (lesson) { - const learnLink = document.querySelector('.learn--link')!; - learnLink.innerText = lesson.title; - const lessonUrl = lesson.url; - learnLink.onclick = () => navigateToUrl(lessonUrl); - learnWrapper.className = 'learn show'; - } - } - - function showCurrentSuggestion() { - const severity = document.querySelector('.severity')!; - const title = document.querySelector('.suggestion .suggestion-text')!; - - // Set title - title.innerHTML = vulnerability.title; - - // Set severity icon - setSeverityIcon(); - - // Fill identifiers line - fillIdentifiers(); - - // Fill summary - fillSummary(); - - // Fill detailed paths - fillDetailedPaths(); - - // Fill overview - fillOverview(); - - function setSeverityIcon() { - if (vulnerability.severity) { - severity.querySelectorAll('img').forEach(n => { - if (n.id.slice(-1) === 'l') { - if (n.id.includes(vulnerability.severity)) n.className = 'icon light-only'; - else n.className = 'icon light-only hidden'; - } else { - if (n.id.includes(vulnerability.severity)) n.className = 'icon dark-only'; - else n.className = 'icon dark-only hidden'; - } - }); - } else { - severity.querySelectorAll('img').forEach(n => (n.className = 'icon hidden')); - } - } - - function fillIdentifiers() { - const identifiers = document.querySelector('.identifiers')!; - identifiers.innerHTML = ''; // reset node - const type = vulnerability.license ? 'License' : 'Vulnerability'; - const typeNode = document.createTextNode(type); - identifiers.appendChild(typeNode); - - vulnerability.identifiers?.CVE.forEach(cve => - appendIdentifierSpan(identifiers, cve, `https://cve.mitre.org/cgi-bin/cvename.cgi?name=${cve}`), - ); - vulnerability.identifiers?.CWE.forEach(cwe => appendIdentifierSpan(identifiers, cwe, getCweLink(cwe))); - if (vulnerability.cvssScore) appendIdentifierSpan(identifiers, `CVSS ${vulnerability.cvssScore}`); - appendIdentifierSpan(identifiers, vulnerability.id.toUpperCase(), `https://snyk.io/vuln/${vulnerability.id}`); - } - - function fillSummary() { - const module = document.querySelector('.module > .content')!; - module.textContent = vulnerability.name; - - const maturity = document.querySelector('.maturity > .content')!; - if (!vulnerability.exploit) { - maturity.classList.add('hidden'); - } else { - maturity.textContent = vulnerability.exploit; - } - - const introducedThrough = document.querySelector('.introduced-through > .content')!; - introducedThrough.innerHTML = ''; // reset node - if (vulnerability.from.length == 0) { - introducedThrough.classList.add('hidden'); - } else { - let modules = vulnerability.matchingIdVulnerabilities - .filter(vuln => vuln.from.length > 1) - .map(vuln => vuln.from[1]); - modules = [...new Set(modules)]; // obtain distinct only - - modules.forEach((module, i, arr) => { - appendIntroducedThroughSpan(introducedThrough, module, vulnerability.packageManager); - if (i != arr.length - 1) introducedThrough.append(document.createTextNode(', ')); - }); - } - - const fixedIn = document.querySelector('.fixed-in > .content')!; - fixedIn.innerHTML = ''; // reset node - if (!vulnerability.fixedIn || vulnerability.fixedIn.length == 0) { - fixedIn.append('Not fixed'); - } else { - fixedIn.append(vulnerability.name + '@'); - vulnerability.fixedIn.forEach((version, i, arr) => { - let versionStr = version; - if (i != arr.length - 1) versionStr = versionStr + ', '; - fixedIn.append(versionStr); - }); - } - } - - function fillDetailedPaths() { - const paths = document.querySelector('.detailed-paths')!; - paths.innerHTML = ''; // reset node - - vulnerability.matchingIdVulnerabilities.forEach(vuln => { - const introducedThrough = vuln.from.join(' > '); - - const isOutdated = vuln.upgradePath && vuln.upgradePath[1] === vuln.from[1]; - - // The logic as in registry - // https://github.com/snyk/registry/blob/5fe141a3c5eeb6b2c5e62cfa2b5a8643df29403d/frontend/src/components/IssueCardVulnerablePath/IssueCardVulnerablePath.vue#L109 - let remediationAdvice: string; - const upgradeMessage = `Upgrade to ${vuln.upgradePath[1]}`; - - if (vuln.isUpgradable || vuln.isPatchable) { - if (isOutdated) { - remediationAdvice = vuln.isPatchable ? upgradeMessage : getOutdatedDependencyMessage(vuln); - } else { - remediationAdvice = upgradeMessage; - } - } else { - remediationAdvice = 'none'; - } - - const html = ` -
-
Introduced through
-
${introducedThrough}
-
-
-
Remediation
-
${remediationAdvice}
-
`; - - const path = document.createElement('div'); - path.className = 'detailed-path'; - path.innerHTML = html; - paths.append(path); - }); - } - - function fillOverview() { - const overview = document.getElementById('overview')!; - overview.innerHTML = vulnerability.overviewHtml; - } - } - - function getCweLink(cwe: string) { - const id = cwe.toUpperCase().replace('CWE-', ''); - return `https://cwe.mitre.org/data/definitions/${id}.html`; - } - - function appendIdentifierSpan(identifiers: Element, id: string, link?: string) { - const delimiter = document.createElement('span'); - // delimiter.innerText = ' | '; - delimiter.className = 'delimiter'; - identifiers.appendChild(delimiter); - - let cveNode: HTMLElement; - if (link) { - cveNode = document.createElement('a'); - cveNode.onclick = () => navigateToUrl(link); - } else { - cveNode = document.createElement('span'); - } - - cveNode.innerText = id; - - identifiers.appendChild(cveNode); - } - - function appendIntroducedThroughSpan(introducedThrough: Element, module: string, packageManager: string) { - const supportedPackageManagers = ['npm']; - - let node: HTMLElement; - // replicate app.snyk.io linking logic from https://github.com/snyk/registry/blob/c78f0ae84dc20f25146880b3d3d5661f3d3e4db2/frontend/src/lib/issue-utils.ts#L547 - if (supportedPackageManagers.includes(packageManager.toLowerCase())) { - node = document.createElement('a'); - node.onclick = () => navigateToUrl(`https://app.snyk.io/test/${packageManager}/${module}`); - } else { - node = document.createElement('span'); - } - - node.innerText = module; - introducedThrough.appendChild(node); - } - - function getOutdatedDependencyMessage(vulnerability: Vulnerability) { - return `Your dependencies are out of date, otherwise you would be using a newer ${vulnerability.name} than ${ - vulnerability.name - }@${vulnerability.version}. - ${ - ['npm', 'yarn', 'yarn-workspace'].includes(vulnerability.packageManager) - ? `Try relocking your lockfile or deleting node_modules and reinstalling your dependencies. If the problem persists, one of your dependencies may be bundling outdated modules.` - : 'Try reinstalling your dependencies. If the problem persists, one of your dependencies may be bundling outdated modules.' - }`; - } - - window.addEventListener('message', event => { - const { type, args } = event.data; - switch (type) { - case 'set': { - vulnerability = args; - vscode.setState({ ...vscode.getState(), vulnerability }); - showCurrentSuggestion(); - break; - } - case 'get': { - vulnerability = vscode.getState()?.vulnerability || {}; - showCurrentSuggestion(); - break; - } - case 'setLesson': { - lesson = args; - vscode.setState({ ...vscode.getState(), lesson }); - fillLearnLink(); - break; - } - case 'getLesson': { - lesson = vscode.getState()?.lesson || null; - fillLearnLink(); - break; - } - } - }); -})(); diff --git a/src/snyk/snykOss/watchers/dailyScanJob.ts b/src/snyk/snykOss/watchers/dailyScanJob.ts deleted file mode 100644 index 6b21793b8..000000000 --- a/src/snyk/snykOss/watchers/dailyScanJob.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { IExtension } from '../../base/modules/interfaces'; - -export class DailyScanJob { - private readonly dayInMs = 86400000; - private job: NodeJS.Timeout; - - constructor(private readonly extension: IExtension) {} - - schedule(): void { - if (this.job) { - this.job.refresh(); - return; - } - - this.job = setTimeout(() => { - void this.extension.runOssScan(false); - }, this.dayInMs); - } -} diff --git a/src/snyk/snykOss/watchers/manifestFileWatcher.ts b/src/snyk/snykOss/watchers/manifestFileWatcher.ts deleted file mode 100644 index 9a13c05c1..000000000 --- a/src/snyk/snykOss/watchers/manifestFileWatcher.ts +++ /dev/null @@ -1,59 +0,0 @@ -import * as vscode from 'vscode'; -import { IExtension } from '../../base/modules/interfaces'; -import { IConfiguration } from '../../common/configuration/configuration'; -import { IVSCodeWorkspace } from '../../common/vscode/workspace'; - -// to be kept in sync with Snyk CLI support list -// copied from https://github.com/snyk/snyk/blob/93ec5896282e3ba1389dc5604589d2773a4bf517/src/lib/package-managers.ts#L21 -enum SUPPORTED_MANIFEST_FILES { - GEMFILE = 'Gemfile', - GEMFILE_LOCK = 'Gemfile.lock', - GEMSPEC = '*.gemspec', - PACKAGE_LOCK_JSON = 'package-lock.json', - POM_XML = 'pom.xml', - JAR = '*.jar', - WAR = '*.war', - BUILD_GRADLE = 'build.gradle', - BUILD_GRADLE_KTS = 'build.gradle.kts', - BUILD_SBT = 'build.sbt', - YARN_LOCK = 'yarn.lock', - PACKAGE_JSON = 'package.json', - PIPFILE = 'Pipfile', - SETUP_PY = 'setup.py', - REQUIREMENTS_TXT = 'requirements.txt', - GOPKG_LOCK = 'Gopkg.lock', - GO_MOD = 'go.mod', - VENDOR_JSON = 'vendor.json', - PROJECT_ASSETS_JSON = 'project.assets.json', - PACKAGES_CONFIG = 'packages.config', - PROJECT_JSON = 'project.json', - PAKET_DEPENDENCIES = 'paket.dependencies', - COMPOSER_LOCK = 'composer.lock', - PODFILE_LOCK = 'Podfile.lock', - COCOAPODS_PODFILE_YAML = 'CocoaPods.podfile.yaml', - COCOAPODS_PODFILE = 'CocoaPods.podfile', - PODFILE = 'Podfile', - POETRY_LOCK = 'poetry.lock', - MIX_EXS = 'mix.exs', -} - -export default function createManifestFileWatcher( - extension: IExtension, - workspace: IVSCodeWorkspace, - configuration: IConfiguration, -): vscode.FileSystemWatcher { - const globPattern = `**/{${Object.values(SUPPORTED_MANIFEST_FILES).join(',')}}`; - const watcher = workspace.createFileSystemWatcher(globPattern); - - watcher.onDidChange(() => runOssScan()); - watcher.onDidDelete(() => runOssScan()); - watcher.onDidCreate(() => runOssScan()); - - function runOssScan() { - if (configuration.shouldAutoScanOss) { - void extension.runOssScan(); - } - } - - return watcher; -} diff --git a/src/test/integration/analytics.test.ts b/src/test/integration/analytics.test.ts deleted file mode 100644 index 8edadf5bf..000000000 --- a/src/test/integration/analytics.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { strictEqual } from 'assert'; -import * as sinon from 'sinon'; -import * as vscode from 'vscode'; -import itly from '../../ampli'; -import { configuration } from '../../snyk/common/configuration/instance'; -import { VSCODE_VIEW_CONTAINER_COMMAND } from '../../snyk/common/constants/commands'; - -suite('Analytics', () => { - let welcomeIsViewed: sinon.SinonSpy; - - setup(async () => { - await configuration.clearToken(); - await configuration.setShouldReportEvents(true); - - welcomeIsViewed = sinon.spy(itly, 'welcomeIsViewed'); - }); - - teardown(() => { - welcomeIsViewed.restore(); - }); - - test('"Welcome Is Viewed" is tracked if telemetry is on', async () => { - await vscode.commands.executeCommand(VSCODE_VIEW_CONTAINER_COMMAND); - - strictEqual(welcomeIsViewed.called, true); - strictEqual(welcomeIsViewed.calledOnce, true); - }); - - test('"Welcome Is Viewed" not tracked if telemetry is off', async () => { - await configuration.setShouldReportEvents(false); - - await vscode.commands.executeCommand('workbench.action.toggleSidebarVisibility'); - await vscode.commands.executeCommand(VSCODE_VIEW_CONTAINER_COMMAND); - - strictEqual(welcomeIsViewed.notCalled, true); - }); - - test('"Welcome Is Viewed" not tracked if using fedramp endpoint', async () => { - await configuration.setEndpoint('https://api.feddramp.snykgov.io'); - await vscode.commands.executeCommand('workbench.action.toggleSidebarVisibility'); - await vscode.commands.executeCommand(VSCODE_VIEW_CONTAINER_COMMAND); - - strictEqual(welcomeIsViewed.notCalled, true); - }); -}); diff --git a/src/test/integration/configuration.test.ts b/src/test/integration/configuration.test.ts index 1e6f92607..5c3e5d43a 100644 --- a/src/test/integration/configuration.test.ts +++ b/src/test/integration/configuration.test.ts @@ -1,33 +1,35 @@ import { deepStrictEqual, strictEqual } from 'assert'; import { FeaturesConfiguration } from '../../snyk/common/configuration/configuration'; import { configuration } from '../../snyk/common/configuration/instance'; +import vscode from 'vscode'; +import { ADVANCED_CUSTOM_ENDPOINT } from '../../snyk/common/constants/settings'; suite('Configuration', () => { - test('configuration constants differ between DEV and PROD', () => { - process.env.SNYK_VSCE_DEVELOPMENT = ''; - strictEqual(configuration.snykCodeBaseURL, 'https://deeproxy.snyk.io'); - strictEqual(configuration.authHost, 'https://snyk.io'); + test('settings change is reflected', async () => { + await vscode.workspace.getConfiguration().update(ADVANCED_CUSTOM_ENDPOINT, ''); + strictEqual(configuration.snykCodeUrl, 'https://app.snyk.io/manage/snyk-code?from=vscode'); + strictEqual(configuration.authHost, 'https://app.snyk.io'); - process.env.SNYK_VSCE_DEVELOPMENT = '1'; - strictEqual(configuration.snykCodeBaseURL, 'https://deeproxy.dev.snyk.io'); - strictEqual(configuration.authHost, 'https://dev.snyk.io'); + await vscode.workspace.getConfiguration().update(ADVANCED_CUSTOM_ENDPOINT, 'https://api.snyk.io'); + strictEqual(configuration.snykCodeUrl, 'https://app.snyk.io/manage/snyk-code?from=vscode'); + strictEqual(configuration.authHost, 'https://app.snyk.io'); + + await vscode.workspace.getConfiguration().update(ADVANCED_CUSTOM_ENDPOINT, 'https://api.dev.snyk.io'); + strictEqual(configuration.snykCodeUrl, 'https://app.dev.snyk.io/manage/snyk-code?from=vscode'); + strictEqual(configuration.authHost, 'https://app.dev.snyk.io'); }); test('configuration change is reflected', async () => { - const token = 'fake-token'; const featuresConfig = { - ossEnabled: true, - codeSecurityEnabled: true, + ossEnabled: false, + codeSecurityEnabled: false, codeQualityEnabled: false, + iacEnabled: false, } as FeaturesConfiguration; - await configuration.setToken(token); await configuration.setFeaturesConfiguration(featuresConfig); - await configuration.setShouldReportEvents(false); - strictEqual(await configuration.getToken(), token); deepStrictEqual(configuration.getFeaturesConfiguration(), featuresConfig); - strictEqual(configuration.shouldReportEvents, false); await configuration.setToken(''); }); }); diff --git a/src/test/integration/index.ts b/src/test/integration/index.ts index 52ed124ae..47430fc61 100644 --- a/src/test/integration/index.ts +++ b/src/test/integration/index.ts @@ -1,8 +1,8 @@ -import path from 'path'; +import { glob } from 'glob'; import Mocha from 'mocha'; -import glob from 'glob'; +import path from 'path'; -export function run(): Promise { +export async function run(): Promise { // Create the mocha test const mocha = new Mocha({ ui: 'tdd', @@ -12,28 +12,22 @@ export function run(): Promise { const testsRoot = path.resolve(__dirname, '.'); - return new Promise((c, e) => { - glob('./**/**.test.js', { cwd: testsRoot }, (err, files) => { - if (err) { - return e(err); - } + try { + const files = await glob('./**/**.test.js', { cwd: testsRoot }); - // Add files to the test suite - files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); + files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); - try { - // Run the mocha test - mocha.run(failures => { - if (failures > 0) { - e(new Error(`${failures} tests failed.`)); - } else { - c(); - } - }); - } catch (err) { - console.error(err); - e(err); - } + return new Promise((resolve, reject) => { + mocha.run(failures => { + if (failures > 0) { + reject(new Error(`${failures} tests failed.`)); + } else { + resolve(); + } + }); }); - }); + } catch (err) { + console.error(err); + throw err; // Rethrow the error for the caller to handle + } } diff --git a/src/test/integration/issueTreeProvider.test.ts b/src/test/integration/issueTreeProvider.test.ts new file mode 100644 index 000000000..d685ab26c --- /dev/null +++ b/src/test/integration/issueTreeProvider.test.ts @@ -0,0 +1,240 @@ +import sinon from 'sinon'; +import * as vscode from 'vscode'; + +import { IVSCodeLanguages } from '../../snyk/common/vscode/languages'; +import { CodeIssueData, ScanProduct } from '../../snyk/common/languageServer/types'; +import { IContextService } from '../../snyk/common/services/contextService'; +import { IProductService } from '../../snyk/common/services/productService'; +import { IssueTreeProvider } from '../../snyk/snykCode/views/issueTreeProvider'; +import { strictEqual } from 'assert'; +import { FEATURE_FLAGS } from '../../snyk/common/constants/featureFlags'; +import { configuration } from '../../snyk/common/configuration/instance'; +import { ISSUE_VIEW_OPTIONS_SETTING } from '../../snyk/common/constants/settings'; +import { IFolderConfigs } from '../../snyk/common/configuration/folderConfigs'; + +suite('Code Issue Tree Provider', () => { + let contextService: IContextService; + let codeService: IProductService; + let languages: IVSCodeLanguages; + let folderConfigs: IFolderConfigs; + + let issueTreeProvider: IssueTreeProvider; + + setup(() => { + contextService = { + shouldShowCodeAnalysis: true, + } as unknown as IContextService; + codeService = { + isLsDownloadSuccessful: true, + isAnyWorkspaceFolderTrusted: true, + isAnalysisRunning: false, + isAnyResultAvailable: () => true, + result: { + values: () => [[]], + }, + getSnykProductType: () => ScanProduct.Code, + } as unknown as IProductService; + configuration.setFeatureFlag(FEATURE_FLAGS.consistentIgnores, true); + languages = {} as unknown as IVSCodeLanguages; + folderConfigs = {} as unknown as IFolderConfigs; + }); + + teardown(() => { + sinon.restore(); + }); + + test('getRootChildren returns no extra root children', () => { + const localCodeService = { + ...codeService, + result: { + values: () => [ + [ + { + filePath: '//folderName//test.js', + isIgnored: false, + additionalData: { + rule: 'some-rule', + hasAIFix: false, + isSecurityType: true, + }, + } as unknown as CodeIssueData, + ], + ], + }, + } as unknown as IProductService; + + issueTreeProvider = new IssueTreeProvider( + contextService, + localCodeService, + configuration, + languages, + true, + folderConfigs, + ); + + sinon.stub(issueTreeProvider, 'getResultNodes').returns([]); + const rootChildren = issueTreeProvider.getRootChildren(); + strictEqual(rootChildren.length, 2); + strictEqual(rootChildren[0].label, 'Snyk found 1 issue'); + strictEqual(rootChildren[1].label, 'There are no issues fixable by Snyk DeepCode AI'); + }); + + test('getRootChildren returns a root child for no results', () => { + const localCodeService = { + ...codeService, + result: { + values: () => [[]], + }, + } as unknown as IProductService; + + issueTreeProvider = new IssueTreeProvider( + contextService, + localCodeService, + configuration, + languages, + true, + folderConfigs, + ); + + sinon.stub(issueTreeProvider, 'getResultNodes').returns([]); + const rootChildren = issueTreeProvider.getRootChildren(); + strictEqual(rootChildren.length, 1); + strictEqual(rootChildren[0].label, '✅ Congrats! No issues found!'); + }); + + test('getRootChildren returns a root child for only open but not visible issues', async () => { + const localCodeService = { + ...codeService, + result: { + values: () => [ + [ + { + filePath: '//folderName//test.js', + additionalData: { + rule: 'some-rule', + hasAIFix: false, + isIgnored: false, + isSecurityType: true, + }, + } as unknown as CodeIssueData, + ], + ], + }, + } as unknown as IProductService; + + await vscode.workspace.getConfiguration().update(ISSUE_VIEW_OPTIONS_SETTING, { + openIssues: false, + ignoredIssues: true, + }); + configuration.issueViewOptions.openIssues = false; + issueTreeProvider = new IssueTreeProvider( + contextService, + localCodeService, + configuration, + languages, + true, + folderConfigs, + ); + + sinon.stub(issueTreeProvider, 'getResultNodes').returns([]); + const rootChildren = issueTreeProvider.getRootChildren(); + strictEqual(rootChildren.length, 3); + strictEqual(rootChildren[0].label, 'Snyk found 1 issue'); + strictEqual(rootChildren[1].label, 'There are no issues fixable by Snyk DeepCode AI'); + strictEqual(rootChildren[2].label, 'Adjust your Issue View Options to see open issues.'); + await vscode.workspace.getConfiguration().update(ISSUE_VIEW_OPTIONS_SETTING, { + openIssues: true, + ignoredIssues: true, + }); + }); + + test('getRootChildren returns a root child for only ignored but not visible issues', async () => { + const localCodeService = { + ...codeService, + result: { + values: () => [ + [ + { + filePath: '//folderName//test.js', + isIgnored: true, + additionalData: { + rule: 'some-rule', + hasAIFix: false, + isSecurityType: true, + }, + } as unknown as CodeIssueData, + ], + ], + }, + } as unknown as IProductService; + + await vscode.workspace.getConfiguration().update(ISSUE_VIEW_OPTIONS_SETTING, { + openIssues: true, + ignoredIssues: false, + }); + issueTreeProvider = new IssueTreeProvider( + contextService, + localCodeService, + configuration, + languages, + true, + folderConfigs, + ); + + sinon.stub(issueTreeProvider, 'getResultNodes').returns([]); + const rootChildren = issueTreeProvider.getRootChildren(); + strictEqual(rootChildren.length, 3); + strictEqual(rootChildren[0].label, 'Snyk found 1 issue'); + strictEqual(rootChildren[1].label, 'There are no issues fixable by Snyk DeepCode AI'); + strictEqual(rootChildren[2].label, 'Adjust your Issue View Options to see ignored issues.'); + await vscode.workspace.getConfiguration().update(ISSUE_VIEW_OPTIONS_SETTING, { + openIssues: true, + ignoredIssues: true, + }); + }); + + test('getRootChildren returns a root child for no visible issues', async () => { + const localCodeService = { + ...codeService, + result: { + values: () => [ + [ + { + filePath: '//folderName//test.js', + isIgnored: false, + additionalData: { + rule: 'some-rule', + hasAIFix: false, + isSecurityType: true, + }, + } as unknown as CodeIssueData, + ], + ], + }, + } as unknown as IProductService; + + await vscode.workspace.getConfiguration().update(ISSUE_VIEW_OPTIONS_SETTING, { + openIssues: false, + ignoredIssues: false, + }); + issueTreeProvider = new IssueTreeProvider( + contextService, + localCodeService, + configuration, + languages, + true, + folderConfigs, + ); + + sinon.stub(issueTreeProvider, 'getResultNodes').returns([]); + const rootChildren = issueTreeProvider.getRootChildren(); + strictEqual(rootChildren.length, 3); + strictEqual(rootChildren[0].label, 'Snyk found 1 issue'); + strictEqual(rootChildren[1].label, 'There are no issues fixable by Snyk DeepCode AI'); + strictEqual(rootChildren[2].label, 'Adjust your Issue View Options to see all issues.'); + await vscode.workspace.getConfiguration().update(ISSUE_VIEW_OPTIONS_SETTING, { + openIssues: true, + ignoredIssues: true, + }); + }); +}); diff --git a/src/test/integration/runTest.ts b/src/test/integration/runTest.ts index 36cbe33d3..d2d12e599 100644 --- a/src/test/integration/runTest.ts +++ b/src/test/integration/runTest.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { runTests } from 'vscode-test'; +import { runTests } from '@vscode/test-electron'; async function main() { try { diff --git a/src/test/unit/base/services/authenticationService.test.ts b/src/test/unit/base/services/authenticationService.test.ts index 51bd29a84..f0a78cd2a 100644 --- a/src/test/unit/base/services/authenticationService.test.ts +++ b/src/test/unit/base/services/authenticationService.test.ts @@ -1,11 +1,8 @@ -import { getIpFamily } from '@snyk/code-client'; -import { rejects, strictEqual } from 'assert'; -import needle, { NeedleResponse } from 'needle'; +import { rejects } from 'assert'; import sinon from 'sinon'; import { IBaseSnykModule } from '../../../../snyk/base/modules/interfaces'; import { AuthenticationService, OAuthToken } from '../../../../snyk/base/services/authenticationService'; import { ILoadingBadge } from '../../../../snyk/base/views/loadingBadge'; -import { IAnalytics } from '../../../../snyk/common/analytics/itly'; import { IConfiguration } from '../../../../snyk/common/configuration/configuration'; import { DID_CHANGE_CONFIGURATION_METHOD } from '../../../../snyk/common/constants/languageServer'; import { SNYK_CONTEXT } from '../../../../snyk/common/constants/views'; @@ -23,24 +20,15 @@ suite('AuthenticationService', () => { let languageClientAdapter: ILanguageClientAdapter; let languageClientSendNotification: sinon.SinonSpy; let setContextSpy: sinon.SinonSpy; + let setEndpointSpy: sinon.SinonSpy; let setTokenSpy: sinon.SinonSpy; let clearTokenSpy: sinon.SinonSpy; let previewFeaturesSpy: sinon.SinonSpy; - const NEEDLE_DEFAULT_TIMEOUT = 1000; - - const overrideNeedleTimeoutOptions = { - // eslint-disable-next-line camelcase - open_timeout: NEEDLE_DEFAULT_TIMEOUT, - // eslint-disable-next-line camelcase - response_timeout: NEEDLE_DEFAULT_TIMEOUT, - // eslint-disable-next-line camelcase - read_timeout: NEEDLE_DEFAULT_TIMEOUT, - }; - setup(() => { baseModule = {} as IBaseSnykModule; setContextSpy = sinon.fake(); + setEndpointSpy = sinon.fake(); setTokenSpy = sinon.fake(); clearTokenSpy = sinon.fake(); languageClientSendNotification = sinon.fake(); @@ -60,6 +48,7 @@ suite('AuthenticationService', () => { config = { authHost: '', + setEndpoint: setEndpointSpy, setToken: setTokenSpy, clearToken: clearTokenSpy, getPreviewFeatures: previewFeaturesSpy, @@ -68,80 +57,12 @@ suite('AuthenticationService', () => { teardown(() => sinon.restore()); - test("Logs 'Authentication Button is Clicked' analytical event", async () => { - const logAuthenticateButtonIsClickedFake = sinon.fake(); - const analytics = { - logAuthenticateButtonIsClicked: logAuthenticateButtonIsClickedFake, - } as unknown as IAnalytics; - const service = new AuthenticationService( - contextService, - baseModule, - config, - windowMock, - analytics, - new LoggerMock(), - languageClientAdapter, - {} as IVSCodeCommands, - ); - - await service.initiateLogin(); - - strictEqual(logAuthenticateButtonIsClickedFake.calledOnce, true); - }); - - // TODO: the following two tests are more of integration tests, since the second requires access to the network layer. Move it to integration test as part of ROAD-625. - test('getIpFamily returns undefined when IPv6 not supported', async () => { - const ipv6ErrorCode = 'EADDRNOTAVAIL'; - - // code-client calls 'needle', thus it's the easiest place to stub the response when IPv6 is not supported by the OS network stack. Otherwise, Node internals must be stubbed to return the error. - sinon.stub(needle, 'request').callsFake((_, uri, data, opts, callback) => { - if (!callback) throw new Error(); - callback( - { - code: ipv6ErrorCode, - errno: ipv6ErrorCode, - } as unknown as Error, - {} as unknown as NeedleResponse, - null, - ); - // eslint-disable-next-line camelcase - return needle.post(uri, data, { ...opts, ...overrideNeedleTimeoutOptions }); - }); - - const ipFamily = await getIpFamily('https://dev.snyk.io'); - - strictEqual(ipFamily, undefined); - }); - - test('getIpFamily returns 6 when IPv6 supported', async () => { - sinon.stub(needle, 'request').callsFake((_, uri, data, opts, callback) => { - if (!callback) throw new Error(); - callback( - null, - { - body: { - response: { - statusCode: 401, - body: {}, - }, - }, - } as NeedleResponse, - null, - ); - return needle.post(uri, data, { ...opts, ...overrideNeedleTimeoutOptions }); - }); - - const ipFamily = await getIpFamily('https://dev.snyk.io'); - strictEqual(ipFamily, 6); - }); - test("Doesn't call setToken when token is empty", async () => { const service = new AuthenticationService( contextService, baseModule, config, windowMock, - {} as IAnalytics, new LoggerMock(), languageClientAdapter, {} as IVSCodeCommands, @@ -160,7 +81,6 @@ suite('AuthenticationService', () => { baseModule, config, windowMock, - {} as IAnalytics, new LoggerMock(), languageClientAdapter, {} as IVSCodeCommands, @@ -174,7 +94,7 @@ suite('AuthenticationService', () => { sinon.assert.calledOnceWithExactly(languageClientSendNotification, DID_CHANGE_CONFIGURATION_METHOD, {}); }); - suite('.updateToken()', () => { + suite('.updateTokenAndEndpoint()', () => { let service: AuthenticationService; const setLoadingBadgeFake = sinon.fake(); @@ -190,7 +110,6 @@ suite('AuthenticationService', () => { baseModule, config, windowMock, - {} as IAnalytics, new LoggerMock(), languageClientAdapter, { @@ -199,15 +118,17 @@ suite('AuthenticationService', () => { ); }); - test('sets the token when a valid token is provided', async () => { + test('sets the token and endpoint when a valid token is provided', async () => { const token = 'be30e2dd-95ac-4450-ad90-5f7cc7429258'; - await service.updateToken(token); + const apiUrl = 'https://api.snyk.io'; + await service.updateTokenAndEndpoint(token, apiUrl); + sinon.assert.calledWith(setEndpointSpy, apiUrl); sinon.assert.calledWith(setTokenSpy, token); }); test('logs out if token is empty', async () => { - await service.updateToken(''); + await service.updateTokenAndEndpoint('', ''); sinon.assert.called(clearTokenSpy); sinon.assert.calledWith(setContextSpy, SNYK_CONTEXT.LOGGEDIN, false); @@ -215,7 +136,8 @@ suite('AuthenticationService', () => { test('sets the proper contexts when setting new token', async () => { const token = 'be30e2dd-95ac-4450-ad90-5f7cc7429258'; - await service.updateToken(token); + const apiUrl = 'https://api.snyk.io'; + await service.updateTokenAndEndpoint(token, apiUrl); sinon.assert.calledWith(setContextSpy, SNYK_CONTEXT.LOGGEDIN, true); sinon.assert.calledWith(setContextSpy, SNYK_CONTEXT.AUTHENTICATING, false); @@ -223,15 +145,17 @@ suite('AuthenticationService', () => { test('sets the loading badge status when setting new token', async () => { const token = 'be30e2dd-95ac-4450-ad90-5f7cc7429258'; - await service.updateToken(token); + const apiUrl = 'https://api.snyk.io'; + await service.updateTokenAndEndpoint(token, apiUrl); sinon.assert.calledWith(setLoadingBadgeFake, false); }); test('errors when invalid token is provided', async () => { const invalidToken = 'thisTokenIsNotValid'; + const apiUrl = 'https://api.snyk.io'; - await rejects(service.updateToken(invalidToken)); + await rejects(service.updateTokenAndEndpoint(invalidToken, apiUrl)); sinon.assert.notCalled(setTokenSpy); }); @@ -244,15 +168,19 @@ suite('AuthenticationService', () => { refresh_token: 'refresh_token', }; const oauthTokenString = JSON.stringify(oauthToken); + const apiUrl = 'https://api.snyk.io'; - await service.updateToken(oauthTokenString); + await service.updateTokenAndEndpoint(oauthTokenString, apiUrl); + sinon.assert.calledWith(setEndpointSpy, apiUrl); sinon.assert.calledWith(setTokenSpy, oauthTokenString); }); test('fails with error on non oauth token json string', async () => { const oauthTokenString = '{}'; + const apiUrl = 'https://api.snyk.io'; + + await rejects(service.updateTokenAndEndpoint(oauthTokenString, apiUrl)); - await rejects(service.updateToken(oauthTokenString)); sinon.assert.notCalled(setTokenSpy); }); @@ -265,8 +193,9 @@ suite('AuthenticationService', () => { refresh_token: 'refresh_token', }; const oauthTokenString = JSON.stringify(oauthToken); + const apiUrl = 'https://api.snyk.io'; - await rejects(service.updateToken(oauthTokenString)); + await rejects(service.updateTokenAndEndpoint(oauthTokenString, apiUrl)); sinon.assert.notCalled(setTokenSpy); }); }); diff --git a/src/test/unit/cli/cliExecutable.test.ts b/src/test/unit/cli/cliExecutable.test.ts index ceb8d6f27..748c7f1a8 100644 --- a/src/test/unit/cli/cliExecutable.test.ts +++ b/src/test/unit/cli/cliExecutable.test.ts @@ -1,5 +1,7 @@ import { strictEqual } from 'assert'; import path from 'path'; +import os from 'os'; +import fs from 'fs/promises'; import sinon from 'sinon'; import { CliExecutable } from '../../../snyk/cli/cliExecutable'; import { Platform } from '../../../snyk/common/platform'; @@ -10,30 +12,70 @@ suite('CliExecutable', () => { }); test('Returns correct filename for different platforms', () => { - strictEqual(CliExecutable.getFilename('linux'), 'snyk-linux'); - strictEqual(CliExecutable.getFilename('darwin'), 'snyk-macos'); - strictEqual(CliExecutable.getFilename('win32'), 'snyk-win.exe'); + strictEqual(CliExecutable.getFileName('linux'), 'snyk-linux'); + strictEqual(CliExecutable.getFileName('linux_alpine'), 'snyk-alpine'); + strictEqual(CliExecutable.getFileName('macos'), 'snyk-macos'); + strictEqual(CliExecutable.getFileName('macos_arm64'), 'snyk-macos-arm64'); + strictEqual(CliExecutable.getFileName('windows'), 'snyk-win.exe'); }); - test('Returns correct extension paths', () => { - const unixExtensionDir = '/Users/user/.vscode/extensions/snyk-security.snyk-vulnerability-scanner-1.1.0'; + test('Returns correct extension paths', async () => { + const homedirStub = sinon.stub(os, 'homedir'); + const unixExtensionDir = '/.local/share/snyk/vscode-cli'; + const macOsExtensionDir = '/Library/Application Support/snyk/vscode-cli'; - const stub = sinon.stub(Platform, 'getCurrent').returns('darwin'); - let expectedCliPath = path.join(unixExtensionDir, 'snyk-macos'); - strictEqual(CliExecutable.getPath(unixExtensionDir), expectedCliPath); + const osStub = sinon.stub(Platform, 'getCurrent').returns('darwin'); + const archStub = sinon.stub(Platform, 'getArch').returns('x64'); + const fsStub = sinon.stub(fs, 'access').returns(Promise.reject()); + let homedir = '/home/user'; + homedirStub.returns(homedir); - stub.returns('linux'); - expectedCliPath = path.join(unixExtensionDir, 'snyk-linux'); - strictEqual(CliExecutable.getPath(unixExtensionDir), expectedCliPath); + let expectedCliPath = path.join(Platform.getHomeDir(), macOsExtensionDir, 'snyk-macos'); + strictEqual(await CliExecutable.getPath(), expectedCliPath); - const winExtensionDir = `C:\\Users\\user\\.vscode\\extensions`; - stub.returns('win32'); - expectedCliPath = path.join(winExtensionDir, 'snyk-win.exe'); - strictEqual(CliExecutable.getPath(winExtensionDir), expectedCliPath); + osStub.returns('linux'); + expectedCliPath = path.join(Platform.getHomeDir(), unixExtensionDir, 'snyk-linux'); + strictEqual(await CliExecutable.getPath(), expectedCliPath); + + fsStub.returns(Promise.resolve()); + expectedCliPath = path.join(Platform.getHomeDir(), unixExtensionDir, 'snyk-alpine'); + strictEqual(await CliExecutable.getPath(), expectedCliPath); + fsStub.returns(Promise.reject()); + + osStub.returns('win32'); + homedir = 'C:\\Users\\user'; + homedirStub.returns(homedir); + expectedCliPath = path.join(Platform.getHomeDir(), '\\AppData\\Local\\', 'snyk', 'vscode-cli', 'snyk-win.exe'); + const actualPath = await CliExecutable.getPath(); + strictEqual(actualPath, expectedCliPath); + + // test arm64 + archStub.returns('arm64'); + + osStub.returns('darwin'); + homedir = '/home/user'; + homedirStub.returns(homedir); + expectedCliPath = path.join(Platform.getHomeDir(), macOsExtensionDir, 'snyk-macos-arm64'); + strictEqual(await CliExecutable.getPath(), expectedCliPath); + + osStub.returns('linux'); + expectedCliPath = path.join(Platform.getHomeDir(), unixExtensionDir, 'snyk-linux-arm64'); + strictEqual(await CliExecutable.getPath(), expectedCliPath); + + fsStub.returns(Promise.resolve()); + expectedCliPath = path.join(Platform.getHomeDir(), unixExtensionDir, 'snyk-alpine-arm64'); + strictEqual(await CliExecutable.getPath(), expectedCliPath); + fsStub.returns(Promise.reject()); + + osStub.returns('win32'); + homedir = 'C:\\Users\\user'; + homedirStub.returns(homedir); + expectedCliPath = path.join(Platform.getHomeDir(), '\\AppData\\Local\\', 'snyk', 'vscode-cli', 'snyk-win.exe'); + strictEqual(await CliExecutable.getPath(), expectedCliPath); }); - test('Return custom path, if provided', () => { + test('Return custom path, if provided', async () => { const customPath = '/path/to/cli'; - strictEqual(CliExecutable.getPath('', customPath), customPath); + strictEqual(await CliExecutable.getPath(customPath), customPath); }); }); diff --git a/src/test/unit/cli/process.test.ts b/src/test/unit/cli/process.test.ts deleted file mode 100644 index ec8104cfb..000000000 --- a/src/test/unit/cli/process.test.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { strictEqual } from 'assert'; -import sinon from 'sinon'; -import { CLI_INTEGRATION_NAME } from '../../../snyk/cli/contants/integration'; -import { CliProcess } from '../../../snyk/cli/process'; -import { Configuration, IConfiguration } from '../../../snyk/common/configuration/configuration'; -import { ILog } from '../../../snyk/common/logger/interfaces'; -import { IVSCodeWorkspace } from '../../../snyk/common/vscode/workspace'; -import { LoggerMock } from '../mocks/logger.mock'; -import { OAuthToken } from '../../../snyk/base/services/authenticationService'; - -suite('CliProcess', () => { - let logger: ILog; - const snykOssApiEndpoint = 'https://snykgov.io/api/'; - const emptyWorkspace = { - getConfiguration: () => undefined, - } as unknown as IVSCodeWorkspace; - - setup(() => { - logger = new LoggerMock(); - }); - - test('Sets DISABLE_ANALYTICS when telemetry is off ', async () => { - const process = new CliProcess( - logger, - { - shouldReportEvents: false, - getToken: () => Promise.resolve(), - snykOssApiEndpoint: snykOssApiEndpoint, - } as IConfiguration, - emptyWorkspace, - ); - const vars = await process.getProcessEnv(); - strictEqual(Object.keys(vars).includes('SNYK_CFG_DISABLE_ANALYTICS'), true); - }); - - test("Doesn't set DISABLE_ANALYTICS when telemetry is on ", async () => { - const process = new CliProcess( - logger, - { - shouldReportEvents: true, - getToken: () => Promise.resolve(), - snykOssApiEndpoint: snykOssApiEndpoint, - } as IConfiguration, - emptyWorkspace, - ); - const vars = await process.getProcessEnv(); - - strictEqual(Object.keys(vars).includes('SNYK_CFG_DISABLE_ANALYTICS'), false); - }); - - test('Sets correct integration name, version, token, API endpoint and organization', async () => { - const token = 'fake-token'; - const snykOssApiEndpoint = 'https://snyk.io/api/'; - const organization = 'test-org'; - const process = new CliProcess( - logger, - { - getToken: () => Promise.resolve(token), - snykOssApiEndpoint: snykOssApiEndpoint, - organization: organization, - } as IConfiguration, - emptyWorkspace, - ); - - const envVars = await process.getProcessEnv(); - - strictEqual(envVars['SNYK_INTEGRATION_NAME'], CLI_INTEGRATION_NAME); - strictEqual(envVars['SNYK_INTEGRATION_VERSION'], await Configuration.getVersion()); - strictEqual(envVars['SNYK_TOKEN'], token); - strictEqual(envVars['SNYK_API'], snykOssApiEndpoint); - strictEqual(envVars['SNYK_CFG_ORG'], organization); - }); - - test('Sets correct token if oauth authentication', async () => { - const token = '{"access_token": "fake-token"}'; - const snykOssApiEndpoint = 'https://snykgov.io/api/'; - const organization = 'test-org'; - const process = new CliProcess( - logger, - { - getToken: () => Promise.resolve(token), - snykOssApiEndpoint: snykOssApiEndpoint, - organization: organization, - } as IConfiguration, - emptyWorkspace, - ); - - const envVars = await process.getProcessEnv(); - const oauthToken = JSON.parse(token) as OAuthToken; - strictEqual(envVars['SNYK_TOKEN'], undefined); - strictEqual(envVars['SNYK_OAUTH_TOKEN'], oauthToken.access_token); - strictEqual(envVars['SNYK_API'], snykOssApiEndpoint); - strictEqual(envVars['SNYK_CFG_ORG'], organization); - }); - - test('Sets correct proxy variable', async () => { - // arrange - const proxy = 'http://my.proxy.com:8080'; - const getConfiguration = sinon.stub(); - getConfiguration.withArgs('http', 'proxy').returns(proxy); - - const process = new CliProcess( - logger, - { - shouldReportEvents: true, - getToken: () => Promise.resolve(), - snykOssApiEndpoint: snykOssApiEndpoint, - } as IConfiguration, - { - getConfiguration: getConfiguration, - } as unknown as IVSCodeWorkspace, - ); - - // act - const vars = await process.getProcessEnv(); - - // assert - strictEqual(vars['HTTPS_PROXY'], proxy); - strictEqual(vars['HTTP_PROXY'], proxy); - }); -}); diff --git a/src/test/unit/cli/services/cliService.test.ts b/src/test/unit/cli/services/cliService.test.ts deleted file mode 100644 index d92429ecc..000000000 --- a/src/test/unit/cli/services/cliService.test.ts +++ /dev/null @@ -1,139 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { deepStrictEqual, ok } from 'assert'; -import { ReplaySubject } from 'rxjs'; -import sinon from 'sinon'; -import { CliProcess } from '../../../../snyk/cli/process'; -import { CliError, CliService } from '../../../../snyk/cli/services/cliService'; -import { IConfiguration } from '../../../../snyk/common/configuration/configuration'; -import { WorkspaceTrust } from '../../../../snyk/common/configuration/trustedFolders'; -import { ILanguageServer } from '../../../../snyk/common/languageServer/languageServer'; -import { ILog } from '../../../../snyk/common/logger/interfaces'; -import { DownloadService } from '../../../../snyk/common/services/downloadService'; -import { ExtensionContext } from '../../../../snyk/common/vscode/extensionContext'; -import { IVSCodeWorkspace } from '../../../../snyk/common/vscode/workspace'; -import { LoggerMock } from '../../mocks/logger.mock'; - -type TestCliResult = - | { - success: boolean; - } - | CliError; - -class TestCliService extends CliService { - protected command: string[] = ['']; - protected mapToResultType(rawCliResult: string): TestCliResult { - return JSON.parse(rawCliResult) as TestCliResult; - } - protected beforeTest(): void { - return; - } - protected afterTest(_result: TestCliResult): void { - return; - } - protected ensureDependencies(): void { - return; - } -} - -suite('CliService', () => { - const extensionPath = 'test/path'; - let logger: ILog; - let testCliService: TestCliService; - let extensionContext: ExtensionContext; - let downloadService: DownloadService; - let configuration: IConfiguration; - - setup(() => { - logger = new LoggerMock(); - - extensionContext = { - extensionPath: extensionPath, - getGlobalStateValue: () => undefined, - } as unknown as ExtensionContext; - - const testFolderPath = 'test-folder'; - configuration = { - getAdditionalCliParameters: () => '', - isAutomaticDependencyManagementEnabled: () => true, - getCliPath: () => undefined, - getTrustedFolders: () => [testFolderPath], - } as unknown as IConfiguration; - - downloadService = { - download: () => false, - isCliInstalled: () => true, - } as unknown as DownloadService; - - const ls = { - cliReady$: new ReplaySubject(1), - } as unknown as ILanguageServer; - ls.cliReady$.next(''); - - testCliService = new TestCliService( - extensionContext, - logger, - configuration, - { - getWorkspaceFolders: () => [testFolderPath], - } as IVSCodeWorkspace, - downloadService, - ls, - new WorkspaceTrust(), - ); - }); - - teardown(() => { - sinon.restore(); - }); - - test('Test returns mapped result when CLI succeeds', async () => { - const cliOutput = { success: true } as TestCliResult; - sinon.stub(CliProcess.prototype, 'spawn').resolves(JSON.stringify(cliOutput)); - const result = await testCliService.test(false, false); - - deepStrictEqual(result, cliOutput); - }); - - test('Test returns error when CLI execution fails with error JSON', async () => { - const cliError = { - ok: false, - error: 'Authentication failed. Please check the API token on https://snyk.io', - path: '/Users/snyk/Git/goof', - }; - - sinon.stub(CliProcess.prototype, 'spawn').resolves(JSON.stringify(cliError)); - - const result = (await testCliService.test(false, false)) as CliError; - - deepStrictEqual(result.error, cliError.error); - deepStrictEqual(result.path, cliError.path); - }); - - test('Test returns error when CLI execution fails without error JSON', async () => { - const errOutput = new Error('Failed to run snyk command.'); - sinon.stub(CliProcess.prototype, 'spawn').rejects(errOutput); - const result = await testCliService.test(false, false); - - ok(result instanceof CliError); - deepStrictEqual(result.error, errOutput); - }); - - test('Test passes cwd and additional CLI arguments from settings', async () => { - const testFolder = 'test-folder'; - const additionalParameters = `--exclude="folder with spaces" --configuration-matching="iamaRegex" --sub-project=snyk`; - sinon.stub(configuration, 'getAdditionalCliParameters').returns(additionalParameters); - - const spawnSpy = sinon.spy(CliProcess.prototype, 'spawn'); - await testCliService.test(false, false); - - const expectedArgs = [ - '', - testFolder, - '--json', - '--exclude="folder with spaces"', - '--configuration-matching="iamaRegex"', - '--sub-project=snyk', - ]; - deepStrictEqual(spawnSpy.calledWith(sinon.match.any, testFolder, expectedArgs), true); - }); -}); diff --git a/src/test/unit/common/analytics/itly.test.ts b/src/test/unit/common/analytics/itly.test.ts deleted file mode 100644 index 02a6c5858..000000000 --- a/src/test/unit/common/analytics/itly.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { strictEqual } from 'assert'; -import { Iteratively } from '../../../../snyk/common/analytics/itly'; -import { SnykConfiguration } from '../../../../snyk/common/configuration/snykConfiguration'; -import { User } from '../../../../snyk/common/user'; -import { LoggerMock } from '../../mocks/logger.mock'; - -suite('Iteratively', () => { - const snykConfig = {} as SnykConfiguration; - const isDevelopment = false; - - suite('.load()', () => { - suite('when connecting to FEDRAMP endpoints', () => { - const isFedramp = true; - [true, false].forEach(shouldReportEvents => { - test(`Returns "null" when shouldReportEvents == ${shouldReportEvents}`, () => { - const iteratively = new Iteratively( - new User(), - new LoggerMock(), - shouldReportEvents, - isFedramp, - isDevelopment, - snykConfig, - ); - - const result = iteratively.load(); - - strictEqual(result, null); - }); - }); - }); - - suite('when connecting to non-FEDRAMP endpoints', () => { - const isFedramp = false; - - test('Returns "null" when shouldReportEvents == false', () => { - const iteratively = new Iteratively(new User(), new LoggerMock(), false, isFedramp, isDevelopment, snykConfig); - - const result = iteratively.load(); - - strictEqual(result, null); - }); - - test('Returns "Iteratively" when shouldReportEvents == true', () => { - const iteratively = new Iteratively(new User(), new LoggerMock(), true, isFedramp, isDevelopment, snykConfig); - - const result = iteratively.load(); - - strictEqual(result instanceof Iteratively, true); - }); - }); - }); -}); diff --git a/src/test/unit/common/commands/commandController.test.ts b/src/test/unit/common/commands/commandController.test.ts index f0b8ef8c6..6d37814c7 100644 --- a/src/test/unit/common/commands/commandController.test.ts +++ b/src/test/unit/common/commands/commandController.test.ts @@ -2,22 +2,21 @@ import sinon from 'sinon'; import * as util from 'util'; import { IAuthenticationService } from '../../../../snyk/base/services/authenticationService'; import { ScanModeService } from '../../../../snyk/base/services/scanModeService'; -import { IAnalytics } from '../../../../snyk/common/analytics/itly'; import { CommandController } from '../../../../snyk/common/commands/commandController'; -import { COMMAND_DEBOUNCE_INTERVAL } from '../../../../snyk/common/constants/general'; +import { CodeIssueData, IacIssueData } from '../../../../snyk/common/languageServer/types'; import { IOpenerService } from '../../../../snyk/common/services/openerService'; +import { IProductService } from '../../../../snyk/common/services/productService'; import { IVSCodeCommands } from '../../../../snyk/common/vscode/commands'; import { IVSCodeWorkspace } from '../../../../snyk/common/vscode/workspace'; -import { OssService } from '../../../../snyk/snykOss/services/ossService'; +import { OssService } from '../../../../snyk/snykOss/ossService'; import { LanguageServerMock } from '../../mocks/languageServer.mock'; import { LoggerMock } from '../../mocks/logger.mock'; import { windowMock } from '../../mocks/window.mock'; -import { IProductService } from '../../../../snyk/common/services/productService'; -import { CodeIssueData, IacIssueData } from '../../../../snyk/common/languageServer/types'; +import { IConfiguration } from '../../../../snyk/common/configuration/configuration'; +import { IFolderConfigs } from '../../../../snyk/common/configuration/folderConfigs'; suite('CommandController', () => { - const sleep = util.promisify(setTimeout); - + util.promisify(setTimeout); let controller: CommandController; setup(() => { @@ -33,7 +32,8 @@ suite('CommandController', () => { windowMock, new LanguageServerMock(), new LoggerMock(), - {} as IAnalytics, + {} as IConfiguration, + {} as IFolderConfigs, ); }); @@ -49,19 +49,4 @@ suite('CommandController', () => { // Assert sinon.assert.calledOnceWithExactly(fakeFunc, args); }); - - test("Doesn't execute debounced command within the debounce interval", async () => { - // Arrange - const fakeFunc = sinon.fake(); - const args = ['test', 0, true]; - - // Act - await controller.executeCommand('snyk.test', fakeFunc, args); - await sleep(COMMAND_DEBOUNCE_INTERVAL + 1); - await controller.executeCommand('snyk.test', fakeFunc, args); - - // Assert - sinon.assert.calledTwice(fakeFunc); - sinon.assert.calledWith(fakeFunc, args); - }); }); diff --git a/src/test/unit/common/configuration.test.ts b/src/test/unit/common/configuration.test.ts index 3f95c8ddc..f8398148d 100644 --- a/src/test/unit/common/configuration.test.ts +++ b/src/test/unit/common/configuration.test.ts @@ -3,30 +3,31 @@ import { deepStrictEqual, strictEqual } from 'assert'; import sinon from 'sinon'; import { Configuration, PreviewFeatures } from '../../../snyk/common/configuration/configuration'; -import { SNYK_TOKEN_KEY } from '../../../snyk/common/constants/general'; import { + ADVANCED_CLI_PATH, + ADVANCED_CLI_RELEASE_CHANNEL, ADVANCED_CUSTOM_ENDPOINT, + ADVANCED_CUSTOM_LS_PATH, FEATURES_PREVIEW_SETTING, SCANNING_MODE, } from '../../../snyk/common/constants/settings'; import SecretStorageAdapter from '../../../snyk/common/vscode/secretStorage'; -import { ExtensionContext } from '../../../snyk/common/vscode/types'; import { IVSCodeWorkspace } from '../../../snyk/common/vscode/workspace'; import { extensionContextMock } from '../mocks/extensionContext.mock'; import { stubWorkspaceConfiguration } from '../mocks/workspace.mock'; +import { extensionContext } from '../../../snyk/common/vscode/extensionContext'; +import { Platform } from '../../../snyk/common/platform'; +import path from 'path'; suite('Configuration', () => { let workspaceStub: IVSCodeWorkspace; - let extensionContext: ExtensionContext; setup(() => { const tokenConfigSection = 'token'; let token = ''; - - extensionContext = extensionContextMock; - SecretStorageAdapter.init(extensionContext); - + SecretStorageAdapter.init(extensionContextMock); + extensionContext.setContext(extensionContextMock); const stub = sinon.stub().returns({ getConfiguration(_configurationIdentifier, _section) { if (_section === tokenConfigSection) return token; @@ -48,134 +49,42 @@ suite('Configuration', () => { sinon.restore(); }); - test('Snyk Code: production base url is returned when not in development', () => { - const workspace = stubWorkspaceConfiguration(ADVANCED_CUSTOM_ENDPOINT, undefined); - const configuration = new Configuration( - { - SNYK_VSCE_DEVELOPMENT: '', - }, - workspace, - ); - - strictEqual(configuration.snykCodeBaseURL, 'https://deeproxy.snyk.io'); - }); - - test('Snyk Code: development base url is returned when in development', () => { - const workspace = stubWorkspaceConfiguration(ADVANCED_CUSTOM_ENDPOINT, undefined); - const configuration = new Configuration( - { - SNYK_VSCE_DEVELOPMENT: '1', - }, - workspace, - ); - strictEqual(configuration.snykCodeBaseURL, 'https://deeproxy.snyk.io'); - }); - - test('Snyk Code: base url respects custom endpoint configuration', () => { - const workspace = stubWorkspaceConfiguration(ADVANCED_CUSTOM_ENDPOINT, 'http://custom.endpoint.com'); - const configuration = new Configuration({}, workspace); - - strictEqual(configuration.snykCodeBaseURL, 'http://deeproxy.custom.endpoint.com'); - }); - - test('Snyk Code: base url respects single tenant endpoint configuration', () => { - const workspace = stubWorkspaceConfiguration(ADVANCED_CUSTOM_ENDPOINT, 'https://app.custom.snyk.io/api'); - const configuration = new Configuration({}, workspace); - - strictEqual(configuration.snykCodeBaseURL, 'https://deeproxy.custom.snyk.io'); - }); - - test('Snyk Code: code url respects custom endpoint configuration', () => { - const workspace = stubWorkspaceConfiguration(ADVANCED_CUSTOM_ENDPOINT, 'https://custom.endpoint.com/api'); + test('Snyk Code URL: respects custom endpoint configuration', () => { + const workspace = stubWorkspaceConfiguration(ADVANCED_CUSTOM_ENDPOINT, 'https://api.custom.endpoint.com'); const configuration = new Configuration({}, workspace); strictEqual(configuration.snykCodeUrl, 'https://app.custom.endpoint.com/manage/snyk-code?from=vscode'); }); - test('Snyk Code: code url respects single tenant endpoint configuration', () => { - const workspace = stubWorkspaceConfiguration(ADVANCED_CUSTOM_ENDPOINT, 'https://app.custom.snyk.io/api'); + test('Snyk Code URL: respects single tenant endpoint configuration', () => { + const workspace = stubWorkspaceConfiguration(ADVANCED_CUSTOM_ENDPOINT, 'https://api.custom.snyk.io'); const configuration = new Configuration({}, workspace); strictEqual(configuration.snykCodeUrl, 'https://app.custom.snyk.io/manage/snyk-code?from=vscode'); }); - test('Snyk Code: Custom base url is returned when in development and custom url specified', () => { - const customUrl = 'https://custom.url'; - const configuration = new Configuration( - { - SNYK_VSCE_DEVELOPMENT: '1', - SNYK_VSCE_DEVELOPMENT_SNYKCODE_BASE_URL: customUrl, - }, - workspaceStub, - ); - strictEqual(configuration.snykCodeBaseURL, customUrl); - }); - - test('Snyk Code: token returns snyk.io token when not in development', async () => { - const token = 'snyk-token'; - - const secretStorageStoreStub = sinon.stub(extensionContext.secrets, 'store').resolves(); - const secretStorageGetStub = sinon.stub(extensionContext.secrets, 'get').resolves(token); - - const configuration = new Configuration(process.env, workspaceStub); - await configuration.setToken(token); - - strictEqual(await configuration.snykCodeToken, token); - secretStorageStoreStub.calledWith(SNYK_TOKEN_KEY, token); - strictEqual(secretStorageGetStub.calledOnce, true); - }); - - test('Snyk Code: token should be cleared if the retrieval method throws', async () => { - const token = 'snyk-token'; - - sinon.stub(extensionContext.secrets, 'store').resolves(); - const secretStorageDeleteStub = sinon.stub(extensionContext.secrets, 'delete').resolves(); - const secretStorageGetStub = sinon.stub(extensionContext.secrets, 'get').rejects('cannot get token'); - - const configuration = new Configuration(process.env, workspaceStub); - await configuration.setToken(token); - - strictEqual(await configuration.snykCodeToken, ''); - strictEqual(secretStorageGetStub.calledOnce, true); - strictEqual(secretStorageDeleteStub.calledOnce, true); - }); - - test('Snyk Code: token returns Snyk Code token when in development', async () => { - const token = 'test-token'; - const snykCodeToken = 'snykCode-token'; - - const secretStorageStoreStub = sinon.stub(extensionContext.secrets, 'store').resolves(); - const secretStorageGetStub = sinon.stub(extensionContext.secrets, 'get').resolves(token); - - const configuration = new Configuration( - { - SNYK_VSCE_DEVELOPMENT: '1', - SNYK_VSCE_DEVELOPMENT_SNYKCODE_TOKEN: snykCodeToken, - }, - workspaceStub, - ); - await configuration.setToken(token); + test('Snyk Code URL: respects FedRAMP endpoint configuration', () => { + const workspace = stubWorkspaceConfiguration(ADVANCED_CUSTOM_ENDPOINT, 'https://api.custom.snykgov.io'); + const configuration = new Configuration({}, workspace); - strictEqual(await configuration.snykCodeToken, snykCodeToken); - secretStorageStoreStub.calledWith('snyk.token', token); - strictEqual(secretStorageGetStub.called, false); + strictEqual(configuration.snykCodeUrl, 'https://app.custom.snykgov.io/manage/snyk-code?from=vscode'); }); - test('Snyk OSS: API endpoint returns default endpoint when no custom set', () => { + test('API endpoint: returns default endpoint when no custom set', () => { const workspace = stubWorkspaceConfiguration(ADVANCED_CUSTOM_ENDPOINT, undefined); const configuration = new Configuration({}, workspace); - strictEqual(configuration.snykOssApiEndpoint, 'https://snyk.io/api/v1'); + strictEqual(configuration.snykApiEndpoint, 'https://api.snyk.io'); }); - test('Snyk OSS: API endpoint returns custom endpoint when set', () => { - const customEndpoint = 'http://custom.endpoint.com/api'; + test('API endpoint: returns custom endpoint when set', () => { + const customEndpoint = 'http://custom.endpoint.com'; const workspace = stubWorkspaceConfiguration(ADVANCED_CUSTOM_ENDPOINT, customEndpoint); const configuration = new Configuration({}, workspace); - strictEqual(configuration.snykOssApiEndpoint, customEndpoint); + strictEqual(configuration.snykApiEndpoint, customEndpoint); }); test('Preview features: not enabled', () => { @@ -186,12 +95,14 @@ suite('Configuration', () => { deepStrictEqual(configuration.getPreviewFeatures(), { advisor: false, + ossQuickfixes: false, } as PreviewFeatures); }); test('Preview features: some features enabled', () => { const previewFeatures = { advisor: false, + ossQuickfixes: false, } as PreviewFeatures; const workspace = stubWorkspaceConfiguration(FEATURES_PREVIEW_SETTING, previewFeatures); @@ -228,5 +139,63 @@ suite('Configuration', () => { strictEqual(configuration.isFedramp, false); }); + + test('CLI Path: Returns default path if empty', async () => { + const workspace = stubWorkspaceConfiguration(ADVANCED_CLI_PATH, ''); + + const configuration = new Configuration({}, workspace); + sinon.stub(Platform, 'getCurrent').returns('linux'); + sinon.stub(Platform, 'getArch').returns('x64'); + + const cliPath = await configuration.getCliPath(); + + const expectedCliPath = path.join(Platform.getHomeDir(), '.local/share/snyk/vscode-cli', 'snyk-linux'); + strictEqual(cliPath, expectedCliPath); + }); + + test('CLI Path: Returns Snyk LS path', async () => { + const workspace = stubWorkspaceConfiguration(ADVANCED_CUSTOM_LS_PATH, '/path/to/ls'); + + const configuration = new Configuration({}, workspace); + + const cliPath = await configuration.getCliPath(); + strictEqual(cliPath, '/path/to/ls'); + }); + + test('CLI Path: Returns CLI Path if set', async () => { + const workspace = stubWorkspaceConfiguration(ADVANCED_CLI_PATH, '/path/to/cli'); + + const configuration = new Configuration({}, workspace); + + const cliPath = await configuration.getCliPath(); + strictEqual(cliPath, '/path/to/cli'); + }); + + test('CLI Release Channel: Return preview if extension is preview and release channel is default', async () => { + const workspace = stubWorkspaceConfiguration(ADVANCED_CLI_RELEASE_CHANNEL, 'stable'); + + const configuration = new Configuration({}, workspace); + configuration.setExtensionId('snyk-vulnerability-scanner-preview'); + const cliReleaseChannel = await configuration.getCliReleaseChannel(); + strictEqual(cliReleaseChannel, 'preview'); + }); + + test('CLI Release Channel: Return current release channel without change if extension is not preview', async () => { + const workspace = stubWorkspaceConfiguration(ADVANCED_CLI_RELEASE_CHANNEL, 'stable'); + + const configuration = new Configuration({}, workspace); + configuration.setExtensionId('snyk-vulnerability-scanner'); + const cliReleaseChannel = await configuration.getCliReleaseChannel(); + strictEqual(cliReleaseChannel, 'stable'); + }); + + test('CLI Release Channel: Return current version if release channel not stable and extension is preview', async () => { + const workspace = stubWorkspaceConfiguration(ADVANCED_CLI_RELEASE_CHANNEL, 'v1.1294.0'); + + const configuration = new Configuration({}, workspace); + configuration.setExtensionId('snyk-vulnerability-scanner-preview'); + const cliReleaseChannel = await configuration.getCliReleaseChannel(); + strictEqual(cliReleaseChannel, 'v1.1294.0'); + }); }); }); diff --git a/src/test/unit/common/editor/codeActionsProvider.test.ts b/src/test/unit/common/editor/codeActionsProvider.test.ts index c30574e7a..e6340782b 100644 --- a/src/test/unit/common/editor/codeActionsProvider.test.ts +++ b/src/test/unit/common/editor/codeActionsProvider.test.ts @@ -1,12 +1,11 @@ import { strictEqual } from 'assert'; import sinon from 'sinon'; -import { IAnalytics, SupportedQuickFixProperties } from '../../../../snyk/common/analytics/itly'; import { SNYK_OPEN_ISSUE_COMMAND, SNYK_OPEN_LOCAL_COMMAND } from '../../../../snyk/common/constants/commands'; import { CodeActionsProvider } from '../../../../snyk/common/editor/codeActionsProvider'; import { Issue } from '../../../../snyk/common/languageServer/types'; import { WorkspaceFolderResult } from '../../../../snyk/common/services/productService'; import { ICodeActionKindAdapter } from '../../../../snyk/common/vscode/codeAction'; -import { CodeAction, Range, TextDocument } from '../../../../snyk/common/vscode/types'; +import { CodeAction, CodeActionContext, Range, TextDocument } from '../../../../snyk/common/vscode/types'; type ProductData = { issueType: string; @@ -34,9 +33,6 @@ class MockProductService extends CodeActionsProvider { } as unknown as CodeAction, ]; } - getAnalyticsActionTypes(): [string, ...string[]] & [SupportedQuickFixProperties, ...SupportedQuickFixProperties[]] { - return ['Show Suggestion']; - } getIssueRange(_: Issue): Range { return { contains: () => true, @@ -46,7 +42,6 @@ class MockProductService extends CodeActionsProvider { suite('Code Actions Provider', () => { let issuesActionsProvider: CodeActionsProvider; - let logQuickFixIsDisplayed: sinon.SinonSpy; setup(() => { const codeResults = new Map>(); @@ -59,16 +54,11 @@ suite('Code Actions Provider', () => { } as unknown as Issue, ]); - logQuickFixIsDisplayed = sinon.fake(); - const analytics = { - logQuickFixIsDisplayed, - } as unknown as IAnalytics; - const codeActionKindAdapter = { getQuickFix: sinon.fake(), } as ICodeActionKindAdapter; - issuesActionsProvider = new MockProductService(codeResults, codeActionKindAdapter, analytics); + issuesActionsProvider = new MockProductService(codeResults, codeActionKindAdapter); }); teardown(() => { @@ -84,26 +74,11 @@ suite('Code Actions Provider', () => { } as unknown as TextDocument; // act - const codeActions = issuesActionsProvider.provideCodeActions(document, {} as Range); + const codeActions = issuesActionsProvider.provideCodeActions(document, {} as Range, {} as CodeActionContext); // verify strictEqual(codeActions?.length, 2); strictEqual(codeActions[0].command?.command, SNYK_OPEN_ISSUE_COMMAND); strictEqual(codeActions[1].command?.command, SNYK_OPEN_LOCAL_COMMAND); }); - - test("Logs 'Quick Fix is Displayed' analytical event", () => { - // arrange - const document = { - uri: { - fsPath: '//folderName//test.js', - }, - } as unknown as TextDocument; - - // act - issuesActionsProvider.provideCodeActions(document, {} as Range); - - // verify - strictEqual(logQuickFixIsDisplayed.calledOnce, true); - }); }); diff --git a/src/test/unit/common/error/errorReporter.test.ts b/src/test/unit/common/error/errorReporter.test.ts deleted file mode 100644 index da56125e4..000000000 --- a/src/test/unit/common/error/errorReporter.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { strictEqual } from 'assert'; -import sentryTestkit from 'sentry-testkit'; -import { IConfiguration } from '../../../../snyk/common/configuration/configuration'; -import { SnykConfiguration } from '../../../../snyk/common/configuration/snykConfiguration'; -import { ErrorReporter, TagKeys } from '../../../../snyk/common/error/errorReporter'; -import { envMock } from '../../mocks/env.mock'; -import { LoggerMock } from '../../mocks/logger.mock'; - -suite('ErrorReporter', () => { - const { testkit, sentryTransport } = sentryTestkit(); - const snykConfig = { - sentryKey: 'https://acacaeaccacacacabcaacdacdacadaca@sentry.io/000001', - } as SnykConfiguration; - let configuration: IConfiguration; - - setup(async () => { - configuration = { isFedramp: false } as IConfiguration; - await ErrorReporter.init(configuration, snykConfig, '', envMock, new LoggerMock(), sentryTransport); - }); - - teardown(async () => { - await ErrorReporter.flush(); - testkit.reset(); - }); - - test('Reports error when shouldReportErrors == true', done => { - configuration.shouldReportErrors = true; - const error = new Error('test error'); - - ErrorReporter.capture(error); - - setTimeout(() => { - strictEqual(testkit.reports().length, 1); - strictEqual(testkit.reports()[0].tags.code_request_id, undefined); - strictEqual(testkit.isExist(error), true); - done(); - }, 10); - }); - - test('Reports error with local scope', done => { - configuration.shouldReportErrors = true; - const error = new Error('test error'); - const requestId = '123456789'; - - ErrorReporter.capture(error, { [TagKeys.CodeRequestId]: requestId }); - - setTimeout(() => { - strictEqual(testkit.reports().length, 1); - strictEqual(testkit.reports()[0].tags.code_request_id, requestId); - strictEqual(testkit.isExist(error), true); - done(); - }, 10); - }); - - test("Doesn't report error when shouldReportErrors == false", () => { - configuration.shouldReportErrors = false; - - ErrorReporter.capture(new Error()); - - strictEqual(testkit.reports().length, 0); - }); - - test("Doesn't report error when isFedramp == true", () => { - configuration.isFedramp = true; - - ErrorReporter.capture(new Error()); - - strictEqual(testkit.reports().length, 0); - }); -}); diff --git a/src/test/unit/common/error/integrations/onUncaughtException.test.ts b/src/test/unit/common/error/integrations/onUncaughtException.test.ts deleted file mode 100644 index 309b93370..000000000 --- a/src/test/unit/common/error/integrations/onUncaughtException.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { strictEqual } from 'assert'; -import { OnUncaughtException } from '../../../../../snyk/common/error/integrations/onUncaughtException'; - -suite('ErrorReporter OnUncaughtException Integration', () => { - let uncaughtExceptionIntegration: OnUncaughtException; - - setup(() => { - uncaughtExceptionIntegration = new OnUncaughtException({ - extensionPath: '/Users/snyk/.vscode/extensions/snyk-security.snyk-vulnerability-scanner-1.2.4', - }); - }); - - test('Is extension origin error', () => { - const error = new Error(); - error.stack = `Error: test error - at Test.Runnable.run (/Users/snyk/.vscode/extensions/snyk-security.snyk-vulnerability-scanner-1.2.4/out/extension.js:100:5)`; - - const res = uncaughtExceptionIntegration.isExtensionOriginError(error); - - strictEqual(res, true); - }); - - test('Is not extension origin error - another extension stacktrace', () => { - const posixError = new Error(); - posixError.stack = `Error: test error - at Test.Runnable.run (/Users/snyk/.vscode/extensions/microsoft.sample-extension-1.2.4/out/extension.js:100:5)`; - - const winError = new Error(); - winError.stack = `Error: test error - at Test.Runnable.run (C:\\Users\\snyk\\.vscode\\extensions\\microsoft.sample-extension-1.2.4\\out\\extension.js:100:5)`; - - const posixRes = uncaughtExceptionIntegration.isExtensionOriginError(posixError); - const winRes = uncaughtExceptionIntegration.isExtensionOriginError(winError); - - strictEqual(posixRes, false); - strictEqual(winRes, false); - }); - - test('Is not extension origin error - extension name within path', () => { - const error = new Error(); - error.stack = `/Users/snyk/Git/vscode-extension/snyk-security.snyk-vulnerability-scanner`; - - const res = uncaughtExceptionIntegration.isExtensionOriginError(error); - - strictEqual(res, false); - }); - - test('Is not extension origin error - no stacktrace', () => { - const error = new Error(); - error.stack = undefined; - - const res = uncaughtExceptionIntegration.isExtensionOriginError(error); - - strictEqual(res, false); - }); -}); diff --git a/src/test/unit/common/experiment/services/experimentService.test.ts b/src/test/unit/common/experiment/services/experimentService.test.ts index c407ca33e..dcbfab2ca 100644 --- a/src/test/unit/common/experiment/services/experimentService.test.ts +++ b/src/test/unit/common/experiment/services/experimentService.test.ts @@ -16,7 +16,6 @@ suite('ExperimentService', () => { sinon.stub(SnykConfiguration, 'get').resolves({ amplitudeExperimentApiKey: 'test', - segmentWriteKey: 'test', } as SnykConfiguration); fetchStub = sinon.stub(); @@ -57,7 +56,7 @@ suite('ExperimentService', () => { shouldReportEvents: true, } as unknown as IConfiguration; - const snykConfig = new SnykConfiguration('test', 'test', 'test'); + const snykConfig = new SnykConfiguration('test', 'test'); const service = new ExperimentService(user, new LoggerMock(), config, snykConfig); service.load(); @@ -74,7 +73,7 @@ suite('ExperimentService', () => { shouldReportEvents: true, } as unknown as IConfiguration; - const snykConfig = new SnykConfiguration('test', 'test', 'test'); + const snykConfig = new SnykConfiguration('test', 'test'); const service = new ExperimentService(user, new LoggerMock(), config, snykConfig); service.load(); diff --git a/src/test/unit/common/languageServer/languageServer.test.ts b/src/test/unit/common/languageServer/languageServer.test.ts index 6155e161c..ddce3a8c5 100644 --- a/src/test/unit/common/languageServer/languageServer.test.ts +++ b/src/test/unit/common/languageServer/languageServer.test.ts @@ -4,7 +4,7 @@ import { ReplaySubject } from 'rxjs'; import sinon from 'sinon'; import { v4 } from 'uuid'; import { IAuthenticationService } from '../../../../snyk/base/services/authenticationService'; -import { IConfiguration } from '../../../../snyk/common/configuration/configuration'; +import { FolderConfig, IConfiguration } from '../../../../snyk/common/configuration/configuration'; import { LanguageServer } from '../../../../snyk/common/languageServer/languageServer'; import { ServerSettings } from '../../../../snyk/common/languageServer/settings'; import { DownloadService } from '../../../../snyk/common/services/downloadService'; @@ -16,6 +16,8 @@ import { defaultFeaturesConfigurationStub } from '../../mocks/configuration.mock import { LoggerMock } from '../../mocks/logger.mock'; import { windowMock } from '../../mocks/window.mock'; import { stubWorkspaceConfiguration } from '../../mocks/workspace.mock'; +import { PROTOCOL_VERSION } from '../../../../snyk/common/constants/languageServer'; +import { ExtensionContext } from '../../../../snyk/common/vscode/extensionContext'; suite('Language Server', () => { const authServiceMock = {} as IAuthenticationService; @@ -24,6 +26,7 @@ suite('Language Server', () => { let configurationMock: IConfiguration; let languageServer: LanguageServer; let downloadServiceMock: DownloadService; + let extensionContextMock: ExtensionContext; const path = 'testPath'; const logger = { info(_msg: string) {}, @@ -34,36 +37,41 @@ suite('Language Server', () => { }, } as unknown as LoggerMock; + let contextGetGlobalStateValue: sinon.SinonStub; + setup(() => { configurationMock = { + getAuthenticationMethod(): string { + return 'oauth'; + }, getInsecure(): boolean { return true; }, - getCliPath(): string | undefined { - return path; + getDeltaFindingsEnabled(): boolean { + return false; + }, + getCliPath(): Promise { + return Promise.resolve(path); }, getToken(): Promise { return Promise.resolve('testToken'); }, - shouldReportEvents: true, shouldReportErrors: true, - getSnykLanguageServerPath(): string { - return path; - }, getAdditionalCliParameters() { return '--all-projects -d'; }, isAutomaticDependencyManagementEnabled() { return true; }, + getFeaturesConfiguration() { + return defaultFeaturesConfigurationStub; + }, getPreviewFeatures() { return { advisor: false, + ossQuickfixes: false, }; }, - getFeaturesConfiguration() { - return defaultFeaturesConfigurationStub; - }, severityFilter: { critical: true, high: true, @@ -73,9 +81,22 @@ suite('Language Server', () => { getTrustedFolders(): string[] { return ['/trusted/test/folder']; }, + getFolderConfigs(): FolderConfig[] { + return []; + }, scanningMode: 'auto', } as IConfiguration; + extensionContextMock = { + extensionPath: 'test/path', + getGlobalStateValue: contextGetGlobalStateValue, + updateGlobalStateValue: sinon.fake(), + setContext: sinon.fake(), + subscriptions: [], + addDisposables: sinon.fake(), + getExtensionUri: sinon.fake(), + } as unknown as ExtensionContext; + downloadServiceMock = { downloadReady$: new ReplaySubject(1), } as DownloadService; @@ -120,6 +141,7 @@ suite('Language Server', () => { authServiceMock, logger, downloadServiceMock, + extensionContextMock, ); downloadServiceMock.downloadReady$.next(); @@ -169,6 +191,7 @@ suite('Language Server', () => { authServiceMock, new LoggerMock(), downloadServiceMock, + extensionContextMock, ); downloadServiceMock.downloadReady$.next(); await languageServer.start(); @@ -194,6 +217,7 @@ suite('Language Server', () => { authServiceMock, new LoggerMock(), downloadServiceMock, + extensionContextMock, ); }); @@ -201,11 +225,11 @@ suite('Language Server', () => { const expectedInitializationOptions: ServerSettings = { activateSnykCodeSecurity: 'true', activateSnykCodeQuality: 'true', + enableDeltaFindings: 'false', activateSnykOpenSource: 'false', activateSnykIac: 'true', token: 'testToken', cliPath: 'testPath', - enableTelemetry: 'true', sendErrorReports: 'true', integrationName: 'VS_CODE', integrationVersion: '0.0.0', @@ -219,7 +243,12 @@ suite('Language Server', () => { enableTrustedFoldersFeature: 'true', trustedFolders: ['/trusted/test/folder'], insecure: 'true', + requiredProtocolVersion: PROTOCOL_VERSION.toString(), scanningMode: 'auto', + folderConfigs: [], + authenticationMethod: 'oauth', + enableSnykOSSQuickFixCodeActions: 'false', + hoverVerbosity: 1, }; deepStrictEqual(await languageServer.getInitializationOptions(), expectedInitializationOptions); @@ -235,12 +264,13 @@ suite('Language Server', () => { authServiceMock, new LoggerMock(), downloadServiceMock, + extensionContextMock, ); const initOptions = await languageServer.getInitializationOptions(); strictEqual(initOptions.activateSnykCodeQuality, `true`); - strictEqual(initOptions.activateSnykCodeQuality, `true`); + strictEqual(initOptions.activateSnykCodeSecurity, `true`); }); ['auto', 'manual'].forEach(expectedScanningMode => { diff --git a/src/test/unit/common/languageServer/lsExecutable.test.ts b/src/test/unit/common/languageServer/lsExecutable.test.ts deleted file mode 100644 index 186bdfc53..000000000 --- a/src/test/unit/common/languageServer/lsExecutable.test.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { strictEqual } from 'assert'; -import os from 'os'; -import path from 'path'; -import sinon from 'sinon'; -import { LsExecutable } from '../../../../snyk/common/languageServer/lsExecutable'; -import { LsSupportedPlatform } from '../../../../snyk/common/languageServer/supportedPlatforms'; - -suite('LsExecutable', () => { - teardown(() => { - sinon.restore(); - }); - - test('Returns correct filename for different platforms', () => { - strictEqual(LsExecutable.getFilename('darwinAmd64'), 'snyk-ls_darwin_amd64'); - strictEqual(LsExecutable.getFilename('darwinArm64'), 'snyk-ls_darwin_arm64'); - strictEqual(LsExecutable.getFilename('linux386'), 'snyk-ls_linux_386'); - strictEqual(LsExecutable.getFilename('linuxAmd64'), 'snyk-ls_linux_amd64'); - strictEqual(LsExecutable.getFilename('linuxArm64'), 'snyk-ls_linux_arm64'); - strictEqual(LsExecutable.getFilename('windows386'), 'snyk-ls_windows_386.exe'); - strictEqual(LsExecutable.getFilename('windowsAmd64'), 'snyk-ls_windows_amd64.exe'); - }); - - test('Returns correct versioned filename for different platforms', () => { - const version = '20220101.101010'; - strictEqual(LsExecutable.getVersionedFilename('darwinAmd64', version), `snyk-ls_${version}_darwin_amd64`); - strictEqual(LsExecutable.getVersionedFilename('darwinArm64', version), `snyk-ls_${version}_darwin_arm64`); - strictEqual(LsExecutable.getVersionedFilename('linux386', version), `snyk-ls_${version}_linux_386`); - strictEqual(LsExecutable.getVersionedFilename('linuxAmd64', version), `snyk-ls_${version}_linux_amd64`); - strictEqual(LsExecutable.getVersionedFilename('linuxArm64', version), `snyk-ls_${version}_linux_arm64`); - strictEqual(LsExecutable.getVersionedFilename('windows386', version), `snyk-ls_${version}_windows_386.exe`); - strictEqual(LsExecutable.getVersionedFilename('windowsAmd64', version), `snyk-ls_${version}_windows_amd64.exe`); - }); - - test('Returns correct paths', () => { - const homedirStub = sinon.stub(os, 'homedir'); - const getCurrentWithArchStub = sinon.stub(LsExecutable, 'getCurrentWithArch'); - - // DarwinAmd64 - let macOSPlatform: LsSupportedPlatform = 'darwinAmd64'; - let homedir = '/Users/user'; - getCurrentWithArchStub.returns(macOSPlatform); - homedirStub.returns(homedir); - - let expectedFilename = LsExecutable.getFilename(macOSPlatform); - let expectedCliPath = path.join(homedir, '/Library/Application Support/', 'snyk-ls', expectedFilename); - strictEqual(LsExecutable.getPath(), expectedCliPath); - - // DarwinArm64 - macOSPlatform = 'darwinArm64'; - getCurrentWithArchStub.returns(macOSPlatform); - - expectedFilename = LsExecutable.getFilename(macOSPlatform); - expectedCliPath = path.join(homedir, '/Library/Application Support/', 'snyk-ls', expectedFilename); - strictEqual(LsExecutable.getPath(), expectedCliPath); - - // Linux386 - let linuxPlatform: LsSupportedPlatform = 'linux386'; - homedir = '/home/user'; - getCurrentWithArchStub.returns(linuxPlatform); - homedirStub.returns(homedir); - - expectedFilename = LsExecutable.getFilename(linuxPlatform); - expectedCliPath = path.join(homedir, '/.local/share/', 'snyk-ls', expectedFilename); - strictEqual(LsExecutable.getPath(), expectedCliPath); - - // LinuxAmd64 - linuxPlatform = 'linuxAmd64'; - getCurrentWithArchStub.returns(linuxPlatform); - - expectedFilename = LsExecutable.getFilename(linuxPlatform); - expectedCliPath = path.join(homedir, '/.local/share/', 'snyk-ls', expectedFilename); - strictEqual(LsExecutable.getPath(), expectedCliPath); - - // LinuxArm64 - linuxPlatform = 'linuxArm64'; - getCurrentWithArchStub.returns(linuxPlatform); - - expectedFilename = LsExecutable.getFilename(linuxPlatform); - expectedCliPath = path.join(homedir, '/.local/share/', 'snyk-ls', expectedFilename); - strictEqual(LsExecutable.getPath(), expectedCliPath); - - // Windows386 - let windowsPlatform: LsSupportedPlatform = 'windows386'; - homedir = 'C:\\Users\\user'; - getCurrentWithArchStub.returns(windowsPlatform); - homedirStub.returns(homedir); - - expectedFilename = LsExecutable.getFilename(windowsPlatform); - expectedCliPath = path.join(homedir, '\\AppData\\Local\\', 'snyk-ls', expectedFilename); - strictEqual(LsExecutable.getPath(), expectedCliPath); - - // WindowsAmd64 - windowsPlatform = 'windowsAmd64'; - getCurrentWithArchStub.returns(windowsPlatform); - - expectedFilename = LsExecutable.getFilename(windowsPlatform); - expectedCliPath = path.join(homedir, '\\AppData\\Local\\', 'snyk-ls', expectedFilename); - strictEqual(LsExecutable.getPath(), expectedCliPath); - }); - - test('Return custom path, if provided', () => { - const customPath = '/path/to/cli'; - strictEqual(LsExecutable.getPath(customPath), customPath); - }); - - test('Returns correct platform architecture', () => { - const platformStub = sinon.stub(os, 'platform'); - const archStub = sinon.stub(os, 'arch'); - - // OSX - platformStub.returns('darwin'); - archStub.returns('x64'); - strictEqual(LsExecutable.getCurrentWithArch(), 'darwinAmd64'); - - archStub.returns('arm64'); - strictEqual(LsExecutable.getCurrentWithArch(), 'darwinArm64'); - - // Linux - platformStub.returns('linux'); - archStub.returns('x64'); - strictEqual(LsExecutable.getCurrentWithArch(), 'linuxAmd64'); - - archStub.returns('arm64'); - strictEqual(LsExecutable.getCurrentWithArch(), 'linuxArm64'); - - archStub.returns('ia32'); - strictEqual(LsExecutable.getCurrentWithArch(), 'linux386'); - - // Windows - platformStub.returns('win32'); - archStub.returns('x64'); - strictEqual(LsExecutable.getCurrentWithArch(), 'windowsAmd64'); - - archStub.returns('ia32'); - strictEqual(LsExecutable.getCurrentWithArch(), 'windows386'); - }); -}); diff --git a/src/test/unit/common/languageServer/middleware.test.ts b/src/test/unit/common/languageServer/middleware.test.ts index 082a383c1..95ce7342c 100644 --- a/src/test/unit/common/languageServer/middleware.test.ts +++ b/src/test/unit/common/languageServer/middleware.test.ts @@ -1,7 +1,7 @@ import assert from 'assert'; import sinon from 'sinon'; import { CliExecutable } from '../../../../snyk/cli/cliExecutable'; -import { IConfiguration } from '../../../../snyk/common/configuration/configuration'; +import { FolderConfig, IConfiguration } from '../../../../snyk/common/configuration/configuration'; import { LanguageClientMiddleware } from '../../../../snyk/common/languageServer/middleware'; import { ServerSettings } from '../../../../snyk/common/languageServer/settings'; import { User } from '../../../../snyk/common/user'; @@ -12,30 +12,38 @@ import type { ResponseError, } from '../../../../snyk/common/vscode/types'; import { defaultFeaturesConfigurationStub } from '../../mocks/configuration.mock'; -import { extensionContextMock } from '../../mocks/extensionContext.mock'; +import { ExtensionContext } from '../../../../snyk/common/vscode/extensionContext'; suite('Language Server: Middleware', () => { let configuration: IConfiguration; let user: User; + let extensionContextMock: ExtensionContext; + let contextGetGlobalStateValue: sinon.SinonStub; setup(() => { user = { anonymousId: 'anonymous-id' } as User; configuration = { - shouldReportEvents: false, + getAuthenticationMethod(): string { + return 'oauth'; + }, shouldReportErrors: false, - snykOssApiEndpoint: 'https://dev.snyk.io/api', + snykApiEndpoint: 'https://dev.snyk.io/api', getAdditionalCliParameters: () => '', organization: 'org', getToken: () => Promise.resolve('token'), isAutomaticDependencyManagementEnabled: () => true, - getCliPath: () => '/path/to/cli', + getCliPath: (): Promise => Promise.resolve('/path/to/cli'), getInsecure(): boolean { return true; }, - getPreviewFeatures: () => { - return { - advisor: false, - }; + getDeltaFindingsEnabled(): boolean { + return false; + }, + getPreviewFeatures() { + return { advisor: false, ossQuickfixes: false }; + }, + getOssQuickFixCodeActionsEnabled(): boolean { + return false; }, getFeaturesConfiguration() { return defaultFeaturesConfigurationStub; @@ -47,7 +55,19 @@ suite('Language Server: Middleware', () => { low: true, }, getTrustedFolders: () => ['/trusted/test/folder'], + getFolderConfigs(): FolderConfig[] { + return []; + }, } as IConfiguration; + extensionContextMock = { + extensionPath: 'test/path', + getGlobalStateValue: contextGetGlobalStateValue, + updateGlobalStateValue: sinon.fake(), + setContext: sinon.fake(), + subscriptions: [], + addDisposables: sinon.fake(), + getExtensionUri: sinon.fake(), + } as unknown as ExtensionContext; }); teardown(() => { @@ -55,7 +75,7 @@ suite('Language Server: Middleware', () => { }); test('Configuration request should translate settings', async () => { - const middleware = new LanguageClientMiddleware(configuration, user); + const middleware = new LanguageClientMiddleware(configuration, user, extensionContextMock); const params: ConfigurationParams = { items: [ { @@ -82,25 +102,21 @@ suite('Language Server: Middleware', () => { assert.strictEqual(serverResult.activateSnykCodeQuality, 'true'); assert.strictEqual(serverResult.activateSnykOpenSource, 'false'); assert.strictEqual(serverResult.activateSnykIac, 'true'); - assert.strictEqual(serverResult.endpoint, configuration.snykOssApiEndpoint); + assert.strictEqual(serverResult.endpoint, configuration.snykApiEndpoint); assert.strictEqual(serverResult.additionalParams, configuration.getAdditionalCliParameters()); assert.strictEqual(serverResult.sendErrorReports, `${configuration.shouldReportErrors}`); assert.strictEqual(serverResult.organization, `${configuration.organization}`); - assert.strictEqual(serverResult.enableTelemetry, `${configuration.shouldReportEvents}`); assert.strictEqual( serverResult.manageBinariesAutomatically, `${configuration.isAutomaticDependencyManagementEnabled()}`, ); - assert.strictEqual( - serverResult.cliPath, - CliExecutable.getPath(extensionContextMock.extensionPath, configuration.getCliPath()), - ); + assert.strictEqual(serverResult.cliPath, await configuration.getCliPath()); assert.strictEqual(serverResult.enableTrustedFoldersFeature, 'true'); assert.deepStrictEqual(serverResult.trustedFolders, configuration.getTrustedFolders()); }); test('Configuration request should return an error', async () => { - const middleware = new LanguageClientMiddleware(configuration, user); + const middleware = new LanguageClientMiddleware(configuration, user, extensionContextMock); const params: ConfigurationParams = { items: [ { diff --git a/src/test/unit/common/languageServer/settings.test.ts b/src/test/unit/common/languageServer/settings.test.ts index a85a486f3..d40fb7ef2 100644 --- a/src/test/unit/common/languageServer/settings.test.ts +++ b/src/test/unit/common/languageServer/settings.test.ts @@ -1,30 +1,25 @@ import assert from 'assert'; -import { IConfiguration } from '../../../../snyk/common/configuration/configuration'; -import { LanguageServerSettings, defaultToTrue } from '../../../../snyk/common/languageServer/settings'; +import { FolderConfig, IConfiguration, PreviewFeatures } from '../../../../snyk/common/configuration/configuration'; +import { LanguageServerSettings } from '../../../../snyk/common/languageServer/settings'; import { User } from '../../../../snyk/common/user'; +import sinon from 'sinon'; +import { ExtensionContext } from '../../../../snyk/common/vscode/extensionContext'; suite('LanguageServerSettings', () => { - suite('defaultToTrue', () => { - test('should return "true" for undefined values', () => { - assert.strictEqual(defaultToTrue(undefined), 'true'); - }); - - test('should return "true" for truthy values', () => { - assert.strictEqual(defaultToTrue(true), 'true'); - }); - - test('should return "false" for false values', () => { - assert.strictEqual(defaultToTrue(false), 'false'); - }); - }); - suite('fromConfiguration', () => { test('should generate server settings with default true values for undefined feature toggles', async () => { const mockUser = { anonymousId: 'anonymous-id' } as User; + const extensionContextMock: ExtensionContext = { + extensionPath: 'test/path', + updateGlobalStateValue: sinon.fake(), + setContext: sinon.fake(), + subscriptions: [], + addDisposables: sinon.fake(), + getExtensionUri: sinon.fake(), + } as unknown as ExtensionContext; const mockConfiguration: IConfiguration = { - shouldReportEvents: true, shouldReportErrors: false, - snykOssApiEndpoint: 'https://dev.snyk.io/api', + snykApiEndpoint: 'https://dev.snyk.io/api', organization: 'my-org', // eslint-disable-next-line @typescript-eslint/require-await getToken: async () => 'snyk-token', @@ -33,10 +28,23 @@ suite('LanguageServerSettings', () => { getAdditionalCliParameters: () => '--all-projects -d', getTrustedFolders: () => ['/trusted/path'], getInsecure: () => false, + getDeltaFindingsEnabled: () => false, isAutomaticDependencyManagementEnabled: () => true, + getFolderConfigs(): FolderConfig[] { + return []; + }, + getPreviewFeatures(): PreviewFeatures { + return { advisor: false, ossQuickfixes: false }; + }, + getOssQuickFixCodeActionsEnabled(): boolean { + return false; + }, + getAuthenticationMethod(): string { + return 'oauth'; + }, severityFilter: { critical: true, high: true, medium: true, low: false }, scanningMode: 'scan-mode', - } as IConfiguration; + } as unknown as IConfiguration; const serverSettings = await LanguageServerSettings.fromConfiguration(mockConfiguration, mockUser); @@ -45,7 +53,6 @@ suite('LanguageServerSettings', () => { assert.strictEqual(serverSettings.activateSnykIac, 'true'); assert.strictEqual(serverSettings.deviceId, 'anonymous-id'); - assert.strictEqual(serverSettings.enableTelemetry, 'true'); assert.strictEqual(serverSettings.sendErrorReports, 'false'); assert.strictEqual(serverSettings.cliPath, '/path/to/cli'); diff --git a/src/test/unit/common/services/downloadService.test.ts b/src/test/unit/common/services/downloadService.test.ts index 864867989..d39a96306 100644 --- a/src/test/unit/common/services/downloadService.test.ts +++ b/src/test/unit/common/services/downloadService.test.ts @@ -1,17 +1,10 @@ import { strictEqual } from 'assert'; import sinon, { stub } from 'sinon'; import { Checksum } from '../../../../snyk/cli/checksum'; -import { CliExecutable } from '../../../../snyk/cli/cliExecutable'; import { IConfiguration } from '../../../../snyk/common/configuration/configuration'; -import { - MEMENTO_LS_CHECKSUM, - MEMENTO_LS_LAST_UPDATE_DATE, - MEMENTO_LS_PROTOCOL_VERSION, -} from '../../../../snyk/common/constants/globalState'; -import { PROTOCOL_VERSION } from '../../../../snyk/common/constants/languageServer'; import { Downloader } from '../../../../snyk/common/download/downloader'; -import { LsExecutable } from '../../../../snyk/common/languageServer/lsExecutable'; -import { IStaticLsApi } from '../../../../snyk/common/languageServer/staticLsApi'; +import { CliExecutable } from '../../../../snyk/cli/cliExecutable'; +import { IStaticCliApi } from '../../../../snyk/cli/staticCliApi'; import { ILog } from '../../../../snyk/common/logger/interfaces'; import { Platform } from '../../../../snyk/common/platform'; import { DownloadService } from '../../../../snyk/common/services/downloadService'; @@ -21,7 +14,7 @@ import { windowMock } from '../../mocks/window.mock'; suite('DownloadService', () => { let logger: ILog; - let lsApi: IStaticLsApi; + let cliApi: IStaticCliApi; let context: ExtensionContext; let downloader: Downloader; let configuration: IConfiguration; @@ -34,10 +27,9 @@ suite('DownloadService', () => { contextGetGlobalStateValue = sinon.stub(); apigetSha256Checksum = sinon.stub(); - lsApi = { - getDownloadUrl: sinon.fake(), + cliApi = { + getLatestCliVersion: sinon.fake(), downloadBinary: sinon.fake(), - getMetadata: sinon.fake(), getSha256Checksum: apigetSha256Checksum, }; @@ -55,24 +47,24 @@ suite('DownloadService', () => { configuration = { isAutomaticDependencyManagementEnabled: () => true, - getCustomCliPath: () => undefined, - getSnykLanguageServerPath: () => 'ab/c', - } as unknown as IConfiguration; + getCliReleaseChannel: () => Promise.resolve('stable'), + getCliPath: () => Promise.resolve('path/to/cli'), + } as IConfiguration; - downloader = new Downloader(configuration, lsApi, windowMock, logger); + downloader = new Downloader(configuration, cliApi, windowMock, logger, context); }); teardown(() => { sinon.restore(); }); - test('Tries to download LS if not installed', async () => { + test('Tries to download CLI if not installed', async () => { configuration = { isAutomaticDependencyManagementEnabled: () => true, - getCustomCliPath: () => undefined, - getSnykLanguageServerPath: () => 'abc/d', - } as unknown as IConfiguration; - const service = new DownloadService(context, configuration, lsApi, windowMock, logger, downloader); + getCliReleaseChannel: () => Promise.resolve('stable'), + getCliPath: () => Promise.resolve('path/to/cli'), + } as IConfiguration; + const service = new DownloadService(context, configuration, cliApi, windowMock, logger, downloader); const downloadSpy = stub(service, 'download'); const updateSpy = stub(service, 'update'); await service.downloadOrUpdate(); @@ -81,14 +73,14 @@ suite('DownloadService', () => { strictEqual(updateSpy.called, false); }); - test('Tries to update LS if installed', async () => { + test('Tries to update CLI if installed', async () => { configuration = { isAutomaticDependencyManagementEnabled: () => true, - getCustomCliPath: () => undefined, - getSnykLanguageServerPath: () => 'abc/d', - } as unknown as IConfiguration; - const service = new DownloadService(context, configuration, lsApi, windowMock, logger, downloader); - stub(service, 'isLsInstalled').resolves(true); + getCliReleaseChannel: () => Promise.resolve('stable'), + getCliPath: () => Promise.resolve('path/to/cli'), + } as IConfiguration; + const service = new DownloadService(context, configuration, cliApi, windowMock, logger, downloader); + stub(service, 'isCliInstalled').resolves(true); const downloadSpy = stub(service, 'download'); const updateSpy = stub(service, 'update'); @@ -98,112 +90,14 @@ suite('DownloadService', () => { strictEqual(updateSpy.calledOnce, true); }); - test('Updates LS if >4 days passed since last update and new version available', async () => { - configuration = { - isAutomaticDependencyManagementEnabled: () => true, - getCustomCliPath: () => undefined, - getSnykLanguageServerPath: () => 'abc/d', - } as unknown as IConfiguration; - const service = new DownloadService(context, configuration, lsApi, windowMock, logger, downloader); - stub(service, 'isLsInstalled').resolves(true); - - const fiveDaysInMs = 5 * 24 * 3600 * 1000; - - contextGetGlobalStateValue.withArgs(MEMENTO_LS_LAST_UPDATE_DATE).returns(Date.now() - fiveDaysInMs); - - stubSuccessDownload(apigetSha256Checksum, downloader); - - const updated = await service.update(); - - strictEqual(updated, true); - }); - - test("Doesn't update LS if >4 days passed since last update but no new version available", async () => { - configuration = { - isAutomaticDependencyManagementEnabled: () => true, - getCustomCliPath: () => undefined, - getSnykLanguageServerPath: () => 'abc/d', - } as unknown as IConfiguration; - const service = new DownloadService(context, configuration, lsApi, windowMock, logger, downloader); - stub(service, 'isLsInstalled').resolves(true); - - const fiveDaysInMs = 5 * 24 * 3600 * 1000; - - contextGetGlobalStateValue.withArgs(MEMENTO_LS_LAST_UPDATE_DATE).returns(Date.now() - fiveDaysInMs); - - const curChecksumStr = 'ba6b3c08ce5b9067ecda4f410e3b6c2662e01c064490994555f57b1cc25840f9'; - const latestChecksumStr = 'ba6b3c08ce5b9067ecda4f410e3b6c2662e01c064490994555f57b1cc25840f9'; - const latestChecksum = Checksum.fromDigest(curChecksumStr, latestChecksumStr); - apigetSha256Checksum.returns(latestChecksumStr); - - sinon.stub(Platform, 'getCurrent').returns('darwin'); - sinon.stub(Checksum, 'getChecksumOf').resolves(latestChecksum); - sinon.stub(downloader, 'download').resolves(new LsExecutable('1.0.0', new Checksum(latestChecksumStr))); - - const updated = await service.update(); - - strictEqual(updated, false); - }); - - test("Doesn't update LS if 3 days passed since last update and LSP version is latest", async () => { - const service = new DownloadService(context, configuration, lsApi, windowMock, logger, downloader); - stub(service, 'isLsInstalled').resolves(true); - - const threeDaysInMs = 3 * 24 * 3600 * 1000; - contextGetGlobalStateValue.withArgs(MEMENTO_LS_LAST_UPDATE_DATE).returns(Date.now() - threeDaysInMs); - contextGetGlobalStateValue.withArgs(MEMENTO_LS_PROTOCOL_VERSION).returns(PROTOCOL_VERSION); - - sinon.stub(downloader, 'download').resolves(new LsExecutable('1.0.0', new Checksum('test'))); - - const updated = await service.update(); - - strictEqual(updated, false); - }); - - test('Updates if 3 days passed since last update and LSP version has increased', async () => { - const service = new DownloadService(context, configuration, lsApi, windowMock, logger, downloader); - stub(service, 'isLsInstalled').resolves(true); - - const threeDaysInMs = 3 * 24 * 3600 * 1000; - contextGetGlobalStateValue.withArgs(MEMENTO_LS_LAST_UPDATE_DATE).returns(Date.now() - threeDaysInMs); - contextGetGlobalStateValue.withArgs(MEMENTO_LS_PROTOCOL_VERSION).returns(PROTOCOL_VERSION - 1); - - stubSuccessDownload(apigetSha256Checksum, downloader); - - const updated = await service.update(); - - strictEqual(updated, true); - }); - - test("Doesn't try to update if last LS update date was not set", async () => { - configuration = { - isAutomaticDependencyManagementEnabled: () => true, - getCustomCliPath: () => undefined, - getSnykLanguageServerPath: () => 'abc/d', - } as unknown as IConfiguration; - const service = new DownloadService(context, configuration, lsApi, windowMock, logger, downloader); - contextGetGlobalStateValue.withArgs(MEMENTO_LS_CHECKSUM).returns(undefined); - contextGetGlobalStateValue.withArgs(MEMENTO_LS_LAST_UPDATE_DATE).returns(undefined); - - stub(CliExecutable, 'exists').resolves(true); - - const downloadSpy = stub(service, 'download'); - const updateSpy = stub(service, 'update'); - - await service.downloadOrUpdate(); - - strictEqual(downloadSpy.called, true); - strictEqual(updateSpy.calledOnce, false); - }); - - test("Doesn't download LS if automatic dependency management disabled", async () => { + test("Doesn't download CLI if automatic dependency management disabled", async () => { configuration = { isAutomaticDependencyManagementEnabled: () => false, - getCustomCliPath: () => undefined, - getSnykLanguageServerPath: () => 'abc/d', - } as unknown as IConfiguration; - const service = new DownloadService(context, configuration, lsApi, windowMock, logger, downloader); - stub(service, 'isLsInstalled').resolves(false); + getCliReleaseChannel: () => Promise.resolve('stable'), + getCliPath: () => Promise.resolve('path/to/cli'), + } as IConfiguration; + const service = new DownloadService(context, configuration, cliApi, windowMock, logger, downloader); + stub(service, 'isCliInstalled').resolves(false); const downloadSpy = stub(service, 'download'); const updateSpy = stub(service, 'update'); @@ -223,5 +117,5 @@ function stubSuccessDownload(apigetSha256Checksum: sinon.SinonStub, downloader: sinon.stub(Platform, 'getCurrent').returns('darwin'); sinon.stub(Checksum, 'getChecksumOf').resolves(latestChecksum); - sinon.stub(downloader, 'download').resolves(new LsExecutable('1.0.1', new Checksum(latestChecksumStr))); + sinon.stub(downloader, 'download').resolves(new CliExecutable('1.0.1', new Checksum(latestChecksumStr))); } diff --git a/src/test/unit/common/services/featureFlagService.test.ts b/src/test/unit/common/services/featureFlagService.test.ts new file mode 100644 index 000000000..c4aa75f0c --- /dev/null +++ b/src/test/unit/common/services/featureFlagService.test.ts @@ -0,0 +1,28 @@ +import { strictEqual } from 'assert'; +import sinon from 'sinon'; +import { IVSCodeCommands } from '../../../../snyk/common/vscode/commands'; +import { FeatureFlagService } from '../../../../snyk/common/services/featureFlagService'; +import { SNYK_FEATURE_FLAG_COMMAND } from '../../../../snyk/common/constants/commands'; + +suite('FeatureFlagService', () => { + let commands: IVSCodeCommands; + const executeCommandFake = sinon.fake(); + setup(() => { + executeCommandFake.resetHistory(); + commands = { + executeCommand: executeCommandFake, + } as IVSCodeCommands; + }); + + teardown(() => { + sinon.restore(); + }); + + test('getCodeLesson executes correct command', async () => { + const featureFlagService = new FeatureFlagService(commands); + + await featureFlagService.fetchFeatureFlag('test'); + strictEqual(executeCommandFake.calledOnce, true); + strictEqual(executeCommandFake.calledWith(SNYK_FEATURE_FLAG_COMMAND, 'test'), true); + }); +}); diff --git a/src/test/unit/common/services/learnService.test.ts b/src/test/unit/common/services/learnService.test.ts index e5715a87d..779a38106 100644 --- a/src/test/unit/common/services/learnService.test.ts +++ b/src/test/unit/common/services/learnService.test.ts @@ -1,10 +1,9 @@ import { strictEqual } from 'assert'; import sinon from 'sinon'; -import { IVSCodeCommands } from '../../../../snyk/common/vscode/commands'; -import { LearnService } from '../../../../snyk/common/services/learnService'; -import { OssIssueCommandArg } from '../../../../snyk/snykOss/views/ossVulnerabilityTreeProvider'; -import { CodeIssueData, Issue, IssueSeverity } from '../../../../snyk/common/languageServer/types'; import { SNYK_GET_LESSON_COMMAND } from '../../../../snyk/common/constants/commands'; +import { CodeIssueData, Issue, IssueSeverity } from '../../../../snyk/common/languageServer/types'; +import { LearnService } from '../../../../snyk/common/services/learnService'; +import { IVSCodeCommands } from '../../../../snyk/common/vscode/commands'; suite('LearnService', () => { let commands: IVSCodeCommands; @@ -20,21 +19,6 @@ suite('LearnService', () => { sinon.restore(); }); - test('getOssLesson executes correct command', async () => { - const learnService = new LearnService(commands); - - const issue: OssIssueCommandArg = { - id: 'id', - packageManager: 'packageManager', - } as OssIssueCommandArg; - - await learnService.getOssLesson(issue); - strictEqual(executeCommandFake.calledOnce, true); - strictEqual( - executeCommandFake.calledWith(SNYK_GET_LESSON_COMMAND, issue.id, issue.packageManager, '', '', 4), - true, - ); - }); test('getCodeLesson executes correct command', async () => { const learnService = new LearnService(commands); const issue: Issue = { @@ -50,10 +34,14 @@ suite('LearnService', () => { cols: [1, 2], rows: [1, 2], isSecurityType: true, + priorityScore: 880, + hasAIFix: false, + details: 'not used', }, title: 'not used', severity: IssueSeverity.Critical, filePath: 'not used', + isIgnored: false, }; await learnService.getCodeLesson(issue); diff --git a/src/test/unit/common/services/notificationService.test.ts b/src/test/unit/common/services/notificationService.test.ts deleted file mode 100644 index e06cb4f3a..000000000 --- a/src/test/unit/common/services/notificationService.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { strictEqual } from 'assert'; -import sinon from 'sinon'; -import { snykMessages } from '../../../../snyk/base/messages/snykMessages'; -import { IAnalytics } from '../../../../snyk/common/analytics/itly'; -import { IConfiguration } from '../../../../snyk/common/configuration/configuration'; -import { NotificationService } from '../../../../snyk/common/services/notificationService'; -import { IVSCodeCommands } from '../../../../snyk/common/vscode/commands'; -import { IVSCodeWindow } from '../../../../snyk/common/vscode/window'; -import { LoggerMock } from '../../mocks/logger.mock'; - -suite('NotificationService', () => { - let commands: IVSCodeCommands; - let configuration: IConfiguration; - - setup(() => { - commands = { - executeCommand: sinon.fake(), - } as IVSCodeCommands; - }); - - teardown(() => { - sinon.restore(); - }); - - test('"Welcome Button Is Clicked" analytical event is logged', async () => { - const logWelcomeButtonIsClickedFake = sinon.fake(); - const window = { - showInformationMessage: () => Promise.resolve(snykMessages.welcome.button), - } as unknown as IVSCodeWindow; - const analytics = { - logWelcomeButtonIsClicked: logWelcomeButtonIsClickedFake, - } as unknown as IAnalytics; - configuration = { - shouldShowWelcomeNotification: true, - hideOssBackgroundScanNotification: sinon.fake(), - } as unknown as IConfiguration; - - const notificationService = new NotificationService(window, commands, configuration, analytics, new LoggerMock()); - await notificationService.init(); - - strictEqual(logWelcomeButtonIsClickedFake.calledOnce, true); - }); -}); diff --git a/src/test/unit/common/services/productService.test.ts b/src/test/unit/common/services/productService.test.ts index 5b073ae20..4caf2ac6c 100644 --- a/src/test/unit/common/services/productService.test.ts +++ b/src/test/unit/common/services/productService.test.ts @@ -13,11 +13,14 @@ import { IVSCodeLanguages } from '../../../../snyk/common/vscode/languages'; import { IVSCodeWorkspace } from '../../../../snyk/common/vscode/workspace'; import { LanguageServerMock } from '../../mocks/languageServer.mock'; import { LoggerMock } from '../../mocks/logger.mock'; +import { IDiagnosticsIssueProvider } from '../../../../snyk/common/services/diagnosticsService'; type ProductData = { productName: string; }; class MockProductService extends ProductService { + productType: ScanProduct; + subscribeToLsScanMessages(): Subscription { return this.languageServer.scan$.subscribe((scan: Scan) => { super.handleLsScanMessage(scan as Scan); @@ -53,6 +56,9 @@ suite('Product Service', () => { new WorkspaceTrust(), ls, {} as IVSCodeLanguages, + { + getIssuesFromDiagnostics: () => [], + } as IDiagnosticsIssueProvider, new LoggerMock(), ); }); @@ -67,6 +73,7 @@ suite('Product Service', () => { folderPath: 'test/path', issues: [], status: ScanStatus.InProgress, + errorMessage: '', }); strictEqual(service.isAnalysisRunning, true); @@ -80,12 +87,14 @@ suite('Product Service', () => { folderPath, issues: [], status: ScanStatus.InProgress, + errorMessage: '', }); ls.scan$.next({ product: ScanProduct.InfrastructureAsCode, folderPath, issues: [], status: ScanStatus.Success, + errorMessage: '', }); strictEqual(service.isAnalysisRunning, false); @@ -99,12 +108,14 @@ suite('Product Service', () => { folderPath, issues: [], status: ScanStatus.InProgress, + errorMessage: 'Scan failed', }); ls.scan$.next({ product: ScanProduct.InfrastructureAsCode, folderPath, issues: [], status: ScanStatus.Error, + errorMessage: 'Scan failed', }); strictEqual(service.isAnalysisRunning, false); @@ -119,18 +130,21 @@ suite('Product Service', () => { folderPath: folder1Path, issues: [], status: ScanStatus.InProgress, + errorMessage: '', }); ls.scan$.next({ product: ScanProduct.InfrastructureAsCode, folderPath: folder2Path, issues: [], status: ScanStatus.InProgress, + errorMessage: '', }); ls.scan$.next({ product: ScanProduct.InfrastructureAsCode, folderPath: folder1Path, issues: [], status: ScanStatus.Success, + errorMessage: '', }); strictEqual(service.isAnalysisRunning, true); @@ -140,6 +154,7 @@ suite('Product Service', () => { folderPath: folder2Path, issues: [], status: ScanStatus.Success, + errorMessage: '', }); strictEqual(service.isAnalysisRunning, false); diff --git a/src/test/unit/common/user.test.ts b/src/test/unit/common/user.test.ts index 6d573531f..8d80b9024 100644 --- a/src/test/unit/common/user.test.ts +++ b/src/test/unit/common/user.test.ts @@ -1,28 +1,10 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { strictEqual } from 'assert'; import sinon from 'sinon'; -import { IAnalytics } from '../../../snyk/common/analytics/itly'; import { User, UserDto } from '../../../snyk/common/user'; import { IVSCodeCommands } from '../../../snyk/common/vscode/commands'; suite('User', () => { - test('Identification calls analytics identify', async () => { - const identifyFake = sinon.fake(); - const analytics = { - identify: identifyFake, - } as unknown as IAnalytics; - const commandExecutor = { - executeCommand(_command, ..._rest) { - return Promise.resolve({ id: 'test', username: 't' } as UserDto); - }, - } as IVSCodeCommands; - - const user = new User(); - await user.identify(commandExecutor, analytics); - - strictEqual(identifyFake.called, true); - }); - test('Returns authenticated id in SHA-256', () => { const user = new User(undefined, '185958e2-6317-4543-b9bc-960d94890353'); diff --git a/src/test/unit/download/downloader.test.ts b/src/test/unit/download/downloader.test.ts index 136630947..358c8fc94 100644 --- a/src/test/unit/download/downloader.test.ts +++ b/src/test/unit/download/downloader.test.ts @@ -4,43 +4,40 @@ import sinon from 'sinon'; import { Checksum } from '../../../snyk/cli/checksum'; import { IConfiguration } from '../../../snyk/common/configuration/configuration'; import { Downloader } from '../../../snyk/common/download/downloader'; -import { LsExecutable } from '../../../snyk/common/languageServer/lsExecutable'; -import { IStaticLsApi, LsMetadata } from '../../../snyk/common/languageServer/staticLsApi'; +import { CliExecutable } from '../../../snyk/cli/cliExecutable'; +import { IStaticCliApi } from '../../../snyk/cli/staticCliApi'; import { ILog } from '../../../snyk/common/logger/interfaces'; import { LoggerMock } from '../mocks/logger.mock'; import { windowMock } from '../mocks/window.mock'; +import { ExtensionContext } from '../../../snyk/common/vscode/extensionContext'; -suite('LS Downloader (LS)', () => { +suite('CLI Downloader (CLI)', () => { let logger: ILog; - let lsApi: IStaticLsApi; + let cliApi: IStaticCliApi; let configuration: IConfiguration; - + let extensionContextMock: ExtensionContext; setup(() => { - lsApi = { - getDownloadUrl: sinon.fake(), + cliApi = { + getLatestCliVersion: sinon.fake(), downloadBinary: sinon.fake(), - getMetadata(): Promise { - return Promise.resolve({ - commit: 'abc', - date: '01.01.2001', - // eslint-disable-next-line camelcase - previous_tag: '', - // eslint-disable-next-line camelcase - project_name: 'testProject', - runtime: 'darwin', - tag: 'v20010101.010101', - version: 'v20010101.010101', - }); - }, getSha256Checksum: sinon.fake(), }; logger = new LoggerMock(); configuration = { isAutomaticDependencyManagementEnabled: () => true, - getSnykLanguageServerPath(): string { - return 'abc/d'; + getCliReleaseChannel: () => Promise.resolve('stable'), + getCliPath(): Promise { + return Promise.resolve('abc/d'); }, } as IConfiguration; + extensionContextMock = { + extensionPath: 'test/path', + updateGlobalStateValue: sinon.fake(), + setContext: sinon.fake(), + subscriptions: [], + addDisposables: sinon.fake(), + getExtensionUri: sinon.fake(), + } as unknown as ExtensionContext; }); // noinspection DuplicatedCode @@ -48,31 +45,30 @@ suite('LS Downloader (LS)', () => { sinon.restore(); }); - test('Download of LS fails if platform is not supported', async () => { - const downloader = new Downloader(configuration, lsApi, windowMock, logger); - sinon.stub(LsExecutable, 'getCurrentWithArch').throws(new Error()); + test('Download of CLI fails if platform is not supported', async () => { + const downloader = new Downloader(configuration, cliApi, windowMock, logger, extensionContextMock); + sinon.stub(CliExecutable, 'getCurrentWithArch').throws(new Error()); await rejects(() => downloader.download()); }); - test('Download of LS removes executable, if it exists', async () => { - const downloader = new Downloader(configuration, lsApi, windowMock, logger); + test('Download of CLI removes executable, if it exists', async () => { + const downloader = new Downloader(configuration, cliApi, windowMock, logger, extensionContextMock); - sinon.stub(LsExecutable, 'getCurrentWithArch').returns('darwinArm64'); + sinon.stub(CliExecutable, 'getCurrentWithArch').resolves('macos_arm64'); sinon.stub(fs, 'access').returns(Promise.resolve()); const unlink = sinon.stub(fs, 'unlink'); await downloader.download(); - const lsPath = LsExecutable.getPath(configuration.getSnykLanguageServerPath()); - - strictEqual(unlink.calledOnceWith(lsPath), true); + const cliPath = (await configuration.getCliPath()) ?? ''; + strictEqual(unlink.calledOnceWith(cliPath), true); }); - test('Rejects downloaded LS when integrity check fails', async () => { - const downloader = new Downloader(configuration, lsApi, windowMock, logger); - sinon.stub(LsExecutable, 'getCurrentWithArch').returns('darwinAmd64'); + test('Rejects downloaded CLI when integrity check fails', async () => { + const downloader = new Downloader(configuration, cliApi, windowMock, logger, extensionContextMock); + sinon.stub(CliExecutable, 'getCurrentWithArch').resolves('macos_arm64'); sinon.stub(fs); - sinon.stub(downloader, 'downloadLs').resolves(new Checksum('test')); + sinon.stub(downloader, 'downloadCli').resolves(new Checksum('test')); await rejects(() => downloader.download()); }); diff --git a/src/test/unit/mocks/extensionContext.mock.ts b/src/test/unit/mocks/extensionContext.mock.ts index 4cc92a339..9d5bc5d99 100644 --- a/src/test/unit/mocks/extensionContext.mock.ts +++ b/src/test/unit/mocks/extensionContext.mock.ts @@ -4,6 +4,6 @@ export const extensionContextMock = { secrets: { store: (_key: string, _value: string) => Promise.resolve(), get: () => Promise.resolve(), - delete: () => Promise.resolve(), }, + extensionPath: 'path/to/extension', } as unknown as ExtensionContext; diff --git a/src/test/unit/mocks/uri.mock.ts b/src/test/unit/mocks/uri.mock.ts deleted file mode 100644 index 3104acb39..000000000 --- a/src/test/unit/mocks/uri.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Uri } from '../../../snyk/common/vscode/types'; -import { IUriAdapter } from '../../../snyk/common/vscode/uri'; - -export class UriAdapterMock implements IUriAdapter { - file(path: string): Uri { - return { - path: path, - } as Uri; - } - - parse(path: string): Uri { - return { - path: path, - } as Uri; - } -} - -export const uriAdapterMock = new UriAdapterMock(); diff --git a/src/test/unit/mocks/workspace.mock.ts b/src/test/unit/mocks/workspace.mock.ts index 04a04df08..a32acf384 100644 --- a/src/test/unit/mocks/workspace.mock.ts +++ b/src/test/unit/mocks/workspace.mock.ts @@ -1,5 +1,3 @@ -import * as os from 'os'; -import path from 'path'; import { IVSCodeWorkspace } from '../../../snyk/common/vscode/workspace'; export function stubWorkspaceConfiguration(configSetting: string, returnValue: T | undefined): IVSCodeWorkspace { @@ -8,13 +6,8 @@ export function stubWorkspaceConfiguration(configSetting: string, returnValue if (`${identifier}.${key}` === configSetting) return returnValue; return undefined; }, + updateConfiguration(_configurationIdentifier, _section, _value, _configurationTarget, _overrideInLanguage) { + return Promise.resolve(); + }, } as IVSCodeWorkspace; } - -export const workspaceMock = { - getWorkspaceFolders() { - return [workspaceFolder]; - }, -} as IVSCodeWorkspace; - -export const workspaceFolder = path.join(os.homedir(), 'snyk/project'); diff --git a/src/test/unit/snykCode/codeActions/codeIssuesActionsProvider.test.ts b/src/test/unit/snykCode/codeActions/codeIssuesActionsProvider.test.ts index 0a5870c19..3a787cf1a 100644 --- a/src/test/unit/snykCode/codeActions/codeIssuesActionsProvider.test.ts +++ b/src/test/unit/snykCode/codeActions/codeIssuesActionsProvider.test.ts @@ -1,21 +1,24 @@ import { strictEqual } from 'assert'; import sinon from 'sinon'; -import { IAnalytics } from '../../../../snyk/common/analytics/itly'; import { SNYK_IGNORE_ISSUE_COMMAND, SNYK_OPEN_ISSUE_COMMAND } from '../../../../snyk/common/constants/commands'; import { CodeIssueData, Issue } from '../../../../snyk/common/languageServer/types'; import { WorkspaceFolderResult } from '../../../../snyk/common/services/productService'; import { ICodeActionAdapter, ICodeActionKindAdapter } from '../../../../snyk/common/vscode/codeAction'; import { IVSCodeLanguages } from '../../../../snyk/common/vscode/languages'; -import { CodeActionKind, Range, TextDocument } from '../../../../snyk/common/vscode/types'; +import { CodeActionContext, CodeActionKind, Range, TextDocument } from '../../../../snyk/common/vscode/types'; import { SnykCodeActionsProvider } from '../../../../snyk/snykCode/codeActions/codeIssuesActionsProvider'; import { IssueUtils } from '../../../../snyk/snykCode/utils/issueUtils'; +import { IConfiguration } from '../../../../snyk/common/configuration/configuration'; suite('Snyk Code actions provider', () => { let issuesActionsProvider: SnykCodeActionsProvider; - let logQuickFixIsDisplayed: sinon.SinonSpy; + let configuration: IConfiguration; + let codeResults: Map>; + let codeActionAdapter: ICodeActionAdapter; + let codeActionKindAdapter: ICodeActionKindAdapter; setup(() => { - const codeResults = new Map>(); + codeResults = new Map>(); codeResults.set('folderName', [ { filePath: '//folderName//test.js', @@ -25,18 +28,13 @@ suite('Snyk Code actions provider', () => { } as unknown as Issue, ]); - logQuickFixIsDisplayed = sinon.fake(); - const analytics = { - logQuickFixIsDisplayed, - } as unknown as IAnalytics; - - const codeActionAdapter = { + codeActionAdapter = { create: (_: string, _kind?: CodeActionKind) => ({ command: {}, }), } as ICodeActionAdapter; - const codeActionKindAdapter = { + codeActionKindAdapter = { getQuickFix: sinon.fake(), } as ICodeActionKindAdapter; @@ -46,12 +44,18 @@ suite('Snyk Code actions provider', () => { sinon.stub(IssueUtils, 'createVsCodeRange').returns(rangeMock); + configuration = { + getFeatureFlag(_: string): boolean { + return true; + }, + } as IConfiguration; + issuesActionsProvider = new SnykCodeActionsProvider( codeResults, codeActionAdapter, codeActionKindAdapter, {} as IVSCodeLanguages, - analytics, + configuration, ); }); @@ -59,7 +63,7 @@ suite('Snyk Code actions provider', () => { sinon.restore(); }); - test('Provides code actions', () => { + test('Provides code actions, inline ignores disabled', () => { // arrange const document = { uri: { @@ -67,17 +71,27 @@ suite('Snyk Code actions provider', () => { }, } as unknown as TextDocument; + issuesActionsProvider = new SnykCodeActionsProvider( + codeResults, + codeActionAdapter, + codeActionKindAdapter, + {} as IVSCodeLanguages, + { + getFeatureFlag(_: string): boolean { + return false; + }, + } as IConfiguration, + ); + // act - const codeActions = issuesActionsProvider.provideCodeActions(document, {} as Range); + const codeActions = issuesActionsProvider.provideCodeActions(document, {} as Range, {} as CodeActionContext); // verify - strictEqual(codeActions?.length, 3); + strictEqual(codeActions?.length, 1); strictEqual(codeActions[0].command?.command, SNYK_OPEN_ISSUE_COMMAND); - strictEqual(codeActions[1].command?.command, SNYK_IGNORE_ISSUE_COMMAND); - strictEqual(codeActions[2].command?.command, SNYK_IGNORE_ISSUE_COMMAND); }); - test("Logs 'Quick Fix is Displayed' analytical event", () => { + test('Provides code actions, inline ignores enabled', () => { // arrange const document = { uri: { @@ -86,9 +100,12 @@ suite('Snyk Code actions provider', () => { } as unknown as TextDocument; // act - issuesActionsProvider.provideCodeActions(document, {} as Range); + const codeActions = issuesActionsProvider.provideCodeActions(document, {} as Range, {} as CodeActionContext); // verify - strictEqual(logQuickFixIsDisplayed.calledOnce, true); + strictEqual(codeActions?.length, 3); + strictEqual(codeActions[0].command?.command, SNYK_OPEN_ISSUE_COMMAND); + strictEqual(codeActions[1].command?.command, SNYK_IGNORE_ISSUE_COMMAND); + strictEqual(codeActions[2].command?.command, SNYK_IGNORE_ISSUE_COMMAND); }); }); diff --git a/src/test/unit/snykCode/codeService.test.ts b/src/test/unit/snykCode/codeService.test.ts index 7aae49382..f5d917817 100644 --- a/src/test/unit/snykCode/codeService.test.ts +++ b/src/test/unit/snykCode/codeService.test.ts @@ -1,6 +1,5 @@ import { strictEqual } from 'assert'; import sinon from 'sinon'; -import { IAnalytics } from '../../../snyk/common/analytics/itly'; import { IConfiguration } from '../../../snyk/common/configuration/configuration'; import { WorkspaceTrust } from '../../../snyk/common/configuration/trustedFolders'; import { ILanguageServer } from '../../../snyk/common/languageServer/languageServer'; @@ -15,6 +14,7 @@ import { ICodeSuggestionWebviewProvider } from '../../../snyk/snykCode/views/int import { LanguageServerMock } from '../mocks/languageServer.mock'; import { languagesMock } from '../mocks/languages.mock'; import { LoggerMock } from '../mocks/logger.mock'; +import { IDiagnosticsIssueProvider } from '../../../snyk/common/services/diagnosticsService'; suite('Code Service', () => { let ls: ILanguageServer; @@ -44,8 +44,8 @@ suite('Code Service', () => { new WorkspaceTrust(), ls, languagesMock, + {} as IDiagnosticsIssueProvider, new LoggerMock(), - {} as IAnalytics, ); }); @@ -59,6 +59,7 @@ suite('Code Service', () => { folderPath: 'test/path', issues: [], status: ScanStatus.InProgress, + errorMessage: '', }); strictEqual(service.isAnalysisRunning, false); diff --git a/src/test/unit/snykCode/helpers.test.ts b/src/test/unit/snykCode/helpers.test.ts new file mode 100644 index 000000000..595e454c3 --- /dev/null +++ b/src/test/unit/snykCode/helpers.test.ts @@ -0,0 +1,70 @@ +import { strictEqual } from 'assert'; +import { ExampleCommitFix } from '../../../snyk/common/languageServer/types'; +import { encodeExampleCommitFixes } from '../../../snyk/snykCode/utils/htmlEncoder'; + +const exampleInput: ExampleCommitFix[] = [ + { + commitURL: + 'https://github.com/hiddentao/fast-levenshtein/commit/8d67bde78c9e75b5e253b0e84d0cbf227ffb98f9?diff=split#diff-a58852f173bee316460a26934b8a3c4d79b1acb88af655346ae74adce78113f7L-1', + lines: [ + { + line: '\t\t\t\t\tuploadUserPicture(req.user.uid, req.files.userPhoto.name, req.files.userPhoto.path, res);\n', + lineNumber: 101, + lineChange: 'removed', + }, + { + line: " files.map(file => path.join(...[dashboardAppPath].concat(file.fileName.split('/'))))\n", + lineNumber: 145, + lineChange: 'added', + }, + ], + }, + { + commitURL: + 'https://github.com/guzzle/guzzle/commit/3d499a1b7ce589c3ef39d78bb1730d83d8a89c79?diff=split#diff-dea67d130560147fa1eeb821ab305ce5c0d44c5a3a0b16f3f11b4cb48008dcbaL-1', + lines: [ + { + line: "\tvar template = routes['/' + req.params.path] || routes['/'];\n", + lineNumber: 43, + lineChange: 'added', + }, + { + line: "\t\t\tconsole.log('Info: Attempting upload to: '+ uploadPath);\n", + lineNumber: 130, + lineChange: 'none', + }, + ], + }, + { + commitURL: 'https://github.com/example/security-fix/commit/1234567890abcdef?diff=split#diff-securityL-1', + lines: [ + { + line: `'that.responses = eval('('+ request.body + ')');\n'`, // Potential security vulnerability: eval with user input + lineNumber: 50, + lineChange: 'removed', + }, + ], + }, +]; + +suite('encodeExampleCommitFixes', () => { + test('should encode lines', () => { + // The `he` library encodes characters into their hexadecimal numeric character reference. + const encodedResults = encodeExampleCommitFixes(exampleInput); + + strictEqual( + encodedResults[0].lines[0].line, + ' uploadUserPicture(req.user.uid, req.files.userPhoto.name, req.files.userPhoto.path, res);\n', + ); + + strictEqual( + encodedResults[0].lines[1].line, + ' files.map(file => path.join(...[dashboardAppPath].concat(file.fileName.split('/'))))\n', + ); + + strictEqual( + encodedResults[2].lines[0].line, + ''that.responses = eval('('+ request.body + ')');\n' + ''', + ); + }); +}); diff --git a/src/test/unit/snykCode/hoverProvider/hoverProvider.test.ts b/src/test/unit/snykCode/hoverProvider/hoverProvider.test.ts deleted file mode 100644 index bd212563c..000000000 --- a/src/test/unit/snykCode/hoverProvider/hoverProvider.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { strictEqual } from 'assert'; -import sinon from 'sinon'; -import { IAnalytics } from '../../../../snyk/common/analytics/itly'; -import { IHoverAdapter } from '../../../../snyk/common/vscode/hover'; -import { IVSCodeLanguages } from '../../../../snyk/common/vscode/languages'; -import { IMarkdownStringAdapter } from '../../../../snyk/common/vscode/markdownString'; -import { Diagnostic, DiagnosticCollection, Position, TextDocument, Uri } from '../../../../snyk/common/vscode/types'; -import { DisposableHoverProvider } from '../../../../snyk/snykCode/hoverProvider/hoverProvider'; -import { ISnykCodeAnalyzer } from '../../../../snyk/snykCode/interfaces'; -import { IssueUtils } from '../../../../snyk/snykCode/utils/issueUtils'; -import { LoggerMock } from '../../mocks/logger.mock'; - -suite('Snyk Code hover provider', () => { - let provider: DisposableHoverProvider; - const logIssueHoverIsDisplayed = sinon.fake(); - - setup(() => { - const analyzer = { - findSuggestion: (_: string) => true, - } as unknown as ISnykCodeAnalyzer; - const vscodeLanguagesMock = sinon.fake() as unknown as IVSCodeLanguages; - - const analytics = { - logIssueHoverIsDisplayed, - } as unknown as IAnalytics; - - provider = new DisposableHoverProvider(analyzer, new LoggerMock(), vscodeLanguagesMock, analytics, { - get: sinon.fake(), - } as IMarkdownStringAdapter); - }); - - teardown(() => { - sinon.restore(); - }); - - test("Logs 'Issue Hover is Displayed' analytical event", () => { - // prepare objects - const snykReview = { - has: (_: Uri): boolean => true, - get: sinon.fake(), - } as unknown as DiagnosticCollection; - - sinon.stub(IssueUtils, 'findIssueWithRange').returns({} as Diagnostic); - - const hoverProvider = provider.getHover(snykReview, { - create: sinon.fake() as unknown, - } as IHoverAdapter); - - const document = { - uri: 'test.js', - } as unknown as TextDocument; - - // act - hoverProvider(document, {} as Position); - - // verify - strictEqual(logIssueHoverIsDisplayed.calledOnce, true); - }); -}); diff --git a/src/test/unit/snykCode/utils/analysisUtils.test.ts b/src/test/unit/snykCode/utils/analysisUtils.test.ts index d7755d2bb..0baa75654 100644 --- a/src/test/unit/snykCode/utils/analysisUtils.test.ts +++ b/src/test/unit/snykCode/utils/analysisUtils.test.ts @@ -1,67 +1,19 @@ -import { Marker } from '@snyk/code-client'; -import { deepStrictEqual, strictEqual } from 'assert'; +import { strictEqual } from 'assert'; import path from 'path'; import sinon from 'sinon'; -import { IVSCodeLanguages } from '../../../../snyk/common/vscode/languages'; import { IVSCodeWorkspace } from '../../../../snyk/common/vscode/workspace'; -import { - createIssueRange, - createIssueRelatedInformation, - getAbsoluteMarkerFilePath, -} from '../../../../snyk/snykCode/utils/analysisUtils'; -import { IssuePlacementPosition } from '../../../../snyk/snykCode/utils/issueUtils'; -import { languagesMock } from '../../mocks/languages.mock'; -import { uriAdapterMock } from '../../mocks/uri.mock'; -import { workspaceFolder, workspaceMock } from '../../mocks/workspace.mock'; +import { getAbsoluteMarkerFilePath } from '../../../../snyk/snykCode/utils/analysisUtils'; suite('Snyk Code Analysis Utils', () => { const createRangeMock = sinon.mock(); - let languages: IVSCodeLanguages; let workspace: IVSCodeWorkspace; setup(() => { - languages = { - createRange: createRangeMock, - } as unknown as IVSCodeLanguages; workspace = {} as IVSCodeWorkspace; }); teardown(() => createRangeMock.reset()); - test('Create issue range copes with non-negative values', () => { - const position: IssuePlacementPosition = { - cols: { - start: 1, - end: 1, - }, - rows: { - start: 1, - end: 1, - }, - }; - - createIssueRange(position, languages); - - sinon.assert.calledOnceWithExactly(createRangeMock, 1, 1, 1, 1); - }); - - test('Create issue range copes with negative values', () => { - const position: IssuePlacementPosition = { - cols: { - start: -1, - end: -1, - }, - rows: { - start: -1, - end: -1, - }, - }; - - createIssueRange(position, languages); - - sinon.assert.calledOnceWithExactly(createRangeMock, 0, 0, 0, 0); - }); - test('Returns correct absolute path if no marker file path provided', () => { // arrange const suggestionFilePath = '/Users/snyk/goof/test.js'; @@ -104,56 +56,4 @@ suite('Snyk Code Analysis Utils', () => { // assert strictEqual(absoluteFilePath, path.resolve(workspaceFolder, relativeMarkerFilePath)); }); - - test('Creates correct related information for inter-file issues', () => { - const file1Uri = 'file1.js'; - const file2Uri = 'file2.js'; - - const markers: Marker[] = [ - { - msg: [0, 16], - pos: [ - { - file: file1Uri, - rows: [1, 1], - cols: [1, 1], - }, - { - file: file2Uri, - rows: [2, 2], - cols: [10, 10], - }, - ], - }, - ]; - - const message = - 'Unsanitized input from data from a remote resource flows into bypassSecurityTrustHtml, where it is used to render an HTML page returned to the user. This may result in a Cross-Site Scripting attack (XSS).'; - - const information = createIssueRelatedInformation( - markers, - file2Uri, - message, - languagesMock, - workspaceMock, - uriAdapterMock, - ); - - deepStrictEqual(information, [ - { - message: 'Unsanitized input', - location: { - uri: { path: path.join(workspaceFolder, file1Uri) }, - range: { start: { line: 0, character: 0 }, end: { line: 0, character: 1 } }, - }, - }, - { - message: 'Unsanitized input', - location: { - uri: { path: path.join(workspaceFolder, file2Uri) }, - range: { start: { line: 1, character: 9 }, end: { line: 1, character: 10 } }, - }, - }, - ]); - }); }); diff --git a/src/test/unit/snykCode/utils/patchUtils.test.ts b/src/test/unit/snykCode/utils/patchUtils.test.ts new file mode 100644 index 000000000..96e5ba63e --- /dev/null +++ b/src/test/unit/snykCode/utils/patchUtils.test.ts @@ -0,0 +1,118 @@ +import assert from 'assert'; +import * as patchUtils from '../../../../snyk/snykCode/utils/patchUtils'; +import { IVSCodeLanguages } from '../../../../snyk/common/vscode/languages'; + +suite('generateDecorationOptions', () => { + let languages: IVSCodeLanguages; + + setup(() => { + languages = { + createRange: (startLine: number, startCharacter: number, endLine: number, endCharacter: number) => ({ + start: { line: startLine, character: startCharacter }, + end: { line: endLine, character: endCharacter }, + }), + } as IVSCodeLanguages; + }); + + test('generates ranges for adding to empty files', () => { + const patch = `--- /home/mike/boom ++++ /home/mike/boom-fixed +@@ -1 1,4 @@ ++ def main(): ++ print("hello world") ++ ++ main()`; + const result = patchUtils.generateDecorationOptions(patch, languages); + assert.strictEqual(result.length, 4); + + assert.strictEqual(result[0].range.start.line, 0); + assert.strictEqual(result[0].range.start.character, 0); + assert.strictEqual(result[0].range.end.line, 0); + assert.strictEqual(result[0].range.end.character, 12); + + assert.strictEqual(result[3].range.start.line, 3); + assert.strictEqual(result[3].range.start.character, 0); + assert.strictEqual(result[3].range.end.line, 3); + assert.strictEqual(result[3].range.end.character, 7); + }); + + test('generates empty result for completely removing a file', () => { + const patch = `--- /home/mike/boom ++++ /home/mike/boom-fixed +@@ -1,4 1 @@ +- def main(): +- print("hello world") +- +- main()`; + const result = patchUtils.generateDecorationOptions(patch, languages); + assert.strictEqual(result.length, 0); + }); + + test('works with single hunks', () => { + const patch = `-- /home/patch/goof ++++ /home/patch/goof-fixed +@@ -1 +15,8 @@ + var fileType = require('file-type'); + var AdmZip = require('adm-zip'); + var fs = require('fs'); ++var RateLimit = require('express-rate-limit'); ++var limiter = new RateLimit({ ++ windowMs: parseInt(process.env.WINDOW_MS, 10), ++ max: parseInt(process.env.MAX_IP_REQUESTS, 10), ++ delayMs:parseInt(process.env.DELAY_MS, 10), ++ headers: true ++}); ++app.user(limiter); + + // prototype-pollution + var _ = require('lodash');`; + + const result = patchUtils.generateDecorationOptions(patch, languages); + + assert.strictEqual(result.length, 8); + + assert.strictEqual(result[0].range.start.line, 17); + assert.strictEqual(result[0].range.start.character, 0); + assert.strictEqual(result[0].range.end.line, 17); + assert.strictEqual(result[0].range.end.character, 46); + + assert.strictEqual(result[7].range.start.line, 24); + assert.strictEqual(result[7].range.start.character, 0); + assert.strictEqual(result[7].range.end.line, 24); + assert.strictEqual(result[7].range.end.character, 18); + }); + + test('works with multiple hunks', () => { + const patch = `-- /home/patch/snek ++++ /home/patch/snek-fixed +@@ -1,2 +1,2 @@ + import math + from my_module import do_some_work + + def generate_number() -> int: +- return math.random() * 100 ++ return math.random() * 20 + + result = do_some_work() + print(result) + +@@ -25,1 +25,1 @@ +-result *= generate_number() ++result += generate_number() +`; + + const result = patchUtils.generateDecorationOptions(patch, languages); + + assert.strictEqual(result.length, 2); + + assert.strictEqual(result[0].range.start.line, 4); + assert.strictEqual(result[0].range.start.character, 0); + assert.strictEqual(result[0].range.end.line, 4); + assert.strictEqual(result[0].range.end.character, 28); + + assert.strictEqual(result[1].range.start.line, 24); + assert.strictEqual(result[1].range.start.character, 0); + assert.strictEqual(result[1].range.end.line, 24); + assert.strictEqual(result[1].range.end.character, 27); + }); +}); diff --git a/src/test/unit/snykIac/codeActions/iacCodeActionsProvider.test.ts b/src/test/unit/snykIac/codeActions/iacCodeActionsProvider.test.ts index 8d59650a0..68da113fd 100644 --- a/src/test/unit/snykIac/codeActions/iacCodeActionsProvider.test.ts +++ b/src/test/unit/snykIac/codeActions/iacCodeActionsProvider.test.ts @@ -1,18 +1,16 @@ import { strictEqual } from 'assert'; import sinon from 'sinon'; -import { IAnalytics } from '../../../../snyk/common/analytics/itly'; import { SNYK_OPEN_ISSUE_COMMAND } from '../../../../snyk/common/constants/commands'; import { IacIssueData, Issue } from '../../../../snyk/common/languageServer/types'; import { WorkspaceFolderResult } from '../../../../snyk/common/services/productService'; import { ICodeActionAdapter, ICodeActionKindAdapter } from '../../../../snyk/common/vscode/codeAction'; import { IVSCodeLanguages } from '../../../../snyk/common/vscode/languages'; -import { CodeActionKind, Range, TextDocument } from '../../../../snyk/common/vscode/types'; +import { CodeActionContext, CodeActionKind, Range, TextDocument } from '../../../../snyk/common/vscode/types'; import { IacCodeActionsProvider } from '../../../../snyk/snykIac/codeActions/iacCodeActionsProvider'; import { IacIssue } from '../../../../snyk/snykIac/issue'; suite('IaC code actions provider', () => { let issuesActionsProvider: IacCodeActionsProvider; - let logQuickFixIsDisplayed: sinon.SinonSpy; setup(() => { const codeResults = new Map>(); @@ -23,11 +21,6 @@ suite('IaC code actions provider', () => { } as unknown as Issue, ]); - logQuickFixIsDisplayed = sinon.fake(); - const analytics = { - logQuickFixIsDisplayed, - } as unknown as IAnalytics; - const codeActionAdapter = { create: (_: string, _kind?: CodeActionKind) => ({ command: {}, @@ -49,7 +42,6 @@ suite('IaC code actions provider', () => { codeActionAdapter, codeActionKindAdapter, {} as IVSCodeLanguages, - analytics, ); }); @@ -66,25 +58,10 @@ suite('IaC code actions provider', () => { } as unknown as TextDocument; // act - const codeActions = issuesActionsProvider.provideCodeActions(document, {} as Range); + const codeActions = issuesActionsProvider.provideCodeActions(document, {} as Range, {} as CodeActionContext); // verify strictEqual(codeActions?.length, 1); strictEqual(codeActions[0].command?.command, SNYK_OPEN_ISSUE_COMMAND); }); - - test("Logs 'Quick Fix is Displayed' analytical event", () => { - // arrange - const document = { - uri: { - fsPath: '//folderName//test.js', - }, - } as unknown as TextDocument; - - // act - issuesActionsProvider.provideCodeActions(document, {} as Range); - - // verify - strictEqual(logQuickFixIsDisplayed.calledOnce, true); - }); }); diff --git a/src/test/unit/snykIac/iacService.test.ts b/src/test/unit/snykIac/iacService.test.ts index 58dca273f..5ed6645e3 100644 --- a/src/test/unit/snykIac/iacService.test.ts +++ b/src/test/unit/snykIac/iacService.test.ts @@ -1,6 +1,5 @@ import { strictEqual } from 'assert'; import sinon from 'sinon'; -import { IAnalytics } from '../../../snyk/common/analytics/itly'; import { IConfiguration } from '../../../snyk/common/configuration/configuration'; import { WorkspaceTrust } from '../../../snyk/common/configuration/trustedFolders'; import { ILanguageServer } from '../../../snyk/common/languageServer/languageServer'; @@ -15,6 +14,7 @@ import { IacService } from '../../../snyk/snykIac/iacService'; import { IacSuggestionWebviewProvider } from '../../../snyk/snykIac/views/suggestion/iacSuggestionWebviewProvider'; import { LanguageServerMock } from '../mocks/languageServer.mock'; import { LoggerMock } from '../mocks/logger.mock'; +import { IDiagnosticsIssueProvider } from '../../../snyk/common/services/diagnosticsService'; suite('IaC Service', () => { let ls: ILanguageServer; @@ -46,8 +46,8 @@ suite('IaC Service', () => { { registerCodeActionsProvider: sinon.fake(), } as unknown as IVSCodeLanguages, + {} as IDiagnosticsIssueProvider, new LoggerMock(), - {} as IAnalytics, ); }); @@ -61,6 +61,7 @@ suite('IaC Service', () => { folderPath: 'test/path', issues: [], status: ScanStatus.InProgress, + errorMessage: '', }); strictEqual(service.isAnalysisRunning, false); diff --git a/src/test/unit/snykOss/ossService.test.ts b/src/test/unit/snykOss/ossService.test.ts new file mode 100644 index 000000000..9950e7bad --- /dev/null +++ b/src/test/unit/snykOss/ossService.test.ts @@ -0,0 +1,81 @@ +import { strictEqual } from 'assert'; +import sinon from 'sinon'; +import { IConfiguration } from '../../../snyk/common/configuration/configuration'; +import { WorkspaceTrust } from '../../../snyk/common/configuration/trustedFolders'; +import { ILanguageServer } from '../../../snyk/common/languageServer/languageServer'; +import { OssIssueData, ScanProduct, ScanStatus } from '../../../snyk/common/languageServer/types'; +import { IProductService } from '../../../snyk/common/services/productService'; +import { IViewManagerService } from '../../../snyk/common/services/viewManagerService'; +import { ICodeActionAdapter, ICodeActionKindAdapter } from '../../../snyk/common/vscode/codeAction'; +import { ExtensionContext } from '../../../snyk/common/vscode/extensionContext'; +import { IVSCodeLanguages } from '../../../snyk/common/vscode/languages'; +import { IVSCodeWorkspace } from '../../../snyk/common/vscode/workspace'; +import { IOssSuggestionWebviewProvider } from '../../../snyk/snykOss/interfaces'; +import { OssService } from '../../../snyk/snykOss/ossService'; +import { LanguageServerMock } from '../mocks/languageServer.mock'; +import { LoggerMock } from '../mocks/logger.mock'; +import { IDiagnosticsIssueProvider } from '../../../snyk/common/services/diagnosticsService'; + +suite('OSS Service', () => { + let ls: ILanguageServer; + let service: IProductService; + let refreshViewFake: sinon.SinonSpy; + + setup(() => { + ls = new LanguageServerMock(); + refreshViewFake = sinon.fake(); + + const viewManagerService = { + refreshOssView: refreshViewFake, + } as unknown as IViewManagerService; + + service = new OssService( + {} as ExtensionContext, + {} as IConfiguration, + {} as IOssSuggestionWebviewProvider, + {} as ICodeActionAdapter, + { getQuickFix: sinon.fake() } as ICodeActionKindAdapter, + viewManagerService, + { + getWorkspaceFolders: () => [''], + } as IVSCodeWorkspace, + new WorkspaceTrust(), + ls, + { + registerCodeActionsProvider: sinon.fake(), + } as unknown as IVSCodeLanguages, + {} as unknown as IDiagnosticsIssueProvider, + new LoggerMock(), + ); + }); + + teardown(() => { + sinon.restore(); + }); + + test('Scan returned for OSS product', () => { + ls.scan$.next({ + product: ScanProduct.OpenSource, + folderPath: 'test/path', + issues: [], + status: ScanStatus.InProgress, + errorMessage: '', + }); + + strictEqual(service.isAnalysisRunning, true); + sinon.assert.calledOnce(refreshViewFake); + }); + + test('Scan not returned for non-OSS product', () => { + ls.scan$.next({ + product: ScanProduct.Code, + folderPath: 'test/path', + issues: [], + status: ScanStatus.InProgress, + errorMessage: '', + }); + + strictEqual(service.isAnalysisRunning, false); + sinon.assert.notCalled(refreshViewFake); + }); +}); diff --git a/src/test/unit/snykOss/providers/ossCodeActionsProvider.test.ts b/src/test/unit/snykOss/providers/ossCodeActionsProvider.test.ts new file mode 100644 index 000000000..42f55e676 --- /dev/null +++ b/src/test/unit/snykOss/providers/ossCodeActionsProvider.test.ts @@ -0,0 +1,112 @@ +import assert from 'assert'; +import sinon from 'sinon'; +import { CodeAction, CodeActionContext, CodeActionKind, Range, TextDocument } from 'vscode'; +import { OpenCommandIssueType, OpenIssueCommandArg } from '../../../../snyk/common/commands/types'; +import { SNYK_OPEN_ISSUE_COMMAND } from '../../../../snyk/common/constants/commands'; +import { Issue, IssueSeverity, OssIssueData } from '../../../../snyk/common/languageServer/types'; +import { WorkspaceFolderResult } from '../../../../snyk/common/services/productService'; +import { ICodeActionAdapter, ICodeActionKindAdapter } from '../../../../snyk/common/vscode/codeAction'; +import { IVSCodeLanguages } from '../../../../snyk/common/vscode/languages'; +import { OssCodeActionsProvider } from '../../../../snyk/snykOss/providers/ossCodeActionsProvider'; + +suite('OSS code actions provider', () => { + let ossActionsProvider: OssCodeActionsProvider; + let rangeMock: Range; + + setup(() => { + const ossResults = new Map>(); + ossResults.set('folderName', [ + { + filePath: '//folderName//package.json', + additionalData: {}, + } as unknown as Issue, + ]); + + const codeActionAdapter = { + create: (_: string, _kind?: CodeActionKind) => ({ + command: {}, + }), + } as ICodeActionAdapter; + + const codeActionKindAdapter = { + getQuickFix: sinon.fake(), + } as ICodeActionKindAdapter; + + rangeMock = { + contains: () => true, + } as unknown as Range; + + ossActionsProvider = new OssCodeActionsProvider( + {} as IVSCodeLanguages, + codeActionAdapter, + codeActionKindAdapter, + ossResults, + ); + }); + + teardown(() => { + sinon.restore(); + }); + + test('Provides the most severe vulnerability CodeAction', () => { + // arrange + const document = { + uri: { + fsPath: '//folderName//package.json', + }, + } as unknown as TextDocument; + + const clickedRange = {} as Range; + const context = {} as CodeActionContext; + + const vulnerabilities = [ + { + id: 'vulnerability1', + severity: IssueSeverity.High, + }, + { + id: 'vulnerability2', + severity: IssueSeverity.Medium, + }, + { + id: 'vulnerability3', + severity: IssueSeverity.Critical, + }, + ] as Issue[]; + + const mostSevereVulnerability = { + id: 'vulnerability3', + severity: IssueSeverity.Critical, + } as Issue; + + const codeActions = [ + { + command: { + command: SNYK_OPEN_ISSUE_COMMAND, + title: SNYK_OPEN_ISSUE_COMMAND, + arguments: [ + { + issueType: OpenCommandIssueType.OssVulnerability, + issue: mostSevereVulnerability, + } as OpenIssueCommandArg, + ], + }, + }, + ] as CodeAction[]; + + sinon.stub(ossActionsProvider, 'getIssueRange').returns(rangeMock); + // stubbing private methods workaround is to cast to any + // eslint-disable-next-line @typescript-eslint/no-explicit-any + sinon.stub(ossActionsProvider, 'getVulnerabilities').returns(vulnerabilities); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + sinon.stub(ossActionsProvider, 'getMostSevereVulnerability').returns(mostSevereVulnerability); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + sinon.stub(ossActionsProvider, 'getActions').returns(codeActions); + + // act + const result = ossActionsProvider.provideCodeActions(document, clickedRange, context); + + // assert + assert.deepStrictEqual(result, codeActions); + }); +}); diff --git a/src/test/unit/snykOss/services/vulnerabilityCount/vulnerabilityCountProvider.test.ts b/src/test/unit/snykOss/providers/vulnerabilityCountProvider.test.ts similarity index 51% rename from src/test/unit/snykOss/services/vulnerabilityCount/vulnerabilityCountProvider.test.ts rename to src/test/unit/snykOss/providers/vulnerabilityCountProvider.test.ts index fb5eb9ca4..6bda8c3bc 100644 --- a/src/test/unit/snykOss/services/vulnerabilityCount/vulnerabilityCountProvider.test.ts +++ b/src/test/unit/snykOss/providers/vulnerabilityCountProvider.test.ts @@ -1,18 +1,21 @@ import { deepStrictEqual, strictEqual } from 'assert'; import sinon from 'sinon'; -import { CliError } from '../../../../../snyk/cli/services/cliService'; -import { Language } from '../../../../../snyk/common/types'; -import { OssResultBody, OssVulnerability } from '../../../../../snyk/snykOss/ossResult'; -import { OssService } from '../../../../../snyk/snykOss/services/ossService'; -import { ImportedModule } from '../../../../../snyk/snykOss/services/vulnerabilityCount/importedModule'; -import { ModuleVulnerabilityCountProvider } from '../../../../../snyk/snykOss/services/vulnerabilityCount/vulnerabilityCountProvider'; -import { ILanguageClientAdapter } from '../../../../../snyk/common/vscode/languageClient'; -import { IUriAdapter } from '../../../../../snyk/common/vscode/uri'; -import { ITextDocumentAdapter } from '../../../../../snyk/common/vscode/textdocument'; - -suite('OSS ModuleVulnerabilityCountProvider', () => { +import { InlineValueText } from 'vscode'; +import { CliError } from '../../../../snyk/cli/services/cliService'; +import { Language } from '../../../../snyk/common/types'; +import { ILanguageClientAdapter } from '../../../../snyk/common/vscode/languageClient'; +import { ITextDocumentAdapter } from '../../../../snyk/common/vscode/textdocument'; +import { IUriAdapter } from '../../../../snyk/common/vscode/uri'; +import { OssResultBody, OssVulnerability } from '../../../../snyk/snykOss/interfaces'; +import { OssService } from '../../../../snyk/snykOss/ossService'; +import { OssVulnerabilityCountProvider } from '../../../../snyk/snykOss/providers/ossVulnerabilityCountProvider'; +import { ImportedModule } from '../../../../snyk/snykOss/services/vulnerabilityCount/importedModule'; +import { VulnerabilityCountEmitter } from '../../../../snyk/snykOss/services/vulnerabilityCount/vulnerabilityCountEmitter'; + +suite('OSS VulnerabilityCountProvider', () => { let ossService: OssService; - let vulnerabilityCountProvider: ModuleVulnerabilityCountProvider; + let vulnerabilityCountProvider: OssVulnerabilityCountProvider; + let vulnerabilityCountEmitterStub: VulnerabilityCountEmitter; const sampleFilePath = 'C:\\git\\project\\test.js'; const sampleModuleName = 'mongo-express'; @@ -53,14 +56,38 @@ suite('OSS ModuleVulnerabilityCountProvider', () => { }, ]; + let sampleInlineValueText = [] as InlineValueText[]; + let sampleFileName = 'package.json'; + const sameplUri = `file:///Users/some.user/Documents/some-project/${sampleFileName}`; + + let languageClientStub: { sendRequest: unknown }; + let uriStub; + setup(() => { + uriStub = sinon.stub().returns(sameplUri); + languageClientStub = { + sendRequest: sinon.stub().resolves(sampleInlineValueText), + }; + ossService = {} as OssService; - vulnerabilityCountProvider = new ModuleVulnerabilityCountProvider( + vulnerabilityCountProvider = new OssVulnerabilityCountProvider( ossService, - {} as ILanguageClientAdapter, - {} as IUriAdapter, - {} as ITextDocumentAdapter, + { + create: sinon.spy(), + getLanguageClient: sinon.stub().returns(languageClientStub), + } as ILanguageClientAdapter, + { + file: uriStub, + parse: sinon.spy(), + } as IUriAdapter, + { + create: sinon.stub().returns({ + uri: uriStub, + lineCount: 1, + }), + } as ITextDocumentAdapter, ); + vulnerabilityCountEmitterStub = sinon.createStubInstance(VulnerabilityCountEmitter); }); teardown(() => { @@ -68,12 +95,13 @@ suite('OSS ModuleVulnerabilityCountProvider', () => { }); test('Not calculated if JS/TS results are not provided', async () => { - ossService.getResultArray = () => undefined; + vulnerabilityCountProvider.getResultArray = () => undefined; const tsCount = await vulnerabilityCountProvider.getVulnerabilityCount( 'test.ts', sampleImportedModule, Language.TypeScript, + vulnerabilityCountEmitterStub, ); const jsCount = await vulnerabilityCountProvider.getVulnerabilityCount( 'test.ts', @@ -82,6 +110,7 @@ suite('OSS ModuleVulnerabilityCountProvider', () => { fileName: 'test.ts', }, Language.JavaScript, + vulnerabilityCountEmitterStub, ); strictEqual(jsCount.hasCount, false); @@ -89,18 +118,36 @@ suite('OSS ModuleVulnerabilityCountProvider', () => { }); test('Gets TS/JS imported module vulnerability results correctly', async () => { - ossService.getResultArray = () => sampleOssResults; - ossService.getUniqueVulnerabilities = () => sampleOssResults[0].vulnerabilities; + const text = 'issues: 2 | Critical: 1, High 1, Medium: 0, Low: 0 | Most Severe: npm:adm-zip:20180415'; + sampleInlineValueText = [ + { + text, + range: { + start: { + line: 1, + character: 16, + } as unknown as InlineValueText['range']['start'], + end: { + line: 1, + character: 29, + } as unknown as InlineValueText['range']['end'], + } as unknown as InlineValueText['range'], + }, + ]; + + sampleFileName = 'test.ts'; + languageClientStub.sendRequest = sinon.stub().resolves(sampleInlineValueText); const count = await vulnerabilityCountProvider.getVulnerabilityCount( - 'test.ts', + sampleFileName, sampleImportedModule, Language.TypeScript, + vulnerabilityCountEmitterStub, ); - strictEqual(count.hasCount, true); - strictEqual(count.count, '2'); - strictEqual(count.line, 1); + strictEqual(count.hasCount, true, 'hasCount is not true'); + strictEqual(count.count, text, `count is not: "${text}"`); + strictEqual(count.line, 1, 'line is not 1'); deepStrictEqual(count.range, { start: { line: 1, @@ -111,84 +158,21 @@ suite('OSS ModuleVulnerabilityCountProvider', () => { column: 29, }, }); - strictEqual(count.severityCounts?.low, 1); - strictEqual(count.severityCounts?.medium, 1); }); test('Gets package.json dependency vulnerability results correctly', async () => { - ossService.getResultArray = () => sampleOssResults; - ossService.getUniqueVulnerabilities = () => sampleOssResults[0].vulnerabilities; + vulnerabilityCountProvider.getResultArray = sinon.stub().returns(sampleOssResults); const count = await vulnerabilityCountProvider.getVulnerabilityCount( 'test.ts', sampleImportedModule, Language.PJSON, + vulnerabilityCountEmitterStub, ); strictEqual(count.hasCount, true); }); - test('Gets only direct dependency vulnerability count', async () => { - const indirectDependency = '@indirect/dependency'; - const ossResultsWithIndirectVulnerability = [ - { - ...sampleOssResults[0], - vulnerabilities: [ - { - name: sampleModuleName, - from: ['goof', sampleModuleName], - } as unknown as OssVulnerability, - { - name: sampleModuleName, - from: ['goof', indirectDependency, sampleModuleName], - } as unknown as OssVulnerability, - ], - }, - ]; - ossService.getResultArray = () => ossResultsWithIndirectVulnerability; - ossService.getUniqueVulnerabilities = () => ossResultsWithIndirectVulnerability[0].vulnerabilities; - - const count = await vulnerabilityCountProvider.getVulnerabilityCount( - 'test.ts', - sampleImportedModule, - Language.TypeScript, - ); - - strictEqual(count.hasCount, true); - strictEqual(count.count, '1'); - }); - - test('Provides a version if same direct dependency has single vulnerable version', async () => { - const version = '1.0.0'; - const ossResultsWithMultipleVersionsVulnerability = [ - { - ...sampleOssResults[0], - vulnerabilities: [ - { - name: sampleModuleName, - from: ['goof', sampleModuleName], - version: version, - } as unknown as OssVulnerability, - { - name: sampleModuleName, - from: ['goof', sampleModuleName], - version: version, - } as unknown as OssVulnerability, - ], - }, - ]; - ossService.getResultArray = () => ossResultsWithMultipleVersionsVulnerability; - ossService.getUniqueVulnerabilities = () => ossResultsWithMultipleVersionsVulnerability[0].vulnerabilities; - - const count = await vulnerabilityCountProvider.getVulnerabilityCount( - 'test.ts', - sampleImportedModule, - Language.TypeScript, - ); - - strictEqual(count.version, version); - }); - test("Doesn't provide a version if same direct dependency has multiple vulnerable versions", async () => { const ossResultsWithMultipleVersionsVulnerability = [ { @@ -207,13 +191,13 @@ suite('OSS ModuleVulnerabilityCountProvider', () => { ], }, ]; - ossService.getResultArray = () => ossResultsWithMultipleVersionsVulnerability; - ossService.getUniqueVulnerabilities = () => ossResultsWithMultipleVersionsVulnerability[0].vulnerabilities; + vulnerabilityCountProvider.getResultArray = sinon.stub().returns(ossResultsWithMultipleVersionsVulnerability); const count = await vulnerabilityCountProvider.getVulnerabilityCount( 'test.ts', sampleImportedModule, Language.TypeScript, + vulnerabilityCountEmitterStub, ); strictEqual(count.version, undefined); diff --git a/src/test/unit/snykOss/services/ossService.test.ts b/src/test/unit/snykOss/services/ossService.test.ts deleted file mode 100644 index de0817279..000000000 --- a/src/test/unit/snykOss/services/ossService.test.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { deepStrictEqual, rejects, strictEqual } from 'assert'; -import * as fs from 'fs/promises'; -import _ from 'lodash'; -import sinon from 'sinon'; -import { CliProcess } from '../../../../snyk/cli/process'; -import { IAnalytics } from '../../../../snyk/common/analytics/itly'; -import { IConfiguration } from '../../../../snyk/common/configuration/configuration'; -import { WorkspaceTrust } from '../../../../snyk/common/configuration/trustedFolders'; -import { ILog } from '../../../../snyk/common/logger/interfaces'; -import { DownloadService } from '../../../../snyk/common/services/downloadService'; -import { INotificationService } from '../../../../snyk/common/services/notificationService'; -import { IViewManagerService } from '../../../../snyk/common/services/viewManagerService'; -import { IWebViewProvider } from '../../../../snyk/common/views/webviewProvider'; -import { ExtensionContext } from '../../../../snyk/common/vscode/extensionContext'; -import { IVSCodeWorkspace } from '../../../../snyk/common/vscode/workspace'; -import { OssFileResult, OssResult, OssSeverity } from '../../../../snyk/snykOss/ossResult'; -import { OssService } from '../../../../snyk/snykOss/services/ossService'; -import { OssIssueCommandArg } from '../../../../snyk/snykOss/views/ossVulnerabilityTreeProvider'; -import { DailyScanJob } from '../../../../snyk/snykOss/watchers/dailyScanJob'; -import { LanguageServerMock } from '../../mocks/languageServer.mock'; -import { LoggerMock } from '../../mocks/logger.mock'; - -suite('OssService', () => { - const extensionPath = 'test/path'; - let logger: ILog; - let ossService: OssService; - - setup(() => { - logger = new LoggerMock(); - - const ls = new LanguageServerMock(); - ls.cliReady$.next(''); - - const testFolderPath = ''; - ossService = new OssService( - { - extensionPath, - } as ExtensionContext, - logger, - { - getAdditionalCliParameters: () => '', - getCliPath: () => undefined, - isAutomaticDependencyManagementEnabled: () => true, - getTrustedFolders: () => [testFolderPath], - } as unknown as IConfiguration, - {} as IWebViewProvider, - { - getWorkspaceFolders: () => [testFolderPath], - } as IVSCodeWorkspace, - { - refreshOssView: () => undefined, - } as IViewManagerService, - {} as DownloadService, - { - schedule: sinon.fake(), - } as unknown as DailyScanJob, - {} as INotificationService, - { - logAnalysisIsReady: sinon.fake(), - } as unknown as IAnalytics, - ls, - new WorkspaceTrust(), - ); - }); - - teardown(() => { - sinon.restore(); - }); - - test('Maps single project result correctly', async () => { - const cliOutput = await fs.readFile('mocked_data/snykOss/single-project-vulnerabilities.json', 'utf-8'); - sinon.stub(CliProcess.prototype, 'spawn').resolves(cliOutput); - - const result = await ossService.test(false, false); - const expected = JSON.parse(cliOutput) as OssResult; - deepStrictEqual(result, expected); - }); - - test('Maps multiple project results correctly', async () => { - const cliOutput = await fs.readFile('mocked_data/snykOss/multi-project-vulnerabilities.json', 'utf-8'); - sinon.stub(CliProcess.prototype, 'spawn').resolves(cliOutput); - - const result = await ossService.test(false, false); - const expected = JSON.parse(cliOutput) as OssResult; - deepStrictEqual(result, expected); - }); - - test('Empty result output throws an error', async () => { - sinon.stub(CliProcess.prototype, 'spawn').resolves(''); - await rejects(async () => await ossService.test(false, false)); - }); - - test('Invalid JSON output throws an error', async () => { - sinon.stub(CliProcess.prototype, 'spawn').resolves('{'); - await rejects(async () => await ossService.test(false, false)); - }); - - test('Gets new critical vulns count correctly for single project', () => { - const oldOssResult = { - vulnerabilities: [ - { - id: '1', - severity: OssSeverity.Critical, - }, - { - id: '2', - severity: OssSeverity.Medium, - }, - ], - displayTargetFile: '', - packageManager: '', - projectName: '', - } as OssFileResult; - - // Assert: latest result has same vulnerability count - strictEqual(ossService.getNewCriticalVulnerabilitiesCount(oldOssResult, oldOssResult), 0); - - const newOssResult = { - ..._.clone(oldOssResult), - vulnerabilities: [ - { - id: '1', - severity: OssSeverity.Critical, - }, - { - id: '2', - severity: OssSeverity.Medium, - }, - { - id: '3', - severity: OssSeverity.Critical, - }, - { - id: '4', - severity: OssSeverity.Medium, - }, - ], - } as OssFileResult; - - // Assert: latest result has more vulnerabilities - strictEqual(ossService.getNewCriticalVulnerabilitiesCount(newOssResult, oldOssResult), 1); - - // Assert: latest result has less vulnerabilities - strictEqual(ossService.getNewCriticalVulnerabilitiesCount(oldOssResult, newOssResult), 0); - }); - - test('Gets new critical vulns count correctly for multiple projects', () => { - const oldOssResult = { - vulnerabilities: [ - { - id: '1', - severity: OssSeverity.Critical, - }, - { - id: '2', - severity: OssSeverity.Medium, - }, - ], - displayTargetFile: '', - packageManager: '', - projectName: '', - } as OssFileResult; - const oldOssResults = [oldOssResult, oldOssResult]; - - // Assert: latest result has same vulnerability count - strictEqual(ossService.getNewCriticalVulnerabilitiesCount(oldOssResults, oldOssResults), 0); - - const newOssResult = { - ..._.clone(oldOssResult), - vulnerabilities: [ - { - id: '1', - severity: OssSeverity.Critical, - }, - { - id: '2', - severity: OssSeverity.Medium, - }, - { - id: '3', - severity: OssSeverity.Critical, - }, - { - id: '4', - severity: OssSeverity.Medium, - }, - ], - } as OssFileResult; - const newOssResults = [newOssResult, newOssResult]; - - // Assert: latest result has more vulnerabilities - strictEqual(ossService.getNewCriticalVulnerabilitiesCount(newOssResults, oldOssResults), 2); - - // Assert: latest result has less vulnerabilities - strictEqual(ossService.getNewCriticalVulnerabilitiesCount(oldOssResults, newOssResults), 0); - }); -}); diff --git a/src/test/unit/snykOss/services/vulnerabilityCount/ossVulnerabilityCountService.test.ts b/src/test/unit/snykOss/services/vulnerabilityCount/ossVulnerabilityCountService.test.ts index 1e8277bc5..c03d8cf38 100644 --- a/src/test/unit/snykOss/services/vulnerabilityCount/ossVulnerabilityCountService.test.ts +++ b/src/test/unit/snykOss/services/vulnerabilityCount/ossVulnerabilityCountService.test.ts @@ -1,23 +1,21 @@ import { strictEqual } from 'assert'; -import { EMPTY } from 'rxjs'; +import { EMPTY, Subject } from 'rxjs'; import sinon from 'sinon'; -import { IAnalytics } from '../../../../../snyk/common/analytics/itly'; import { IConfiguration } from '../../../../../snyk/common/configuration/configuration'; -import { ICodeActionKindAdapter } from '../../../../../snyk/common/vscode/codeAction'; +import { ILanguageClientAdapter } from '../../../../../snyk/common/vscode/languageClient'; import { IVSCodeLanguages } from '../../../../../snyk/common/vscode/languages'; +import { ITextDocumentAdapter } from '../../../../../snyk/common/vscode/textdocument'; import { IThemeColorAdapter } from '../../../../../snyk/common/vscode/theme'; import { TextDocument, TextEditor } from '../../../../../snyk/common/vscode/types'; +import { IUriAdapter } from '../../../../../snyk/common/vscode/uri'; import { IVSCodeWindow } from '../../../../../snyk/common/vscode/window'; import { IVSCodeWorkspace } from '../../../../../snyk/common/vscode/workspace'; import { EditorDecorator } from '../../../../../snyk/snykOss/editor/editorDecorator'; -import { OssFileResult } from '../../../../../snyk/snykOss/ossResult'; -import { OssService } from '../../../../../snyk/snykOss/services/ossService'; +import { OssFileResult } from '../../../../../snyk/snykOss/interfaces'; +import { OssService } from '../../../../../snyk/snykOss/ossService'; +import { OssVulnerabilityCountProvider } from '../../../../../snyk/snykOss/providers/ossVulnerabilityCountProvider'; import { OssVulnerabilityCountService } from '../../../../../snyk/snykOss/services/vulnerabilityCount/ossVulnerabilityCountService'; -import { ModuleVulnerabilityCountProvider } from '../../../../../snyk/snykOss/services/vulnerabilityCount/vulnerabilityCountProvider'; import { LoggerMock } from '../../../mocks/logger.mock'; -import { ILanguageClientAdapter } from '../../../../../snyk/common/vscode/languageClient'; -import { IUriAdapter } from '../../../../../snyk/common/vscode/uri'; -import { ITextDocumentAdapter } from '../../../../../snyk/common/vscode/textdocument'; suite('OSS VulnerabilityCountService', () => { let workspace: IVSCodeWorkspace; @@ -25,12 +23,13 @@ suite('OSS VulnerabilityCountService', () => { let languages: IVSCodeLanguages; let ossVulnerabilityCountService: OssVulnerabilityCountService; let ossService: OssService; - let vulnerabilityCountProvider: ModuleVulnerabilityCountProvider; + let vulnerabilityCountProvider: OssVulnerabilityCountProvider; setup(() => { const logger = new LoggerMock(); ossService = { scanFinished$: EMPTY, + newResultAvailable$: new Subject(), } as unknown as OssService; workspace = {} as IVSCodeWorkspace; window = { @@ -41,7 +40,7 @@ suite('OSS VulnerabilityCountService', () => { registerCodeActionsProvider: sinon.fake(), registerHoverProvider: sinon.fake(), } as unknown as IVSCodeLanguages; - vulnerabilityCountProvider = new ModuleVulnerabilityCountProvider( + vulnerabilityCountProvider = new OssVulnerabilityCountProvider( ossService, {} as ILanguageClientAdapter, {} as IUriAdapter, @@ -49,10 +48,6 @@ suite('OSS VulnerabilityCountService', () => { ); const editorDecorator = new EditorDecorator(window, languages, {} as IThemeColorAdapter); - const codeActionProvider = { - getQuickFix: sinon.fake(), - } as ICodeActionKindAdapter; - const analytics = {} as IAnalytics; const configuration = {} as IConfiguration; ossVulnerabilityCountService = new OssVulnerabilityCountService( @@ -63,8 +58,6 @@ suite('OSS VulnerabilityCountService', () => { ossService, logger, editorDecorator, - codeActionProvider, - analytics, configuration, ); }); @@ -97,7 +90,7 @@ suite('OSS VulnerabilityCountService', () => { strictEqual(onDidChangeActiveTextEditor.calledOnce, true); }); - test('Processes file if active editor is opened on activation', () => { + test('Processes file on receiving new scan result', () => { window.getActiveTextEditor = () => ({ document: undefined, @@ -109,9 +102,10 @@ suite('OSS VulnerabilityCountService', () => { const processFileSpy = sinon.spy(ossVulnerabilityCountService, 'processFile'); ossVulnerabilityCountService.activate(); + ossService.newResultAvailable$.next(); - strictEqual(getActiveTextEditorSpy.called, true); - strictEqual(processFileSpy.calledOnce, true); + strictEqual(getActiveTextEditorSpy.called, true, 'getActiveTextEditor should be called'); + strictEqual(processFileSpy.calledOnce, true, 'processFile should be called'); }); test("Doesn't process if file is language not supported", () => { @@ -125,7 +119,7 @@ suite('OSS VulnerabilityCountService', () => { }); test("Doesn't process if file is supported and OSS scan hasn't run", () => { - ossService.getResultArray = () => undefined; + vulnerabilityCountProvider.getResultArray = () => undefined; const tsDocument = { fileName: 'C:\\git\\project\\test.ts', languageId: 'typescript', @@ -150,7 +144,7 @@ suite('OSS VulnerabilityCountService', () => { languageId: 'typescript', getText: () => 'const x = require("react")', } as TextDocument; - ossService.getResultArray = () => [{} as OssFileResult]; + vulnerabilityCountProvider.getResultArray = () => [{} as OssFileResult]; sinon.stub(vulnerabilityCountProvider, 'isFilePartOfOssTest').returns(true); const processed = ossVulnerabilityCountService.processFile(document); diff --git a/src/test/unit/snykOss/services/vulnerabilityCount/parsers/moduleParserProvider.test.ts b/src/test/unit/snykOss/services/vulnerabilityCount/parsers/moduleParserProvider.test.ts index 3061a353a..4467a9570 100644 --- a/src/test/unit/snykOss/services/vulnerabilityCount/parsers/moduleParserProvider.test.ts +++ b/src/test/unit/snykOss/services/vulnerabilityCount/parsers/moduleParserProvider.test.ts @@ -16,7 +16,7 @@ suite('OSS ModuleParserProvider', () => { }); test('Undefined instance is returned for non-supported language', () => { - const parser = ModuleParserProvider.getInstance(-1, new LoggerMock(), configuration); + const parser = ModuleParserProvider.getInstance(-1 as Language, new LoggerMock(), configuration); strictEqual(parser, undefined); }); }); diff --git a/src/test/unit/snykOss/services/watchers/dailyScanJob.test.ts b/src/test/unit/snykOss/services/watchers/dailyScanJob.test.ts deleted file mode 100644 index a9de4a5eb..000000000 --- a/src/test/unit/snykOss/services/watchers/dailyScanJob.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { strictEqual } from 'assert'; -import sinon from 'sinon'; -import { IExtension } from '../../../../../snyk/base/modules/interfaces'; -import { DailyScanJob } from '../../../../../snyk/snykOss/watchers/dailyScanJob'; - -suite('OSS DailyScanJob', () => { - let extension: IExtension; - let clock: sinon.SinonFakeTimers; - let ossScanSpy: sinon.SinonSpy; - - setup(() => { - ossScanSpy = sinon.fake(); - extension = { - runOssScan: ossScanSpy, - } as unknown as IExtension; - clock = sinon.useFakeTimers(); - }); - - teardown(() => { - sinon.restore(); - clock; - }); - - test('Runs a scan after 24 hours have passed', () => { - const job = new DailyScanJob(extension); - job.schedule(); - - clock.tick(86400000); - strictEqual(ossScanSpy.calledOnce, true); - }); - - test("Doesn't run scan before 24 hours have passed", () => { - const job = new DailyScanJob(extension); - job.schedule(); - - clock.tick(86399999); - strictEqual(ossScanSpy.calledOnce, false); - }); - - test('24h timer is reset when new schedule happens', () => { - const job = new DailyScanJob(extension); - job.schedule(); - - clock.tick(86399999); - strictEqual(ossScanSpy.called, false); - - job.schedule(); - - clock.tick(86399999); - strictEqual(ossScanSpy.called, false); - - clock.tick(1); - strictEqual(ossScanSpy.calledOnce, true); - }); -}); diff --git a/tsconfig.json b/tsconfig.json index 5820efd66..06223fac9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,7 @@ "noImplicitThis": true, "noImplicitAny": true, "strictNullChecks": true, - "suppressImplicitAnyIndexErrors": true, + "ignoreDeprecations": "5.0", "noUnusedParameters": true, "esModuleInterop": true, "resolveJsonModule": true