diff --git a/.cirrus.star b/.cirrus.star deleted file mode 100644 index 28b17b70fc3..00000000000 --- a/.cirrus.star +++ /dev/null @@ -1,4 +0,0 @@ -load("github.com/SonarSource/cirrus-modules@v2", "load_features") - -def main(ctx): - return load_features(ctx) diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index 99c4b618c48..00000000000 --- a/.cirrus.yml +++ /dev/null @@ -1,234 +0,0 @@ -env: - CIRRUS_VAULT_URL: https://vault.sonar.build:8200 - CIRRUS_VAULT_AUTH_PATH: jwt-cirrusci - CIRRUS_VAULT_ROLE: cirrusci-${CIRRUS_REPO_OWNER}-${CIRRUS_REPO_NAME} - - ARTIFACTORY_URL: VAULT[development/kv/data/repox data.url] - ARTIFACTORY_PRIVATE_USERNAME: vault-${CIRRUS_REPO_OWNER}-${CIRRUS_REPO_NAME}-private-reader - ARTIFACTORY_PRIVATE_PASSWORD: VAULT[development/artifactory/token/${CIRRUS_REPO_OWNER}-${CIRRUS_REPO_NAME}-private-reader access_token] - ARTIFACTORY_DEPLOY_USERNAME: vault-${CIRRUS_REPO_OWNER}-${CIRRUS_REPO_NAME}-qa-deployer - ARTIFACTORY_DEPLOY_PASSWORD: VAULT[development/artifactory/token/${CIRRUS_REPO_OWNER}-${CIRRUS_REPO_NAME}-qa-deployer access_token] - ARTIFACTORY_DEPLOY_REPO: sonarsource-public-qa - ARTIFACTORY_ACCESS_TOKEN: VAULT[development/artifactory/token/${CIRRUS_REPO_OWNER}-${CIRRUS_REPO_NAME}-private-reader access_token] - GITHUB_TOKEN: VAULT[development/github/token/licenses-ro token] - # burgr notification - BURGR_URL: VAULT[development/kv/data/burgr data.url] - BURGR_USERNAME: VAULT[development/kv/data/burgr data.cirrus_username] - BURGR_PASSWORD: VAULT[development/kv/data/burgr data.cirrus_password] - - # Use bash (instead of sh on linux or cmd.exe on windows) - CIRRUS_SHELL: bash - -container_definition: &CONTAINER_DEFINITION - dockerfile: .cirrus/nodejs.Dockerfile - docker_arguments: - CIRRUS_AWS_ACCOUNT: ${CIRRUS_AWS_ACCOUNT} - cluster_name: ${CIRRUS_CLUSTER_NAME} - builder_role: cirrus-builder - builder_image: docker-builder-v* - builder_instance_type: t3.small - builder_subnet_id: ${CIRRUS_AWS_SUBNET} - region: eu-central-1 - namespace: default - use_in_memory_disk: true - -maven_cache_definition: &MAVEN_CACHE - maven_cache: - folder: ${CIRRUS_WORKING_DIR}/.m2/repository - fingerprint_script: cat **/pom.xml - -win_vm_definition: &WINDOWS_VM_DEFINITION - ec2_instance: - experimental: true # see https://github.com/cirruslabs/cirrus-ci-docs/issues/1051 - image: base-windows-jdk11-v* - platform: windows - region: eu-central-1 - type: t3.2xlarge - subnet_id: ${CIRRUS_AWS_SUBNET} - preemptible: false - use_ssd: true - -only_sonarsource_qa: &ONLY_SONARSOURCE_QA - only_if: $CIRRUS_USER_COLLABORATOR == 'true' && ($CIRRUS_PR != "" || $CIRRUS_BRANCH == "master" || $CIRRUS_BRANCH =~ "branch-.*" || $CIRRUS_BRANCH =~ "dogfood-on-.*") - -plugin_qa_body: &PLUGIN_QA_BODY - depends_on: - - build - <<: *ONLY_SONARSOURCE_QA - eks_container: - <<: *CONTAINER_DEFINITION - cpu: 15 - memory: 30G - env: - CIRRUS_CLONE_DEPTH: 10 - SONARSOURCE_QA: true - <<: *MAVEN_CACHE - node_version_script: - - node -v - qa_script: - - source cirrus-env QA - - source set_maven_build_version $BUILD_NUMBER - - mvn -f its/plugin/pom.xml -Dsonar.runtimeVersion=${SQ_VERSION} -B -e -V verify surefire-report:report - cleanup_before_cache_script: cleanup_maven_repository - - -build_task: - eks_container: - <<: *CONTAINER_DEFINITION - cpu: 15 - memory: 30G - env: - # analysis on next - SONAR_TOKEN: VAULT[development/kv/data/next data.token] - SONAR_HOST_URL: https://next.sonarqube.com/sonarqube - #allow deployment of pull request artifacts to repox - DEPLOY_PULL_REQUEST: true - #sign artifacts - SIGN_KEY: VAULT[development/kv/data/sign data.key] - PGP_PASSPHRASE: VAULT[development/kv/data/sign data.passphrase] - <<: *MAVEN_CACHE - sonar_cache: - folder: ${HOME}/.sonar/cache - fingerprint_script: - - echo ${CIRRUS_OS} - - curl --silent ${SONAR_HOST_URL}/deploy/plugins/index.txt | sort - build_script: - - source cirrus-env BUILD - - npm config set registry "${ARTIFACTORY_URL}/api/npm/npm" - - regular_mvn_build_deploy_analyze - cleanup_before_cache_script: cleanup_maven_repository - -build_win_task: - depends_on: - - build - <<: *WINDOWS_VM_DEFINITION - <<: *ONLY_SONARSOURCE_QA - <<: *MAVEN_CACHE - build_script: - - source cirrus-env CI - - npm config set registry "${ARTIFACTORY_URL}/api/npm/npm" - - mvn test - cleanup_before_cache_script: cleanup_maven_repository - -ws_scan_task: - depends_on: - - build - eks_container: - <<: *CONTAINER_DEFINITION - cpu: 4 - memory: 8G - # run only on master and long-term branches - only_if: $CIRRUS_USER_COLLABORATOR == 'true' && ($CIRRUS_BRANCH == "master" || $CIRRUS_BRANCH =~ "branch-.*") - env: - WS_APIKEY: VAULT[development/kv/data/mend data.apikey] - <<: *MAVEN_CACHE - whitesource_script: - - source cirrus-env QA - - npm config set registry "${ARTIFACTORY_URL}/api/npm/npm" - - source set_maven_build_version $BUILD_NUMBER - - mvn clean install -DskipTests - - source ws_scan.sh - allow_failures: "true" - always: - ws_artifacts: - path: "whitesource/**/*" - -plugin_qa_task: - <<: *PLUGIN_QA_BODY - eks_container: - dockerfile: .cirrus/nodejs.jdk17.Dockerfile - docker_arguments: - matrix: - - NODE_VERSION: 14 - - NODE_VERSION: 16 - - NODE_VERSION: 18 - env: - SQ_VERSION: LATEST_RELEASE - -plugin_qa_sq_dev_task: - <<: *PLUGIN_QA_BODY - eks_container: - dockerfile: .cirrus/nodejs.jdk17.Dockerfile - env: - SQ_VERSION: DEV - -# Plugin QA for Windows is splint into 2 parts to make it faster -plugin_qa_win_task: - depends_on: - - build - <<: *WINDOWS_VM_DEFINITION - <<: *ONLY_SONARSOURCE_QA - env: - SONARSOURCE_QA: true - SQ_VERSION: LATEST_RELEASE - matrix: - - TEST: "!CoverageTest,!TypeScriptAnalysisTest,!EslintBasedRulesTest,!SonarLintTest" - - TEST: "CoverageTest,TypeScriptAnalysisTest,EslintBasedRulesTest,SonarLintTest" - <<: *MAVEN_CACHE - qa_script: - - source /c/buildTools-docker/bin/cirrus-env QA - - source /c/buildTools-docker/bin/set_maven_build_version $BUILD_NUMBER - # building the custom plugin required for the further tests - - mvn clean package -f its/plugin/plugins/pom.xml - - mvn -f its/plugin/tests/pom.xml -Dsonar.runtimeVersion=${SQ_VERSION} "-Dtest=${TEST}" -B -e -V verify surefire-report:report - cleanup_before_cache_script: cleanup_maven_repository - always: - surefire_report_artifacts: - path: "its/plugin/tests/target/site/**/*" - type: text/html - surefire_artifacts: - path: "its/plugin/tests/target/surefire-reports/**/*" - type: text/xml - -ruling_task: - depends_on: - - build - <<: *ONLY_SONARSOURCE_QA - eks_container: - <<: *CONTAINER_DEFINITION - dockerfile: .cirrus/nodejs.jdk17.Dockerfile - cpu: 15 - memory: 24G - env: - CIRRUS_CLONE_DEPTH: 10 - SONARSOURCE_QA: true - matrix: - - RULING: JavaScriptRulingTest - - RULING: TypeScriptRulingTest - - RULING: CssRulingTest - <<: *MAVEN_CACHE - submodules_script: - - git submodule update --init - ruling_script: - - source cirrus-env QA - - source set_maven_build_version $BUILD_NUMBER - - cd its/ruling - - mvn verify -Dtest=${RULING} -Dsonar.runtimeVersion=LATEST_RELEASE -Dmaven.test.redirectTestOutputToFile=false -Djunit.jupiter.execution.parallel.config.dynamic.factor=1 -B -e -V - cleanup_before_cache_script: cleanup_maven_repository - on_failure: - diff_artifacts: - path: "**/target/actual/**/*" - -promote_task: - depends_on: - - ws_scan - - build_win - - plugin_qa - - plugin_qa_sq_dev - - plugin_qa_win - - ruling - <<: *ONLY_SONARSOURCE_QA - eks_container: - <<: *CONTAINER_DEFINITION - cpu: 1 - memory: 1G - env: - #promotion cloud function - GCF_ACCESS_TOKEN: VAULT[development/kv/data/promote data.token] - PROMOTE_URL: VAULT[development/kv/data/promote data.url] - GITHUB_TOKEN: VAULT[development/github/token/${CIRRUS_REPO_OWNER}-${CIRRUS_REPO_NAME}-promotion token] - #artifacts that will have downloadable links in burgr - ARTIFACTS: org.sonarsource.javascript:sonar-javascript-plugin:jar - <<: *MAVEN_CACHE - script: cirrus_promote_maven - cleanup_before_cache_script: cleanup_maven_repository diff --git a/.cirrus/nodejs.Dockerfile b/.cirrus/nodejs.Dockerfile deleted file mode 100644 index 5f4405cd8b7..00000000000 --- a/.cirrus/nodejs.Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -ARG CIRRUS_AWS_ACCOUNT=275878209202 -FROM ${CIRRUS_AWS_ACCOUNT}.dkr.ecr.eu-central-1.amazonaws.com/base:j11-latest - -USER root - -RUN apt-get update && apt-get install -y nodejs=14.* - -USER sonarsource diff --git a/.cirrus/nodejs.jdk17.Dockerfile b/.cirrus/nodejs.jdk17.Dockerfile deleted file mode 100644 index 12bc05cff1b..00000000000 --- a/.cirrus/nodejs.jdk17.Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -ARG CIRRUS_AWS_ACCOUNT=275878209202 -FROM ${CIRRUS_AWS_ACCOUNT}.dkr.ecr.eu-central-1.amazonaws.com/base:j17-latest - -USER root - -ARG NODE_VERSION=14 - -RUN apt-get update && apt-get install -y nodejs=${NODE_VERSION}.* - -USER sonarsource diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 4a7e762f813..00000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -.github/CODEOWNERS @SonarSource/languages-team-jsts diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index f67751d930c..00000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,20 +0,0 @@ - diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 27d5672816d..00000000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1 +0,0 @@ -Fixes # diff --git a/.github/workflows/CreatePullRequest.yml b/.github/workflows/CreatePullRequest.yml deleted file mode 100644 index 155ac80456e..00000000000 --- a/.github/workflows/CreatePullRequest.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Create Pull Request - -on: - pull_request: - types: ["opened"] - -jobs: - CreateCardForStandalonePR_job: - name: Assign PR to the author and create a Kanban card - runs-on: ubuntu-latest - # Single quotes must be used here https://docs.github.com/en/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions#literals - # PRs from forks don't have required token authorization - # Dependabot works directly under our repository, but doesn't have enough priviledges to create project card - if: | - github.event.pull_request.head.repo.full_name == github.repository - && github.event.sender.type != 'Bot' - steps: - - uses: sonarsource/gh-action-lt-backlog/CreateCardForStandalonePR@v1 - with: - github-token: ${{secrets.GITHUB_TOKEN}} - column-id: 16320787 diff --git a/.github/workflows/RequestReview.yml b/.github/workflows/RequestReview.yml deleted file mode 100644 index 29447da40b5..00000000000 --- a/.github/workflows/RequestReview.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Request review - -on: - pull_request: - types: ["review_requested"] - -jobs: - MoveCardToReview_job: - name: Move card to review - runs-on: ubuntu-latest - # PRs from forks don't have required token authorization - if: github.event.pull_request.head.repo.full_name == github.repository - steps: - - uses: sonarsource/gh-action-lt-backlog/MoveCardToReview@v1 - with: - github-token: ${{secrets.GITHUB_TOKEN}} - column-id: 16320793 # Kanban "In review" column diff --git a/.github/workflows/StartProgress.yml b/.github/workflows/StartProgress.yml deleted file mode 100644 index e58003977d0..00000000000 --- a/.github/workflows/StartProgress.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Start Progress - -on: - project_card: - types: ["moved"] - -jobs: - AssignCardToSender_job: - runs-on: ubuntu-latest - if: | - github.event.changes.column_id.from == 16320786 - && github.event.project_card.content_url != null - steps: - - uses: sonarsource/gh-action-lt-backlog/AssignCardToSender@v1 - with: - github-token: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/SubmitReview.yml b/.github/workflows/SubmitReview.yml deleted file mode 100644 index 3ffd61658f8..00000000000 --- a/.github/workflows/SubmitReview.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Submit Review - -on: - pull_request_review: - types: ["submitted"] - -jobs: - MoveCardToProgress_job: - name: Move card to progress - runs-on: ubuntu-latest - # Single quotes must be used here https://docs.github.com/en/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions#literals - # PRs from forks don't have required token authorization - if: | - github.event.pull_request.head.repo.full_name == github.repository - && github.event.review.state == 'changes_requested' - steps: - - uses: sonarsource/gh-action-lt-backlog/MoveCardAfterReview@v1 - with: - github-token: ${{secrets.GITHUB_TOKEN}} - column-id: 16320787 # Kanban "In progress" column - - ReviewApproved_job: - name: Move card to review approved - runs-on: ubuntu-latest - if: | - github.event.pull_request.head.repo.full_name == github.repository - && github.event.review.state == 'approved' - steps: - - uses: sonarsource/gh-action-lt-backlog/MoveCardAfterReview@v1 - with: - github-token: ${{secrets.GITHUB_TOKEN}} - column-id: 16320799 # Kanban "Resolved" column diff --git a/.github/workflows/dogfood.yml b/.github/workflows/dogfood.yml deleted file mode 100644 index 7723b8c9bb1..00000000000 --- a/.github/workflows/dogfood.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: dogfood merge -# This workflow is triggered on pushes to master and dogfood branches -on: - push: - branches: - - master - - 'dogfood/*' - -jobs: - dogfood_merge: - runs-on: ubuntu-latest - name: Update dogfood branch - steps: - - name: git octopus step - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - id: dogfood - uses: SonarSource/gh-action_dogfood_merge@master - with: - dogfood-branch: 'dogfood-on-peach' - # Use the output from the `dogfood` step - - name: Get the name of the dogfood branch and its HEAD SHA1 - run: echo "The dogfood branch was ${{ steps.dogfood.outputs.dogfood-branch }} and its HEAD SHA1 was ${{ steps.dogfood.outputs.sha1 }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 1509fd23168..00000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: sonar-release -# This workflow is triggered when publishing a new github release -# yamllint disable-line rule:truthy -on: - release: - types: - - published - -jobs: - release: - permissions: - id-token: write - contents: write - uses: SonarSource/gh-action_release/.github/workflows/main.yaml@v5 - with: - publishToBinaries: true - mavenCentralSync: true - slackChannel: team-lang-js-ts-css diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 90d5480835d..00000000000 --- a/.gitmodules +++ /dev/null @@ -1,89 +0,0 @@ - -[submodule "its/typescript-test-sources"] - path = its/typescript-test-sources - url = https://github.com/SonarSource/typescript-test-sources.git - ignore = untracked -[submodule "its/sources/jquery"] - path = its/sources/jquery - url = https://github.com/SonarSource/jquery.git - ignore = untracked -[submodule "its/sources/angular.js"] - path = its/sources/angular.js - url = https://github.com/SonarSource/angular.js.git - ignore = untracked -[submodule "its/sources/p5.js"] - path = its/sources/p5.js - url = https://github.com/SonarSource/p5.js.git - ignore = untracked -[submodule "its/sources/amplify"] - path = its/sources/amplify - url = https://github.com/SonarSource/amplify.git - ignore = untracked -[submodule "its/sources/backbone"] - path = its/sources/backbone - url = https://github.com/SonarSource/backbone.git - ignore = untracked -[submodule "its/sources/es5-shim"] - path = its/sources/es5-shim - url = https://github.com/SonarSource/es5-shim.git - ignore = untracked -[submodule "its/sources/fireact"] - path = its/sources/fireact - url = https://github.com/chaoming/fireact.git - ignore = untracked -[submodule "its/sources/jira-clone"] - path = its/sources/jira-clone - url = https://github.com/oldboyxx/jira_clone.git - ignore = untracked -[submodule "its/sources/jshint"] - path = its/sources/jshint - url = https://github.com/SonarSource/jshint.git - ignore = untracked -[submodule "its/sources/jStorage"] - path = its/sources/jStorage - url = https://github.com/SonarSource/jStorage.git - ignore = untracked -[submodule "its/sources/knockout"] - path = its/sources/knockout - url = https://github.com/SonarSource/knockout.git - ignore = untracked -[submodule "its/sources/mootools-core"] - path = its/sources/mootools-core - url = https://github.com/SonarSource/mootools-core.git - ignore = untracked -[submodule "its/sources/ocanvas"] - path = its/sources/ocanvas - url = https://github.com/SonarSource/ocanvas.git - ignore = untracked -[submodule "its/sources/paper.js"] - path = its/sources/paper.js - url = https://github.com/SonarSource/paper.js.git - ignore = untracked -[submodule "its/sources/prototype"] - path = its/sources/prototype - url = https://github.com/SonarSource/prototype.git - ignore = untracked -[submodule "its/sources/qunit"] - path = its/sources/qunit - url = https://github.com/SonarSource/qunit.git - ignore = untracked -[submodule "its/sources/react-cloud-music"] - path = its/sources/react-cloud-music - url = https://github.com/sanyuan0704/react-cloud-music.git - ignore = untracked -[submodule "its/sources/sizzle"] - path = its/sources/sizzle - url = https://github.com/SonarSource/sizzle.git - ignore = untracked -[submodule "its/sources/underscore"] - path = its/sources/underscore - url = https://github.com/SonarSource/underscore.git - ignore = untracked - -[submodule "its/sources/javascript-test-sources"] - path = its/sources/javascript-test-sources - url = https://github.com/SonarSource/javascript-test-sources.git - ignore = untracked -[submodule "its/css-sources/projects"] - path = its/css-sources/projects - url = https://github.com/SonarSource/css-test-sources diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 0a041280bd0..00000000000 --- a/LICENSE.txt +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/NOTICE.txt b/NOTICE.txt deleted file mode 100644 index f12bd85fae3..00000000000 --- a/NOTICE.txt +++ /dev/null @@ -1,6 +0,0 @@ -JavaScript -Copyright (C) 2011-2017 SonarSource SA -mailto:info AT sonarsource DOT com - -This product includes software developed at -SonarSource (http://www.sonarsource.com/). diff --git a/README.md b/README.md deleted file mode 100644 index 0504ba7c3f5..00000000000 --- a/README.md +++ /dev/null @@ -1,43 +0,0 @@ -[![Quality Gate](https://next.sonarqube.com/sonarqube/api/project_badges/measure?project=org.sonarsource.javascript%3Ajavascript&metric=alert_status)](https://next.sonarqube.com/sonarqube/dashboard?id=org.sonarsource.javascript%3Ajavascript) [![Coverage](https://next.sonarqube.com/sonarqube/api/project_badges/measure?project=org.sonarsource.javascript%3Ajavascript&metric=coverage)](https://next.sonarqube.com/sonarqube/component_measures/domain/Coverage?id=org.sonarsource.javascript%3Ajavascript) - -This SonarSource project is a [static code analyser](https://en.wikipedia.org/wiki/Static_program_analysis) for JavaScript, TypeScript and CSS languages. - -:arrow_right: [Have some feedback?](#support) - -:arrow_right: [eslint-plugin-sonarjs](https://github.com/SonarSource/eslint-plugin-sonarjs), our plugin for ESLint - -# Features - -* Advanced rules based on pattern matching and control flow analysis -* ~280 rules for [JavaScript](https://rules.sonarsource.com/javascript) and [TypeScript](https://rules.sonarsource.com/typescript) -* ~30 rules for [CSS](https://rules.sonarsource.com/css) -* Compatible with ECMAScript 2015-2020 -* React JSX, Flow and Vue support for JavaScript and TypeScript -* CSS, SCSS, Less, also 'style' inside PHP, HTML and VueJS files -* Metrics (complexity, number of lines etc.) -* Import of test coverage reports -* Import of ESLint, TSLint and Stylelint issues - -# Documentation -You can find [documentation here](https://docs.sonarqube.org/latest/analysis/languages/javascript/) - -# Have question or feedback? -### SonarSource Community Forum -If you want to report a bug, request a feature or provide other kind of feedback, please use [SonarQube Community Forum](https://community.sonarsource.com/). Please do not forget to specify the details of your request, code reproducer, versions of projects you use. - -# Contributing - -#### 1. Request a new feature -To request a new feature, create a new thread in [SonarSource Community Forum](https://community.sonarsource.com/). Even if you plan to implement it yourself and submit it back to the community, please create a thread to be sure that we can follow up on it. - -#### 2. Pull Request -To submit a contribution, create a pull request for this repository. Please make sure that you follow our [code style](https://github.com/SonarSource/sonar-developer-toolset) and all [tests](/docs/DEV.md#testing) are passing. - -#### Work with us -Would you like to work on this project full-time? We are hiring! Check out https://www.sonarsource.com/hiring - -## License - -Copyright 2011-2021 SonarSource. - -Licensed under the [GNU Lesser General Public License, Version 3.0](http://www.gnu.org/licenses/lgpl.txt) diff --git a/check-license-compliance.sh b/check-license-compliance.sh deleted file mode 100755 index de09f1f5640..00000000000 --- a/check-license-compliance.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# See https://xtranet.sonarsource.com/display/DEV/Open+Source+Licenses - -mvn org.codehaus.mojo:license-maven-plugin:aggregate-add-third-party diff --git a/css-sonarpedia/sonarpedia.json b/css-sonarpedia/sonarpedia.json deleted file mode 100644 index 4a2865b6c17..00000000000 --- a/css-sonarpedia/sonarpedia.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "rules-metadata-path": "../sonar-javascript-plugin/src/main/resources/org/sonar/l10n/css/rules/css", - "languages": [ - "CSS" - ], - "latest-update": "2023-01-12T15:04:36.239650Z", - "options": { - "no-language-in-filenames": true - } -} \ No newline at end of file diff --git a/docs/DEV.md b/docs/DEV.md deleted file mode 100644 index dc6d8d67191..00000000000 --- a/docs/DEV.md +++ /dev/null @@ -1,264 +0,0 @@ -# Developer Guide - -## Prerequisites -- [JDK 11](https://docs.aws.amazon.com/corretto/latest/corretto-11-ug/what-is-corretto-11.html) -- [Maven](https://maven.apache.org/install.html) -- Node.js (we recommend using [NVM](https://github.com/nvm-sh/nvm#installing-and-updating)) - -You can also use Docker container defined in `./.cirrus/nodejs-lts.Dockerfile` which bundles all required dependencies and is used for our CI pipeline. - -## Build and run unit tests -To build the plugin and run its unit tests, execute this command from the project's root directory: - -```sh -mvn clean install -``` - -## Integration Tests -First make sure the submodules are checked out: - -```sh - git submodule init - git submodule update -``` - -### Plugin Tests -The "Plugin Test" is an integration test which verifies plugin features such as metric calculation, coverage etc. -```sh -cd its/plugin -mvn clean install -``` - -### Ruling Tests -The "Ruling Test" is an integration test which launches the analysis of a large code base (stored as submodules), saves the issues created by the plugin in report files, and then compares those results to the set of expected issues (stored as JSON files). -```sh -cd its/ruling -mvn verify -Dtest=JavaScriptRulingTest -Dmaven.test.redirectTestOutputToFile=false -mvn verify -Dtest=TypeScriptRulingTest -Dmaven.test.redirectTestOutputToFile=false -mvn verify -Dtest=CssRulingTest -Dmaven.test.redirectTestOutputToFile=false -``` - -This test gives you the opportunity to examine the issues created by each rule and make sure that they are what you expect. You can inspect new/lost issues checking the SonarQube UI (use DEBUG mode and put a breakpoint on the assertion) at the end of analysis. - -If everything looks good to you, you can copy the file with the actual issues located at `its/ruling/target/actual/` -into the directory with the expected issues `its/ruling/src/test/resources/expected/`. - -From `its/ruling/`: -* for JS `cp -R target/actual/js/ src/test/expected/js` -* for TS `cp -R target/actual/ts/ src/test/expected/ts` -* for CSS `cp -R target/actual/css/ src/test/expected/css` - -You can review the Ruling difference by running `diff -rq src/test/expected/js target/actual/js` from `its/ruling`. - -To review the Ruling difference in SonarQube UI, put the breakpoint on `assertThat(...)` in `{JavaScript/CSS}RulingTest.java` and open in the browser the orchestrated local SonarQube. -Note that you can fix the port in `orchestrator.properties files`, e.g. `orchestrator.container.port=9100`. - -## Adding a rule - -### Rule Description -1. Create a PR with a rule description in RSPEC repo like described [here](https://github.com/SonarSource/rspec#create-or-modify-a-rule) -2. Link this RSPEC PR to the implementation issue in this repo -5. Make sure the implementation issue title contains the RSPEC number and name - -### Implementing a rule -1. Generate rule metadata (JSON and HTML files) from [RSPEC](https://github.com/SonarSource/rspec#4-implement-the-rule) by running this command from the project's root: - -```sh -java -jar generate -rule S1234 [-branch ] -``` - -2. Generate other files required for a new rule. If the rule is already covered by ESLint or its plugins, use the existing and add the `eslint` option. -```sh -cd eslint-bridge -npm run new-rule S1234 -// e.g. -npm run new-rule S1234 no-invalid-something [eslint] -``` -This script: -* generates a Java check class for the rule `NoInvalidSomethingCheck.java` -* generates a `no-invalid-something.ts` file for the rule implementation -* generates a `comment-based/no-invalid-something.js` test file -* updates the `index.ts` file to include the new rule -* updates the `CheckList.java` to include the new rule - -3. Update generated files - * Make sure annotations in the Java class specify languages to cover (`@JavaScriptRule` and/or `@TypeScriptRule`) - * If required, override the `configurations()` method of the Java check class - * If writing a rule for the test files, replace `implements EslintBasedCheck` with `extends TestFileCheck` in the Java class - * In the generated metadata JSON file `javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/S1234.json`, add (one or both): - ```json - "compatibleLanguages": [ - "JAVASCRIPT", - "TYPESCRIPT" - ] - ``` -4. Implement the rule logic in `no-invalid-something.ts` - * Prefer using `meta.messages` to specify messages through `messageId`s. Message can be part of the RSPEC description, like [here](https://sonarsource.github.io/rspec/#/rspec/S4036/javascript#message). - * Note that there are some helper functions in `src/linting/eslint/rules/helpers/` - * If writing a regex rule, use [createRegExpRule](https://github.com/SonarSource/SonarJS/blob/2831eb9a53da914d58b8e063a017c68e71eab839/eslint-bridge/src/linting/eslint/rules/helpers/regex/rule-template.ts#L52) - * If possible implement quick fixes for the rule (then add its rule key in `eslint-bridge/src/linting/eslint/linter/quickfixes/rules.ts`). - -## Testing a rule - -`eslint-bridge` supports 2 kinds of rule unit-tests: ESLint's [RuleTester](https://eslint.org/docs/developer-guide/nodejs-api#ruletester) or our comment-based tests. Prefer comment-based tests as they are more readable! - -### Comment-based testing - -These tests are located in `eslint-bridge/tests/linting/eslint/rules/comment-based/` and they **MUST** be named after the rule they are testing (i.e. `semi.[(js|ts)x?]` to test ESLint `semi` rule). If options are to be passed to the tested rule, add a JSON file to the same directory following the same naming convention but with a `.json` extension (i.e. `semi.json`). The file must contain the array of options. - -The contents of the test code have the following structure: - -```javascript -some.clean.code(); -some.faulty.code(); // Noncompliant N [[qf1,qf2,...]] {{Optional message to assert}} -// ^^^^^^ -// fix@qf1 {{Optional suggestion description}} -// edit@qf1 [[sc=1;ec=5]] {{text to replace line from [sc] column to [ec] column}} -faulty.setFaultyParam(true) -// ^^^^^^^^^^^^^^< {{Optional secondary message to assert}} -``` - -The contents of the options file must be a valid JSON array: - -```javascript -// brace-style.json -["1tbs", { "allowSingleLine": true }] -``` - -#### Tests syntax - -Given the above test snippet: the issue primary location (`// ^^^^`), issue messages (`{{...}}`), secondary location(s) (`// ^^^<`), issues count (`N`) and quick fixes are optional. - -`N` is an integer defining the amount of issues will be reported in the line. - -Only one of the methods (`{{messageN}}+` OR `N`) to define the expected issues can be used in a `Noncompliant` line. If you set both `N` and messages, the framework will throw an error. - -If no `N` nor messages are provided, the engine will expect one issue to be raised. Meaning, `//Noncompliant` is equivalent to `//Noncompliant 1`. - -`Noncompliant` lines will be associated by default to the line of code where they are writen. The syntax `@line_number` allows for an issue to be associated to another line: - -```javascript -// Noncompliant@2 N [[qf1,qf2,...]] {{Optional message to assert}} -some.faulty.code(); -``` - -Another option is to use relative line increments (`@+line_increment`) or decrements (`@-line_decrement`): -```javascript -// Noncompliant@+1 -some.faulty.code(); - -another.faulty.code(); -// another comment -// Noncompliant@-2 -``` - -#### Secondary locations - -Secondary locations are part of [Sonar issues](https://docs.sonarqube.org/latest/user-guide/issues/). They provide additional context to the raised issue. In order to use them, you must call the [toEncodedMessage()](https://github.com/SonarSource/SonarJS/blob/66c14e5d1a68232940d540a19fb89872d41c206d/eslint-bridge/src/linting/eslint/rules/helpers/location.ts#L44) function when reporting the issue message like this: - -```javascript -context.report({ - node, - message: toEncodedMessage(...), -}); -``` - -In order to indicate secondary locations, you must use either `// ^^^^^<` or `// ^^^^>`, the arrow indicating whether the matching main location is either before or after the secondary one. - -As stated before, the message is optional. - -**/!\** If you have used a secondary location in your test file, you must always report error messages using [toEncodedMessage()](https://github.com/SonarSource/SonarJS/blob/66c14e5d1a68232940d540a19fb89872d41c206d/eslint-bridge/src/linting/eslint/rules/helpers/location.ts#L44) in your rule, as it will be expecting it. - -#### Quick fixes - -Quick fixes refer to both ESLint [Suggestions](https://eslint.org/docs/latest/developer-guide/working-with-rules#providing-suggestions) and [Fixes](https://eslint.org/docs/latest/developer-guide/working-with-rules#applying-fixes). In our comment-based framework both use the same syntax, with the difference that a quick fix ID followed by an exclamation mark (`!`) will be internally treated as a `fix` with ESLint instead of as a suggestion. Please note that rules providing fixes **MUST** be tested always with fixes, otherwise the test will fail with the following error: `The rule fixed the code. Please add 'output' property.`. On the other side, it is optional to check against rule suggestions, meaning that even if a rule provides them, the tests can choose not to test their contents. - -The `fix@` comment referring to a quick fix provides the suggestion description and is optional. Eslint fixes do not support descriptions, meaning a quick fix ID declared with an exclamation mark (i.e. `qf1!`) must **NOT** have a `fix@` matching comment (i.e. `fix@qf1`). - -Each quick fix can have multiple editions associated to it. There are three different kind of operations to edit the code with quick fixes. Given a quick fix ID `qf`, these are the syntaxes used for each operation: - -- `add@qf {{code to add}}` Add the string between the double brackets to a new line in the code. -- `del@qf` Remove the line -- `edit@qf1 [[sc=1;ec=5]] {{text to replace the range }}` Edit the line from start column `sc` to end column `ec` (both 0-based) with the provided string between the double brackets. Alternatively, one can conveniently use only `sc` or `ec`. also optional, meaning this syntax can be used too: - - `edit@qf1 {{text to replace the whole line -do not include //Noncompliant comment- }}` - -The line affected in each of these operations will be the line of the issue to which the quick fix is linked to. It is possible to use the line modifier syntax (`@[+|-]?line`). When using line increments/decrements, keep in mind the base number is the issue line number, not the line of the quick fix edit comment. Example for rule `brace-style`: - -```javascript -//Noncompliant@+1 [[qf!]] -if (condition) { doSomething() -} -// edit@qf [[sc=16]] {{}} -// add@qf@+1 {{ doSomething()}} -``` -The expected output is: -```javascript -if (condition) { - doSomething() -} -``` -Let's go through the syntax used in this example: -- The test provides a fix (note the `!` after the ID `qf`). -- The line `//Noncompliant@+1 [[qf!]]` means that in the following (`@+1`) line there is an issue for which we provide a quick fix. -- The line `// edit@qf [[sc=16]] {{}}` is providing an edit to the same line of the issue, replacing the contents after column 16 (`sc=16`) by an empty string (`{{}}`). An alternative with the same effect would be `// edit@qf {{if (condition) {}}`, which would replace the whole line by `if (condition) {`. -- Lastly, the line `// add@qf@+1 {{ doSomething()}}` will add a new line just after the issue line (`@+1`) with the contents ` doSomething()` - - - -Note that the length of the list of quick fixes cannot surpass the number of issues declared by `N` or the number of expected messages unless their matching issue is reassigned (see below). - -Quick fixes IDs can be any `string`, they don't have to follow the `qfN` convention. The order of the list is important, as they will be assigned to the message in the matching position. If one provides 3 messages and 2 quick fixes which are not to be matched against first and second message, there are two options: - -* A *dummy* quick fix can be used as placeholder: - -```javascript -some.faulty.code(); // Noncompliant [[qf1,qf2,qf3]] {{message1}} {{message2}} {{message3}} -// edit@qf1 {{fix for message1}} -// edit@qf3 {{fix for message3}} -// qf2 is declared but never used --> ignored by the engine -``` - -* Explicitly set the index (0-based) of the message to which the quick fix refers to with the syntax `=index` next to the quick fix ID: - -```javascript -some.faulty.code(); // Noncompliant [[qf1,qf3=2]] {{message1}} {{message2}} {{message3}} -// edit@qf1 {{fix for message1}} -// edit@qf3 {{fix for message3}} -``` - -This last syntax is also needed if multiple suggestions are to be provided for the same issue: - -```javascript -some.faulty.code(); // Noncompliant [[qf1,qf2=0]] -// fix@qf1 {{first alternative quickfix description}} -// edit@qf1 {{some.faulty?.code();}} -// fix@qf2 {{second alternative quickfix description}} -// edit@qf2 {{some.faulty && some.faulty.code();}} -``` - -To execute a single comment-based test: -```sh -npm run ctest -- -t="no-invalid-something" -``` - -#### Ruling - -Make sure to run [Ruling ITs](#ruling-tests) for the new or updated rule (don't forget to rebuild the jar before that!). - -If your rule does not raise any issue, you should write your own code that triggers your rule in: -- `its/sources/file-for-rules/S1234.js` for code -- `its/sources/file-for-rules/tests/S1234.js` for test code - -You can simply copy and paste compliant and non-compliant examples from your RSPEC HTML description. - -## Examples - -* Security Hotspot implementation: [PR](https://github.com/SonarSource/SonarJS/pull/3148) -* Quality rule implemented with quickfix: [PR](https://github.com/SonarSource/SonarJS/pull/3141) -* Adding a rule already covered by ESLint or its plugins: [PR](https://github.com/SonarSource/SonarJS/pull/3134) -* Adding a quickfix for rule covered by ESLint or its plugins: [PR](https://github.com/SonarSource/SonarJS/pull/3058) - -## Misc -* Use issue number for a branch name, e.g. `issue-1234` -* You can use [AST explorer](https://astexplorer.net/) to explore the tree share. Use the `regexpp` parser when implementing a Regex rule. -* [ESlint's working with rules](https://eslint.org/docs/developer-guide/working-with-rules) diff --git a/eslint-bridge/.gitignore b/eslint-bridge/.gitignore deleted file mode 100644 index c65962f165a..00000000000 --- a/eslint-bridge/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -lib/ -node_modules/ -coverage/ -test-report.xml diff --git a/eslint-bridge/.prettierignore b/eslint-bridge/.prettierignore deleted file mode 100644 index f6f05a13bdc..00000000000 --- a/eslint-bridge/.prettierignore +++ /dev/null @@ -1,3 +0,0 @@ -*.lint.js -tests/**/fixtures -tests/**/rules/comment-based diff --git a/eslint-bridge/.vscode/launch.json b/eslint-bridge/.vscode/launch.json deleted file mode 100644 index 23624a04d61..00000000000 --- a/eslint-bridge/.vscode/launch.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "All Tests", - "program": "${workspaceFolder}/node_modules/.bin/jest", - "args": ["-i"], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "request": "launch", - "name": "Current Open Test", - "program": "${workspaceFolder}/node_modules/.bin/jest", - "args": ["-i", "${fileBasenameNoExtension}"], - "internalConsoleOptions": "openOnSessionStart" - } - ] -} diff --git a/eslint-bridge/.vscode/settings.json b/eslint-bridge/.vscode/settings.json deleted file mode 100644 index b42a197153e..00000000000 --- a/eslint-bridge/.vscode/settings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true - }, - "sonarlint.connectedMode.project": { - "projectKey": "org.sonarsource.javascript:javascript" - } -} diff --git a/eslint-bridge/bin/server b/eslint-bridge/bin/server deleted file mode 100644 index 989246e39d7..00000000000 --- a/eslint-bridge/bin/server +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env node - -/** - * This script expects following arguments - * - * port - port number on which server should listen - * host - host address on which server should listen - * workDir - working directory from SonarQube API - * shouldUseTypeScriptParserForJS - whether TypeScript parser should be used for JS code (default true, can be set to false in case of perf issues) - * sonarlint - when running in SonarLint (used to not compute metrics, highlighting, etc) - * bundles - ; or : delimited paths to additional rule bundles - */ - -const server = require('../lib/server'); -const path = require('path'); -const context = require('../lib/helpers'); - -const port = process.argv[2]; -const host = process.argv[3]; -const workDir = process.argv[4]; -const shouldUseTypeScriptParserForJS = process.argv[5] === 'true'; -const sonarlint = process.argv[6] === 'true'; - -let bundles = []; -if (process.argv[7]) { - bundles = process.argv[7].split(path.delimiter); -} - -context.setContext({ workDir, shouldUseTypeScriptParserForJS, sonarlint, bundles }); -server.start(port, host); diff --git a/eslint-bridge/jest.config.js b/eslint-bridge/jest.config.js deleted file mode 100644 index d365c61c6c0..00000000000 --- a/eslint-bridge/jest.config.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - collectCoverageFrom: ['src/**/*.ts'], - globals: { - 'ts-jest': { - tsconfig: 'tests/tsconfig.json', - }, - }, - moduleFileExtensions: ['js', 'ts', 'json'], - moduleDirectories: ['node_modules', '/src', '/tests/**/fixtures'], - modulePathIgnorePatterns: [ - '/tests/linting/eslint/rules/fixtures/no-implicit-dependencies/bom-package-json-project/package.json', - ], - testResultsProcessor: 'jest-sonar-reporter', - transform: { - '^.+\\.ts$': 'ts-jest', - }, - testMatch: ['/tests/**/*.test.ts'], - testTimeout: 20000, -}; diff --git a/eslint-bridge/package-lock.json b/eslint-bridge/package-lock.json deleted file mode 100644 index 594572c5a8b..00000000000 --- a/eslint-bridge/package-lock.json +++ /dev/null @@ -1,18574 +0,0 @@ -{ - "name": "eslint-bridge", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "eslint-bridge", - "version": "1.0.0", - "bundleDependencies": [ - "@typescript-eslint/eslint-plugin", - "@typescript-eslint/experimental-utils", - "@typescript-eslint/parser", - "@babel/core", - "@babel/eslint-parser", - "@babel/plugin-proposal-decorators", - "@babel/preset-env", - "@babel/preset-flow", - "@babel/preset-react", - "builtin-modules", - "bytes", - "eslint", - "eslint-plugin-react", - "eslint-plugin-react-hooks", - "eslint-plugin-sonarjs", - "express", - "functional-red-black-tree", - "lodash.clone", - "module-alias", - "postcss-html", - "postcss-less", - "postcss-scss", - "postcss-syntax", - "postcss-value-parser", - "regexpp", - "run-node", - "scslre", - "stylelint", - "tmp", - "vue-eslint-parser", - "typescript", - "yaml" - ], - "license": "LGPL-3.0", - "dependencies": { - "@babel/core": "7.19.0", - "@babel/eslint-parser": "7.18.9", - "@babel/plugin-proposal-decorators": "7.19.3", - "@babel/preset-env": "7.19.0", - "@babel/preset-flow": "7.18.6", - "@babel/preset-react": "7.18.6", - "@typescript-eslint/eslint-plugin": "5.48.1", - "@typescript-eslint/experimental-utils": "5.48.1", - "@typescript-eslint/parser": "5.48.1", - "builtin-modules": "3.3.0", - "bytes": "3.1.2", - "eslint": "8.26.0", - "eslint-plugin-react": "7.31.8", - "eslint-plugin-react-hooks": "4.6.0", - "eslint-plugin-sonarjs": "0.18.0", - "express": "4.18.1", - "functional-red-black-tree": "1.0.1", - "lodash.clone": "4.5.0", - "module-alias": "2.2.2", - "postcss-html": "0.36.0", - "postcss-less": "6.0.0", - "postcss-scss": "4.0.3", - "postcss-syntax": "0.36.2", - "postcss-value-parser": "4.2.0", - "regexpp": "3.2.0", - "run-node": "2.0.0", - "scslre": "0.1.6", - "stylelint": "14.13.0", - "tmp": "0.2.1", - "typescript": "4.9.4", - "vue-eslint-parser": "9.1.0", - "yaml": "2.1.1" - }, - "devDependencies": { - "@types/bytes": "3.1.1", - "@types/eslint": " 8.4.10", - "@types/eslint-scope": "3.7.4", - "@types/estree": "1.0.0", - "@types/express": "4.17.14", - "@types/functional-red-black-tree": "1.0.1", - "@types/jest": "28.1.6", - "@types/lodash.clone": "4.5.7", - "@types/node": "16.11.9", - "@types/tmp": "0.2.3", - "jest": "28.1.3", - "jest-sonar-reporter": "2.0.0", - "mkdirp": "1.0.4", - "prettier": "2.7.1", - "ts-jest": "28.0.7", - "ts-node": "10.9.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "inBundle": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "inBundle": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.20.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz", - "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==", - "inBundle": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", - "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", - "inBundle": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/eslint-parser": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.18.9.tgz", - "integrity": "sha512-KzSGpMBggz4fKbRbWLNyPVTuQr6cmCcBhOyXTw/fieOVaw5oYAwcAj4a7UKcDYCPxQq+CG1NCDZH9e2JTXquiQ==", - "inBundle": true, - "dependencies": { - "eslint-scope": "^5.1.1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.11.0", - "eslint": "^7.5.0 || ^8.0.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", - "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", - "inBundle": true, - "dependencies": { - "@babel/types": "^7.20.7", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "inBundle": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "inBundle": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", - "inBundle": true, - "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "inBundle": true, - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz", - "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-member-expression-to-functions": "^7.20.7", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/helper-split-export-declaration": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", - "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", - "inBundle": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.2.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "inBundle": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "inBundle": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", - "inBundle": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "inBundle": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "inBundle": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz", - "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==", - "inBundle": true, - "dependencies": { - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "inBundle": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", - "inBundle": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.10", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", - "inBundle": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "inBundle": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", - "inBundle": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", - "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", - "inBundle": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.20.7", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "inBundle": true, - "dependencies": { - "@babel/types": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", - "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", - "inBundle": true, - "dependencies": { - "@babel/types": "^7.20.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "inBundle": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "inBundle": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "inBundle": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "inBundle": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", - "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", - "inBundle": true, - "dependencies": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz", - "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==", - "inBundle": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "inBundle": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", - "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", - "inBundle": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", - "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-proposal-optional-chaining": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", - "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", - "inBundle": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz", - "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.19.3.tgz", - "integrity": "sha512-MbgXtNXqo7RTKYIXVchVJGPvaVufQH3pxvQyfbGvNw1DObIhph+PesYXJTcd8J4DdWibvf6Z2eanOyItX8WnJg==", - "inBundle": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.19.1", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/plugin-syntax-decorators": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", - "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", - "inBundle": true, - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz", - "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", - "inBundle": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", - "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.20.5", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "inBundle": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz", - "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", - "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", - "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", - "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", - "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", - "inBundle": true, - "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz", - "integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz", - "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-split-export-declaration": "^7.18.6", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", - "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/template": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", - "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", - "inBundle": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", - "inBundle": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz", - "integrity": "sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/plugin-syntax-flow": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", - "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", - "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", - "inBundle": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz", - "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==", - "inBundle": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-simple-access": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", - "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", - "inBundle": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-identifier": "^7.19.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", - "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", - "inBundle": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.20.5", - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", - "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", - "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.20.7.tgz", - "integrity": "sha512-Tfq7qqD+tRj3EoDhY00nn2uP2hsRxgYGi5mLQ5TimKav0a9Lrpd4deE+fcLXU8zFYRjlKPHZhpCvfEA6qnBxqQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-jsx": "^7.18.6", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", - "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", - "inBundle": true, - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", - "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", - "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "regenerator-transform": "^0.15.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", - "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", - "inBundle": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.0.tgz", - "integrity": "sha512-1YUju1TAFuzjIQqNM9WsF4U6VbD/8t3wEAlw3LFYuuEr+ywqLRcSXxFKz4DCEj+sN94l/XTDiUXYRrsvMpz9WQ==", - "inBundle": true, - "dependencies": { - "@babel/compat-data": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.19.0", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.9", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.18.9", - "@babel/plugin-transform-classes": "^7.19.0", - "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.18.13", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.8", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.18.6", - "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/plugin-transform-modules-systemjs": "^7.19.0", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.0", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.18.8", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.19.0", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.2", - "babel-plugin-polyfill-corejs3": "^0.5.3", - "babel-plugin-polyfill-regenerator": "^0.4.0", - "core-js-compat": "^3.22.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-flow": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.18.6.tgz", - "integrity": "sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-flow-strip-types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-react": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", - "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", - "inBundle": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-react-display-name": "^7.18.6", - "@babel/plugin-transform-react-jsx": "^7.18.6", - "@babel/plugin-transform-react-jsx-development": "^7.18.6", - "@babel/plugin-transform-react-pure-annotations": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", - "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", - "inBundle": true, - "dependencies": { - "regenerator-runtime": "^0.13.11" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "inBundle": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz", - "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==", - "inBundle": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "inBundle": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@csstools/selector-specificity": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", - "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", - "inBundle": true, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2", - "postcss-selector-parser": "^6.0.10" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", - "inBundle": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "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/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", - "inBundle": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/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==", - "inBundle": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "inBundle": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "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==", - "inBundle": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "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==", - "inBundle": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", - "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/console/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/console/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/console/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/console/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/console/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", - "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", - "dev": true, - "dependencies": { - "@jest/console": "^28.1.3", - "@jest/reporters": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^28.1.3", - "jest-config": "^28.1.3", - "jest-haste-map": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-resolve-dependencies": "^28.1.3", - "jest-runner": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "jest-watcher": "^28.1.3", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/core/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/core/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/environment": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", - "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "jest-mock": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", - "dev": true, - "dependencies": { - "expect": "^28.1.3", - "jest-snapshot": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", - "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", - "dev": true, - "dependencies": { - "jest-get-type": "^28.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", - "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", - "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", - "dev": true, - "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/expect": "^28.1.3", - "@jest/types": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", - "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@jridgewell/trace-mapping": "^0.3.13", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "jest-worker": "^28.1.3", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/reporters/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "28.1.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", - "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.13", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", - "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", - "dev": true, - "dependencies": { - "@jest/console": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", - "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^28.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", - "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^28.1.3", - "@jridgewell/trace-mapping": "^0.3.13", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.3", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/transform/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/transform/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/transform/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/transform/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/transform/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "inBundle": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "inBundle": true, - "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==", - "inBundle": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "inBundle": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "inBundle": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "inBundle": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "inBundle": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "inBundle": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "node_modules/@types/babel__core": { - "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", - "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bytes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/bytes/-/bytes-3.1.1.tgz", - "integrity": "sha512-lOGyCnw+2JVPKU3wIV0srU0NyALwTBJlVSx5DfMQOFuuohA8y9S8orImpuIQikZ0uIQ8gehrRjxgQC1rLRi11w==", - "dev": true - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/eslint": { - "version": "8.4.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", - "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", - "dev": true - }, - "node_modules/@types/express": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", - "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.32", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz", - "integrity": "sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "node_modules/@types/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-gUXkc6hiRJ2yPyiidbDbtU5YDt0c8JjYjq671QPYmJg2kiYS53/814Hg2SY4wqL/hfCzfa3NZzeh2e30YhALww==", - "dev": true - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "28.1.6", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.6.tgz", - "integrity": "sha512-0RbGAFMfcBJKOmqRazM8L98uokwuwD5F8rHrv/ZMbrZBwVOWZUyPG6VFNscjYr/vjM3Vu4fRrCPbOs42AfemaQ==", - "dev": true, - "dependencies": { - "jest-matcher-utils": "^28.0.0", - "pretty-format": "^28.0.0" - } - }, - "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==", - "inBundle": true - }, - "node_modules/@types/lodash": { - "version": "4.14.191", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", - "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", - "dev": true - }, - "node_modules/@types/lodash.clone": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/@types/lodash.clone/-/lodash.clone-4.5.7.tgz", - "integrity": "sha512-jugWYM+xBUQCpWbn7p6BSbf8bRMHtJYnEIGZYngbStaU0aN4VFgAAkGgsc+MtHuepBOmjyUGiGv+dHnQQIGLZA==", - "dev": true, - "dependencies": { - "@types/lodash": "*" - } - }, - "node_modules/@types/mime": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", - "dev": true - }, - "node_modules/@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "inBundle": true - }, - "node_modules/@types/node": { - "version": "16.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.9.tgz", - "integrity": "sha512-MKmdASMf3LtPzwLyRrFjtFFZ48cMf8jmX5VRYrDQiJa8Ybu5VAmkqBWqKU8fdCwD8ysw4mQ9nrEHvzg6gunR7A==", - "dev": true - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", - "inBundle": true - }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "inBundle": true - }, - "node_modules/@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true - }, - "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==", - "inBundle": true - }, - "node_modules/@types/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", - "dev": true, - "dependencies": { - "@types/mime": "*", - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", - "integrity": "sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", - "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", - "inBundle": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/type-utils": "5.48.1", - "@typescript-eslint/utils": "5.48.1", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.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" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/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==", - "inBundle": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "inBundle": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "inBundle": true - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.48.1.tgz", - "integrity": "sha512-8OoIZZuOeqsm5cxn2f01qHWtVC3M4iixSsfZXPiQUg4Sl4LiU+b5epcJFwxNfqeoLl+SGncELyi3x99zI6C0ng==", - "inBundle": true, - "dependencies": { - "@typescript-eslint/utils": "5.48.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", - "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", - "inBundle": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", - "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", - "inBundle": true, - "dependencies": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", - "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", - "inBundle": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.48.1", - "@typescript-eslint/utils": "5.48.1", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", - "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", - "inBundle": 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/typescript-estree": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", - "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", - "inBundle": true, - "dependencies": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/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==", - "inBundle": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "inBundle": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "inBundle": true - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", - "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", - "inBundle": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/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==", - "inBundle": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "inBundle": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "inBundle": true - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", - "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", - "inBundle": true, - "dependencies": { - "@typescript-eslint/types": "5.48.1", - "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/visitor-keys/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==", - "inBundle": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "inBundle": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "inBundle": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "inBundle": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "inBundle": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "inBundle": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "inBundle": true - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "inBundle": true - }, - "node_modules/array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "inBundle": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/babel-jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", - "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", - "dev": true, - "dependencies": { - "@jest/transform": "^28.1.3", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^28.1.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/babel-jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/babel-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", - "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "inBundle": true, - "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", - "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", - "inBundle": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.2", - "core-js-compat": "^3.21.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "inBundle": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", - "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^28.1.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "inBundle": true - }, - "node_modules/body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", - "inBundle": true, - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "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==", - "inBundle": 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": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "inBundle": 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==", - "inBundle": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "inBundle": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "inBundle": true, - "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "inBundle": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "inBundle": 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==", - "inBundle": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "inBundle": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "inBundle": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "inBundle": true, - "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001442", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001442.tgz", - "integrity": "sha512-239m03Pqy0hwxYPYR5JwOIxRJfLTWtle9FV8zosfV5pHg+/51uD4nxcUlM8+mWWGfwKtt8lJNHnD3cWw9VZ6ow==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ], - "inBundle": true - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "inBundle": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", - "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "inBundle": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "inBundle": true - }, - "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "inBundle": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "inBundle": true - }, - "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==", - "inBundle": 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", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "inBundle": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "inBundle": true - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "inBundle": 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": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "inBundle": true - }, - "node_modules/core-js-compat": { - "version": "3.27.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.1.tgz", - "integrity": "sha512-Dg91JFeCDA17FKnneN7oCMz4BkQ4TcffkgHP4OWwp9yx3pi7ubqMDXXSacfNak1PQqjc95skyt+YBLHQJnkJwA==", - "inBundle": true, - "dependencies": { - "browserslist": "^4.21.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "inBundle": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cosmiconfig/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "inBundle": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "inBundle": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-functions-list": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.1.0.tgz", - "integrity": "sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w==", - "inBundle": true, - "engines": { - "node": ">=12.22" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "inBundle": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "inBundle": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "inBundle": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-is": { - "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==", - "inBundle": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "inBundle": true, - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "inBundle": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "inBundle": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", - "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "inBundle": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "inBundle": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "inBundle": true, - "dependencies": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - } - }, - "node_modules/dom-serializer/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "inBundle": true - }, - "node_modules/dom-serializer/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "inBundle": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "inBundle": true - }, - "node_modules/domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "inBundle": true, - "dependencies": { - "domelementtype": "1" - } - }, - "node_modules/domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "inBundle": true, - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "inBundle": true - }, - "node_modules/electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", - "inBundle": true - }, - "node_modules/emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "inBundle": true - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "inBundle": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "inBundle": true - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "inBundle": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.0.tgz", - "integrity": "sha512-GUGtW7eXQay0c+PRq0sGIKSdaBorfVqsCMhGHo4elP7YVqZu9nCZS4UkK4gv71gOWNMra/PaSKD3ao1oWExO0g==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.0", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.4", - "is-array-buffer": "^3.0.0", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "inBundle": true, - "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "inBundle": true, - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "inBundle": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "inBundle": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "inBundle": 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", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "inBundle": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz", - "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==", - "inBundle": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "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.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", - "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-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.31.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", - "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==", - "inBundle": true, - "dependencies": { - "array-includes": "^3.1.5", - "array.prototype.flatmap": "^1.3.0", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.5", - "object.fromentries": "^2.0.5", - "object.hasown": "^1.1.1", - "object.values": "^1.1.5", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "inBundle": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "inBundle": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "inBundle": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-sonarjs": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.18.0.tgz", - "integrity": "sha512-DJ3osLnt6KFdT5e9ZuIDOjT5A6wUGSLeiJJT03lPgpdD+7CVWlYAw9Goe3bt7SmbFO3Xh89NOCZAuB9XA7bAUQ==", - "inBundle": true, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "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==", - "inBundle": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-scope/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "inBundle": true, - "engines": { - "node": ">=4.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==", - "inBundle": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "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==", - "inBundle": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "inBundle": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "inBundle": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "inBundle": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "inBundle": true - }, - "node_modules/eslint/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==", - "inBundle": true, - "engines": { - "node": ">=10" - }, - "funding": { - "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==", - "inBundle": 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/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==", - "inBundle": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", - "inBundle": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "inBundle": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/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==", - "inBundle": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", - "inBundle": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/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==", - "inBundle": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "inBundle": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "inBundle": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "inBundle": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "inBundle": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", - "inBundle": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.0", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.10.3", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "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==", - "inBundle": 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": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "inBundle": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "inBundle": true - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "inBundle": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "inBundle": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "inBundle": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "inBundle": true - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "inBundle": true, - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "inBundle": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "inBundle": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "inBundle": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "inBundle": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.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==", - "inBundle": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "inBundle": true - }, - "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==", - "inBundle": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "inBundle": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "inBundle": true - }, - "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==", - "inBundle": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "inBundle": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "inBundle": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "inBundle": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "inBundle": true - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "inBundle": 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==", - "inBundle": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "inBundle": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "inBundle": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "inBundle": 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/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "inBundle": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "inBundle": true, - "dependencies": { - "global-prefix": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "inBundle": true, - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "inBundle": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "inBundle": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "inBundle": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "inBundle": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globjoin": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", - "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", - "inBundle": true - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "inBundle": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "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==", - "inBundle": true - }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "inBundle": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "inBundle": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "inBundle": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "inBundle": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "inBundle": true, - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "inBundle": 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", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "inBundle": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "inBundle": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "inBundle": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/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==", - "inBundle": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "inBundle": true - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/html-tags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", - "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", - "inBundle": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "inBundle": true, - "dependencies": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "inBundle": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "inBundle": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "inBundle": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "inBundle": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "inBundle": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/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==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "inBundle": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "inBundle": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "inBundle": true - }, - "node_modules/internal-slot": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", - "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", - "inBundle": true, - "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.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==", - "inBundle": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", - "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "inBundle": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "inBundle": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "inBundle": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "inBundle": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "inBundle": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "inBundle": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "inBundle": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "inBundle": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "inBundle": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "inBundle": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "inBundle": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "inBundle": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "inBundle": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", - "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", - "dev": true, - "dependencies": { - "@jest/core": "^28.1.3", - "@jest/types": "^28.1.3", - "import-local": "^3.0.2", - "jest-cli": "^28.1.3" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", - "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", - "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", - "dev": true, - "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/expect": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^28.1.3", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "p-limit": "^3.1.0", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-circus/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-circus/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", - "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", - "dev": true, - "dependencies": { - "@jest/core": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-cli/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", - "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^28.1.3", - "@jest/types": "^28.1.3", - "babel-jest": "^28.1.3", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^28.1.3", - "jest-environment-node": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-runner": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-config/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-config/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-config/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", - "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^28.1.1", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-docblock": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", - "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-each": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", - "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "jest-util": "^28.1.3", - "pretty-format": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-each/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-each/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-each/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-each/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-node": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", - "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", - "dev": true, - "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", - "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.3", - "jest-worker": "^28.1.3", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", - "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", - "dev": true, - "dependencies": { - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", - "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-matcher-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-message-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-message-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-mock": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", - "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", - "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", - "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", - "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", - "dev": true, - "dependencies": { - "jest-regex-util": "^28.0.2", - "jest-snapshot": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-resolve/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-resolve/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-resolve/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", - "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", - "dev": true, - "dependencies": { - "@jest/console": "^28.1.3", - "@jest/environment": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "graceful-fs": "^4.2.9", - "jest-docblock": "^28.1.1", - "jest-environment-node": "^28.1.3", - "jest-haste-map": "^28.1.3", - "jest-leak-detector": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-resolve": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-util": "^28.1.3", - "jest-watcher": "^28.1.3", - "jest-worker": "^28.1.3", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-runner/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runner/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runner/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", - "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", - "dev": true, - "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/globals": "^28.1.3", - "@jest/source-map": "^28.1.2", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-runtime/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runtime/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runtime/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", - "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^28.1.3", - "graceful-fs": "^4.2.9", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-haste-map": "^28.1.3", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "natural-compare": "^1.4.0", - "pretty-format": "^28.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-snapshot/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot/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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-snapshot/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/jest-sonar-reporter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jest-sonar-reporter/-/jest-sonar-reporter-2.0.0.tgz", - "integrity": "sha512-ZervDCgEX5gdUbdtWsjdipLN3bKJwpxbvhkYNXTAYvAckCihobSLr9OT/IuyNIRT1EZMDDwR6DroWtrq+IL64w==", - "dev": true, - "dependencies": { - "xml": "^1.0.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", - "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "leven": "^3.1.0", - "pretty-format": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-validate/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-validate/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-validate/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-validate/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", - "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", - "dev": true, - "dependencies": { - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^28.1.3", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watcher/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-watcher/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-watcher/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", - "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", - "inBundle": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "inBundle": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "inBundle": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "inBundle": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "inBundle": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "inBundle": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "inBundle": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "inBundle": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", - "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", - "inBundle": true, - "dependencies": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/known-css-properties": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.25.0.tgz", - "integrity": "sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==", - "inBundle": true - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "inBundle": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "inBundle": true - }, - "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==", - "inBundle": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "inBundle": true - }, - "node_modules/lodash.clone": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", - "integrity": "sha512-GhrVeweiTD6uTmmn5hV/lzgCQhccwReIVRLHp7LT4SopOjqEZ5BbX8b5WWEtAKasjmy8hR7ZPwsYlxRCku5odg==", - "inBundle": true - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "inBundle": true - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "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==", - "inBundle": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "inBundle": true - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "inBundle": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "inBundle": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "inBundle": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mathml-tag-names": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", - "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", - "inBundle": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "inBundle": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/meow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", - "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", - "inBundle": true, - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize": "^1.2.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "inBundle": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "inBundle": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "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==", - "inBundle": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "inBundle": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "inBundle": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "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==", - "inBundle": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "inBundle": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "inBundle": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "inBundle": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "inBundle": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "inBundle": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/module-alias": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz", - "integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==", - "inBundle": true - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "inBundle": true - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "inBundle": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "inBundle": 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==", - "inBundle": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "inBundle": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", - "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==", - "inBundle": true - }, - "node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "inBundle": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/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==", - "inBundle": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "inBundle": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "inBundle": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "inBundle": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "inBundle": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.hasown": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", - "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", - "inBundle": true, - "dependencies": { - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "inBundle": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "inBundle": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "inBundle": true, - "dependencies": { - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "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==", - "inBundle": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "inBundle": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "inBundle": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "inBundle": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "inBundle": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "inBundle": true, - "engines": { - "node": ">= 0.8" - } - }, - "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==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "inBundle": true - }, - "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": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "inBundle": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "inBundle": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "inBundle": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "inBundle": true, - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-html": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz", - "integrity": "sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==", - "inBundle": true, - "dependencies": { - "htmlparser2": "^3.10.0" - }, - "peerDependencies": { - "postcss": ">=5.0.0", - "postcss-syntax": ">=0.36.0" - } - }, - "node_modules/postcss-less": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-6.0.0.tgz", - "integrity": "sha512-FPX16mQLyEjLzEuuJtxA8X3ejDLNGGEG503d2YGZR5Ask1SpDN8KmZUMpzCvyalWRywAn1n1VOA5dcqfCLo5rg==", - "inBundle": true, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "postcss": "^8.3.5" - } - }, - "node_modules/postcss-media-query-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", - "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "inBundle": true - }, - "node_modules/postcss-resolve-nested-selector": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", - "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==", - "inBundle": true - }, - "node_modules/postcss-safe-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", - "inBundle": true, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.3.3" - } - }, - "node_modules/postcss-scss": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.3.tgz", - "integrity": "sha512-j4KxzWovfdHsyxwl1BxkUal/O4uirvHgdzMKS1aWJBAV0qh2qj5qAZqpeBfVUYGWv+4iK9Az7SPyZ4fyNju1uA==", - "inBundle": true, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.3.3" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", - "inBundle": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-syntax": { - "version": "0.36.2", - "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz", - "integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==", - "inBundle": true, - "peerDependencies": { - "postcss": ">=5.0.0" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "inBundle": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "inBundle": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "inBundle": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "inBundle": 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==", - "inBundle": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/punycode": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", - "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==", - "inBundle": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", - "inBundle": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true - }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "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==", - "inBundle": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "inBundle": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "inBundle": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "inBundle": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "inBundle": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "inBundle": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "inBundle": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "inBundle": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "inBundle": true - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "inBundle": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "inBundle": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "inBundle": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "inBundle": true, - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/refa": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/refa/-/refa-0.9.1.tgz", - "integrity": "sha512-egU8LgFq2VXlAfUi8Jcbr5X38wEOadMFf8tCbshgcpVCYlE7k84pJOSlnvXF+muDB4igkdVMq7Z/kiNPqDT9TA==", - "inBundle": true, - "dependencies": { - "regexpp": "^3.2.0" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "inBundle": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", - "inBundle": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "inBundle": true - }, - "node_modules/regenerator-transform": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", - "inBundle": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regexp-ast-analysis": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.2.4.tgz", - "integrity": "sha512-8L7kOZQaKPxKKAwGuUZxTQtlO3WZ+tiXy4s6G6PKL6trbOXcZoumwC3AOHHFtI/xoSbNxt7jgLvCnP1UADLWqg==", - "inBundle": true, - "dependencies": { - "refa": "^0.9.0", - "regexpp": "^3.2.0" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "inBundle": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/regexpu-core": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", - "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", - "inBundle": true, - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsgen": "^0.7.1", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", - "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", - "inBundle": true - }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "inBundle": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "inBundle": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "inBundle": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "inBundle": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "inBundle": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "inBundle": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-node": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/run-node/-/run-node-2.0.0.tgz", - "integrity": "sha512-M024oSKOfXRbBZ4dzWeS4mZfLlkVrLbR+02lSno344whh60hFN7qjWnf3QXm/JePD9CR7W4gRe9tt4H/2PGkcw==", - "inBundle": true, - "bin": { - "run-node": "run-node" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true, - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/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==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true - }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.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", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "inBundle": true - }, - "node_modules/scslre": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.1.6.tgz", - "integrity": "sha512-JORxVRlQTfjvlOAaiQKebgFElyAm5/W8b50lgaZ0OkEnKnagJW2ufDh3xRfU75UD9z3FGIu1gL1IyR3Poa6Qmw==", - "inBundle": true, - "dependencies": { - "refa": "^0.9.0", - "regexp-ast-analysis": "^0.2.3", - "regexpp": "^3.2.0" - } - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "inBundle": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "inBundle": true, - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "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==", - "inBundle": 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": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "inBundle": 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==", - "inBundle": true - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "inBundle": true, - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "inBundle": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "inBundle": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "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==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "inBundle": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "inBundle": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "inBundle": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "inBundle": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "inBundle": true - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "inBundle": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "inBundle": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "inBundle": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", - "inBundle": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "inBundle": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "inBundle": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "inBundle": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", - "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "inBundle": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "inBundle": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "inBundle": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/style-search": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", - "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", - "inBundle": true - }, - "node_modules/stylelint": { - "version": "14.13.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.13.0.tgz", - "integrity": "sha512-NJSAdloiAB/jgVJKxMR90mWlctvmeBFGFVUvyKngi9+j/qPSJ5ZB+u8jOmGbLTnS7OHrII9NFGehPRyar8U5vg==", - "inBundle": true, - "dependencies": { - "@csstools/selector-specificity": "^2.0.2", - "balanced-match": "^2.0.0", - "colord": "^2.9.3", - "cosmiconfig": "^7.0.1", - "css-functions-list": "^3.1.0", - "debug": "^4.3.4", - "fast-glob": "^3.2.12", - "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^6.0.1", - "global-modules": "^2.0.0", - "globby": "^11.1.0", - "globjoin": "^0.1.4", - "html-tags": "^3.2.0", - "ignore": "^5.2.0", - "import-lazy": "^4.0.0", - "imurmurhash": "^0.1.4", - "is-plain-object": "^5.0.0", - "known-css-properties": "^0.25.0", - "mathml-tag-names": "^2.1.3", - "meow": "^9.0.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.16", - "postcss-media-query-parser": "^0.2.3", - "postcss-resolve-nested-selector": "^0.1.1", - "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.10", - "postcss-value-parser": "^4.2.0", - "resolve-from": "^5.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "style-search": "^0.1.0", - "supports-hyperlinks": "^2.3.0", - "svg-tags": "^1.0.0", - "table": "^6.8.0", - "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^4.0.2" - }, - "bin": { - "stylelint": "bin/stylelint.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/stylelint" - } - }, - "node_modules/stylelint/node_modules/balanced-match": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", - "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", - "inBundle": true - }, - "node_modules/stylelint/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "inBundle": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "inBundle": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "inBundle": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "inBundle": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svg-tags": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", - "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", - "inBundle": true - }, - "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", - "inBundle": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "inBundle": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "inBundle": true - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "inBundle": true - }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "inBundle": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "inBundle": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "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==", - "inBundle": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "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==", - "inBundle": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "inBundle": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ts-jest": { - "version": "28.0.7", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.7.tgz", - "integrity": "sha512-wWXCSmTwBVmdvWrOpYhal79bDpioDy4rTT+0vyUnE3ZzM7LOAAGG9NXwzkEL/a516rQEgnMmS/WKP9jBPCVJyA==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^28.0.0", - "json5": "^2.2.1", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^21.0.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/types": "^28.0.0", - "babel-jest": "^28.0.0", - "jest": "^28.0.0", - "typescript": ">=4.3" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-jest/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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-jest/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/ts-jest/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "inBundle": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "inBundle": 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" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "inBundle": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "inBundle": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "inBundle": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", - "inBundle": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "inBundle": true, - "dependencies": { - "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/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "inBundle": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "inBundle": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", - "inBundle": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "inBundle": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "inBundle": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "inBundle": true, - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "inBundle": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "inBundle": true - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "inBundle": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "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==", - "inBundle": true - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "inBundle": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "inBundle": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vue-eslint-parser": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.1.0.tgz", - "integrity": "sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==", - "inBundle": true, - "dependencies": { - "debug": "^4.3.4", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", - "lodash": "^4.17.21", - "semver": "^7.3.6" - }, - "engines": { - "node": "^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=6.0.0" - } - }, - "node_modules/vue-eslint-parser/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==", - "inBundle": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/vue-eslint-parser/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==", - "inBundle": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/vue-eslint-parser/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==", - "inBundle": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/vue-eslint-parser/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "inBundle": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/vue-eslint-parser/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "inBundle": true - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "inBundle": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "inBundle": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "inBundle": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "inBundle": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "inBundle": true - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "inBundle": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/xml": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "inBundle": true - }, - "node_modules/yaml": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.1.tgz", - "integrity": "sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==", - "inBundle": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "inBundle": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "inBundle": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.20.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz", - "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==" - }, - "@babel/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", - "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - } - }, - "@babel/eslint-parser": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.18.9.tgz", - "integrity": "sha512-KzSGpMBggz4fKbRbWLNyPVTuQr6cmCcBhOyXTw/fieOVaw5oYAwcAj4a7UKcDYCPxQq+CG1NCDZH9e2JTXquiQ==", - "requires": { - "eslint-scope": "^5.1.1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - } - }, - "@babel/generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", - "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", - "requires": { - "@babel/types": "^7.20.7", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", - "requires": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "requires": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz", - "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-member-expression-to-functions": "^7.20.7", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/helper-split-export-declaration": "^7.18.6" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", - "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.2.1" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "requires": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz", - "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==", - "requires": { - "@babel/types": "^7.20.7" - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.10", - "@babel/types": "^7.20.7" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==" - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-replace-supers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", - "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.20.7", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "requires": { - "@babel/types": "^7.20.2" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", - "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", - "requires": { - "@babel/types": "^7.20.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" - }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" - }, - "@babel/helper-wrap-function": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", - "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", - "requires": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" - } - }, - "@babel/helpers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz", - "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==", - "requires": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", - "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==" - }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", - "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-proposal-optional-chaining": "^7.20.7" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", - "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz", - "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-decorators": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.19.3.tgz", - "integrity": "sha512-MbgXtNXqo7RTKYIXVchVJGPvaVufQH3pxvQyfbGvNw1DObIhph+PesYXJTcd8J4DdWibvf6Z2eanOyItX8WnJg==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.19.1", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/plugin-syntax-decorators": "^7.19.0" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", - "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", - "requires": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz", - "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", - "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.20.5", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-decorators": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz", - "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-flow": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", - "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-import-assertions": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", - "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", - "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", - "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", - "requires": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz", - "integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz", - "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-split-export-declaration": "^7.18.6", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", - "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/template": "^7.20.7" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", - "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-flow-strip-types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz", - "integrity": "sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg==", - "requires": { - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/plugin-syntax-flow": "^7.18.6" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", - "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", - "requires": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", - "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", - "requires": { - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz", - "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==", - "requires": { - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-simple-access": "^7.20.2" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", - "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", - "requires": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-identifier": "^7.19.1" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", - "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", - "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.20.5", - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", - "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-react-display-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", - "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.20.7.tgz", - "integrity": "sha512-Tfq7qqD+tRj3EoDhY00nn2uP2hsRxgYGi5mLQ5TimKav0a9Lrpd4deE+fcLXU8zFYRjlKPHZhpCvfEA6qnBxqQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-jsx": "^7.18.6", - "@babel/types": "^7.20.7" - } - }, - "@babel/plugin-transform-react-jsx-development": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", - "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", - "requires": { - "@babel/plugin-transform-react-jsx": "^7.18.6" - } - }, - "@babel/plugin-transform-react-pure-annotations": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", - "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", - "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "regenerator-transform": "^0.15.1" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", - "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/preset-env": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.0.tgz", - "integrity": "sha512-1YUju1TAFuzjIQqNM9WsF4U6VbD/8t3wEAlw3LFYuuEr+ywqLRcSXxFKz4DCEj+sN94l/XTDiUXYRrsvMpz9WQ==", - "requires": { - "@babel/compat-data": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.19.0", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.9", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.18.9", - "@babel/plugin-transform-classes": "^7.19.0", - "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.18.13", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.8", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.18.6", - "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/plugin-transform-modules-systemjs": "^7.19.0", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.0", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.18.8", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.19.0", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.2", - "babel-plugin-polyfill-corejs3": "^0.5.3", - "babel-plugin-polyfill-regenerator": "^0.4.0", - "core-js-compat": "^3.22.1", - "semver": "^6.3.0" - } - }, - "@babel/preset-flow": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.18.6.tgz", - "integrity": "sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-flow-strip-types": "^7.18.6" - } - }, - "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/preset-react": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", - "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-react-display-name": "^7.18.6", - "@babel/plugin-transform-react-jsx": "^7.18.6", - "@babel/plugin-transform-react-jsx-development": "^7.18.6", - "@babel/plugin-transform-react-pure-annotations": "^7.18.6" - } - }, - "@babel/runtime": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", - "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", - "requires": { - "regenerator-runtime": "^0.13.11" - } - }, - "@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/traverse": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz", - "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "dependencies": { - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } - } - }, - "@csstools/selector-specificity": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", - "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", - "requires": {} - }, - "@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", - "requires": { - "type-fest": "^0.20.2" - } - }, - "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==" - } - } - }, - "@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" - }, - "@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==" - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", - "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", - "dev": true, - "requires": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "slash": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/core": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", - "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", - "dev": true, - "requires": { - "@jest/console": "^28.1.3", - "@jest/reporters": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^28.1.3", - "jest-config": "^28.1.3", - "jest-haste-map": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-resolve-dependencies": "^28.1.3", - "jest-runner": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "jest-watcher": "^28.1.3", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/environment": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", - "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "jest-mock": "^28.1.3" - } - }, - "@jest/expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", - "dev": true, - "requires": { - "expect": "^28.1.3", - "jest-snapshot": "^28.1.3" - } - }, - "@jest/expect-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", - "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", - "dev": true, - "requires": { - "jest-get-type": "^28.0.2" - } - }, - "@jest/fake-timers": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", - "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", - "dev": true, - "requires": { - "@jest/types": "^28.1.3", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" - } - }, - "@jest/globals": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", - "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", - "dev": true, - "requires": { - "@jest/environment": "^28.1.3", - "@jest/expect": "^28.1.3", - "@jest/types": "^28.1.3" - } - }, - "@jest/reporters": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", - "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@jridgewell/trace-mapping": "^0.3.13", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "jest-worker": "^28.1.3", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.24.1" - } - }, - "@jest/source-map": { - "version": "28.1.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", - "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.13", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - } - }, - "@jest/test-result": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", - "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", - "dev": true, - "requires": { - "@jest/console": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", - "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", - "dev": true, - "requires": { - "@jest/test-result": "^28.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "slash": "^3.0.0" - } - }, - "@jest/transform": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", - "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^28.1.3", - "@jridgewell/trace-mapping": "^0.3.13", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.3", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dev": true, - "requires": { - "@jest/schemas": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - }, - "@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==" - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "@types/babel__core": { - "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", - "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/bytes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/bytes/-/bytes-3.1.1.tgz", - "integrity": "sha512-lOGyCnw+2JVPKU3wIV0srU0NyALwTBJlVSx5DfMQOFuuohA8y9S8orImpuIQikZ0uIQ8gehrRjxgQC1rLRi11w==", - "dev": true - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/eslint": { - "version": "8.4.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", - "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", - "dev": true - }, - "@types/express": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", - "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.32", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz", - "integrity": "sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-gUXkc6hiRJ2yPyiidbDbtU5YDt0c8JjYjq671QPYmJg2kiYS53/814Hg2SY4wqL/hfCzfa3NZzeh2e30YhALww==", - "dev": true - }, - "@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "28.1.6", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.6.tgz", - "integrity": "sha512-0RbGAFMfcBJKOmqRazM8L98uokwuwD5F8rHrv/ZMbrZBwVOWZUyPG6VFNscjYr/vjM3Vu4fRrCPbOs42AfemaQ==", - "dev": true, - "requires": { - "jest-matcher-utils": "^28.0.0", - "pretty-format": "^28.0.0" - } - }, - "@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==" - }, - "@types/lodash": { - "version": "4.14.191", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", - "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", - "dev": true - }, - "@types/lodash.clone": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/@types/lodash.clone/-/lodash.clone-4.5.7.tgz", - "integrity": "sha512-jugWYM+xBUQCpWbn7p6BSbf8bRMHtJYnEIGZYngbStaU0aN4VFgAAkGgsc+MtHuepBOmjyUGiGv+dHnQQIGLZA==", - "dev": true, - "requires": { - "@types/lodash": "*" - } - }, - "@types/mime": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", - "dev": true - }, - "@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==" - }, - "@types/node": { - "version": "16.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.9.tgz", - "integrity": "sha512-MKmdASMf3LtPzwLyRrFjtFFZ48cMf8jmX5VRYrDQiJa8Ybu5VAmkqBWqKU8fdCwD8ysw4mQ9nrEHvzg6gunR7A==", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==" - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" - }, - "@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true - }, - "@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==" - }, - "@types/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", - "dev": true, - "requires": { - "@types/mime": "*", - "@types/node": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==", - "dev": true - }, - "@types/yargs": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", - "integrity": "sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", - "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", - "requires": { - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/type-utils": "5.48.1", - "@typescript-eslint/utils": "5.48.1", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "dependencies": { - "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" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "@typescript-eslint/experimental-utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.48.1.tgz", - "integrity": "sha512-8OoIZZuOeqsm5cxn2f01qHWtVC3M4iixSsfZXPiQUg4Sl4LiU+b5epcJFwxNfqeoLl+SGncELyi3x99zI6C0ng==", - "requires": { - "@typescript-eslint/utils": "5.48.1" - } - }, - "@typescript-eslint/parser": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", - "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", - "requires": { - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", - "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", - "requires": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", - "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", - "requires": { - "@typescript-eslint/typescript-estree": "5.48.1", - "@typescript-eslint/utils": "5.48.1", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", - "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==" - }, - "@typescript-eslint/typescript-estree": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", - "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", - "requires": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "dependencies": { - "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" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "@typescript-eslint/utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", - "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", - "requires": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" - }, - "dependencies": { - "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" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", - "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", - "requires": { - "@typescript-eslint/types": "5.48.1", - "eslint-visitor-keys": "^3.3.0" - }, - "dependencies": { - "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==" - } - } - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==" - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "requires": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "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==" - }, - "array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==" - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" - }, - "babel-jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", - "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", - "dev": true, - "requires": { - "@jest/transform": "^28.1.3", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^28.1.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", - "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "requires": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", - "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.2", - "core-js-compat": "^3.21.0" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", - "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^28.1.3", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==" - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "requires": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - } - }, - "caniuse-lite": { - "version": "1.0.30001442", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001442.tgz", - "integrity": "sha512-239m03Pqy0hwxYPYR5JwOIxRJfLTWtle9FV8zosfV5pHg+/51uD4nxcUlM8+mWWGfwKtt8lJNHnD3cWw9VZ6ow==" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "ci-info": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", - "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "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==", - "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", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "core-js-compat": { - "version": "3.27.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.1.tgz", - "integrity": "sha512-Dg91JFeCDA17FKnneN7oCMz4BkQ4TcffkgHP4OWwp9yx3pi7ubqMDXXSacfNak1PQqjc95skyt+YBLHQJnkJwA==", - "requires": { - "browserslist": "^4.21.4" - } - }, - "cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "dependencies": { - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" - } - } - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "css-functions-list": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.1.0.tgz", - "integrity": "sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w==" - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" - }, - "decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "requires": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "dependencies": { - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==" - } - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "deep-is": { - "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==" - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "diff-sequences": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", - "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - } - } - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" - }, - "emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.0.tgz", - "integrity": "sha512-GUGtW7eXQay0c+PRq0sGIKSdaBorfVqsCMhGHo4elP7YVqZu9nCZS4UkK4gv71gOWNMra/PaSKD3ao1oWExO0g==", - "requires": { - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.0", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.4", - "is-array-buffer": "^3.0.0", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - } - }, - "es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - } - }, - "es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "requires": { - "has": "^1.0.3" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "eslint": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz", - "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==", - "requires": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "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.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", - "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-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "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==" - }, - "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==", - "requires": { - "esrecurse": "^4.3.0", - "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==" - }, - "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", - "requires": { - "type-fest": "^0.20.2" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "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==" - } - } - }, - "eslint-plugin-react": { - "version": "7.31.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", - "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==", - "requires": { - "array-includes": "^3.1.5", - "array.prototype.flatmap": "^1.3.0", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.5", - "object.fromentries": "^2.0.5", - "object.hasown": "^1.1.1", - "object.values": "^1.1.5", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.7" - }, - "dependencies": { - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "requires": { - "esutils": "^2.0.2" - } - }, - "resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "requires": {} - }, - "eslint-plugin-sonarjs": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.18.0.tgz", - "integrity": "sha512-DJ3osLnt6KFdT5e9ZuIDOjT5A6wUGSLeiJJT03lPgpdD+7CVWlYAw9Goe3bt7SmbFO3Xh89NOCZAuB9XA7bAUQ==", - "requires": {} - }, - "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==", - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "dependencies": { - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" - } - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "requires": { - "eslint-visitor-keys": "^2.0.0" - } - }, - "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==" - }, - "espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "dependencies": { - "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==" - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "requires": { - "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==" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true - }, - "expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", - "dev": true, - "requires": { - "@jest/expect-utils": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3" - } - }, - "express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.0", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.10.3", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "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==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" - }, - "fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==" - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "requires": { - "reusify": "^1.0.4" - } - }, - "fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "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==", - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "requires": { - "is-callable": "^1.1.3" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "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": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==" - }, - "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==" - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "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==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "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" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "requires": { - "is-glob": "^4.0.3" - } - }, - "global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "requires": { - "global-prefix": "^3.0.0" - } - }, - "global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "requires": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "requires": { - "define-properties": "^1.1.3" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "globjoin": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", - "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==" - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "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==" - }, - "hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "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" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "html-tags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", - "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==" - }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - } - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==" - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" - }, - "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==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "internal-slot": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", - "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", - "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "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==" - }, - "is-array-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", - "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-typed-array": "^1.1.10" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" - }, - "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "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==" - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "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==" - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==" - }, - "is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", - "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", - "dev": true, - "requires": { - "@jest/core": "^28.1.3", - "@jest/types": "^28.1.3", - "import-local": "^3.0.2", - "jest-cli": "^28.1.3" - } - }, - "jest-changed-files": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", - "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - } - }, - "jest-circus": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", - "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", - "dev": true, - "requires": { - "@jest/environment": "^28.1.3", - "@jest/expect": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^28.1.3", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "p-limit": "^3.1.0", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-cli": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", - "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", - "dev": true, - "requires": { - "@jest/core": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-config": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", - "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^28.1.3", - "@jest/types": "^28.1.3", - "babel-jest": "^28.1.3", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^28.1.3", - "jest-environment-node": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-runner": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-diff": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", - "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^28.1.1", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-docblock": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", - "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", - "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", - "dev": true, - "requires": { - "@jest/types": "^28.1.3", - "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "jest-util": "^28.1.3", - "pretty-format": "^28.1.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-environment-node": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", - "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", - "dev": true, - "requires": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" - } - }, - "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true - }, - "jest-haste-map": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", - "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", - "dev": true, - "requires": { - "@jest/types": "^28.1.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.3", - "jest-worker": "^28.1.3", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-leak-detector": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", - "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", - "dev": true, - "requires": { - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - } - }, - "jest-matcher-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", - "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-mock": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", - "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", - "dev": true, - "requires": { - "@jest/types": "^28.1.3", - "@types/node": "*" - } - }, - "jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", - "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", - "dev": true - }, - "jest-resolve": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", - "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-resolve-dependencies": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", - "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", - "dev": true, - "requires": { - "jest-regex-util": "^28.0.2", - "jest-snapshot": "^28.1.3" - } - }, - "jest-runner": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", - "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", - "dev": true, - "requires": { - "@jest/console": "^28.1.3", - "@jest/environment": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "graceful-fs": "^4.2.9", - "jest-docblock": "^28.1.1", - "jest-environment-node": "^28.1.3", - "jest-haste-map": "^28.1.3", - "jest-leak-detector": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-resolve": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-util": "^28.1.3", - "jest-watcher": "^28.1.3", - "jest-worker": "^28.1.3", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-runtime": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", - "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", - "dev": true, - "requires": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/globals": "^28.1.3", - "@jest/source-map": "^28.1.2", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-snapshot": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", - "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^28.1.3", - "graceful-fs": "^4.2.9", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-haste-map": "^28.1.3", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "natural-compare": "^1.4.0", - "pretty-format": "^28.1.3", - "semver": "^7.3.5" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "jest-sonar-reporter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jest-sonar-reporter/-/jest-sonar-reporter-2.0.0.tgz", - "integrity": "sha512-ZervDCgEX5gdUbdtWsjdipLN3bKJwpxbvhkYNXTAYvAckCihobSLr9OT/IuyNIRT1EZMDDwR6DroWtrq+IL64w==", - "dev": true, - "requires": { - "xml": "^1.0.1" - } - }, - "jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", - "dev": true, - "requires": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-validate": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", - "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", - "dev": true, - "requires": { - "@jest/types": "^28.1.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "leven": "^3.1.0", - "pretty-format": "^28.1.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-watcher": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", - "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", - "dev": true, - "requires": { - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^28.1.3", - "string-length": "^4.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-worker": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", - "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" - }, - "jsx-ast-utils": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", - "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", - "requires": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "known-css-properties": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.25.0.tgz", - "integrity": "sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==" - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "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==", - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.clone": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", - "integrity": "sha512-GhrVeweiTD6uTmmn5hV/lzgCQhccwReIVRLHp7LT4SopOjqEZ5BbX8b5WWEtAKasjmy8hR7ZPwsYlxRCku5odg==" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "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==" - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==" - }, - "mathml-tag-names": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", - "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==" - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" - }, - "meow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", - "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", - "requires": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize": "^1.2.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "dependencies": { - "type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==" - } - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "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": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "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==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "requires": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "module-alias": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz", - "integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" - }, - "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==" - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node-releases": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", - "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==" - }, - "normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "requires": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "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" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "object.entries": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.hasown": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", - "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", - "requires": { - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "requires": { - "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" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "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==", - "requires": { - "p-limit": "^3.0.2" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "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==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } - } - }, - "postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "postcss-html": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz", - "integrity": "sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==", - "requires": { - "htmlparser2": "^3.10.0" - } - }, - "postcss-less": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-6.0.0.tgz", - "integrity": "sha512-FPX16mQLyEjLzEuuJtxA8X3ejDLNGGEG503d2YGZR5Ask1SpDN8KmZUMpzCvyalWRywAn1n1VOA5dcqfCLo5rg==", - "requires": {} - }, - "postcss-media-query-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", - "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==" - }, - "postcss-resolve-nested-selector": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", - "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==" - }, - "postcss-safe-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", - "requires": {} - }, - "postcss-scss": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.3.tgz", - "integrity": "sha512-j4KxzWovfdHsyxwl1BxkUal/O4uirvHgdzMKS1aWJBAV0qh2qj5qAZqpeBfVUYGWv+4iK9Az7SPyZ4fyNju1uA==", - "requires": {} - }, - "postcss-selector-parser": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-syntax": { - "version": "0.36.2", - "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz", - "integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==", - "requires": {} - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" - }, - "prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true - }, - "pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", - "dev": true, - "requires": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } - } - }, - "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==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "punycode": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", - "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==" - }, - "qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" - }, - "quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==" - }, - "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==" - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" - } - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "requires": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - } - }, - "refa": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/refa/-/refa-0.9.1.tgz", - "integrity": "sha512-egU8LgFq2VXlAfUi8Jcbr5X38wEOadMFf8tCbshgcpVCYlE7k84pJOSlnvXF+muDB4igkdVMq7Z/kiNPqDT9TA==", - "requires": { - "regexpp": "^3.2.0" - } - }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", - "requires": { - "regenerate": "^1.4.2" - } - }, - "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "regenerator-transform": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regexp-ast-analysis": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.2.4.tgz", - "integrity": "sha512-8L7kOZQaKPxKKAwGuUZxTQtlO3WZ+tiXy4s6G6PKL6trbOXcZoumwC3AOHHFtI/xoSbNxt7jgLvCnP1UADLWqg==", - "requires": { - "refa": "^0.9.0", - "regexpp": "^3.2.0" - } - }, - "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" - }, - "regexpu-core": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", - "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", - "requires": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsgen": "^0.7.1", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - } - }, - "regjsgen": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", - "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==" - }, - "regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" - } - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" - }, - "resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - }, - "run-node": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/run-node/-/run-node-2.0.0.tgz", - "integrity": "sha512-M024oSKOfXRbBZ4dzWeS4mZfLlkVrLbR+02lSno344whh60hFN7qjWnf3QXm/JePD9CR7W4gRe9tt4H/2PGkcw==" - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "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==" - }, - "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "scslre": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.1.6.tgz", - "integrity": "sha512-JORxVRlQTfjvlOAaiQKebgFElyAm5/W8b50lgaZ0OkEnKnagJW2ufDh3xRfU75UD9z3FGIu1gL1IyR3Poa6Qmw==", - "requires": { - "refa": "^0.9.0", - "regexp-ast-analysis": "^0.2.3", - "regexpp": "^3.2.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - } - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==" - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string.prototype.matchall": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", - "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4" - } - }, - "string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "requires": { - "min-indent": "^1.0.0" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" - }, - "style-search": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", - "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==" - }, - "stylelint": { - "version": "14.13.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.13.0.tgz", - "integrity": "sha512-NJSAdloiAB/jgVJKxMR90mWlctvmeBFGFVUvyKngi9+j/qPSJ5ZB+u8jOmGbLTnS7OHrII9NFGehPRyar8U5vg==", - "requires": { - "@csstools/selector-specificity": "^2.0.2", - "balanced-match": "^2.0.0", - "colord": "^2.9.3", - "cosmiconfig": "^7.0.1", - "css-functions-list": "^3.1.0", - "debug": "^4.3.4", - "fast-glob": "^3.2.12", - "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^6.0.1", - "global-modules": "^2.0.0", - "globby": "^11.1.0", - "globjoin": "^0.1.4", - "html-tags": "^3.2.0", - "ignore": "^5.2.0", - "import-lazy": "^4.0.0", - "imurmurhash": "^0.1.4", - "is-plain-object": "^5.0.0", - "known-css-properties": "^0.25.0", - "mathml-tag-names": "^2.1.3", - "meow": "^9.0.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.16", - "postcss-media-query-parser": "^0.2.3", - "postcss-resolve-nested-selector": "^0.1.1", - "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.10", - "postcss-value-parser": "^4.2.0", - "resolve-from": "^5.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "style-search": "^0.1.0", - "supports-hyperlinks": "^2.3.0", - "svg-tags": "^1.0.0", - "table": "^6.8.0", - "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^4.0.2" - }, - "dependencies": { - "balanced-match": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", - "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==" - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" - } - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - }, - "svg-tags": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", - "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==" - }, - "table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", - "requires": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - } - } - }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "requires": { - "rimraf": "^3.0.0" - } - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" - }, - "to-regex-range": { - "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==", - "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==" - }, - "trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==" - }, - "ts-jest": { - "version": "28.0.7", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.7.tgz", - "integrity": "sha512-wWXCSmTwBVmdvWrOpYhal79bDpioDy4rTT+0vyUnE3ZzM7LOAAGG9NXwzkEL/a516rQEgnMmS/WKP9jBPCVJyA==", - "dev": true, - "requires": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^28.0.0", - "json5": "^2.2.1", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^21.0.1" - }, - "dependencies": { - "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==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - } - } - }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - } - }, - "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==", - "requires": { - "tslib": "^1.8.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "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==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "requires": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - } - }, - "typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==" - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "requires": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==" - }, - "unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" - }, - "update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" - }, - "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==" - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - } - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" - }, - "vue-eslint-parser": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.1.0.tgz", - "integrity": "sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==", - "requires": { - "debug": "^4.3.4", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", - "lodash": "^4.17.21", - "semver": "^7.3.6" - }, - "dependencies": { - "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==", - "requires": { - "esrecurse": "^4.3.0", - "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==" - }, - "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" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - } - }, - "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==" - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "xml": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "yaml": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.1.tgz", - "integrity": "sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==" - }, - "yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", - "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "dependencies": { - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - } - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - } - } -} diff --git a/eslint-bridge/package.json b/eslint-bridge/package.json deleted file mode 100644 index 62634bf1567..00000000000 --- a/eslint-bridge/package.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "name": "eslint-bridge", - "version": "1.0.0", - "description": "bridge between SonarJS and ESLint", - "scripts": { - "build": "npm ci && npm run check-format && npm run clear && npm run compile", - "clear": "tsc -b src tests --clean", - "check-format": "prettier --list-different \"{src,tests}/**/!(*.lint).ts\"", - "test": "jest", - "ctest": "jest tests/tools/testers/comment-based/launcher.test.ts --verbose=false", - "format": "prettier --write \"{src,tests,tools,profiling}/**/!(*.lint).ts\"", - "compile": "tsc -b src tests profiling", - "jar": "npm pack && mkdirp target/classes && mv eslint-bridge-1.0.0.tgz target/classes && bash tools/check-distribution-filepath-length.sh", - "new-rule": "ts-node tools/newRule.ts" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/SonarSource/SonarJS.git" - }, - "license": "LGPL-3.0", - "bugs": { - "url": "https://github.com/SonarSource/SonarJS/issues" - }, - "homepage": "https://github.com/SonarSource/SonarJS#readme", - "engines": { - "node": ">=14" - }, - "type": "commonjs", - "devDependencies": { - "@types/bytes": "3.1.1", - "@types/eslint": " 8.4.10", - "@types/eslint-scope": "3.7.4", - "@types/estree": "1.0.0", - "@types/express": "4.17.14", - "@types/functional-red-black-tree": "1.0.1", - "@types/jest": "28.1.6", - "@types/lodash.clone": "4.5.7", - "@types/node": "16.11.9", - "@types/tmp": "0.2.3", - "jest": "28.1.3", - "jest-sonar-reporter": "2.0.0", - "mkdirp": "1.0.4", - "prettier": "2.7.1", - "ts-jest": "28.0.7", - "ts-node": "10.9.1" - }, - "dependencies": { - "@babel/core": "7.19.0", - "@babel/eslint-parser": "7.18.9", - "@babel/plugin-proposal-decorators": "7.19.3", - "@babel/preset-env": "7.19.0", - "@babel/preset-flow": "7.18.6", - "@babel/preset-react": "7.18.6", - "@typescript-eslint/eslint-plugin": "5.48.1", - "@typescript-eslint/experimental-utils": "5.48.1", - "@typescript-eslint/parser": "5.48.1", - "builtin-modules": "3.3.0", - "bytes": "3.1.2", - "eslint": "8.26.0", - "eslint-plugin-react": "7.31.8", - "eslint-plugin-react-hooks": "4.6.0", - "eslint-plugin-sonarjs": "0.18.0", - "express": "4.18.1", - "functional-red-black-tree": "1.0.1", - "lodash.clone": "4.5.0", - "module-alias": "2.2.2", - "postcss-html": "0.36.0", - "postcss-less": "6.0.0", - "postcss-scss": "4.0.3", - "postcss-syntax": "0.36.2", - "postcss-value-parser": "4.2.0", - "regexpp": "3.2.0", - "run-node": "2.0.0", - "scslre": "0.1.6", - "stylelint": "14.13.0", - "tmp": "0.2.1", - "typescript": "4.9.4", - "vue-eslint-parser": "9.1.0", - "yaml": "2.1.1" - }, - "bundledDependencies": [ - "@typescript-eslint/eslint-plugin", - "@typescript-eslint/experimental-utils", - "@typescript-eslint/parser", - "@babel/core", - "@babel/eslint-parser", - "@babel/plugin-proposal-decorators", - "@babel/preset-env", - "@babel/preset-flow", - "@babel/preset-react", - "builtin-modules", - "bytes", - "eslint", - "eslint-plugin-react", - "eslint-plugin-react-hooks", - "eslint-plugin-sonarjs", - "express", - "functional-red-black-tree", - "lodash.clone", - "module-alias", - "postcss-html", - "postcss-less", - "postcss-scss", - "postcss-syntax", - "postcss-value-parser", - "regexpp", - "run-node", - "scslre", - "stylelint", - "tmp", - "vue-eslint-parser", - "typescript", - "yaml" - ], - "prettier": { - "printWidth": 100, - "trailingComma": "all", - "singleQuote": true, - "arrowParens": "avoid", - "endOfLine": "lf" - }, - "files": [ - "lib/", - "bin/" - ], - "_moduleAliases": { - "errors": "lib/errors", - "helpers": "lib/helpers", - "linting": "lib/linting", - "parsing": "lib/parsing", - "routing": "lib/routing", - "services": "lib/services" - } -} diff --git a/eslint-bridge/pom.xml b/eslint-bridge/pom.xml deleted file mode 100644 index ccf6e76b606..00000000000 --- a/eslint-bridge/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - 4.0.0 - - - org.sonarsource.javascript - javascript - 10.0.0-SNAPSHOT - - - eslint-bridge - SonarQube JavaScript :: ESLint-bridge - - - src - tests - coverage/lcov.info - ${project.basedir}/tests/tsconfig.json - tests/**/fixtures/**/*,tests/**/rules/comment-based/**/* - - - - - - org.codehaus.mojo - exec-maven-plugin - - - npm run build - generate-resources - exec - - npm - - run - build - - - - - npm run test - test - - exec - - - npm - run test -- --coverage --silent - ${skipTests} - - - - npm run jar - prepare-package - - exec - - - npm - - run - jar - - - - - - - com.mycila - license-maven-plugin - - - - src/**/*.ts - src/**/*.tsx - tests/**/*.ts - - - tests/**/fixtures/**/* - tests/linting/**/comment-based/**/* - - - - - - diff --git a/eslint-bridge/profiling/README.md b/eslint-bridge/profiling/README.md deleted file mode 100644 index 9ea53403edf..00000000000 --- a/eslint-bridge/profiling/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# ESlint-bridge profiling - -This tool allows identifying the bottlenecks of a rule performance. - -## Fetch dependencies - -Run: `npm i` - -## Chrome dev tools - -The Chrome dev tools allow you to see what functions took how much CPU time as: -- a top-down tree -- a bottom-up tree -- a (flame) graph - -1. Boot the server in debug mode: `npm run server`. (or `npm run compile-server` if you have modifications in `eslint-bridge/`) -2. Open dev tools on chrome, using F12 -3. You should see a green NodeJS icon like that, click it to connect the dev tools to the server's debugger: - -![dev tools](images/dev-tools.png) - -4. You might need to make sure the server starts by going to the "sources" tab and pressing the "play" button -5. In the server logs, you should see that the server is listening -6. Select the "Profiler" tab -5. Select "Profiles" on the left -6. Press "Start" on the bottom - -![profiler](images/profiler.png) - -7. Launch the Analysis on ruling projects: `npm run profile ` - 1. `ts` for TS-only projects, `all` for both JS and TS, JS-only by default. - 2. `parallelism` sets the number of parallel files sent to the `eslint-bridge` for analysis. Defaults to 5. -8. Press "Stop" -9. View the profile -10. Change the view from "Heavy (Bottom Up)" to "Tree (Top Down)" (on the top menu, above "Self Time") - -![profile](images/profile.png) - -11. If you prefer, you can also select the "Chart" view to display a flame graph - -![flame graph](images/flame.png) - -## Links - -- [Chrome profiling](https://medium.com/@basakabhijoy/debugging-and-profiling-memory-leaks-in-nodejs-using-chrome-e8ece4560dba) -- [Chrome profiling - views](https://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art037) -- [Flame graphs with 0x](https://github.com/davidmarkclements/0x) -- [NodeJS profiling](https://nodejs.org/en/docs/guides/simple-profiling/) diff --git a/eslint-bridge/profiling/images/0x-flame-graph.png b/eslint-bridge/profiling/images/0x-flame-graph.png deleted file mode 100644 index 92787b89395..00000000000 Binary files a/eslint-bridge/profiling/images/0x-flame-graph.png and /dev/null differ diff --git a/eslint-bridge/profiling/images/dev-tools.png b/eslint-bridge/profiling/images/dev-tools.png deleted file mode 100644 index 92662afda76..00000000000 Binary files a/eslint-bridge/profiling/images/dev-tools.png and /dev/null differ diff --git a/eslint-bridge/profiling/images/flame.png b/eslint-bridge/profiling/images/flame.png deleted file mode 100644 index b402f249edc..00000000000 Binary files a/eslint-bridge/profiling/images/flame.png and /dev/null differ diff --git a/eslint-bridge/profiling/images/profile.png b/eslint-bridge/profiling/images/profile.png deleted file mode 100644 index fff8856f2dd..00000000000 Binary files a/eslint-bridge/profiling/images/profile.png and /dev/null differ diff --git a/eslint-bridge/profiling/images/profiler.png b/eslint-bridge/profiling/images/profiler.png deleted file mode 100644 index 37a89c956c0..00000000000 Binary files a/eslint-bridge/profiling/images/profiler.png and /dev/null differ diff --git a/eslint-bridge/profiling/package-lock.json b/eslint-bridge/profiling/package-lock.json deleted file mode 100644 index e34d881afdf..00000000000 --- a/eslint-bridge/profiling/package-lock.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "name": "profiling", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "profiling", - "version": "1.0.0", - "license": "LGPL-3.0", - "devDependencies": { - "tsconfig-paths": "^4.1.0" - } - }, - "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://repox.jfrog.io/repox/api/npm/npm/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimist": { - "version": "1.2.7", - "resolved": "https://repox.jfrog.io/repox/api/npm/npm/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "dev": true - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://repox.jfrog.io/repox/api/npm/npm/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tsconfig-paths": { - "version": "4.1.0", - "resolved": "https://repox.jfrog.io/repox/api/npm/npm/tsconfig-paths/-/tsconfig-paths-4.1.0.tgz", - "integrity": "sha512-AHx4Euop/dXFC+Vx589alFba8QItjF+8hf8LtmuiCwHyI4rHXQtOOENaM8kvYf5fR0dRChy3wzWIZ9WbB7FWow==", - "dev": true, - "dependencies": { - "json5": "^2.2.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - } - }, - "dependencies": { - "json5": { - "version": "2.2.1", - "resolved": "https://repox.jfrog.io/repox/api/npm/npm/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true - }, - "minimist": { - "version": "1.2.7", - "resolved": "https://repox.jfrog.io/repox/api/npm/npm/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "dev": true - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://repox.jfrog.io/repox/api/npm/npm/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - }, - "tsconfig-paths": { - "version": "4.1.0", - "resolved": "https://repox.jfrog.io/repox/api/npm/npm/tsconfig-paths/-/tsconfig-paths-4.1.0.tgz", - "integrity": "sha512-AHx4Euop/dXFC+Vx589alFba8QItjF+8hf8LtmuiCwHyI4rHXQtOOENaM8kvYf5fR0dRChy3wzWIZ9WbB7FWow==", - "dev": true, - "requires": { - "json5": "^2.2.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - } - } -} diff --git a/eslint-bridge/profiling/package.json b/eslint-bridge/profiling/package.json deleted file mode 100644 index b041403906e..00000000000 --- a/eslint-bridge/profiling/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "profiling", - "version": "1.0.0", - "description": "", - "main": "server.js", - "scripts": { - "server": "node --inspect-brk server.js", - "compile-server": "cd ..; npm run compile; cd profiling; node --inspect-brk server.js", - "profile": "../node_modules/.bin/ts-node profile-rule.ts" - }, - "license": "LGPL-3.0", - "devDependencies": { - "tsconfig-paths": "^4.1.0" - } -} diff --git a/eslint-bridge/profiling/profile-rule.ts b/eslint-bridge/profiling/profile-rule.ts deleted file mode 100644 index 8b73d50fd04..00000000000 --- a/eslint-bridge/profiling/profile-rule.ts +++ /dev/null @@ -1,277 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import * as http from 'http'; -import path from 'path'; -import * as fs from 'fs'; -import { request } from '../tests/tools'; - -const server = { - // must be the same as the one used in ./server.js - address: () => { - return { port: 64829 }; - }, -}; - -const start = Date.now(); - -try { - const ruleId = extractRuleFromArgs(); - const { js: jsProjects, ts: tsProjects } = extractScopeFromArgs() as any; - const parallelism = extractParallelismFromArgs(); - - (async () => { - await requestInitLinter(server as http.Server, 'MAIN', ruleId); - - if (jsProjects !== undefined) { - for (let i = 0; i < jsProjects.length; i++) { - await analyzeJSProject(server as http.Server, jsProjects[i], parallelism); - } - } - if (tsProjects !== undefined) { - for (let i = 0; i < tsProjects.length; i++) { - await analyzeTsProject(server as http.Server, tsProjects[i], parallelism); - } - } - })(); -} catch (e) { - console.error(`Profiling exited because of Error: ${e.message}`); -} finally { - const timeSeconds = (Date.now() - start) / 1000; - console.log(`done in ${timeSeconds}s`); -} - -function extractRuleFromArgs() { - if (process.argv.length <= 2) { - throw new Error('Missing rule id. Please provide a rule id as CLI argument'); - } - return process.argv[2]; -} - -function extractScopeFromArgs() { - const SCOPES = ['js', 'ts', 'all']; - const JS_PROJECTS = { - js: [ - 'amplify/src', - 'angular.js/src', - 'backbone', - 'es5-shim', - 'file-for-rules', - 'fireact/src', - 'javascript-test-sources/src', - 'jira-clone', - 'jquery/src', - 'jshint/src', - 'jStorage', - 'knockout/src', - 'mootools-core/Source', - 'ocanvas/src', - 'p5.js/src', - 'paper.js/src', - 'prototype/src', - 'qunit/src', - 'react-cloud-music/src', - 'sizzle/src', - 'underscore', - ], - }; - JS_PROJECTS.js = JS_PROJECTS.js.map(filePath => - path.join(__dirname, '../../its/sources/', filePath), - ); - const TS_PROJECTS = { - ts: [ - 'ag-grid/tsconfig.json', - 'ant-design/tsconfig.json', - 'console/tsconfig.json', - // there are other folders in courselit - 'courselit/apps/web/tsconfig.json', - 'desktop/tsconfig.json', - 'eigen/tsconfig.json', - 'fireface/src/tsconfig.json', - 'ionic2-auth/tsconfig.json', - 'Joust/tsconfig.json', - // other folders as well here - 'moose/main/tsconfig.json', - 'postgraphql/tsconfig.json', - 'prettier-vscode/tsconfig.json', - 'rxjs/tsconfig.json', - // other folders as well - 'searchkit/packages/searchkit-cli/tsconfig.json', - // other folders as well - 'TypeScript/src/compiler/tsconfig.json', - ], - }; - TS_PROJECTS.ts = TS_PROJECTS.ts.map(filePath => - path.join(__dirname, '../../its/typescript-test-sources/src/', filePath), - ); - - if (process.argv.length < 4) { - return JS_PROJECTS; - } - const scope = process.argv[3]; - if (!SCOPES.includes(scope)) { - throw new Error( - `Unknown scope. Please provide one of the available: ${SCOPES.map(scope => `"${scope}"`)}`, - ); - } - switch (scope) { - case 'js': - return { ...JS_PROJECTS, ts: undefined }; - case 'ts': - return { js: undefined, ...TS_PROJECTS }; - case 'all': - return { ...JS_PROJECTS, ...TS_PROJECTS }; - } -} - -function extractParallelismFromArgs() { - let parallelism = 5; - if (process.argv.length < 5) { - return parallelism; - } - parallelism = parseInt(process.argv[4]); - if (isNaN(parallelism) || parallelism < 1) { - throw new Error( - `Invalid parallelism parameter at 3rd position "${process.argv[4]}". Please prove a positive number.`, - ); - } - return parallelism; -} - -function requestInitLinter(server: http.Server, fileType: string, ruleId: string) { - const config = { - rules: [{ key: ruleId, configurations: [], fileTypeTarget: fileType }], - }; - return request(server, '/init-linter', 'POST', config); -} - -async function analyzeTsProject(server: http.Server, tsConfigPath: string, parallelism) { - console.log('####################################'); - console.log(`Analyzing TS project ${tsConfigPath}`); - console.log('####################################'); - - const { programId, files } = await createProgram(server, tsConfigPath); - console.log(`Created program with programId ${programId} containing ${files.length} files`); - const promises: (() => Promise)[] = buildPromises(server, programId, files); - await executePromises(promises, parallelism, files, tsConfigPath); - await deleteProgram(server, programId); - - async function createProgram(server: http.Server, tsConfigPath: string): Promise { - try { - const response = await request(server, '/create-program', 'POST', { tsConfig: tsConfigPath }); - return JSON.parse(response as string); - } catch (e) { - console.error(`Error while creating program for ${tsConfigPath}. Error: ${e.message}`); - } - } - - async function deleteProgram(server: http.Server, programId: string) { - try { - await request(server, '/delete-program', 'POST', { programId }); - } catch (e) { - console.error( - `Error while deleting program with programId: ${programId}. Error: ${e.message}`, - ); - } - } - - function buildPromises(server: http.Server, tsConfigId: string, files: string[]) { - const promises: (() => Promise)[] = []; - for (const file of files) { - promises.push(() => analyzeFile(server, tsConfigId, file)); - } - return promises; - - async function analyzeFile( - server: http.Server, - programId: string, - filePath: string, - ): Promise { - return request(server, '/analyze-ts', 'POST', { programId, filePath }); - } - } -} - -async function analyzeJSProject(server: http.Server, projectPath: string, parallelism: number) { - console.log('####################################'); - console.log(`Analyzing JS project ${projectPath}`); - console.log('####################################'); - - let files: string[] = []; - collectFilesInFolder(projectPath, files); - console.log(`Found ${files.length} files`); - files = files.filter(isJSFile); - console.log(`of which ${files.length} are JS files`); - const promises = buildPromises(server, files); - await executePromises(promises, parallelism, files, projectPath); - - function isJSFile(filePath: string) { - return filePath.endsWith('.js'); - } - - function buildPromises(server: http.Server, files: string[]) { - const promises: (() => Promise)[] = []; - files.forEach(filePath => { - promises.push(() => analyzeFile(server, filePath)); - }); - return promises; - - async function analyzeFile(server: http.Server, filePath: string) { - const response = await request(server, '/analyze-js', 'POST', { - filePath, - fileType: 'MAIN', - linterId: 'default', - }); - return response; - } - } -} - -function collectFilesInFolder(folder: string, files: string[]) { - fs.readdirSync(folder).forEach(file => { - const filePath = path.join(folder, file); - if (fs.statSync(filePath).isDirectory()) { - return collectFilesInFolder(filePath, files); - } else { - return files.push(filePath); - } - }); -} - -async function executePromises( - promises: (() => Promise)[], - parallelism: number, - files: string[], - projectPath: string, -) { - for (let i = 0; i < promises.length; i += parallelism) { - const endIndex = Math.min(i + parallelism - 1, promises.length - 1); - try { - console.log( - `Analysing files from ${i + 1} to ${endIndex + 1} (out of ${ - promises.length - }) for ${projectPath}`, - ); - await Promise.all(promises.slice(i, endIndex + 1).map(fn => fn())); - } catch (e) { - console.error(`Failed analyzing files: ${files.slice(i, endIndex + 1)}`); - } - } -} diff --git a/eslint-bridge/profiling/server.js b/eslint-bridge/profiling/server.js deleted file mode 100644 index 1f8ade837cf..00000000000 --- a/eslint-bridge/profiling/server.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - - -const server = require('../lib/server'); -const path = require('path'); -const context = require('../lib/helpers'); -const { tmpdir } = require('os'); - -// must be the same as the one used in ./profile-rule.ts -const port = 64829; -const host = '127.0.0.1'; -const workDir = tmpdir(); - -context.setContext({ workDir, shouldUseTypeScriptParserForJS: false, sonarlint: false, bundles: [] }); -const BIG_TIMEOUT = 1719925474; -server.start(port, host, BIG_TIMEOUT); diff --git a/eslint-bridge/profiling/tsconfig.json b/eslint-bridge/profiling/tsconfig.json deleted file mode 100644 index 69c12ad95d9..00000000000 --- a/eslint-bridge/profiling/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../src/tsconfig.json", - "compilerOptions": { - "composite": false, - "noEmit": true, - "strictNullChecks": false, - "noImplicitAny": false, - "baseUrl": ".", - "paths": { - "*": ["../src/*"] - }, - }, - "references": [ - { - "path": "../src/tsconfig.json" - } - ], - "ts-node": { - // Do not forget to `npm i -D tsconfig-paths` - "require": ["tsconfig-paths/register"] - } -} diff --git a/eslint-bridge/src/errors/error.ts b/eslint-bridge/src/errors/error.ts deleted file mode 100644 index e6dc2a214a6..00000000000 --- a/eslint-bridge/src/errors/error.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -/** - * The possible codes of analysis errors - * - * The `Unexpected` value denotes a runtime error which is either - * unpredictable or occurs rarely to deserve its own category. - */ -export enum ErrorCode { - Parsing = 'PARSING', - FailingTypeScript = 'FAILING_TYPESCRIPT', - // We are stuck with this name because of possible external dependents - Unexpected = 'GENERAL_ERROR', - LinterInitialization = 'LINTER_INITIALIZATION', -} - -export interface ErrorData { - line: number; -} - -export class APIError extends Error { - code: ErrorCode; - data?: ErrorData; - - private constructor(code: ErrorCode, message: string, data?: ErrorData) { - super(message); - this.code = code; - this.data = data; - } - - /** - * Builds a failing TypeScript error. - */ - static failingTypeScriptError(message: string) { - return new APIError(ErrorCode.FailingTypeScript, message); - } - - /** - * Builds a linter initialization error. - */ - static linterError(message: string) { - return new APIError(ErrorCode.LinterInitialization, message); - } - - /** - * Builds a parsing error. - */ - static parsingError(message: string, data: ErrorData) { - return new APIError(ErrorCode.Parsing, message, data); - } - - /** - * Builds an unexpected runtime error. - */ - static unexpectedError(message: string) { - return new APIError(ErrorCode.Unexpected, message); - } -} diff --git a/eslint-bridge/src/errors/index.ts b/eslint-bridge/src/errors/index.ts deleted file mode 100644 index 71836e539e5..00000000000 --- a/eslint-bridge/src/errors/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './error'; diff --git a/eslint-bridge/src/helpers/context.ts b/eslint-bridge/src/helpers/context.ts deleted file mode 100644 index fa3fe93a79e..00000000000 --- a/eslint-bridge/src/helpers/context.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -/** - * A container of contextual information - * - * @param workDir the working directory of the analyzed project - * @param shouldUseTypeScriptParserForJS a flag for parsing JavaScript code with TypeScript ESLint parser - * @param sonarlint a flag for indicating whether the bridge is used in SonarLint context - * @param bundles a set of rule bundles to load - */ -export interface Context { - workDir: string; - shouldUseTypeScriptParserForJS: boolean; - sonarlint: boolean; - bundles: string[]; -} - -/** - * The global context - * - * It is available anywhere within the bridge as well as in - * external and custom rules provided their definition sets - * the `sonar-context` internal parameter. - */ -let context: Context; - -/** - * Returns the global context - * @returns the global context - */ -export function getContext(): Context { - return context; -} - -/** - * Sets the global context - * @param ctx the new global context - */ -export function setContext(ctx: Context) { - context = { ...ctx }; -} diff --git a/eslint-bridge/src/helpers/debug.ts b/eslint-bridge/src/helpers/debug.ts deleted file mode 100644 index 3da875f48af..00000000000 --- a/eslint-bridge/src/helpers/debug.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -/** - * Prints a message to `stdout` like `console.log` by prefixing it with `DEBUG`. - * - * The `DEBUG` prefix is recognized by the scanner, which - * will show the logged message in the scanner debug logs. - * - * @param message the message to log - */ -export function debug(message: string) { - console.log(`DEBUG ${message}`); -} diff --git a/eslint-bridge/src/helpers/files.ts b/eslint-bridge/src/helpers/files.ts deleted file mode 100644 index a7e17836022..00000000000 --- a/eslint-bridge/src/helpers/files.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import fs from 'fs/promises'; -import path from 'path'; - -/** - * Byte Order Marker - */ -const BOM_BYTE = 0xfeff; - -/** - * The type of input file - * - * The scanner indexes input files based on the project configuration, - * if any. It determines wheter an input file denotes a `MAIN` file, - * i.e., a source file, or a `TEST` file. - * - * The type of input file is then used by the linter to select which - * rule configurations to apply, that is, which rules the linter should - * use to analyze the file. - */ -export type FileType = 'MAIN' | 'TEST'; - -/** - * Asynchronous read of file contents from a file path - * - * The function gets rid of any Byte Order Marker (BOM) - * present in the file's header. - * - * @param filePath the path of a file - * @returns Promise which resolves with the content of the file - */ -export async function readFile(filePath: string) { - const fileContent = await fs.readFile(filePath, { encoding: 'utf8' }); - return stripBOM(fileContent); -} - -/** - * Removes any Byte Order Marker (BOM) from a string's head - * - * A string's head is nothing else but its first character. - * - * @param str the input string - * @returns the stripped string - */ -export function stripBOM(str: string) { - if (str.charCodeAt(0) === BOM_BYTE) { - return str.slice(1); - } - return str; -} -/** - * Converts a path to Unix format - * @param path the path to convert - * @returns the converted path - */ -export function toUnixPath(path: string) { - return path.replace(/[\\/]+/g, '/').replace(/(\.\/)/, ''); -} - -/** - * Adds tsconfig.json to a path if it does not exist - * - * @param tsConfig - */ -export async function addTsConfigIfDirectory(tsConfig: string) { - try { - if ((await fs.lstat(tsConfig)).isDirectory()) { - return path.join(tsConfig, 'tsconfig.json'); - } - - return tsConfig; - } catch { - return null; - } -} diff --git a/eslint-bridge/src/helpers/index.ts b/eslint-bridge/src/helpers/index.ts deleted file mode 100644 index 06e4660f208..00000000000 --- a/eslint-bridge/src/helpers/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './context'; -export * from './debug'; -export * from './files'; diff --git a/eslint-bridge/src/linting/eslint/index.ts b/eslint-bridge/src/linting/eslint/index.ts deleted file mode 100644 index 55cd18e58cf..00000000000 --- a/eslint-bridge/src/linting/eslint/index.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { APIError } from 'errors'; -import { debug } from 'helpers'; -import { LinterWrapper, RuleConfig } from './linter'; - -export * from './linter'; -export * from './rules'; -type Linters = { [id: string]: LinterWrapper }; -/** - * The global ESLint linters - * - * Any linter is expected to be initialized before use. - * To this end, the plugin is expected to explicitly send a request to - * initialize a linter before starting the actual analysis of a file. - * The global linters object will keep the already initialized linters - * indexed by their linterId. If no linterId is provided, `default` will - * be used. - * Having multiple linters (each with different set of rules enabled) - * is needed in order to not run all rules on 'unchanged' files - */ -const linters: Linters = {}; - -/** - * Initializes the global linter wrapper - * @param inputRules the rules from the active quality profiles - * @param environments the JavaScript execution environments - * @param globals the global variables - * @param linterId key of the linter - */ -export function initializeLinter( - inputRules: RuleConfig[], - environments: string[] = [], - globals: string[] = [], - linterId = 'default', -) { - debug(`Initializing linter "${linterId}" with ${inputRules.map(rule => rule.key)}`); - linters[linterId] = new LinterWrapper({ inputRules, environments, globals }); -} - -/** - * Returns the linter with the given ID - * - * @param linterId key of the linter - * - * Throws a runtime error if the global linter wrapper is not initialized. - */ -export function getLinter(linterId: keyof Linters = 'default') { - if (!linters[linterId]) { - throw APIError.linterError(`Linter ${linterId} does not exist. Did you call /init-linter?`); - } - return linters[linterId]; -} diff --git a/eslint-bridge/src/linting/eslint/linter/bundle-loader.ts b/eslint-bridge/src/linting/eslint/linter/bundle-loader.ts deleted file mode 100755 index 4befc04b2a5..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/bundle-loader.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Linter, Rule } from 'eslint'; -import { eslintRules } from 'linting/eslint/rules/core'; -import { rules as pluginRules } from 'eslint-plugin-sonarjs'; -import { rules as reactESLintRules } from 'eslint-plugin-react'; -import { rules as typescriptESLintRules } from '@typescript-eslint/eslint-plugin'; -import { rules as internalRules } from 'linting/eslint'; -import { customRules as internalCustomRules, CustomRule } from './custom-rules'; -import { decorateExternalRules } from './decoration'; -import { debug, getContext } from 'helpers'; - -export function loadCustomRules(linter: Linter, rules: CustomRule[] = []) { - for (const rule of rules) { - linter.defineRule(rule.ruleId, rule.ruleModule); - } -} - -export function loadBundles(linter: Linter, rulesBundles: (keyof typeof loaders)[]) { - for (const bundleId of rulesBundles) { - loaders[bundleId](linter); - } -} - -/** - * Loaders for each of the predefined rules bundles. Each bundle comes with a - * different data structure (array/record/object), plus on some cases - * there are specifics that must be taken into account, like ignoring some - * rules from some bundles or decorating them in order to be compatible. - */ -const loaders: { [key: string]: Function } = { - /** - * Loads external rules - * - * The external ESLint-based rules include all the rules that are - * not implemented internally, in other words, rules from external - * dependencies which include ESLint core rules. Furthermore, the - * returned rules are decorated either by internal decorators or by - * special decorations. - */ - externalRules(linter: Linter) { - const externalRules: { [key: string]: Rule.RuleModule } = {}; - /** - * The order of defining rules from external dependencies is important here. - * Core ESLint rules could be overridden by the implementation from specific - * dependencies, which should be the default behaviour in most cases. If for - * some reason a different behaviour is needed for a particular rule, one can - * specify it in `decorateExternalRules`. - */ - const dependencies = [eslintRules, typescriptESLintRules, reactESLintRules]; - for (const dependencyRules of dependencies) { - for (const [name, module] of Object.entries(dependencyRules)) { - externalRules[name] = module; - } - } - linter.defineRules(decorateExternalRules(externalRules)); - }, - /** - * Loads plugin rules - * - * Adds the rules from the Sonar ESLint plugin. - */ - pluginRules(linter: Linter) { - linter.defineRules(pluginRules); - }, - /** - * Loads internal rules - * - * Adds the rules from SonarJS plugin, i.e. rules in path - * /src/linting/eslint/rules - */ - internalRules(linter: Linter) { - linter.defineRules(internalRules); - }, - /** - * Loads global context rules - * - * Context bundles define a set of external custom rules (like the taint analysis rule) - * including rule keys and rule definitions that cannot be provided to the linter - * wrapper using the same feeding channel as rules from the active quality profile. - */ - contextRules(linter: Linter) { - const { bundles } = getContext(); - const customRules: CustomRule[] = []; - for (const ruleBundle of bundles) { - const bundle = require(ruleBundle); - customRules.push(...bundle.rules); - const ruleIds = bundle.rules.map((r: CustomRule) => r.ruleId); - debug(`Loaded rules ${ruleIds} from ${ruleBundle}`); - } - loadCustomRules(linter, customRules); - }, - /** - * Loads internal custom rules - * - * These are rules used internally by SonarQube to have the symbol highlighting and - * the cognitive complexity metrics. - */ - internalCustomRules(linter: Linter) { - loadCustomRules(linter, internalCustomRules); - }, -}; diff --git a/eslint-bridge/src/linting/eslint/linter/config/index.ts b/eslint-bridge/src/linting/eslint/linter/config/index.ts deleted file mode 100644 index 2d4cd813910..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/config/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './linter-config'; -export * from './rule-config'; diff --git a/eslint-bridge/src/linting/eslint/linter/config/linter-config.ts b/eslint-bridge/src/linting/eslint/linter/config/linter-config.ts deleted file mode 100644 index be806ebaa01..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/config/linter-config.ts +++ /dev/null @@ -1,133 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Linter, Rule } from 'eslint'; -import { getContext } from 'helpers'; -import { customRules as internalCustomRules } from '../custom-rules'; -import { extendRuleConfig, RuleConfig } from './rule-config'; - -/** - * Creates an ESLint linting configuration - * - * A linter configuration is created based on the input rules enabled by - * the user through the active quality profile and the rules provided by - * the linter wrapper. - * - * The configuration includes the rules with their configuration that are - * used during linting as well as the global variables and the JavaScript - * execution environments defined through the analyzer's properties. - * - * @param inputRules the rules from the active quality profile - * @param linterRules the wrapper's rule database - * @param environments the JavaScript execution environments - * @param globs the global variables - * @returns the created ESLint linting configuration - */ -export function createLinterConfig( - inputRules: RuleConfig[], - linterRules: Map, - environments: string[], - globs: string[], -) { - const env = createEnv(environments); - const globals = createGlobals(globs); - const parserOptions = { sourceType: 'module', ecmaVersion: 2018 } as Linter.ParserOptions; - const config: Linter.Config = { - env, - globals, - parserOptions, - rules: {}, - /* using "max" version to prevent `eslint-plugin-react` from printing a warning */ - settings: { react: { version: '999.999.999' } }, - }; - enableRules(config, inputRules, linterRules); - enableInternalCustomRules(config); - return config; -} - -/** - * Creates an ESLint execution environments configuration - * @param environments the JavaScript execution environments to enable - * @returns a configuration of JavaScript execution environments - */ -function createEnv(environments: string[]) { - const env: { [name: string]: boolean } = { es6: true }; - for (const key of environments) { - env[key] = true; - } - return env; -} - -/** - * Creates an ESLint global variables configuration - * @param globs the global variables to enable - * @returns a configuration of global variables - */ -function createGlobals(globs: string[]) { - const globals: { [name: string]: boolean } = {}; - for (const key of globs) { - globals[key] = true; - } - return globals; -} - -/** - * Enables input rules - * - * Enabling an input rule is similar to how rule enabling works with ESLint. - * However, in the particular case of internal rules, the rule configuration - * can be decorated with special markers to activate internal features. - * - * For example, an ESLint rule configuration for a rule that reports secondary - * locations would be `["error", "sonar-runtime"]`, where the "sonar-runtime"` - * is a marker for a post-linting processing to decode such locations. - * - * @param config the configuration to augment with rule enabling - * @param inputRules the input rules to enable - * @param linterRules the linter rules available - */ -function enableRules( - config: Linter.Config, - inputRules: RuleConfig[], - linterRules: Map, -) { - for (const inputRule of inputRules) { - const ruleModule = linterRules.get(inputRule.key); - config.rules![inputRule.key] = ['error', ...extendRuleConfig(ruleModule, inputRule)]; - } -} - -/** - * Enables internal custom rules in the provided configuration - * - * Custom rules like cognitive complexity and symbol highlighting - * are always enabled as part of metrics computation. Such rules - * are, therefore, added in the linting configuration by default. - * - * _Internal custom rules are not enabled in SonarLint context._ - * - * @param config the configuration to augment with custom rule enabling - */ -function enableInternalCustomRules(config: Linter.Config) { - if (!getContext().sonarlint) { - for (const internalCustomRule of internalCustomRules) { - config.rules![internalCustomRule.ruleId] = ['error', ...internalCustomRule.ruleConfig]; - } - } -} diff --git a/eslint-bridge/src/linting/eslint/linter/config/rule-config.ts b/eslint-bridge/src/linting/eslint/linter/config/rule-config.ts deleted file mode 100644 index fc97b91fff9..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/config/rule-config.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import { FileType, getContext } from 'helpers'; -import { hasSonarRuntimeOption, SONAR_RUNTIME, hasSonarContextOption } from '../parameters'; - -/** - * An input rule configuration for linting - * - * @param key an ESLint rule key that maps a SonarQube rule identifier (SXXX) to the rule implementation - * @param configurations an ESLint rule configuration provided from the anaylzer if the rule behaviour is customizable - * @param fileTypeTarget a list of file type targets to filter issues in case the rule applies to main files, test files, or both - * - * The configuration of a rule is used to uniquely identify a rule, customize its behaviour, - * and define what type(s) of file it should apply to during linting. - * - * An ESLint rule configuration can theoretically be a plain JavaScript object or a string. However, given the - * nature of SonarQube' rule properties, it is currently used in the form of a string. - */ -export interface RuleConfig { - key: string; - configurations: any[]; - fileTypeTarget: FileType[]; -} - -/** - * Extends an input rule configuration - * - * A rule configuration might be extended depending on the rule definition. - * The purpose of the extension is to activate additional features during - * linting, e.g., secondary locations. - * - * _A rule extension only applies to rules whose implementation is available._ - * - * @param ruleModule the rule definition - * @param inputRule the rule configuration - * @returns the extended rule configuration - */ -export function extendRuleConfig(ruleModule: Rule.RuleModule | undefined, inputRule: RuleConfig) { - const options = [...inputRule.configurations]; - if (hasSonarRuntimeOption(ruleModule, inputRule.key)) { - options.push(SONAR_RUNTIME); - } - if (hasSonarContextOption(ruleModule, inputRule.key)) { - options.push(getContext()); - } - return options; -} diff --git a/eslint-bridge/src/linting/eslint/linter/custom-rules/cognitive-complexity.ts b/eslint-bridge/src/linting/eslint/linter/custom-rules/cognitive-complexity.ts deleted file mode 100644 index 5997cffe806..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/custom-rules/cognitive-complexity.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { rules as sonarjsESLintRules } from 'eslint-plugin-sonarjs'; -import { CustomRule } from './custom-rule'; - -/** - * The internal _cognitive complexity_ custom rule - * - * The rule computes file-level cognitive complexity. - */ -export const rule: CustomRule = { - ruleId: 'internal-cognitive-complexity', - ruleModule: sonarjsESLintRules['cognitive-complexity'], - ruleConfig: ['metric'], -}; diff --git a/eslint-bridge/src/linting/eslint/linter/custom-rules/custom-rule.ts b/eslint-bridge/src/linting/eslint/linter/custom-rules/custom-rule.ts deleted file mode 100644 index cbc993cd8de..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/custom-rules/custom-rule.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; - -/** - * An ESLint-based custom rule - * - * @param ruleId the ESLint rule key - * @param ruleModule the ESLint rule implementation - * @param rule the ESLint rule configuration - */ -export interface CustomRule { - ruleId: string; - ruleModule: Rule.RuleModule; - ruleConfig: any[]; -} diff --git a/eslint-bridge/src/linting/eslint/linter/custom-rules/index.ts b/eslint-bridge/src/linting/eslint/linter/custom-rules/index.ts deleted file mode 100644 index 19b834ebf8d..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/custom-rules/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { rule as cognitiveComplexity } from './cognitive-complexity'; -import { CustomRule } from './custom-rule'; -import { rule as symbolHighlighting } from './symbol-highlighting'; - -export * from './custom-rule'; - -/** - * The set of internal custom rules - */ -export const customRules: CustomRule[] = [cognitiveComplexity, symbolHighlighting]; diff --git a/eslint-bridge/src/linting/eslint/linter/custom-rules/symbol-highlighting.ts b/eslint-bridge/src/linting/eslint/linter/custom-rules/symbol-highlighting.ts deleted file mode 100644 index 7f43d24b149..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/custom-rules/symbol-highlighting.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { CustomRule } from './custom-rule'; -import { rule as symbolHighlightingRule } from '../visitors/symbol-highlighting'; - -/** - * The internal _symbol highlighting_ custom rule - */ -export const rule: CustomRule = { - ruleId: 'internal-symbol-highlighting', - ruleModule: symbolHighlightingRule, - ruleConfig: [], -}; diff --git a/eslint-bridge/src/linting/eslint/linter/decoration/decorate.ts b/eslint-bridge/src/linting/eslint/linter/decoration/decorate.ts deleted file mode 100644 index 055fcfd8faa..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/decoration/decorate.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import { rules as typescriptESLintRules } from '@typescript-eslint/eslint-plugin'; -import { decorators } from 'linting/eslint/rules/decorators'; -import { eslintRules } from 'linting/eslint/rules/core'; -import { sanitizeTypeScriptESLintRule } from './sanitize'; -/** - * Decorates external rules - * - * Decorating an external rule means customizing the original behaviour of the rule that - * can't be done through rule configuration and requires special adjustments, among which - * are internal decorators. - * - * @param externalRules the external rules to decorate - */ -export function decorateExternalRules(externalRules: { [name: string]: Rule.RuleModule }): { - [name: string]: Rule.RuleModule; -} { - const decoratedRules = { ...externalRules }; - /** - * S1537 ('comma-dangle'), S3723 ('enforce-trailing-comma') - * - * S1537 and S3723 both depend on the same ESLint implementation but the - * plugin doesn't allow duplicates of the same rule key. - */ - const commaDangleRuleId = 'comma-dangle'; - const enforceTrailingCommaRuleId = 'enforce-trailing-comma'; - decoratedRules[enforceTrailingCommaRuleId] = eslintRules[commaDangleRuleId]; - - /** - * S3696 ('no-throw-literal') - * - * TypeScript ESLint implementation of no-throw-literal does not support JavaScript code. - */ - const noThrowLiteralRuleId = 'no-throw-literal'; - decoratedRules[noThrowLiteralRuleId] = eslintRules[noThrowLiteralRuleId]; - - /** - * TypeScript ESLint rules sanitization - * - * TypeScript ESLint rules that rely on type information fail at runtime because - * they unconditionally assume that TypeScript's type checker is available. - */ - for (const ruleKey of Object.keys(typescriptESLintRules)) { - decoratedRules[ruleKey] = sanitizeTypeScriptESLintRule(decoratedRules[ruleKey]); - } - - /** - * Decorate (TypeScript-) ESLint external rules - * - * External rules are decorated with internal decorators to refine their - * behaviour: exceptions, quick fixes, secondary locations, etc. - */ - for (const ruleKey in decorators) { - decoratedRules[ruleKey] = decorators[ruleKey](decoratedRules[ruleKey]); - } - return decoratedRules; -} diff --git a/eslint-bridge/src/linting/eslint/linter/decoration/index.ts b/eslint-bridge/src/linting/eslint/linter/decoration/index.ts deleted file mode 100644 index efd7ef6f896..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/decoration/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './decorate'; -export * from './sanitize'; diff --git a/eslint-bridge/src/linting/eslint/linter/decoration/sanitize.ts b/eslint-bridge/src/linting/eslint/linter/decoration/sanitize.ts deleted file mode 100644 index 871e040474b..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/decoration/sanitize.ts +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; - -/** - * Sanitizes a TypeScript ESLint rule - * - * TypeScript ESLint rules that relies on TypeScript's type system unconditionally assumes - * that the type checker is always available. Linting a source code with such rules could - * lead to a runtime error if that assumption turned out to be wrong for whatever reason. - * - * Aa TypeScript ESLint rule needs, therefore, to be sanitized in case its implementation - * relies on type checking. The metadata of such a rule sets the `requiresTypeChecking` - * property to `true`. - * - * The sanitization of a rule is nothing more than a decoration of its implementation. It - * determines whether the rule uses type checking and checks whether type information is - * available at runtime. If so, the execution of the rule proceeds; otherwise, it stops. - * - * @param rule a TypeScript ESLint rule to sanitize - * @returns the sanitized rule - */ -export function sanitizeTypeScriptESLintRule(rule: Rule.RuleModule): Rule.RuleModule { - return { - ...(!!rule.meta && { meta: rule.meta }), - create(originalContext: Rule.RuleContext) { - const interceptingContext: Rule.RuleContext = { - id: originalContext.id, - options: originalContext.options, - settings: originalContext.settings, - parserPath: originalContext.parserPath, - parserOptions: originalContext.parserOptions, - parserServices: originalContext.parserServices, - - getCwd(): string { - return originalContext.getCwd(); - }, - - getPhysicalFilename(): string { - return originalContext.getPhysicalFilename(); - }, - - getAncestors() { - return originalContext.getAncestors(); - }, - - getDeclaredVariables(node: Rule.Node) { - return originalContext.getDeclaredVariables(node); - }, - - getFilename() { - return originalContext.getFilename(); - }, - - getScope() { - return originalContext.getScope(); - }, - - getSourceCode() { - return originalContext.getSourceCode(); - }, - - markVariableAsUsed(name: string) { - return originalContext.markVariableAsUsed(name); - }, - - report(descriptor: Rule.ReportDescriptor): void { - return originalContext.report(descriptor); - }, - }; - /** - * Overrides the rule behaviour if it requires TypeScript's type checker - * but type information is missing. - */ - if ( - rule.meta?.docs && - (rule.meta.docs as any).requiresTypeChecking === true && - interceptingContext.parserServices.hasFullTypeInformation !== true - ) { - return {}; - } - return rule.create(interceptingContext); - }, - }; -} diff --git a/eslint-bridge/src/linting/eslint/linter/index.ts b/eslint-bridge/src/linting/eslint/linter/index.ts deleted file mode 100644 index 2d997a3eec4..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './config'; -export * from './custom-rules'; -export * from './issues'; -export * from './quickfixes'; -export * from './visitors'; -export * from './wrapper'; diff --git a/eslint-bridge/src/linting/eslint/linter/issues/decode.ts b/eslint-bridge/src/linting/eslint/linter/issues/decode.ts deleted file mode 100644 index 832bec69225..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/issues/decode.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import { EncodedMessage } from 'eslint-plugin-sonarjs/lib/utils/locations'; -import { Issue } from './issue'; -import { hasSonarRuntimeOption } from '../parameters'; - -/** - * Decodes an issue with secondary locations, if any - * - * Decoding an issue with secondary locations consists in checking - * if the rule definition claims using secondary locations by the - * definition of the `sonar-runtime` internal parameter. If it is - * the case, secondary locations are then decoded and a well-formed - * issue is then returned. Otherwise, the original issue is returned - * unchanged. - * - * @param ruleModule the rule definition - * @param issue the issue to decode - * @throws a runtime error in case of an invalid encoding - * @returns the decoded issue (or the original one) - */ -export function decodeSonarRuntime(ruleModule: Rule.RuleModule | undefined, issue: Issue): Issue { - if (hasSonarRuntimeOption(ruleModule, issue.ruleId)) { - try { - const encodedMessage: EncodedMessage = JSON.parse(issue.message); - return { ...issue, ...encodedMessage }; - } catch (e) { - throw new Error( - `Failed to parse encoded issue message for rule ${issue.ruleId}:\n"${issue.message}". ${e.message}`, - ); - } - } - return issue; -} diff --git a/eslint-bridge/src/linting/eslint/linter/issues/extract.ts b/eslint-bridge/src/linting/eslint/linter/issues/extract.ts deleted file mode 100644 index 2aa3bb88ab4..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/issues/extract.ts +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Issue } from './issue'; -import { rule as cognitiveComplexityRule } from '../custom-rules/cognitive-complexity'; -import { rule as symbolHighlightingRule } from '../custom-rules/symbol-highlighting'; -import { SymbolHighlight } from '../visitors'; - -/** - * Extracts the symbol highlighting - * - * The linter enables the internal custom rule for symbol highlighting - * which eventually creates an issue to this end. The issue encodes the - * symbol highlighting as a serialized JSON object in its message, which - * can safely be extracted if it exists in the list of returned issues - * after linting. - * - * @param issues the issues to process - * @returns the symbol highlighting - */ -export function extractHighlightedSymbols(issues: Issue[]) { - const issue = findAndRemoveFirstIssue(issues, symbolHighlightingRule.ruleId); - if (issue) { - return JSON.parse(issue.message) as SymbolHighlight[]; - } - return []; -} - -/** - * Extracts the cognitive complexity - * - * The linter enables the internal custom rule for cognitive complexity - * which eventually creates an issue to this end. The issue encodes the - * complexity as a number in its message, which can safely be extracted - * if it exists in the list of returned issues after linting. - * - * @param issues the issues to process - * @returns the cognitive complexity - */ -export function extractCognitiveComplexity(issues: Issue[]) { - const issue = findAndRemoveFirstIssue(issues, cognitiveComplexityRule.ruleId); - if (issue && !isNaN(Number(issue.message))) { - return Number(issue.message); - } - return undefined; -} - -/** - * Finds the first issue matching a rule id - * - * The functions removes the issue from the list if it exists. - * - * @param issues the issues to process - * @param ruleId the rule id that is looked for - * @returns the found issue, if any - */ -function findAndRemoveFirstIssue(issues: Issue[], ruleId: string) { - for (const issue of issues) { - if (issue.ruleId === ruleId) { - const index = issues.indexOf(issue); - issues.splice(index, 1); - return issue; - } - } - return undefined; -} diff --git a/eslint-bridge/src/linting/eslint/linter/issues/index.ts b/eslint-bridge/src/linting/eslint/linter/issues/index.ts deleted file mode 100644 index ea8df2247e6..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/issues/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './extract'; -export * from './issue'; -export * from './message'; -export * from './transform'; diff --git a/eslint-bridge/src/linting/eslint/linter/issues/issue.ts b/eslint-bridge/src/linting/eslint/linter/issues/issue.ts deleted file mode 100644 index 99352806746..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/issues/issue.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { QuickFix } from '../quickfixes'; -import { Location } from './location'; - -/** - * A SonarQube-compatible source code issue - * - * It is used to send back a JS/TS analysis response to the plugin, which - * eventually saves the issue data to SonarQube. - * - * @param ruleId the rule key - * @param line the issue starting line - * @param column the issue starting column - * @param endLine the issue ending line - * @param endColumn the issue ending column - * @param message the issue message - * @param cost the cost to fix the issue - * @param secondaryLocations the issue secondary locations - * @param quickFixes the issue quick fixes - */ -export interface Issue { - ruleId: string; - line: number; - column: number; - endLine?: number; - endColumn?: number; - message: string; - cost?: number; - secondaryLocations: Location[]; - quickFixes?: QuickFix[]; -} diff --git a/eslint-bridge/src/linting/eslint/linter/issues/location.ts b/eslint-bridge/src/linting/eslint/linter/issues/location.ts deleted file mode 100644 index 8d6ecdd6c7f..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/issues/location.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -/** - * An issue location container - * - * It is used for quick fixes and secondary locations. - * - * @param line the issue starting line - * @param column the issue starting column - * @param endLine the issue ending line - * @param endColumn the issue ending column - * @param message the issue message - */ -export interface Location { - line: number; - column: number; - endLine: number; - endColumn: number; - message?: string; -} diff --git a/eslint-bridge/src/linting/eslint/linter/issues/message.ts b/eslint-bridge/src/linting/eslint/linter/issues/message.ts deleted file mode 100644 index f86551595da..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/issues/message.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Linter, SourceCode } from 'eslint'; -import { transformFixes } from '../quickfixes'; -import { Issue } from './issue'; - -/** - * Converts an ESLint message into a SonarQube issue - * - * Converting an ESLint message into a SonarQube issue consists in extracting - * the relevant properties from the message for the most of it. Furthermore, - * it transforms ESLint fixes into SonarLint quick fixes, if any. On the other - * hand, encoded secondary locations remain in the issue message at this stage - * and are decoded in a subsequent step. - * - * @param source the source code - * @param message the ESLint message to convert - * @returns the converted SonarQube issue - */ -export function convertMessage(source: SourceCode, message: Linter.LintMessage): Issue | null { - /** - * The property `ruleId` equals `null` on parsing errors, but it should not - * happen because we lint ready SourceCode instances and not file contents. - */ - if (!message.ruleId) { - console.error("Illegal 'null' ruleId for eslint issue"); - return null; - } - return { - ruleId: message.ruleId, - line: message.line, - column: message.column, - endLine: message.endLine, - endColumn: message.endColumn, - message: message.message, - quickFixes: transformFixes(source, message), - secondaryLocations: [], - }; -} diff --git a/eslint-bridge/src/linting/eslint/linter/issues/normalize.ts b/eslint-bridge/src/linting/eslint/linter/issues/normalize.ts deleted file mode 100644 index 39c68ca268b..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/issues/normalize.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Issue } from './issue'; - -/** - * Normalizes an issue location - * - * SonarQube uses 0-based column indexing when it comes to issue locations - * while ESLint uses 1-based column indexing for message locations. - * - * @param issue the issue to normalize - * @returns the normalized issue - */ -export function normalizeLocation(issue: Issue): Issue { - issue.column -= 1; - if (issue.endColumn) { - issue.endColumn -= 1; - } - return issue; -} diff --git a/eslint-bridge/src/linting/eslint/linter/issues/transform.ts b/eslint-bridge/src/linting/eslint/linter/issues/transform.ts deleted file mode 100644 index 25e3772ed0c..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/issues/transform.ts +++ /dev/null @@ -1,115 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Linter, Rule, SourceCode } from 'eslint'; -import { decodeSonarRuntime } from './decode'; -import { Issue } from './issue'; -import { convertMessage } from './message'; -import { extractCognitiveComplexity, extractHighlightedSymbols } from './extract'; -import { SymbolHighlight } from '../visitors'; - -/** - * The result of linting a source code - * - * ESLint API returns what it calls messages as results of linting a file. - * A linting result in the context of the analyzer includes more than that - * as it needs not only to transform ESLint messages into SonarQube issues - * as well as analysis data about the analyzed source code, namely symbol - * highlighting and cognitive complexity. - * - * @param issues the issues found in the code - * @param ucfgPaths list of paths of ucfg files written to disk - * @param highlightedSymbols the symbol highlighting of the code - * @param cognitiveComplexity the cognitive complexity of the code - */ -export type LintingResult = { - issues: Issue[]; - ucfgPaths: string[]; - highlightedSymbols: SymbolHighlight[]; - cognitiveComplexity?: number; -}; - -/** - * Transforms ESLint messages into SonarQube issues - * - * The result of linting a source code requires post-linting transformations - * to return SonarQube issues. These transformations include extracting ucfg - * paths, decoding issues with secondary locations as well as converting - * quick fixes. - * - * Besides issues, a few metrics are computed during linting in the form of - * an internal custom rule execution, namely cognitive complexity and symbol - * highlighting. These custom rules also produce issues that are extracted. - * - * Transforming an ESLint message into a SonarQube issue implies: - * - extracting UCFG rule file paths - * - converting ESLint messages into SonarQube issues - * - converting ESLint fixes into SonarLint quick fixes - * - decoding encoded secondary locations - * - normalizing issue locations - * - * @param messages ESLint messages to transform - * @param ctx contextual information - * @returns the linting result - */ -export function transformMessages( - messages: Linter.LintMessage[], - ctx: { sourceCode: SourceCode; rules: Map }, -): LintingResult { - const issues: Issue[] = []; - const ucfgPaths: string[] = []; - - for (const message of messages) { - if (message.ruleId === 'ucfg') { - ucfgPaths.push(message.message); - } else { - let issue = convertMessage(ctx.sourceCode, message); - if (issue !== null) { - issue = normalizeLocation(decodeSonarRuntime(ctx.rules.get(issue.ruleId), issue)); - issues.push(issue); - } - } - } - - const highlightedSymbols = extractHighlightedSymbols(issues); - const cognitiveComplexity = extractCognitiveComplexity(issues); - return { - issues, - ucfgPaths, - highlightedSymbols, - cognitiveComplexity, - }; -} - -/** - * Normalizes an issue location - * - * SonarQube uses 0-based column indexing when it comes to issue locations - * while ESLint uses 1-based column indexing for message locations. - * - * @param issue the issue to normalize - * @returns the normalized issue - */ -function normalizeLocation(issue: Issue): Issue { - issue.column -= 1; - if (issue.endColumn) { - issue.endColumn -= 1; - } - return issue; -} diff --git a/eslint-bridge/src/linting/eslint/linter/parameters/helpers/index.ts b/eslint-bridge/src/linting/eslint/linter/parameters/helpers/index.ts deleted file mode 100644 index 9d761336af4..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/parameters/helpers/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './schema'; diff --git a/eslint-bridge/src/linting/eslint/linter/parameters/helpers/schema.ts b/eslint-bridge/src/linting/eslint/linter/parameters/helpers/schema.ts deleted file mode 100644 index 0b11e52ff32..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/parameters/helpers/schema.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import { debug } from 'helpers'; - -/** - * Extracts the schema of a rule - * @param ruleModule the rule definition - * @param ruleId the rule id - * @returns the extracted rule schema, if any - */ -export function getRuleSchema(ruleModule: Rule.RuleModule | undefined, ruleId: string) { - if (!ruleModule) { - debug(`ruleModule not found for rule ${ruleId}`); - return undefined; - } - if (!ruleModule.meta || !ruleModule.meta.schema) { - return undefined; - } - const { schema } = ruleModule.meta; - return Array.isArray(schema) ? schema : [schema]; -} diff --git a/eslint-bridge/src/linting/eslint/linter/parameters/index.ts b/eslint-bridge/src/linting/eslint/linter/parameters/index.ts deleted file mode 100644 index 3ec32f2f310..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/parameters/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './sonar-context'; -export * from './sonar-runtime'; diff --git a/eslint-bridge/src/linting/eslint/linter/parameters/sonar-context.ts b/eslint-bridge/src/linting/eslint/linter/parameters/sonar-context.ts deleted file mode 100644 index ed2e4c90a21..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/parameters/sonar-context.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import { getRuleSchema } from './helpers/schema'; - -/** - * An internal rule parameter for context-passing support - * - * Rules implemented in the bridge all have access to the global - * context since they share the same code base. However, external - * rules like custom rules don't benefit from the same visibilty. - * - * To remedy this, rules that need to access the global context - * for whatever reason can do so by first setting this parameter: - * - * - * ``` - * meta: { - * schema: [{ - * title: 'sonar-context', - * }] - * } - * ``` - * - * The global context object can then be retrieved from the options - * of ESLint's rule context, that is, `context.options`. - */ -export const SONAR_CONTEXT = 'sonar-context'; - -/** - * Checks if the rule schema sets the `sonar-context` internal parameter - * @param ruleModule the rule definition - * @param ruleId the ESLint rule key - * @returns true if the rule definition includes the parameter - */ -export function hasSonarContextOption( - ruleModule: Rule.RuleModule | undefined, - ruleId: string, -): boolean { - const schema = getRuleSchema(ruleModule, ruleId); - return !!schema && schema.some(option => option.title === SONAR_CONTEXT); -} diff --git a/eslint-bridge/src/linting/eslint/linter/parameters/sonar-runtime.ts b/eslint-bridge/src/linting/eslint/linter/parameters/sonar-runtime.ts deleted file mode 100644 index 5d6a8b055b8..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/parameters/sonar-runtime.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import { getRuleSchema } from './helpers'; - -/** - * An internal rule parameter for secondary location support - * - * ESLint API for reporting messages does not provide a mechanism to - * include more than locations and fixes in the generated report. It - * prevents us from having a proper support for secondary locations. - * - * As a workaround, internal rules (or even decorated ones) that want - * to use secondary locations first need to include in their schema a - * `sonar-runtime` parameter as follows: - * - * ``` - * meta: { - * schema: [{ - * enum: [SONAR_RUNTIME] - * }] - * } - * ``` - * - * Rules then need to encode secondary locations in the report descriptor - * with the `toEncodedMessage` helper. This helper function encodes such - * locations through stringified JSON objects in the `message` property - * of the descriptor. - * - * The linter wrapper eventually decodes issues with secondary locations - * by checking the presence of the internal parameter in the rule schema - * while transforming an ESLint message into a SonarQube issue. - */ -export const SONAR_RUNTIME = 'sonar-runtime'; - -/** - * Checks if the rule schema sets the `sonar-runtime` internal parameter - * @param ruleModule the rule definition - * @param ruleId the ESLint rule key - * @returns true if the rule definition includes the parameter - */ -export function hasSonarRuntimeOption( - ruleModule: Rule.RuleModule | undefined, - ruleId: string, -): boolean { - const schema = getRuleSchema(ruleModule, ruleId); - return !!schema && schema.some(option => !!option.enum && option.enum.includes(SONAR_RUNTIME)); -} diff --git a/eslint-bridge/src/linting/eslint/linter/quickfixes/index.ts b/eslint-bridge/src/linting/eslint/linter/quickfixes/index.ts deleted file mode 100644 index f5cbee9a27b..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/quickfixes/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './messages'; -export * from './quickfix'; -export * from './rules'; -export * from './transform'; diff --git a/eslint-bridge/src/linting/eslint/linter/quickfixes/messages.ts b/eslint-bridge/src/linting/eslint/linter/quickfixes/messages.ts deleted file mode 100644 index b135ca8d2ba..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/quickfixes/messages.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -/** - * A mapping of ESLint rule keys to quick fix messages - * - * Since SonarLint quick fixes always include a message, - * one needs to define a message for every enabled ESLint - * rule that includes a fix. - */ -const quickFixMessages = new Map([ - ['comma-dangle', 'Remove this trailing comma'], - ['eol-last', 'Add a new line at the end of file'], - ['no-extra-semi', 'Remove extra semicolon'], - ['no-trailing-spaces', 'Remove trailing space'], - ['no-var', "Replace 'var' with 'let'"], - ['object-shorthand', 'Use shorthand property'], - ['prefer-const', "Replace with 'const'"], - ['prefer-template', 'Replace with template string literal'], - ['quotes', 'Fix quotes'], - ['radix', 'Add 10 as radix'], - ['semi', 'Add semicolon'], - ['prefer-immediate-return', 'Return value immediately'], - ['prefer-while', "Replace with 'while' loop"], - ['no-empty-interface', 'Replace with type alias'], - ['no-inferrable-types', 'Remove type declaration'], - ['no-unnecessary-type-arguments', 'Remove type argument'], - ['no-unnecessary-type-assertion', 'Remove type assertion'], - ['prefer-namespace-keyword', "Replace with 'namespace' keyword"], - ['prefer-readonly', "Add 'readonly'"], - ['no-non-null-assertion', "Replace with optional chaining '.?'"], -]); - -/** - * Gets the quick fix message for a fixable ESLint rule - * - * A fixable ESLint rule here means an ESLint rule that provides - * a fix that doesn't include a message contrary to suggestions. - * - * @param ruleKey the rule key of a fixable ESLint rule - * @throws a runtime error if there are no corresponding messages - * @returns the corresponding quick fix message - */ -export function getQuickFixMessage(ruleKey: string): string { - if (!quickFixMessages.has(ruleKey)) { - throw Error(`Missing message for quick fix '${ruleKey}'`); - } - return quickFixMessages.get(ruleKey)!; -} diff --git a/eslint-bridge/src/linting/eslint/linter/quickfixes/quickfix.ts b/eslint-bridge/src/linting/eslint/linter/quickfixes/quickfix.ts deleted file mode 100644 index 5876e9d7603..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/quickfixes/quickfix.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Location } from '../issues/location'; - -/** - * A SonarLint quick fix - * - * @param message a message describing an action to trigger - * @param edits a list of changes to apply to the user code - * - * _For the record, ESLint defines two types of code fix:_ - * - * - _A fix is a single change applied to a code snippet_ - * - _Suggestions provide multiple changes at once_ - * - * _ESLint fixes don't include a message contrary to ESLint suggestions._ - */ -export interface QuickFix { - message: string; - edits: QuickFixEdit[]; -} - -/** - * A SonarLint quick fix edit - * - * It represents a change to apply to the user code at a location in the source file. - * - * @param loc a location in the code to change - * @param text a change to apply in the code - */ -export interface QuickFixEdit { - loc: Location; - text: string; -} diff --git a/eslint-bridge/src/linting/eslint/linter/quickfixes/rules.ts b/eslint-bridge/src/linting/eslint/linter/quickfixes/rules.ts deleted file mode 100644 index d7038c254fd..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/quickfixes/rules.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -/** - * The set of enabled rules with quick fixes - * - * The purpose of this set is to declare all the rules providing - * ESLint fixes and suggestions that the linter should consider - * during the transformation of an ESLint message into a SonarQube - * issue, including quick fixes. - * - * This set needs to be updated whenever one wants to provide (or - * filter out) the quick fix of a rule, be it an internal one or - * an external one. - */ -export const quickFixRules = new Set([ - // eslint core - 'comma-dangle', - 'eol-last', - 'no-extra-semi', - 'no-trailing-spaces', - 'no-unsafe-negation', - 'no-var', - 'object-shorthand', - 'prefer-const', - 'prefer-regex-literals', - 'prefer-template', - 'quotes', - 'radix', - 'semi', - - // decorated eslint core - 'no-dupe-keys', - 'no-duplicate-imports', - 'no-empty', - 'no-empty-function', - 'no-throw-literal', - 'no-unreachable', - 'use-isnan', - - // eslint-plugin-sonarjs - 'no-collection-size-mischeck', - 'no-inverted-boolean-check', - 'no-redundant-jump', - 'non-existent-operator', - 'prefer-immediate-return', - 'prefer-single-boolean-return', - 'prefer-while', - - // @typescript-eslint plugin - 'no-empty-interface', - 'no-explicit-any', - 'no-inferrable-types', - 'no-unnecessary-type-arguments', - 'no-unnecessary-type-assertion', - 'prefer-namespace-keyword', - 'prefer-readonly', - 'no-non-null-assertion', - - // decorated @typescript-eslint plugin - 'prefer-for-of', - - // sonarjs - 'different-types-comparison', - 'inverted-assertion-arguments', - 'no-alphabetical-sort', - 'no-commented-code', - 'no-duplicate-in-composite', - 'no-exclusive-tests', - 'no-global-this', - 'no-in-misuse', - 'no-primitive-wrappers', - 'no-redundant-optional', - 'no-redundant-parentheses', - 'no-undefined-argument', - 'no-unthrown-error', - 'no-unused-function-argument', - 'prefer-promise-shorthand', - 'prefer-type-guard', - 'unused-import', -]); diff --git a/eslint-bridge/src/linting/eslint/linter/quickfixes/transform.ts b/eslint-bridge/src/linting/eslint/linter/quickfixes/transform.ts deleted file mode 100644 index b6150c37fd3..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/quickfixes/transform.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Linter, Rule, SourceCode } from 'eslint'; -import { getQuickFixMessage } from './messages'; -import { QuickFix, QuickFixEdit } from './quickfix'; -import { quickFixRules } from './rules'; - -/** - * Transforms ESLint fixes and suggestions into SonarLint quick fixes - * @param source the source code - * @param messages the ESLint messages to transform - * @returns the transformed quick fixes - */ -export function transformFixes(source: SourceCode, messages: Linter.LintMessage): QuickFix[] { - if (!hasQuickFix(messages)) { - return []; - } - const quickFixes: QuickFix[] = []; - if (messages.fix) { - quickFixes.push({ - message: getQuickFixMessage(messages.ruleId!), - edits: [fixToEdit(source, messages.fix)], - }); - } - if (messages.suggestions) { - messages.suggestions.forEach(suggestion => { - quickFixes.push({ - message: suggestion.desc, - edits: [fixToEdit(source, suggestion.fix)], - }); - }); - } - return quickFixes; -} - -/** - * Checks if an ESLint fix is convertible into a SonarLint quick fix - * - * An ESLint fix is convertible into a SonarLint quick fix iff: - * - it includes a fix or suggestions - * - the quick fix of the rule is enabled - * - * @param message an ESLint message - * @returns true if the message is convertible - */ -function hasQuickFix(message: Linter.LintMessage): boolean { - if (!message.fix && (!message.suggestions || message.suggestions.length === 0)) { - return false; - } - return !!message.ruleId && quickFixRules.has(message.ruleId); -} - -/** - * Transform an ESLint fix into a SonarLint quick fix edit - * @param source the source code - * @param fix the ESLint fix to transform - * @returns the transformed SonarLint quick fix edit - */ -function fixToEdit(source: SourceCode, fix: Rule.Fix): QuickFixEdit { - const [start, end] = fix.range; - const startPos = source.getLocFromIndex(start); - const endPos = source.getLocFromIndex(end); - return { - loc: { - line: startPos.line, - column: startPos.column, - endLine: endPos.line, - endColumn: endPos.column, - }, - text: fix.text, - }; -} diff --git a/eslint-bridge/src/linting/eslint/linter/recognizers/CodeRecognizer.ts b/eslint-bridge/src/linting/eslint/linter/recognizers/CodeRecognizer.ts deleted file mode 100644 index 82b4411683d..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/recognizers/CodeRecognizer.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import LanguageFootprint from './LanguageFootprint'; - -export class CodeRecognizer { - language: LanguageFootprint; - threshold: number; - - constructor(threshold: number, language: LanguageFootprint) { - this.language = language; - this.threshold = threshold; - } - - recognition(line: string) { - let probability = 0; - for (const pattern of this.language.getDetectors()) { - probability = 1 - (1 - probability) * (1 - pattern.recognition(line)); - } - return probability; - } - - extractCodeLines(lines: string[]): string[] { - return lines.filter(line => this.recognition(line) >= this.threshold); - } - - isLineOfCode(line: string): boolean { - return this.recognition(line) - this.threshold > 0; - } -} diff --git a/eslint-bridge/src/linting/eslint/linter/recognizers/Detector.ts b/eslint-bridge/src/linting/eslint/linter/recognizers/Detector.ts deleted file mode 100644 index 8b129c08c72..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/recognizers/Detector.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export default abstract class Detector { - probability: number; - - constructor(probability: number) { - if (probability < 0 || probability > 1) { - throw new Error('probability should be between [0 .. 1]'); - } - this.probability = probability; - } - - abstract scan(line: string): number; - - recognition(line: string): number { - const matchers = this.scan(line); - if (matchers === 0) { - return 0; - } else { - return 1 - Math.pow(1 - this.probability, matchers); - } - } -} diff --git a/eslint-bridge/src/linting/eslint/linter/recognizers/JavaScriptFootPrint.ts b/eslint-bridge/src/linting/eslint/linter/recognizers/JavaScriptFootPrint.ts deleted file mode 100644 index 520c2a90843..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/recognizers/JavaScriptFootPrint.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import Detector from './Detector'; -import CamelCaseDetector from './detectors/CamelCaseDetector'; -import ContainsDetector from './detectors/ContainsDetector'; -import EndWithDetector from './detectors/EndWithDetector'; -import KeywordsDetector from './detectors/KeywordsDetector'; -import LanguageFootprint from './LanguageFootprint'; - -export class JavaScriptFootPrint implements LanguageFootprint { - detectors: Set = new Set(); - - constructor() { - this.detectors.add(new EndWithDetector(0.95, '}', ';', '{')); - this.detectors.add(new KeywordsDetector(0.7, '++', '||', '&&', '===', '?.', '??')); - this.detectors.add( - new KeywordsDetector( - 0.3, - 'public', - 'abstract', - 'class', - 'implements', - 'extends', - 'return', - 'throw', - 'private', - 'protected', - 'enum', - 'continue', - 'assert', - 'boolean', - 'this', - 'instanceof', - 'interface', - 'static', - 'void', - 'super', - 'true', - 'case:', - 'let', - 'const', - 'var', - 'async', - 'await', - 'break', - 'yield', - 'typeof', - 'import', - 'export', - ), - ); - this.detectors.add( - new ContainsDetector( - 0.95, - 'for(', - 'if(', - 'while(', - 'catch(', - 'switch(', - 'try{', - 'else{', - 'this.', - 'window.', - /;\s+\/\//, - "import '", - 'import "', - 'require(', - ), - ); - this.detectors.add(new CamelCaseDetector(0.5)); - } - - getDetectors(): Set { - return this.detectors; - } -} diff --git a/eslint-bridge/src/linting/eslint/linter/recognizers/LanguageFootprint.ts b/eslint-bridge/src/linting/eslint/linter/recognizers/LanguageFootprint.ts deleted file mode 100644 index efc7f8fd429..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/recognizers/LanguageFootprint.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import Detector from './Detector'; - -export default interface LanguageFootprint { - getDetectors(): Set; -} diff --git a/eslint-bridge/src/linting/eslint/linter/recognizers/detectors/CamelCaseDetector.ts b/eslint-bridge/src/linting/eslint/linter/recognizers/detectors/CamelCaseDetector.ts deleted file mode 100644 index a792b80ba48..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/recognizers/detectors/CamelCaseDetector.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import Detector from '../Detector'; - -export default class CamelCaseDetector extends Detector { - constructor(probability: number) { - super(probability); - } - - scan(line: string): number { - let previousChar = ' '; - let currentChar; - for (let i = 0; i < line.length; i++) { - currentChar = line.charAt(i); - if (isLowerCaseThenUpperCase(previousChar, currentChar)) { - return 1; - } - previousChar = currentChar; - } - return 0; - } -} - -function isLowerCaseThenUpperCase(previousChar: string, char: string): boolean { - return isLowercase(previousChar) && isUpprcase(char); - - function isLowercase(char: string): boolean { - return char.toLowerCase() === char; - } - function isUpprcase(char: string): boolean { - return char.toUpperCase() === char; - } -} diff --git a/eslint-bridge/src/linting/eslint/linter/recognizers/detectors/ContainsDetector.ts b/eslint-bridge/src/linting/eslint/linter/recognizers/detectors/ContainsDetector.ts deleted file mode 100644 index e558e20a096..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/recognizers/detectors/ContainsDetector.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import Detector from '../Detector'; - -export default class ContainsDetector extends Detector { - strings: (string | RegExp)[]; - - constructor(probability: number, ...strings: (string | RegExp)[]) { - super(probability); - this.strings = strings; - } - - scan(line: string): number { - const lineWithoutSpaces = line.replace(/\s+/, ''); - let matchers = 0; - for (const str of this.strings) { - let regex = str; - if (typeof str === 'string') { - regex = new RegExp(escapeRegex(str), 'g'); - } - matchers += (lineWithoutSpaces.match(regex) || []).length; - } - return matchers; - } -} - -function escapeRegex(value: string) { - return value.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); -} diff --git a/eslint-bridge/src/linting/eslint/linter/recognizers/detectors/EndWithDetector.ts b/eslint-bridge/src/linting/eslint/linter/recognizers/detectors/EndWithDetector.ts deleted file mode 100644 index af59711d5a8..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/recognizers/detectors/EndWithDetector.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import Detector from '../Detector'; - -export default class EndWithDetector extends Detector { - endOfLines: string[]; - - constructor(probability: number, ...endOfLines: string[]) { - super(probability); - this.endOfLines = endOfLines; - } - - scan(line: string): number { - for (let i = line.length - 1; i >= 0; i--) { - const char = line.charAt(i); - for (const endOfLine of this.endOfLines) { - if (char === endOfLine) { - return 1; - } - } - if (!isWhitespace(char) && char !== '*' && char !== '/') { - return 0; - } - } - return 0; - - function isWhitespace(char: string): boolean { - return /\s/.test(char); - } - } -} diff --git a/eslint-bridge/src/linting/eslint/linter/recognizers/detectors/KeywordsDetector.ts b/eslint-bridge/src/linting/eslint/linter/recognizers/detectors/KeywordsDetector.ts deleted file mode 100644 index 6e987ed517a..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/recognizers/detectors/KeywordsDetector.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import Detector from '../Detector'; - -export default class KeywordsDetector extends Detector { - keywords: string[]; - - constructor(probability: number, ...keywords: string[]) { - super(probability); - this.keywords = keywords; - } - - scan(line: string): number { - let matchers = 0; - const words = line.split(/[ \t(),{}]/); - for (const word of words) { - if (this.keywords.includes(word)) { - matchers++; - } - } - return matchers; - } -} diff --git a/eslint-bridge/src/linting/eslint/linter/recognizers/index.ts b/eslint-bridge/src/linting/eslint/linter/recognizers/index.ts deleted file mode 100644 index b93e21646c3..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/recognizers/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// Inspired from sonar-java and sonar-analyzer-commons -// - https://github.com/SonarSource/sonar-java/blob/e3b4ce381eb994235ab811d253953e400d12aab2/java-checks/src/main/java/org/sonar/java/checks/JavaFootprint.java#L31 -// - https://github.com/SonarSource/sonar-analyzer-commons/blob/e2881512ce632259981c65b587652151e876d736/recognizers/src/main/java/org/sonarsource/analyzer/commons/recognizers/CodeRecognizer.java#L25 - -export * from './JavaScriptFootPrint'; -export * from './CodeRecognizer'; diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/cpd.ts b/eslint-bridge/src/linting/eslint/linter/visitors/cpd.ts deleted file mode 100644 index b117bf97661..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/cpd.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { SourceCode, AST } from 'eslint'; -import { visit } from './visitor'; -import { Location } from './metrics/helpers'; - -/** - * A copy-paste detector token (cpd) - * - * A cpd token is used by SonarQube to compute code duplication - * within a code base. It relies on a token location as well as - * an image, that is, the token value except for string literal - * which is anonymised to extend the scope of what a duplicated - * code pattern can be. - * - * @param location the token location - * @param image the token - */ -export interface CpdToken { - location: Location; - image: string; -} - -/** - * Extracts the copy-paste detector (cpd) tokens - * @param sourceCode the source code to extract from - * @returns the cpd tokens - */ -export function getCpdTokens(sourceCode: SourceCode): { cpdTokens: CpdToken[] } { - const cpdTokens: CpdToken[] = []; - const tokens = sourceCode.ast.tokens; - const { jsxTokens, importTokens, requireTokens } = extractTokens(sourceCode); - - tokens.forEach(token => { - let text = token.value; - - if (text.trim().length === 0) { - // for EndOfFileToken and JsxText tokens containing only whitespaces - return; - } - - if (importTokens.includes(token)) { - // for tokens from import statements - return; - } - - if (requireTokens.includes(token)) { - // for tokens from require statements - return; - } - - if (isStringLiteralToken(token) && !jsxTokens.includes(token)) { - text = 'LITERAL'; - } - - const startPosition = token.loc.start; - const endPosition = token.loc.end; - - cpdTokens.push({ - location: { - startLine: startPosition.line, - startCol: startPosition.column, - endLine: endPosition.line, - endCol: endPosition.column, - }, - image: text, - }); - }); - - return { cpdTokens }; -} - -/** - * Extracts specific tokens to be ignored by copy-paste detection - * @param sourceCode the source code to extract from - * @returns a list of tokens to be ignored - */ -function extractTokens(sourceCode: SourceCode): { - jsxTokens: AST.Token[]; - importTokens: AST.Token[]; - requireTokens: AST.Token[]; -} { - const jsxTokens: AST.Token[] = []; - const importTokens: AST.Token[] = []; - const requireTokens: AST.Token[] = []; - visit(sourceCode, (node: estree.Node) => { - const tsNode = node as TSESTree.Node; - switch (tsNode.type) { - case 'JSXAttribute': - if (tsNode.value?.type === 'Literal') { - jsxTokens.push(...sourceCode.getTokens(tsNode.value as estree.Node)); - } - break; - case 'ImportDeclaration': - importTokens.push(...sourceCode.getTokens(tsNode as estree.Node)); - break; - case 'CallExpression': - if (tsNode.callee.type === 'Identifier' && tsNode.callee.name === 'require') { - requireTokens.push(...sourceCode.getTokens(tsNode as estree.Node)); - } - break; - } - }); - return { jsxTokens, importTokens, requireTokens }; -} - -function isStringLiteralToken(token: AST.Token) { - return token.value.startsWith('"') || token.value.startsWith("'") || token.value.startsWith('`'); -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/index.ts b/eslint-bridge/src/linting/eslint/linter/visitors/index.ts deleted file mode 100644 index 9a92a0c2ca6..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './cpd'; -export * from './metrics'; -export * from './symbol-highlighting'; -export * from './syntax-highlighting'; -export * from './visitor'; diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/classes.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/classes.ts deleted file mode 100644 index d03d1252264..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/classes.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { SourceCode } from 'eslint'; -import { visitAndCountIf } from './helpers'; - -/** - * The ESLint class node types - */ -const CLASS_NODES = ['ClassDeclaration', 'ClassExpression']; - -/** - * Computes the number of classes in the source code - */ -export function countClasses(sourceCode: SourceCode): number { - return visitAndCountIf(sourceCode, node => CLASS_NODES.includes(node.type)); -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/comments.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/comments.ts deleted file mode 100644 index d460d71a029..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/comments.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { SourceCode } from 'eslint'; -import { addLines } from './helpers'; - -/** - * A comment marker to tell SonarQube to ignore any issue on the same line - * as the one with a comment whose text is `NOSONAR` (case-insensitive). - */ -const NOSONAR = 'NOSONAR'; - -/** - * Finds the line numbers of comments in the source code - * @param sourceCode the source code to visit - * @param ignoreHeaderComments a flag to ignore file header comments - * @returns the line numbers of comments - */ -export function findCommentLines( - sourceCode: SourceCode, - ignoreHeaderComments: boolean, -): { commentLines: number[]; nosonarLines: number[] } { - const commentLines: Set = new Set(); - const nosonarLines: Set = new Set(); - - let comments = sourceCode.ast.comments; - - // ignore header comments -> comments before first token - const firstToken = sourceCode.getFirstToken(sourceCode.ast); - if (firstToken && ignoreHeaderComments) { - const header = sourceCode.getCommentsBefore(firstToken); - comments = comments.slice(header.length); - } - - for (const comment of comments) { - if (comment.loc) { - const commentValue = comment.value.startsWith('*') - ? comment.value.substring(1).trim() - : comment.value.trim(); - if (commentValue.toUpperCase().startsWith(NOSONAR)) { - addLines(comment.loc.start.line, comment.loc.end.line, nosonarLines); - } else if (commentValue.length > 0) { - addLines(comment.loc.start.line, comment.loc.end.line, commentLines); - } - } - } - - return { - commentLines: Array.from(commentLines).sort((a, b) => a - b), - nosonarLines: Array.from(nosonarLines).sort((a, b) => a - b), - }; -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/compute.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/compute.ts deleted file mode 100644 index d196881569d..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/compute.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { SourceCode } from 'eslint'; -import { countClasses } from './classes'; -import { findCommentLines } from './comments'; -import { computeCyclomaticComplexity } from './cyclomatic-complexity'; -import { findExecutableLines } from './executable-lines'; -import { countFunctions } from './functions'; -import { Metrics } from './metrics'; -import { findNcloc } from './ncloc'; -import { countStatements } from './statements'; - -/** - * Computes the metrics of an ESLint source code - * @param sourceCode the ESLint source code - * @param ignoreHeaderComments a flag to ignore file header comments - * @param cognitiveComplexity the cognitive complexity of the source code - * @returns the source code metrics - */ -export function computeMetrics( - sourceCode: SourceCode, - ignoreHeaderComments: boolean, - cognitiveComplexity = 0, -): Metrics { - return { - ncloc: findNcloc(sourceCode), - ...findCommentLines(sourceCode, ignoreHeaderComments), - executableLines: findExecutableLines(sourceCode), - functions: countFunctions(sourceCode), - statements: countStatements(sourceCode), - classes: countClasses(sourceCode), - complexity: computeCyclomaticComplexity(sourceCode), - cognitiveComplexity, - }; -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/cyclomatic-complexity.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/cyclomatic-complexity.ts deleted file mode 100644 index 7aeacdd20f4..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/cyclomatic-complexity.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { SourceCode } from 'eslint'; -import { visit } from 'linting/eslint'; - -/** - * The ESLint loop node types - */ -const LOOP_NODES = [ - 'ForStatement', - 'ForInStatement', - 'ForOfStatement', - 'WhileStatement', - 'DoWhileStatement', -]; - -/** - * The ESLint conditional node types - */ -const CONDITIONAL_NODES = ['IfStatement', 'ConditionalExpression', 'SwitchCase']; - -/** - * The ESLint function node types - */ -const FUNCTION_NODES = ['FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression']; - -/** - * The ESLint node types increasing complexity - */ -const COMPLEXITY_NODES = [ - ...CONDITIONAL_NODES, - ...FUNCTION_NODES, - ...LOOP_NODES, - 'LogicalExpression', -]; - -/** - * Computes the cyclomatic complexity of an ESLint source code - * @param sourceCode the ESLint source code - * @returns the cyclomatic complexity - */ -export function computeCyclomaticComplexity(sourceCode: SourceCode): number { - let complexity = 0; - visit(sourceCode, node => { - if (COMPLEXITY_NODES.includes(node.type)) { - complexity++; - } - }); - return complexity; -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/executable-lines.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/executable-lines.ts deleted file mode 100644 index 4722c9f3a8b..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/executable-lines.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { SourceCode } from 'eslint'; -import { visit } from 'linting/eslint'; - -/** - * The ESLint executable node types - */ -const EXECUTABLE_NODES = [ - 'ExpressionStatement', - 'IfStatement', - 'LabeledStatement', - 'BreakStatement', - 'ContinueStatement', - 'WithStatement', - 'SwitchStatement', - 'ReturnStatement', - 'ThrowStatement', - 'TryStatement', - 'WhileStatement', - 'DoWhileStatement', - 'ForStatement', - 'ForInStatement', - 'DebuggerStatement', - 'VariableDeclaration', - 'ForOfStatement', -]; - -/** - * Finds the line numbers of executable lines in the source code - */ -export function findExecutableLines(sourceCode: SourceCode): number[] { - const lines: Set = new Set(); - visit(sourceCode, node => { - if (EXECUTABLE_NODES.includes(node.type) && node.loc) { - lines.add(node.loc.start.line); - } - }); - return Array.from(lines).sort((a, b) => a - b); -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/functions.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/functions.ts deleted file mode 100644 index 2c4d53dce62..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/functions.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { SourceCode } from 'eslint'; -import { visitAndCountIf } from './helpers'; - -/** - * The ESLint function node types - */ -const FUNCTION_NODES = ['FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression']; - -/** - * Computes the number of functions in the source code - */ -export function countFunctions(sourceCode: SourceCode): number { - return visitAndCountIf(sourceCode, node => FUNCTION_NODES.includes(node.type)); -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/counter.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/counter.ts deleted file mode 100644 index e299f275841..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/counter.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as estree from 'estree'; -import { SourceCode } from 'eslint'; -import { visit } from 'linting/eslint'; - -/** - * Counts the number of nodes matching a predicate - * @param sourceCode the source code to vist - * @param predicate the condition to count the node - * @returns the number of nodes matching the predicate - */ -export function visitAndCountIf( - sourceCode: SourceCode, - predicate: (node: estree.Node) => boolean, -): number { - let results = 0; - visit(sourceCode, node => { - if (predicate(node)) { - results++; - } - }); - return results; -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/index.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/index.ts deleted file mode 100644 index 9a78f926741..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './counter'; -export * from './lines'; -export * from './location'; -export * from './tokens'; diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/lines.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/lines.ts deleted file mode 100644 index 0222b9d19a5..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/lines.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -/** - * Adds the line numbers within a range into a set - * @param startLine the lower bound - * @param endLine the upper bound - * @param lines the set of lines number to extend - */ -export function addLines(startLine: number, endLine: number, lines: Set) { - for (let line = startLine; line <= endLine; line++) { - lines.add(line); - } -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/location.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/location.ts deleted file mode 100644 index 52bfe6e19c8..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/location.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as estree from 'estree'; - -/** - * A metric location - * - * @param startLine the starting line of the metric - * @param startCol the starting column of the metric - * @param endLine the ending line of the metric - * @param endCol the ending column of the metric - */ -export interface Location { - startLine: number; - startCol: number; - endLine: number; - endCol: number; -} - -/** - * Converts an ESLint location into a metric location - * @param loc the ESLint location to convert - * @returns the converted location - */ -export function convertLocation(loc: estree.SourceLocation): Location { - return { - startLine: loc.start.line, - startCol: loc.start.column, - endLine: loc.end.line, - endCol: loc.end.column, - }; -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/tokens.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/tokens.ts deleted file mode 100644 index 4a941cd0e64..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/helpers/tokens.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { SourceCode } from 'eslint'; -import { AST } from 'vue-eslint-parser'; - -/** - * Extracts comments and tokens from an ESLint source code - * - * The returned extracted comments includes also those from - * the template section of a Vue.js Single File Component. - * - * @param sourceCode the source code to extract from - * @returns the extracted tokens and comments - */ -export function extractTokensAndComments(sourceCode: SourceCode): { - tokens: AST.Token[]; - comments: AST.Token[]; -} { - const ast = sourceCode.ast as AST.ESLintProgram; - const tokens = [...(ast.tokens || [])]; - const comments = [...(ast.comments || [])]; - if (ast.templateBody) { - const { templateBody } = ast; - tokens.push(...templateBody.tokens); - comments.push(...templateBody.comments); - } - return { tokens, comments }; -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/index.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/index.ts deleted file mode 100644 index b73f91597ac..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './compute'; -export * from './metrics'; -export * from './nosonar'; diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/metrics.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/metrics.ts deleted file mode 100644 index 51be452061d..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/metrics.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -/** - * Metrics of the source code - * - * @param ncloc the line numbers of physical code - * @param commentLines the line numbers of comments - * @param nosonarLines the line numbers of NOSONAR comments - * @param executableLines the line numbers of executable code - * @param functions the number of functions - * @param statements the number of statements - * @param classes the number of classes - * @param complexity the cyclomatic complexity - * @param cognitiveComplexity the cognitive complexity - */ -export interface Metrics { - ncloc?: number[]; - commentLines?: number[]; - nosonarLines: number[]; - executableLines?: number[]; - functions?: number; - statements?: number; - classes?: number; - complexity?: number; - cognitiveComplexity?: number; -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/ncloc.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/ncloc.ts deleted file mode 100644 index 586fb721a31..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/ncloc.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { SourceCode } from 'eslint'; -import { AST } from 'vue-eslint-parser'; -import { addLines } from './helpers'; - -/** - * Finds the line numbers of code (ncloc) - * - * The line numbers of code denote physical lines that contain at least - * one character which is neither a whitespace nor a tabulation nor part - * of a comment. - * - * @param sourceCode the ESLint source code - * @returns the line numbers of code - */ -export function findNcloc(sourceCode: SourceCode): number[] { - const lines: Set = new Set(); - const ast = sourceCode.ast as AST.ESLintProgram; - const tokens = [...(ast.tokens || [])]; - if (ast.templateBody) { - tokens.push(...extractVuejsTokens(ast.templateBody)); - } - for (const token of tokens) { - addLines(token.loc.start.line, token.loc.end.line, lines); - } - return Array.from(lines).sort((a, b) => a - b); -} - -/** - * Extracts Vue.js-specific tokens - * - * The template section parsed by `vue-eslint-parser` includes tokens for the whole `.vue` file. - * Everything that is not template-related is either raw text or whitespace. Although the style - * section is not parsed, its tokens are made available. Therefore, in addition to the tokens of - * the script section, we consider tokens from the template and style sections as well, provided - * that they don't denote whitespace or comments. - */ -function extractVuejsTokens(templateBody: AST.VElement & AST.HasConcreteInfo) { - const tokens = []; - - let withinStyle = false; - let withinComment = false; - for (const token of templateBody.tokens) { - /** - * Style section - */ - if (token.type === 'HTMLTagOpen' && token.value === 'style') { - withinStyle = true; - } else if (token.type === 'HTMLEndTagOpen' && token.value === 'style') { - withinStyle = false; - } - - /** - * Whitespace tokens should be ignored in accordance with the - * definition of ncloc. - */ - if (token.type === 'HTMLWhitespace') { - continue; - } - - /** - * Tokens of type 'HTMLRawText' denote either tokens from the - * style section or tokens from the script section. Since the - * tokens from the script section are already retrieved from - * the root of the ast, we ignore those and only consider the - * tokens from the style section. - */ - if (token.type === 'HTMLRawText' && !withinStyle) { - continue; - } - - /** - * CSS comment tokens should be ignored in accordance with the - * definition of ncloc. - */ - if (withinStyle && !withinComment && token.value === '/*') { - withinComment = true; - continue; - } else if (withinStyle && withinComment) { - withinComment = token.value !== '*/'; - continue; - } - - tokens.push(token); - } - - return tokens; -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/nosonar.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/nosonar.ts deleted file mode 100644 index 0d7fb96d40b..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/nosonar.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { SourceCode } from 'eslint'; -import { findCommentLines } from './comments'; - -/** - * Finds the line numbers of `NOSONAR` comments - * - * `NOSONAR` comments are indicators for SonarQube to ignore - * any issues raised on the same lines as those where appear - * such comments. - * - * @param sourceCode the source code to visit - * @returns the line numbers of `NOSONAR` comments - */ -export function findNoSonarLines(sourceCode: SourceCode) { - return { - nosonarLines: findCommentLines(sourceCode, false).nosonarLines, - }; -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/statements.ts b/eslint-bridge/src/linting/eslint/linter/visitors/metrics/statements.ts deleted file mode 100644 index a51affb8a5e..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/metrics/statements.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { SourceCode } from 'eslint'; -import { visitAndCountIf } from './helpers'; - -/** - * The ESLint statement node types - */ -const STATEMENT_NODES = [ - 'VariableDeclaration', - 'EmptyStatement', - 'ExpressionStatement', - 'IfStatement', - 'DoWhileStatement', - 'WhileStatement', - 'ForInStatement', - 'ForOfStatement', - 'ForStatement', - 'ContinueStatement', - 'BreakStatement', - 'ReturnStatement', - 'WithStatement', - 'SwitchStatement', - 'ThrowStatement', - 'TryStatement', - 'DebuggerStatement', -]; - -/** - * Computes the number of statements in the source code - */ -export function countStatements(sourceCode: SourceCode): number { - return visitAndCountIf(sourceCode, node => STATEMENT_NODES.includes(node.type)); -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/symbol-highlighting.ts b/eslint-bridge/src/linting/eslint/linter/visitors/symbol-highlighting.ts deleted file mode 100644 index 08f7fb1d432..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/symbol-highlighting.ts +++ /dev/null @@ -1,143 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { AST } from 'vue-eslint-parser'; -import { convertLocation, extractTokensAndComments, Location } from './metrics/helpers'; - -/** - * A symbol highlight - * - * @param declaration the location where the symbol is declared - * @param references the locations where the symbol is referenced - */ -export interface SymbolHighlight { - declaration: Location; - references: Location[]; -} - -/** - * A rule for computing the symbol highlighting of the source code - * - * We use an ESLint rule as we need to access declared variables which - * are only available only through the rule context. - */ -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - let variables: Set; - - /* - Remove TypeAnnotation part from location of identifier for purpose of symbol highlighting. - This was motivated by following code - - var XMLHttpRequest: { - new(): XMLHttpRequest; // this is reference to var, not interface - }; - interface XMLHttpRequest {} - - where XMLHttpRequest is both type and variable name. Issue type annotation inside the variable declaration - is reference to the variable (this is likely a bug in parser), which causes overlap between declaration and - reference, which makes SQ API fail with RuntimeException. As a workaround we remove TypeAnnotation part of - identifier node from its location, so no overlap is possible (arguably this is also better UX for symbol - highlighting). - */ - function identifierLocation(node: TSESTree.Node) { - const source = context.getSourceCode(); - const loc = { - start: node.loc.start, - end: - node.type === 'Identifier' && node.typeAnnotation - ? source.getLocFromIndex(node.typeAnnotation.range[0]) - : node.loc.end, - }; - return convertLocation(loc); - } - - return { - Program() { - // clear "variables" for each file - variables = new Set(); - }, - '*': (node: estree.Node) => { - context.getDeclaredVariables(node).forEach(v => variables.add(v)); - }, - 'Program:exit': (node: estree.Node) => { - const result: SymbolHighlight[] = []; - variables.forEach(v => { - // if variable is initialized during declaration it is part of references as well - // so we merge declarations and references to remove duplicates and take the earliest in the file as the declaration - const allRef = [ - ...new Set([...v.defs.map(d => d.name), ...v.references.map(r => r.identifier)]), - ] - .filter(i => !!i.loc) - .sort((a, b) => a.loc!.start.line - b.loc!.start.line); - if (allRef.length === 0) { - // defensive check, this should never happen - return; - } - const highlightedSymbol: SymbolHighlight = { - declaration: identifierLocation(allRef[0] as TSESTree.Node), - references: allRef.slice(1).map(r => identifierLocation(r as TSESTree.Node)), - }; - result.push(highlightedSymbol); - }); - - const openCurlyBracesStack: AST.Token[] = []; - const openHtmlTagsStack: AST.Token[] = []; - extractTokensAndComments(context.getSourceCode()).tokens.forEach(token => { - switch (token.type) { - case 'Punctuator': - if (token.value === '{') { - openCurlyBracesStack.push(token); - } else if (token.value === '}') { - const highlightedSymbol: SymbolHighlight = { - declaration: convertLocation(openCurlyBracesStack.pop()!.loc), - references: [convertLocation(token.loc)], - }; - result.push(highlightedSymbol); - } - break; - case 'HTMLTagOpen': - openHtmlTagsStack.push(token); - break; - case 'HTMLSelfClosingTagClose': - openHtmlTagsStack.pop(); - break; - case 'HTMLEndTagOpen': - const openHtmlTag = openHtmlTagsStack.pop(); - if (openHtmlTag) { - const highlightedSymbol: SymbolHighlight = { - declaration: convertLocation(openHtmlTag.loc), - references: [convertLocation(token.loc)], - }; - result.push(highlightedSymbol); - } - break; - } - }); - - // as issues are the only communication channel of a rule - // we pass data as serialized json as an issue message - context.report({ node, message: JSON.stringify(result) }); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/syntax-highlighting.ts b/eslint-bridge/src/linting/eslint/linter/visitors/syntax-highlighting.ts deleted file mode 100644 index 5bb58d13ddd..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/syntax-highlighting.ts +++ /dev/null @@ -1,107 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { SourceCode } from 'eslint'; -import * as ESTree from 'estree'; -import { AST } from 'vue-eslint-parser'; -import { extractTokensAndComments, Location } from './metrics/helpers'; - -/** - * A syntax highlight - * - * A syntax highlight is used by SonarQube to display a source code - * with syntax highlighting. - * - * @param location the highlight location - * @param textType the highlight type - */ -export interface SyntaxHighlight { - location: Location; - textType: TextType; -} - -/** - * Denotes a highlight type of a token - * - * The set of possible values for a token highlight is defined by SonarQube, which - * uses this value to decide how to highlight a token. - */ -export type TextType = 'CONSTANT' | 'COMMENT' | 'STRUCTURED_COMMENT' | 'KEYWORD' | 'STRING'; - -/** - * Computes the syntax highlighting of an ESLint source code - * @param sourceCode the source code to highlight - * @returns a list of highlighted tokens - */ -export function getSyntaxHighlighting(sourceCode: SourceCode) { - const { tokens, comments } = extractTokensAndComments(sourceCode); - const highlights: SyntaxHighlight[] = []; - for (const token of tokens) { - switch (token.type as any) { - case 'HTMLTagOpen': - case 'HTMLTagClose': - case 'HTMLEndTagOpen': - case 'HTMLSelfClosingTagClose': - case 'Keyword': - highlight(token, 'KEYWORD', highlights); - break; - case 'HTMLLiteral': - case 'String': - case 'Template': - case 'RegularExpression': - highlight(token, 'STRING', highlights); - break; - case 'Numeric': - highlight(token, 'CONSTANT', highlights); - break; - } - } - for (const comment of comments) { - if ( - (comment.type === 'Block' && comment.value.startsWith('*')) || - comment.type === 'HTMLBogusComment' - ) { - highlight(comment, 'STRUCTURED_COMMENT', highlights); - } else { - highlight(comment, 'COMMENT', highlights); - } - } - return { highlights }; -} - -function highlight( - node: AST.Token | ESTree.Comment, - highlightKind: TextType, - highlights: SyntaxHighlight[], -) { - if (!node.loc) { - return; - } - const startPosition = node.loc.start; - const endPosition = node.loc.end; - highlights.push({ - location: { - startLine: startPosition.line, - startCol: startPosition.column, - endLine: endPosition.line, - endCol: endPosition.column, - }, - textType: highlightKind, - }); -} diff --git a/eslint-bridge/src/linting/eslint/linter/visitors/visitor.ts b/eslint-bridge/src/linting/eslint/linter/visitors/visitor.ts deleted file mode 100644 index 2e011ed0ee6..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/visitors/visitor.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as estree from 'estree'; -import { SourceCode } from 'eslint'; - -/** - * Visits the abstract syntax tree of an ESLint source code - * @param sourceCode the source code to visit - * @param callback a callback function invoked at each node visit - */ -export function visit(sourceCode: SourceCode, callback: (node: estree.Node) => void): void { - const stack: estree.Node[] = [sourceCode.ast]; - while (stack.length) { - const node = stack.pop() as estree.Node; - callback(node); - stack.push(...childrenOf(node, sourceCode.visitorKeys).reverse()); - } -} - -/** - * Returns the direct children of a node - * @param node the node to get the children - * @param visitorKeys the visitor keys provided by the source code - * @returns the node children - */ -export function childrenOf(node: estree.Node, visitorKeys: SourceCode.VisitorKeys): estree.Node[] { - const keys = visitorKeys[node.type]; - const children = []; - if (keys) { - for (const key of keys) { - /** - * A node's child may be a node or an array of nodes, e.g., `body` in `estree.Program`. - * If it's an array, we extract all the nodes from it; if not, we just add the node. - */ - const child = (node as any)[key]; - if (Array.isArray(child)) { - children.push(...child); - } else { - children.push(child); - } - } - } - return children.filter(Boolean); -} diff --git a/eslint-bridge/src/linting/eslint/linter/wrapper.ts b/eslint-bridge/src/linting/eslint/linter/wrapper.ts deleted file mode 100644 index e247daade44..00000000000 --- a/eslint-bridge/src/linting/eslint/linter/wrapper.ts +++ /dev/null @@ -1,163 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Linter, SourceCode } from 'eslint'; -import { loadBundles, loadCustomRules } from './bundle-loader'; -import { createLinterConfig, RuleConfig } from './config'; -import { FileType } from 'helpers'; -import { transformMessages, LintingResult } from './issues'; -import { CustomRule } from './custom-rules'; - -/** - * Wrapper's constructor initializer. All the parameters are optional, - * having the option to create a Linter without any additional rules - * loaded, aside of the preexisting ESLint core rules. - * - * @param inputRules the quality profile rules, enabled rules - * @param environments the JavaScript environments - * @param globals the global variables - * @param ruleBundles the bundles of rules to load in the linter - * @param customRules array of rules to load in the linter - */ -export interface WrapperOptions { - inputRules?: RuleConfig[]; - environments?: string[]; - globals?: string[]; - ruleBundles?: string[]; - customRules?: CustomRule[]; -} - -/** - * When a linter is created, by default all these bundles of rules will - * be loaded into the linter internal rules map. This behaviour can be - * adjusted by passing which bundles, if any, should be loaded instead. - * The order of this array is important here. Rules from a previous bundle - * will be overridden by the implementation of the same rule key in a - * subsequent bundle. - */ -const defaultRuleBundles = [ - 'externalRules', - 'pluginRules', - 'internalRules', - 'contextRules', - 'internalCustomRules', -]; - -/** - * A wrapper of ESLint linter - * - * The purpose of the wrapper is to configure the behaviour of ESLint linter, - * which includes: - * - * - defining the rules that should be used during linting, - * - declaring globals that need to be considered as such - * - defining the environments bringing a set of predefined variables - * - * Because some rules target main files while other target test files (or even - * both), the wrapper relies on two linting configurations to decide which set - * of rules should be considered during linting. - * - * Last but not least, the linter wrapper eventually turns ESLint problems, - * also known as messages, into SonarQube issues. - */ -export class LinterWrapper { - /** The wrapper's internal ESLint linter instance */ - readonly linter: Linter; - - /** The wrapper's linting configuration */ - readonly config: { [key in FileType]: Linter.Config }; - - /** - * Constructs an ESLint linter wrapper - * - * Constructing a linter wrapper consists in building the rule database - * the internal ESLint linter shall consider during linting. Furthermore, - * it creates a linting configuration that configures which rules should - * be used on linting based on the active quality profile and file type. - * - * The order of defining rules is important here because internal rules - * and external ones might share the same name by accident, which would - * unexpectedly overwrite the behaviour of the internal one in favor of - * the external one. This is why some internal rules are named with the - * prefix `sonar-`, e.g., `sonar-no-fallthrough`. - * - * @param options the wrapper's options - */ - constructor(options: WrapperOptions = {}) { - this.linter = new Linter(); - loadBundles(this.linter, options.ruleBundles ?? defaultRuleBundles); - loadCustomRules(this.linter, options.customRules); - this.config = this.createConfig(options); - } - - /** - * Lints an ESLint source code instance - * - * Linting a source code implies using ESLint linting functionality to find - * problems in the code. It selects which linting configuration needs to be - * considered during linting based on the file type. - * - * @param sourceCode the ESLint source code - * @param filePath the path of the source file - * @param fileType the type of the source file - * @returns the linting result - */ - lint(sourceCode: SourceCode, filePath: string, fileType: FileType = 'MAIN'): LintingResult { - const fileTypeConfig = this.config[fileType]; - const config = { ...fileTypeConfig, settings: { ...fileTypeConfig.settings, fileType } }; - const options = { filename: filePath, allowInlineConfig: false }; - const messages = this.linter.verify(sourceCode, config, options); - return transformMessages(messages, { sourceCode, rules: this.linter.getRules() }); - } - - /** - * Creates the wrapper's linting configuration - * - * The wrapper's linting configuration actually includes two - * ESLint configurations: one per file type. - * - * @returns the wrapper's linting configuration - */ - private createConfig(options: WrapperOptions) { - const mainRules: RuleConfig[] = []; - const testRules: RuleConfig[] = []; - for (const inputRule of options.inputRules ?? []) { - if (inputRule.fileTypeTarget.includes('MAIN')) { - mainRules.push(inputRule); - } - if (inputRule.fileTypeTarget.includes('TEST')) { - testRules.push(inputRule); - } - } - const linterRules = this.linter.getRules(); - const mainConfig = createLinterConfig( - mainRules, - linterRules, - options.environments ?? [], - options.globals ?? [], - ); - const testConfig = createLinterConfig( - testRules, - linterRules, - options.environments ?? [], - options.globals ?? [], - ); - return { ['MAIN']: mainConfig, ['TEST']: testConfig }; - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/anchor-precedence.ts b/eslint-bridge/src/linting/eslint/rules/anchor-precedence.ts deleted file mode 100644 index d920c14fb18..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/anchor-precedence.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5850/javascript - -import { Rule } from 'eslint'; -import { AST } from 'regexpp'; -import { createRegExpRule } from './helpers/regex'; - -enum Position { - BEGINNING, - END, -} - -export const rule: Rule.RuleModule = createRegExpRule(context => { - return { - onPatternEnter: (pattern: AST.Pattern) => { - const { alternatives } = pattern; - if ( - alternatives.length > 1 && - (anchoredAt(alternatives, Position.BEGINNING) || anchoredAt(alternatives, Position.END)) && - notAnchoredElseWhere(alternatives) - ) { - context.reportRegExpNode({ - message: - 'Group parts of the regex together to make the intended operator precedence explicit.', - node: context.node, - regexpNode: pattern, - }); - } - }, - }; -}); - -function anchoredAt(alternatives: AST.Alternative[], position: Position): boolean { - const itemIndex = position === Position.BEGINNING ? 0 : alternatives.length - 1; - const firstOrLast = alternatives[itemIndex]; - return isAnchored(firstOrLast, position); -} - -function notAnchoredElseWhere(alternatives: AST.Alternative[]): boolean { - if ( - isAnchored(alternatives[0], Position.END) || - isAnchored(alternatives[alternatives.length - 1], Position.BEGINNING) - ) { - return false; - } - for (const alternative of alternatives.slice(1, alternatives.length - 1)) { - if (isAnchored(alternative, Position.BEGINNING) || isAnchored(alternative, Position.END)) { - return false; - } - } - return true; -} - -function isAnchored(alternative: AST.Alternative, position: Position): boolean { - const { elements } = alternative; - if (elements.length === 0) { - return false; - } - const index = position === Position.BEGINNING ? 0 : elements.length - 1; - const firstOrLast = elements[index]; - return isAnchor(firstOrLast); -} - -function isAnchor(element: AST.Element) { - return element.type === 'Assertion' && (element.kind === 'start' || element.kind === 'end'); -} diff --git a/eslint-bridge/src/linting/eslint/rules/argument-type.ts b/eslint-bridge/src/linting/eslint/rules/argument-type.ts deleted file mode 100644 index dcb8e81afae..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/argument-type.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3782/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getTypeFromTreeNode, isRequiredParserServices } from './helpers'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import ts, { SyntaxKind } from 'typescript'; - -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - const tc = services.program.getTypeChecker(); - - function isBuiltInMethod(symbol: ts.Symbol) { - const parent = symbol.valueDeclaration?.parent; - if (!parent || parent.kind !== SyntaxKind.InterfaceDeclaration) { - return false; - } - const parentSymbol = tc.getSymbolAtLocation((parent as ts.InterfaceDeclaration).name); - if (!parentSymbol) { - return false; - } - const fqn = tc.getFullyQualifiedName(parentSymbol); - // some of the built-in objects are deliberately excluded, because they generate many FPs - // and no relevant TP, e.g. RegExp, Function - return ['String', 'Math', 'Array', 'Number', 'Date'].includes(fqn); - } - - function isVarArg(param: ts.ParameterDeclaration) { - return !!param.dotDotDotToken; - } - - function isTypeParameter(type: ts.Type) { - return type.getFlags() & ts.TypeFlags.TypeParameter; - } - - function declarationMismatch( - declaration: ts.SignatureDeclaration, - callExpression: estree.CallExpression, - ) { - const parameters = declaration.parameters; - for (let i = 0; i < Math.min(parameters.length, callExpression.arguments.length); i++) { - const parameterType = parameters[i].type; - if (!parameterType) { - return null; - } - const declaredType = tc.getTypeFromTypeNode(parameterType); - const actualType = getTypeFromTreeNode(callExpression.arguments[i], services); - if ( - // @ts-ignore private API, see https://github.com/microsoft/TypeScript/issues/9879 - !tc.isTypeAssignableTo(actualType, declaredType) && - !isTypeParameter(declaredType) && - !ts.isFunctionTypeNode(parameterType) && - !isVarArg(parameters[i]) - ) { - return { actualType, declaredType, node: callExpression.arguments[i] }; - } - } - return null; - } - - function typeToString(type: ts.Type) { - return tc.typeToString(tc.getBaseTypeOfLiteralType(type)); - } - - return { - CallExpression: (node: estree.Node) => { - const callExpression = node as estree.CallExpression; - const tsCallExpr = services.esTreeNodeToTSNodeMap.get( - callExpression.callee as TSESTree.Node, - ); - const symbol = tc.getSymbolAtLocation(tsCallExpr); - - if (symbol && symbol.declarations && isBuiltInMethod(symbol)) { - let mismatch: { - actualType: ts.Type; - declaredType: ts.Type; - node: estree.Node; - } | null = null; - for (const declaration of symbol.declarations) { - mismatch = declarationMismatch(declaration as ts.SignatureDeclaration, callExpression); - if (!mismatch) { - return; - } - } - if (mismatch) { - context.report({ - node: mismatch.node, - message: `Verify that argument is of correct type: expected '${typeToString( - mismatch.declaredType, - )}' instead of '${typeToString(mismatch.actualType)}'.`, - }); - } - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/arguments-order.ts b/eslint-bridge/src/linting/eslint/rules/arguments-order.ts deleted file mode 100644 index 8d5448e0f97..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/arguments-order.ts +++ /dev/null @@ -1,273 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2234/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { EncodedMessage } from 'eslint-plugin-sonarjs/lib/utils/locations'; -import { isIdentifier } from 'eslint-plugin-sonarjs/lib/utils/nodes'; -import { - FunctionNodeType, - isRequiredParserServices, - isFunctionNode, - resolveFromFunctionReference, - getSignatureFromCallee, - getTypeAsString, - resolveIdentifiers, -} from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -interface FunctionSignature { - params: Array; - declaration?: FunctionNodeType; -} - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - - create(context: Rule.RuleContext) { - const services = context.parserServices; - const canResolveType = isRequiredParserServices(services); - - function checkArguments(functionCall: estree.CallExpression) { - const resolvedFunction = resolveFunctionDeclaration(functionCall); - if (!resolvedFunction) { - return; - } - - const { params: functionParameters, declaration: functionDeclaration } = resolvedFunction; - const argumentNames = functionCall.arguments.map(arg => { - const argument = arg as TSESTree.Node; - return isIdentifier(argument) ? argument.name : undefined; - }); - - for (let argumentIndex = 0; argumentIndex < argumentNames.length; argumentIndex++) { - const argumentName = argumentNames[argumentIndex]; - if (argumentName) { - const swappedArgumentName = getSwappedArgumentName( - argumentNames, - functionParameters, - argumentName, - argumentIndex, - functionCall, - ); - if (swappedArgumentName && !areComparedArguments([argumentName, swappedArgumentName])) { - raiseIssue(argumentName, swappedArgumentName, functionDeclaration, functionCall); - return; - } - } - } - } - - function areComparedArguments(argumentNames: string[]): boolean { - function getName(node: estree.Node): string | undefined { - switch (node.type) { - case 'Identifier': - return node.name; - case 'CallExpression': - return getName(node.callee); - case 'MemberExpression': - return getName(node.object); - default: - return undefined; - } - } - function checkComparedArguments(lhs: estree.Node, rhs: estree.Node): boolean { - return ( - [lhs, rhs].map(getName).filter(name => name && argumentNames.includes(name)).length === - argumentNames.length - ); - } - const maybeIfStmt = context - .getAncestors() - .reverse() - .find(ancestor => ancestor.type === 'IfStatement'); - if (maybeIfStmt) { - const { test } = maybeIfStmt as estree.IfStatement; - switch (test.type) { - case 'BinaryExpression': - const binExpr = test; - if (['==', '!=', '===', '!==', '<', '<=', '>', '>='].includes(binExpr.operator)) { - const { left: lhs, right: rhs } = binExpr; - return checkComparedArguments(lhs, rhs); - } - break; - case 'CallExpression': - const callExpr = test; - if (callExpr.arguments.length === 1 && callExpr.callee.type === 'MemberExpression') { - const [lhs, rhs] = [callExpr.callee.object, callExpr.arguments[0]]; - return checkComparedArguments(lhs, rhs); - } - break; - } - } - return false; - } - - function resolveFunctionDeclaration(node: estree.CallExpression): FunctionSignature | null { - if (canResolveType) { - return resolveFromTSSignature(node); - } - - let functionDeclaration: FunctionNodeType | null = null; - - if (isFunctionNode(node.callee)) { - functionDeclaration = node.callee; - } else if (node.callee.type === 'Identifier') { - functionDeclaration = resolveFromFunctionReference(context, node.callee); - } - - if (!functionDeclaration) { - return null; - } - - return { - params: extractFunctionParameters(functionDeclaration), - declaration: functionDeclaration, - }; - } - - function resolveFromTSSignature(node: estree.CallExpression) { - const signature = getSignatureFromCallee(node, services); - if (signature && signature.declaration) { - return { - params: signature.parameters.map(param => param.name), - declaration: services.tsNodeToESTreeNodeMap.get(signature.declaration), - }; - } - return null; - } - - function getSwappedArgumentName( - argumentNames: Array, - functionParameters: Array, - argumentName: string, - argumentIndex: number, - node: estree.CallExpression, - ) { - const indexInFunctionDeclaration = functionParameters.findIndex( - functionParameterName => functionParameterName === argumentName, - ); - if (indexInFunctionDeclaration >= 0 && indexInFunctionDeclaration !== argumentIndex) { - const potentiallySwappedArgument = argumentNames[indexInFunctionDeclaration]; - if ( - potentiallySwappedArgument && - potentiallySwappedArgument === functionParameters[argumentIndex] && - haveCompatibleTypes( - node.arguments[argumentIndex], - node.arguments[indexInFunctionDeclaration], - ) - ) { - return potentiallySwappedArgument; - } - } - return null; - } - - function haveCompatibleTypes(arg1: estree.Node, arg2: estree.Node) { - if (canResolveType) { - const type1 = normalizeType(getTypeAsString(arg1, services)); - const type2 = normalizeType(getTypeAsString(arg2, services)); - return type1 === type2; - } - return true; - } - - function raiseIssue( - arg1: string, - arg2: string, - functionDeclaration: FunctionNodeType | undefined, - node: estree.CallExpression, - ) { - const primaryMessage = `Arguments '${arg1}' and '${arg2}' have the same names but not the same order as the function parameters.`; - const encodedMessage: EncodedMessage = { - message: primaryMessage, - secondaryLocations: getSecondaryLocations(functionDeclaration), - }; - - context.report({ - message: JSON.stringify(encodedMessage), - loc: getParametersClauseLocation(node.arguments), - }); - } - - return { - NewExpression: (node: estree.Node) => { - checkArguments(node as estree.NewExpression); - }, - CallExpression: (node: estree.Node) => { - checkArguments(node as estree.CallExpression); - }, - }; - }, -}; - -function extractFunctionParameters(functionDeclaration: FunctionNodeType) { - return functionDeclaration.params.map(param => { - const identifiers = resolveIdentifiers(param as TSESTree.Node); - if (identifiers.length === 1 && identifiers[0]) { - return identifiers[0].name; - } - return undefined; - }); -} - -function getSecondaryLocations(functionDeclaration: FunctionNodeType | undefined) { - if (functionDeclaration && functionDeclaration.params && functionDeclaration.params.length > 0) { - const { start, end } = getParametersClauseLocation(functionDeclaration.params); - return [ - { - message: 'Formal parameters', - line: start.line, - column: start.column, - endLine: end.line, - endColumn: end.column, - }, - ]; - } - return []; -} - -function getParametersClauseLocation(parameters: Array) { - const firstParam = parameters[0] as TSESTree.Node; - const lastParam = parameters[parameters.length - 1] as TSESTree.Node; - return { start: firstParam.loc.start, end: lastParam.loc.end }; -} - -function normalizeType(typeAsString: string) { - switch (typeAsString) { - case 'String': - return 'string'; - case 'Boolean': - return 'boolean'; - case 'Number': - return 'number'; - default: - return typeAsString; - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/arguments-usage.ts b/eslint-bridge/src/linting/eslint/rules/arguments-usage.ts deleted file mode 100644 index a85517f1466..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/arguments-usage.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3513/javascript - -import { Rule, Scope } from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -const MESSAGE = "Use the rest syntax to declare this function's arguments."; -const SECONDARY_MESSAGE = 'Replace this reference to "arguments".'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - return { - // Ignore root scope containing global variables - 'Program:exit': () => - context - .getScope() - .childScopes.forEach(child => checkArgumentsUsageInScopeRecursively(context, child)), - }; - }, -}; - -function checkArgumentsUsageInScopeRecursively( - context: Rule.RuleContext, - scope: Scope.Scope, -): void { - scope.variables - .filter(variable => variable.name === 'arguments') - .forEach(variable => checkArgumentsVariableWithoutDefinition(context, variable)); - scope.childScopes.forEach(child => checkArgumentsUsageInScopeRecursively(context, child)); -} - -function checkArgumentsVariableWithoutDefinition( - context: Rule.RuleContext, - variable: Scope.Variable, -): void { - // if variable is a parameter, variable.defs contains one ParameterDefinition with a type: 'Parameter' - // if variable is a local variable, variable.defs contains one Definition with a type: 'Variable' - // but if variable is the function arguments, variable.defs is just empty without other hint - const isLocalVariableOrParameter = variable.defs.length > 0; - const references = variable.references.filter(ref => !isFollowedByLengthProperty(ref)); - if (!isLocalVariableOrParameter && references.length > 0) { - const firstReference = references[0]; - const secondaryLocations = references.slice(1).map(ref => ref.identifier) as TSESTree.Node[]; - context.report({ - node: firstReference.identifier, - message: toEncodedMessage( - MESSAGE, - secondaryLocations, - Array(secondaryLocations.length).fill(SECONDARY_MESSAGE), - ), - }); - } -} - -function isFollowedByLengthProperty(reference: Scope.Reference): boolean { - const parent = (reference.identifier as TSESTree.Node).parent; - return ( - !!parent && - parent.type === 'MemberExpression' && - parent.property.type === 'Identifier' && - parent.property.name === 'length' - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/array-callback-without-return.ts b/eslint-bridge/src/linting/eslint/rules/array-callback-without-return.ts deleted file mode 100644 index 4c2f9aa5a45..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/array-callback-without-return.ts +++ /dev/null @@ -1,118 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3796/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { getMainFunctionTokenLocation } from 'eslint-plugin-sonarjs/lib/utils/locations'; -import { - isArray, - RequiredParserServices, - isRequiredParserServices, - isMemberExpression, - RuleContext, -} from './helpers'; - -const message = `Add a "return" statement to this callback.`; - -const methodsWithCallback = [ - 'every', - 'filter', - 'find', - 'findIndex', - 'map', - 'reduce', - 'reduceRight', - 'some', - 'sort', -]; - -function hasCallBackWithoutReturn(argument: estree.Node, services: RequiredParserServices) { - const checker = services.program.getTypeChecker(); - const type = checker.getTypeAtLocation( - services.esTreeNodeToTSNodeMap.get(argument as TSESTree.Node), - ); - const signatures = type.getCallSignatures(); - return ( - signatures.length > 0 && - signatures.every(sig => checker.typeToString(sig.getReturnType()) === 'void') - ); -} - -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - const services = context.parserServices; - - if (!isRequiredParserServices(services)) { - return {}; - } - - return { - 'CallExpression[callee.type="MemberExpression"]'(node: estree.Node) { - const callExpression = node as estree.CallExpression; - const args = callExpression.arguments; - const memberExpression = callExpression.callee as estree.MemberExpression; - const { property, object } = memberExpression; - if (memberExpression.computed || property.type !== 'Identifier' || args.length === 0) { - return; - } - if ( - methodsWithCallback.includes(property.name) && - isArray(object, services) && - hasCallBackWithoutReturn(args[0], services) - ) { - context.report({ - message, - ...getNodeToReport(args[0], node, context), - }); - } else if ( - isMemberExpression(callExpression.callee, 'Array', 'from') && - args.length > 1 && - hasCallBackWithoutReturn(args[1], services) - ) { - context.report({ - message, - ...getNodeToReport(args[1], node, context), - }); - } - }, - }; - }, -}; - -function getNodeToReport(node: estree.Node, parent: estree.Node, context: Rule.RuleContext) { - if ( - node.type === 'FunctionDeclaration' || - node.type === 'FunctionExpression' || - node.type === 'ArrowFunctionExpression' - ) { - return { - loc: getMainFunctionTokenLocation( - node as TSESTree.FunctionLike, - parent as TSESTree.Node, - context as unknown as RuleContext, - ), - }; - } - return { - node, - }; -} diff --git a/eslint-bridge/src/linting/eslint/rules/array-constructor.ts b/eslint-bridge/src/linting/eslint/rules/array-constructor.ts deleted file mode 100644 index ed65aa46af9..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/array-constructor.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1528/javascript -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - function checkNewExpression(node: estree.Node) { - const newExpression = node as estree.NewExpression; - if (newExpression.callee.type === 'Identifier' && newExpression.callee.name === 'Array') { - let message = 'Use either a literal or "Array.from()" instead of the "Array" constructor.'; - if ( - newExpression.arguments.length === 1 && - newExpression.arguments[0].type === 'Literal' && - typeof newExpression.arguments[0].value === 'number' - ) { - message = 'Use "Array.from()" instead of the "Array" constructor.'; - } - context.report({ node, message }); - } - } - - return { - NewExpression: checkNewExpression, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/arrow-function-convention.ts b/eslint-bridge/src/linting/eslint/rules/arrow-function-convention.ts deleted file mode 100644 index a212805be50..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/arrow-function-convention.ts +++ /dev/null @@ -1,137 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3524/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -const MESSAGE_ADD_PARAMETER = 'Add parentheses around the parameter of this arrow function.'; -const MESSAGE_REMOVE_PARAMETER = 'Remove parentheses around the parameter of this arrow function.'; -const MESSAGE_ADD_BODY = 'Add curly braces and "return" to this arrow function body.'; -const MESSAGE_REMOVE_BODY = 'Remove curly braces and "return" from this arrow function body.'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - type: 'object', - properties: { - requireParameterParentheses: { - type: 'boolean', - }, - requireBodyBraces: { - type: 'boolean', - }, - }, - additionalProperties: false, - }, - ], - }, - - create(context: Rule.RuleContext) { - const options = context.options[0] || {}; - const requireParameterParentheses = !!options.requireParameterParentheses; - const requireBodyBraces = !!options.requireBodyBraces; - return { - ArrowFunctionExpression(node: estree.Node) { - const arrowFunction = node as estree.ArrowFunctionExpression; - checkParameters(context, requireParameterParentheses, arrowFunction); - checkBody(context, requireBodyBraces, arrowFunction); - }, - }; - }, -}; - -function checkParameters( - context: Rule.RuleContext, - requireParameterParentheses: boolean, - arrowFunction: estree.ArrowFunctionExpression, -) { - if (arrowFunction.params.length !== 1) { - return; - } - const parameter = arrowFunction.params[0]; - // Looking at the closing parenthesis after the parameter to avoid problems with cases like - // `functionTakingCallbacks(x => {...})` where the opening parenthesis before `x` isn't part - // of the function literal - const tokenAfterParameter = context.getSourceCode().getTokenAfter(parameter); - const hasParameterParentheses = tokenAfterParameter && tokenAfterParameter.value === ')'; - - if (requireParameterParentheses && !hasParameterParentheses) { - context.report({ node: parameter, message: MESSAGE_ADD_PARAMETER }); - } else if ( - !requireParameterParentheses && - !hasGeneric(context, arrowFunction) && - hasParameterParentheses - ) { - const arrowFunctionComments = context.getSourceCode().getCommentsInside(arrowFunction); - const arrowFunctionBodyComments = context.getSourceCode().getCommentsInside(arrowFunction.body); - // parameters comments inside parentheses are not available, so use the following subtraction: - const hasArrowFunctionParamsComments = - arrowFunctionComments.filter(comment => !arrowFunctionBodyComments.includes(comment)).length > - 0; - if ( - parameter.type === 'Identifier' && - !hasArrowFunctionParamsComments && - !(parameter as TSESTree.Identifier).typeAnnotation && - !(arrowFunction as TSESTree.ArrowFunctionExpression).returnType - ) { - context.report({ node: parameter, message: MESSAGE_REMOVE_PARAMETER }); - } - } -} - -function hasGeneric(context: Rule.RuleContext, arrowFunction: estree.ArrowFunctionExpression) { - const offset = arrowFunction.async ? 1 : 0; - const firstTokenIgnoreAsync = context.getSourceCode().getFirstToken(arrowFunction, offset); - return firstTokenIgnoreAsync && firstTokenIgnoreAsync.value === '<'; -} - -function checkBody( - context: Rule.RuleContext, - requireBodyBraces: boolean, - arrowFunction: estree.ArrowFunctionExpression, -) { - const hasBodyBraces = arrowFunction.body.type === 'BlockStatement'; - if (requireBodyBraces && !hasBodyBraces) { - context.report({ node: arrowFunction.body, message: MESSAGE_ADD_BODY }); - } else if (!requireBodyBraces && hasBodyBraces) { - const statements = (arrowFunction.body as estree.BlockStatement).body; - if (statements.length === 1) { - const statement = statements[0]; - if (isRemovableReturn(statement)) { - context.report({ node: arrowFunction.body, message: MESSAGE_REMOVE_BODY }); - } - } - } -} - -function isRemovableReturn(statement: estree.Statement) { - if (statement.type === 'ReturnStatement') { - const returnStatement = statement; - const returnExpression = returnStatement.argument; - if (returnExpression && returnExpression.type !== 'ObjectExpression') { - const location = returnExpression.loc; - return location && location.start.line === location.end.line; - } - } - return false; -} diff --git a/eslint-bridge/src/linting/eslint/rules/assertions-in-tests.ts b/eslint-bridge/src/linting/eslint/rules/assertions-in-tests.ts deleted file mode 100644 index 29990e80c79..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/assertions-in-tests.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2699/javascript -import { Rule, SourceCode } from 'eslint'; -import * as estree from 'estree'; -import { childrenOf } from 'linting/eslint'; -import { Chai, isFunctionCall, Mocha, resolveFunction } from './helpers'; - -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - const testCases: Mocha.TestCase[] = []; - return { - 'CallExpression:exit': (node: estree.Node) => { - const testCase = Mocha.extractTestCase(node); - if (testCase !== null) { - testCases.push(testCase); - } - }, - 'Program:exit': () => { - if (Chai.isImported(context)) { - testCases.forEach(testCase => checkAssertions(testCase, context)); - } - }, - }; - }, -}; - -function checkAssertions(testCase: Mocha.TestCase, context: Rule.RuleContext) { - const { node, callback } = testCase; - const visitor = new TestCaseAssertionVisitor(context); - visitor.visit(callback.body); - if (visitor.missingAssertions()) { - context.report({ node, message: 'Add at least one assertion to this test case.' }); - } -} - -class TestCaseAssertionVisitor { - private readonly visitorKeys: SourceCode.VisitorKeys; - private hasAssertions: boolean; - - constructor(private readonly context: Rule.RuleContext) { - this.visitorKeys = context.getSourceCode().visitorKeys; - this.hasAssertions = false; - } - - visit(node: estree.Node) { - if (this.hasAssertions) { - return; - } - if (Chai.isAssertion(node)) { - this.hasAssertions = true; - return; - } - if (isFunctionCall(node)) { - const functionDef = resolveFunction(this.context, node.callee); - if (functionDef) { - this.visit(functionDef.body); - } - } - for (const child of childrenOf(node, this.visitorKeys)) { - this.visit(child); - } - } - - missingAssertions() { - return !this.hasAssertions; - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/aws-apigateway-public-api.ts b/eslint-bridge/src/linting/eslint/rules/aws-apigateway-public-api.ts deleted file mode 100644 index 287582c316f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-apigateway-public-api.ts +++ /dev/null @@ -1,146 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6333/javascript - -import { Rule } from 'eslint'; -import { AwsCdkCheckArguments, AwsCdkTemplate, normalizeFQN } from './helpers/aws/cdk'; -import { CallExpression, MemberExpression, NewExpression, Node } from 'estree'; -import { getResultOfExpression } from './helpers/result'; -import { - getFullyQualifiedName, - getUniqueWriteUsageOrNode, - isMemberWithProperty, - isMethodCall, -} from './helpers'; - -const REST_API_PROPERTIES_POSITION = 2; -const RESOURCE_ADD_RESOURCE_PROPERTIES_POSITION = 1; -const RESOURCE_ADD_METHOD_POSITION = 2; - -const REST_API_ROOT_PROPERTY = 'root'; - -const DEFAULT_METHOD_OPTIONS = 'defaultMethodOptions'; - -const AUTHORIZATION_TYPE = 'authorizationType'; -const NONE_AUTHORIZATION_TYPE = 'aws_cdk_lib.aws_apigateway.AuthorizationType.NONE'; - -const ADD_METHOD = 'addMethod'; -const ADD_RESOURCE = 'addResource'; -const GET_RESOURCE = 'getResource'; -const PARENT_RESOURCE = 'parentResource'; - -const messages = { - publicApi: 'Make sure that creating public APIs is safe here.', - omittedAuthorizationType: - 'Omitting "authorizationType" disables authentication. Make sure it is safe here.', -}; - -const apigatewayChecker = AwsCdkCheckArguments( - ['omittedAuthorizationType', 'publicApi'], - true, - AUTHORIZATION_TYPE, - { primitives: { invalid: ['NONE'] } }, -); - -function consumersFactory(ctx: Rule.RuleContext) { - const defaultAuthorizationTypes = new Map(); - const restApiDefaultCollector = defaultsCollector(REST_API_PROPERTIES_POSITION); - const resourceDefaultCollector = defaultsCollector(RESOURCE_ADD_RESOURCE_PROPERTIES_POSITION); - - return { - 'aws_cdk_lib.aws_apigateway.CfnMethod': apigatewayChecker, - 'aws_cdk_lib.aws_apigatewayv2.CfnRoute': apigatewayChecker, - 'aws_cdk_lib.aws_apigateway.RestApi': restApiDefaultCollector, - 'aws_cdk_lib.aws_apigateway.RestApi.root': { - methods: [ADD_METHOD, ADD_RESOURCE, GET_RESOURCE, PARENT_RESOURCE], - - callExpression: (expr: CallExpression, _ctx: Rule.RuleContext, fqn: string) => { - if (fqn.endsWith(ADD_METHOD)) { - checkResourceMethod(expr); - } else if (fqn.endsWith(ADD_RESOURCE)) { - resourceDefaultCollector(expr); - } - }, - }, - }; - - function checkResourceMethod(expr: CallExpression) { - const properties = getResultOfExpression(ctx, expr).getArgument(RESOURCE_ADD_METHOD_POSITION); - const authorizationType = properties.getProperty(AUTHORIZATION_TYPE); - if (authorizationType.isFound && isSensitiveAuthorizationType(authorizationType.node)) { - ctx.report({ - messageId: 'publicApi', - node: authorizationType.node, - }); - } else if (authorizationType.isMissing) { - const defaultAuthorizationType = getDefaultAuthorizationType(expr.callee); - if (defaultAuthorizationType == null) { - ctx.report({ - messageId: 'omittedAuthorizationType', - node: authorizationType.node, - }); - } else if (isSensitiveAuthorizationType(defaultAuthorizationType)) { - ctx.report({ - messageId: 'publicApi', - node: expr, - }); - } - } - } - - function getDefaultAuthorizationType(node: Node): Node | undefined { - const resource = getUniqueWriteUsageOrNode(ctx, node); - if (defaultAuthorizationTypes.has(resource)) { - return defaultAuthorizationTypes.get(resource); - } else if (isDefaultFromCallee(resource)) { - return getDefaultAuthorizationType(resource.callee); - } else if (isDefaultFromObject(resource, ADD_METHOD, ADD_RESOURCE, REST_API_ROOT_PROPERTY)) { - return getDefaultAuthorizationType(resource.object); - } else { - return undefined; - } - } - - function defaultsCollector(position: number) { - return (expr: NewExpression | CallExpression) => { - const properties = getResultOfExpression(ctx, expr).getArgument(position); - const defaultMethodOptions = properties.getProperty(DEFAULT_METHOD_OPTIONS); - const authorizationType = defaultMethodOptions.getProperty(AUTHORIZATION_TYPE); - if (authorizationType.isFound) { - defaultAuthorizationTypes.set(expr, authorizationType.node); - } - }; - } - - function isSensitiveAuthorizationType(node: Node) { - const fqn = normalizeFQN(getFullyQualifiedName(ctx, node)); - return fqn === NONE_AUTHORIZATION_TYPE; - } -} - -function isDefaultFromObject(node: Node, ...names: string[]): node is MemberExpression { - return node.type === 'MemberExpression' && names.some(name => isMemberWithProperty(node, name)); -} - -function isDefaultFromCallee(node: Node): node is CallExpression { - return node.type === 'CallExpression' && isMethodCall(node); -} - -export const rule: Rule.RuleModule = AwsCdkTemplate(consumersFactory, { meta: { messages } }); diff --git a/eslint-bridge/src/linting/eslint/rules/aws-ec2-rds-dms-public.ts b/eslint-bridge/src/linting/eslint/rules/aws-ec2-rds-dms-public.ts deleted file mode 100644 index ffb96f6d772..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-ec2-rds-dms-public.ts +++ /dev/null @@ -1,144 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6329/javascript - -import { AwsCdkCheckArguments, AwsCdkTemplate } from './helpers/aws/cdk'; -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { Node } from 'estree'; -import { getResultOfExpression, Result } from './helpers/result'; -import { getFullyQualifiedName, isCallingMethod } from './helpers'; - -const PROPERTIES_POSITION = 2; - -const PRIVATE_SUBNETS = [ - 'aws_cdk_lib.aws_ec2.SubnetType.PRIVATE_ISOLATED', - 'aws_cdk_lib.aws_ec2.SubnetType.PRIVATE_WITH_EGRESS', - 'aws_cdk_lib.aws_ec2.SubnetType.PRIVATE_WITH_NAT', -]; - -const PUBLIC_SUBNET = 'aws_cdk_lib.aws_ec2.SubnetType.PUBLIC'; - -export const rule: Rule.RuleModule = AwsCdkTemplate( - { - 'aws-cdk-lib.aws-ec2.Instance': AwsCdkCheckArguments( - 'publicNetwork', - false, - ['vpcSubnets', 'subnetType'], - { fqns: { invalid: [PUBLIC_SUBNET] } }, - ), - 'aws-cdk-lib.aws-ec2.CfnInstance': checkCfnInstance, - 'aws-cdk-lib.aws_rds.DatabaseInstance': checkDatabaseInstance, - 'aws-cdk-lib.aws_rds.CfnDBInstance': AwsCdkCheckArguments( - 'publicNetwork', - false, - 'publiclyAccessible', - { primitives: { invalid: [true] } }, - ), - 'aws-cdk-lib.aws_dms.CfnReplicationInstance': AwsCdkCheckArguments( - 'publicNetwork', - true, - 'publiclyAccessible', - { primitives: { invalid: [true] } }, - ), - }, - { - meta: { - messages: { - publicNetwork: 'Make sure allowing public network access is safe here.', - }, - }, - }, -); - -function checkCfnInstance(expr: estree.NewExpression, ctx: Rule.RuleContext) { - const properties = getResultOfExpression(ctx, expr).getArgument(PROPERTIES_POSITION); - const networkInterfaces = properties.getProperty('networkInterfaces'); - const sensitiveNetworkInterface = networkInterfaces.findInArray(result => - getSensitiveNetworkInterface(result, ctx), - ); - - if (sensitiveNetworkInterface.isFound) { - ctx.report({ - messageId: 'publicNetwork', - node: sensitiveNetworkInterface.node, - }); - } -} - -function getSensitiveNetworkInterface(networkInterface: Result, ctx: Rule.RuleContext) { - const associatePublicIpAddress = networkInterface.getProperty('associatePublicIpAddress'); - if (associatePublicIpAddress.isTrue && !isFoundPrivateSubnet(networkInterface, ctx)) { - return associatePublicIpAddress; - } else { - return null; - } -} - -function isFoundPrivateSubnet(networkInterface: Result, ctx: Rule.RuleContext) { - const subnetId = networkInterface.getProperty('subnetId'); - const selectSubnetsCall = getSelectSubnetsCall(subnetId); - const argument = selectSubnetsCall.getArgument(0); - const subnetType = argument.getProperty('subnetType'); - return subnetType.isFound && isPrivateSubnet(subnetType.node, ctx); -} - -function getSelectSubnetsCall(subnetId: Result) { - let current = subnetId; - while (current.ofType('MemberExpression')) { - current = current.getMemberObject(); - } - return current.filter(n => n.type === 'CallExpression' && isCallingMethod(n, 1, 'selectSubnets')); -} - -function checkDatabaseInstance(expr: estree.NewExpression, ctx: Rule.RuleContext) { - const properties = getResultOfExpression(ctx, expr).getArgument(PROPERTIES_POSITION); - const vpcSubnets = properties.getProperty('vpcSubnets'); - const subnetType = vpcSubnets.getProperty('subnetType'); - const publiclyAccessible = properties.getProperty('publiclyAccessible'); - - if (subnetType.isFound && isPrivateSubnet(subnetType.node, ctx)) { - return; - } - - if (publiclyAccessible.isTrue) { - ctx.report({ - messageId: 'publicNetwork', - node: publiclyAccessible.node, - }); - } else if ( - !publiclyAccessible.isFound && - subnetType.isFound && - isPublicSubnet(subnetType.node, ctx) - ) { - ctx.report({ - messageId: 'publicNetwork', - node: subnetType.node, - }); - } -} - -function isPrivateSubnet(node: Node, ctx: Rule.RuleContext) { - return PRIVATE_SUBNETS.some(net => net === getFullyQualifiedName(ctx, node)?.replace(/-/g, '_')); -} - -function isPublicSubnet(node: Node, ctx: Rule.RuleContext) { - return PUBLIC_SUBNET === getFullyQualifiedName(ctx, node)?.replace(/-/g, '_'); -} diff --git a/eslint-bridge/src/linting/eslint/rules/aws-ec2-unencrypted-ebs-volume.ts b/eslint-bridge/src/linting/eslint/rules/aws-ec2-unencrypted-ebs-volume.ts deleted file mode 100644 index 1ed050ca8f1..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-ec2-unencrypted-ebs-volume.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6275/javascript - -import { Rule } from 'eslint'; -import { AwsCdkCheckArguments, AwsCdkTemplate } from './helpers/aws/cdk'; - -export const rule: Rule.RuleModule = AwsCdkTemplate( - { - 'aws-cdk-lib.aws-ec2.Volume': AwsCdkCheckArguments( - ['encryptionOmitted', 'encryptionDisabled'], - true, - 'encrypted', - { primitives: { invalid: [false] } }, - ), - }, - { - meta: { - messages: { - encryptionDisabled: 'Make sure that using unencrypted volumes is safe here.', - encryptionOmitted: - 'Omitting "encrypted" disables volumes encryption. Make sure it is safe here.', - }, - }, - }, -); diff --git a/eslint-bridge/src/linting/eslint/rules/aws-efs-unencrypted.ts b/eslint-bridge/src/linting/eslint/rules/aws-efs-unencrypted.ts deleted file mode 100644 index b103a32f946..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-efs-unencrypted.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6332/javascript - -import { Rule } from 'eslint'; -import { AwsCdkCheckArguments, AwsCdkTemplate } from './helpers/aws/cdk'; - -export const rule: Rule.RuleModule = AwsCdkTemplate( - { - 'aws-cdk-lib.aws_efs.FileSystem': AwsCdkCheckArguments( - 'FSEncryptionDisabled', - false, - 'encrypted', - { primitives: { invalid: [false] } }, - ), - 'aws-cdk-lib.aws_efs.CfnFileSystem': AwsCdkCheckArguments( - ['CFSEncryptionOmitted', 'CFSEncryptionDisabled'], - true, - 'encrypted', - { primitives: { valid: [true] } }, - ), - }, - { - meta: { - messages: { - FSEncryptionDisabled: 'Make sure that using unencrypted file systems is safe here.', - CFSEncryptionDisabled: 'Make sure that using unencrypted file systems is safe here.', - CFSEncryptionOmitted: - 'Omitting "encrypted" disables EFS encryption. Make sure it is safe here.', - }, - }, - }, -); diff --git a/eslint-bridge/src/linting/eslint/rules/aws-iam-all-privileges.ts b/eslint-bridge/src/linting/eslint/rules/aws-iam-all-privileges.ts deleted file mode 100644 index 52570668e02..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-iam-all-privileges.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6302/javascript - -import { Rule } from 'eslint'; -import { Node } from 'estree'; -import { toEncodedMessage } from './helpers'; -import { getResultOfExpression, Result } from './helpers/result'; -import { - AwsIamPolicyTemplate, - getSensitiveEffect, - isAnyLiteral, - PolicyCheckerOptions, -} from './helpers/aws/iam'; - -const MESSAGES = { - message: 'Make sure granting all privileges is safe here.', - secondary: 'Related effect', -}; - -export const rule: Rule.RuleModule = AwsIamPolicyTemplate(allPrivilegesStatementChecker); - -function allPrivilegesStatementChecker( - expr: Node, - ctx: Rule.RuleContext, - options: PolicyCheckerOptions, -) { - const properties = getResultOfExpression(ctx, expr); - const effect = getSensitiveEffect(properties, ctx, options); - const action = getSensitiveAction(properties, options); - - if (effect.isMissing && action) { - ctx.report({ - message: toEncodedMessage(MESSAGES.message), - node: action, - }); - } else if (effect.isFound && action) { - ctx.report({ - message: toEncodedMessage(MESSAGES.message, [effect.node], [MESSAGES.secondary]), - node: action, - }); - } -} - -function getSensitiveAction(properties: Result, options: PolicyCheckerOptions) { - return getActionLiterals(properties, options).find(isAnyLiteral); -} - -function getActionLiterals(properties: Result, options: PolicyCheckerOptions) { - return properties.getProperty(options.actions.property).asStringLiterals(); -} diff --git a/eslint-bridge/src/linting/eslint/rules/aws-iam-all-resources-accessible.ts b/eslint-bridge/src/linting/eslint/rules/aws-iam-all-resources-accessible.ts deleted file mode 100644 index cd0e9e9f24f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-iam-all-resources-accessible.ts +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6304/javascript - -import { Rule } from 'eslint'; -import { Node } from 'estree'; -import { StringLiteral, toEncodedMessage } from './helpers'; -import { getResultOfExpression, Result } from './helpers/result'; -import { - AwsIamPolicyTemplate, - getSensitiveEffect, - isAnyLiteral, - PolicyCheckerOptions, -} from './helpers/aws/iam'; - -const MESSAGES = { - message: 'Make sure granting access to all resources is safe here.', - secondary: 'Related effect', -}; - -const KMS_PREFIX = 'kms:'; - -export const rule: Rule.RuleModule = AwsIamPolicyTemplate(allResourcesAccessibleStatementCheck); - -function allResourcesAccessibleStatementCheck( - expr: Node, - ctx: Rule.RuleContext, - options: PolicyCheckerOptions, -) { - const properties = getResultOfExpression(ctx, expr); - const effect = getSensitiveEffect(properties, ctx, options); - const resource = getSensitiveResource(properties, options); - - if (isException(properties, options)) { - return; - } - - if (effect.isMissing && resource) { - ctx.report({ - message: toEncodedMessage(MESSAGES.message), - node: resource, - }); - } else if (effect.isFound && resource) { - ctx.report({ - message: toEncodedMessage(MESSAGES.message, [effect.node], [MESSAGES.secondary]), - node: resource, - }); - } -} - -function isException(properties: Result, options: PolicyCheckerOptions) { - return properties.getProperty(options.actions.property).everyStringLiteral(isKmsAction); -} - -function isKmsAction(action: StringLiteral) { - return action.value.startsWith(KMS_PREFIX); -} - -function getSensitiveResource(properties: Result, options: PolicyCheckerOptions) { - return getSensitiveResources(properties, options).find(isAnyLiteral); -} - -function getSensitiveResources(properties: Result, options: PolicyCheckerOptions) { - return properties.getProperty(options.resources.property).asStringLiterals(); -} diff --git a/eslint-bridge/src/linting/eslint/rules/aws-iam-privilege-escalation.ts b/eslint-bridge/src/linting/eslint/rules/aws-iam-privilege-escalation.ts deleted file mode 100644 index 48a173b6669..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-iam-privilege-escalation.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6317/javascript - -import { Rule } from 'eslint'; -import { Node } from 'estree'; -import { StringLiteral, toEncodedMessage } from './helpers'; -import { getResultOfExpression, Result } from './helpers/result'; -import { AwsIamPolicyTemplate, getSensitiveEffect, PolicyCheckerOptions } from './helpers/aws/iam'; - -const SENSITIVE_RESOURCE = /^(\*|arn:[^:]*:[^:]*:[^:]*:[^:]*:(role|user|group)\/\*)$/; - -const SENSITIVE_ACTIONS = [ - 'cloudformation:CreateStack', - 'datapipeline:CreatePipeline', - 'datapipeline:PutPipelineDefinition', - 'ec2:RunInstances', - 'glue:CreateDevEndpoint', - 'glue:UpdateDevEndpoint', - 'iam:AddUserToGroup', - 'iam:AttachGroupPolicy', - 'iam:AttachRolePolicy', - 'iam:AttachUserPolicy', - 'iam:CreateAccessKey', - 'iam:CreateLoginProfile', - 'iam:CreatePolicyVersion', - 'iam:PassRole', - 'iam:PutGroupPolicy', - 'iam:PutRolePolicy', - 'iam:PutUserPolicy', - 'iam:SetDefaultPolicyVersion', - 'iam:UpdateAssumeRolePolicy', - 'iam:UpdateLoginProfile', - 'lambda:AddPermission', - 'lambda:CreateEventSourceMapping', - 'lambda:CreateFunction', - 'lambda:InvokeFunction', - 'lambda:UpdateFunctionCode', - 'sts:AssumeRole', -]; - -const MESSAGES = { - message: (attackVectorName: string) => - `This policy is vulnerable to the "${attackVectorName}" privilege escalation vector. ` + - 'Remove permissions or restrict the set of resources they apply to.', - secondary: 'Permissions are granted on all resources.', -}; - -export const rule: Rule.RuleModule = AwsIamPolicyTemplate(privilegeEscalationStatementChecker); - -function privilegeEscalationStatementChecker( - expr: Node, - ctx: Rule.RuleContext, - options: PolicyCheckerOptions, -) { - const properties = getResultOfExpression(ctx, expr); - const effect = getSensitiveEffect(properties, ctx, options); - const resource = getSensitiveResource(properties, options); - const action = getSensitiveAction(properties, options); - - if ( - !hasExceptionProperties(properties, options) && - (effect.isFound || effect.isMissing) && - resource && - action - ) { - ctx.report({ - message: toEncodedMessage(MESSAGES.message(action.value), [action], [MESSAGES.secondary]), - node: resource, - }); - } -} - -function getSensitiveAction(properties: Result, options: PolicyCheckerOptions) { - const actions = properties.getProperty(options.actions.property); - return actions.asStringLiterals().find(isSensitiveAction); -} - -function getSensitiveResource(properties: Result, options: PolicyCheckerOptions) { - const resources = properties.getProperty(options.resources.property); - return resources.asStringLiterals().find(isSensitiveResource); -} - -function isSensitiveAction(action: StringLiteral) { - return SENSITIVE_ACTIONS.includes(action.value); -} - -function isSensitiveResource(resource: StringLiteral) { - return SENSITIVE_RESOURCE.test(resource.value); -} - -function hasExceptionProperties(properties: Result, options: PolicyCheckerOptions) { - const exceptionProperties = [options.principals.property, options.conditions.property]; - return exceptionProperties.some(prop => !properties.getProperty(prop).isMissing); -} diff --git a/eslint-bridge/src/linting/eslint/rules/aws-iam-public-access.ts b/eslint-bridge/src/linting/eslint/rules/aws-iam-public-access.ts deleted file mode 100644 index ffa9b8de182..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-iam-public-access.ts +++ /dev/null @@ -1,144 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6270/javascript - -import { Rule } from 'eslint'; -import { NewExpression, Node } from 'estree'; -import { - getFullyQualifiedName, - isArrayExpression, - isStringLiteral, - StringLiteral, - toEncodedMessage, -} from './helpers'; -import { getResultOfExpression, Result } from './helpers/result'; -import { - AwsIamPolicyTemplate, - getSensitiveEffect, - isAnyLiteral, - PolicyCheckerOptions, -} from './helpers/aws/iam'; -import { normalizeFQN } from './helpers/aws/cdk'; - -const AWS_PRINCIPAL_PROPERTY = 'AWS'; - -const ARN_PRINCIPAL = 'aws_cdk_lib.aws_iam.ArnPrincipal'; - -const MESSAGES = { - message: 'Make sure granting public access is safe here.', - secondary: 'Related effect', -}; - -export const rule: Rule.RuleModule = AwsIamPolicyTemplate(publicAccessStatementChecker); - -function publicAccessStatementChecker( - expr: Node, - ctx: Rule.RuleContext, - options: PolicyCheckerOptions, -) { - const properties = getResultOfExpression(ctx, expr); - const effect = getSensitiveEffect(properties, ctx, options); - const principal = getSensitivePrincipal(properties, ctx, options); - - if (effect.isMissing && principal) { - ctx.report({ - message: toEncodedMessage(MESSAGES.message), - node: principal, - }); - } else if (effect.isFound && principal) { - ctx.report({ - message: toEncodedMessage(MESSAGES.message, [effect.node], [MESSAGES.secondary]), - node: principal, - }); - } -} - -function getSensitivePrincipal( - properties: Result, - ctx: Rule.RuleContext, - options: PolicyCheckerOptions, -) { - const principal = properties.getProperty(options.principals.property); - if (!principal.isFound) { - return null; - } else if (options.principals.type === 'FullyQualifiedName') { - return getSensitivePrincipalFromFullyQualifiedName(ctx, principal.node, options); - } else { - return getSensitivePrincipalFromJson(ctx, principal.node); - } -} - -function getSensitivePrincipalFromFullyQualifiedName( - ctx: Rule.RuleContext, - node: Node, - options: PolicyCheckerOptions, -) { - return getPrincipalNewExpressions(node).find(expr => - isSensitivePrincipalNewExpression(ctx, expr, options), - ); -} - -function getPrincipalNewExpressions(node: Node) { - const newExpressions: NewExpression[] = []; - - if (isArrayExpression(node)) { - for (const element of node.elements) { - if (element?.type === 'NewExpression') { - newExpressions.push(element); - } - } - } - - return newExpressions; -} - -function getSensitivePrincipalFromJson(ctx: Rule.RuleContext, node: Node) { - return getPrincipalLiterals(node, ctx).find(isAnyLiteral); -} - -function isSensitivePrincipalNewExpression( - ctx: Rule.RuleContext, - newExpression: NewExpression, - options: PolicyCheckerOptions, -) { - return (options.principals.anyValues ?? []).some(anyValue => { - if (anyValue === ARN_PRINCIPAL) { - const argument = newExpression.arguments[0]; - return isStringLiteral(argument) && isAnyLiteral(argument); - } else { - return anyValue === normalizeFQN(getFullyQualifiedName(ctx, newExpression.callee)); - } - }); -} - -function getPrincipalLiterals(node: Node, ctx: Rule.RuleContext) { - const literals: StringLiteral[] = []; - - if (isStringLiteral(node)) { - literals.push(node); - } else { - const awsLiterals = getResultOfExpression(ctx, node) - .getProperty(AWS_PRINCIPAL_PROPERTY) - .asStringLiterals(); - literals.push(...awsLiterals); - } - - return literals; -} diff --git a/eslint-bridge/src/linting/eslint/rules/aws-opensearchservice-domain.ts b/eslint-bridge/src/linting/eslint/rules/aws-opensearchservice-domain.ts deleted file mode 100644 index 86f643feb16..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-opensearchservice-domain.ts +++ /dev/null @@ -1,141 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6308/javascript - -import { Rule } from 'eslint'; -import { AwsCdkTemplate } from './helpers/aws/cdk'; -import { NewExpression, Node } from 'estree'; -import { getFullyQualifiedName, isBooleanLiteral, isStringLiteral } from './helpers'; -import { getResultOfExpression } from './helpers/result'; - -const DOMAIN_PROPS_POSITION = 2; -const ENABLED_PROPERTY = 'enabled'; -const OPEN_SEARCH = 'OpenSearch'; -const ELASTIC_SEARCH = 'Elasticsearch'; - -interface DomainCheckerOptions { - encryptionProperty: string; - version: { - valueType: 'ElasticsearchVersion' | 'EngineVersion' | 'string'; - property: string; - defaultValue: typeof OPEN_SEARCH | typeof ELASTIC_SEARCH; - }; -} - -export const rule: Rule.RuleModule = AwsCdkTemplate( - { - 'aws-cdk-lib.aws-opensearchservice.Domain': domainChecker({ - encryptionProperty: 'encryptionAtRest', - version: { - valueType: 'EngineVersion', - property: 'version', - defaultValue: OPEN_SEARCH, - }, - }), - 'aws-cdk-lib.aws-opensearchservice.CfnDomain': domainChecker({ - encryptionProperty: 'encryptionAtRestOptions', - version: { - valueType: 'string', - property: 'engineVersion', - defaultValue: OPEN_SEARCH, - }, - }), - 'aws-cdk-lib.aws-elasticsearch.Domain': domainChecker({ - encryptionProperty: 'encryptionAtRest', - version: { - valueType: 'ElasticsearchVersion', - property: 'version', - defaultValue: ELASTIC_SEARCH, - }, - }), - 'aws-cdk-lib.aws-elasticsearch.CfnDomain': domainChecker({ - encryptionProperty: 'encryptionAtRestOptions', - version: { - valueType: 'string', - property: 'elasticsearchVersion', - defaultValue: ELASTIC_SEARCH, - }, - }), - }, - { - meta: { - messages: { - encryptionDisabled: 'Make sure that using unencrypted {{search}} domains is safe here.', - encryptionOmitted: - 'Omitting {{encryptionPropertyName}} causes encryption of data at rest to be ' + - 'disabled for this {{search}} domain. Make sure it is safe here.', - }, - }, - }, -); - -function domainChecker(options: DomainCheckerOptions) { - return (expr: NewExpression, ctx: Rule.RuleContext) => { - const call = getResultOfExpression(ctx, expr); - const argument = call.getArgument(DOMAIN_PROPS_POSITION); - const encryption = argument.getProperty(options.encryptionProperty); - const version = argument.getProperty(options.version.property); - const isEnabled = encryption.getProperty(ENABLED_PROPERTY); - const search = version.map(getSearchEngine) ?? options.version.defaultValue; - - if (isEnabled.isMissing) { - ctx.report({ - messageId: 'encryptionOmitted', - node: isEnabled.node, - data: { - encryptionPropertyName: options.encryptionProperty, - search, - }, - }); - } else if (isEnabled.isFound && isUnencrypted(isEnabled.node)) { - ctx.report({ - messageId: 'encryptionDisabled', - node: isEnabled.node, - data: { - search, - }, - }); - } - - function isUnencrypted(node: Node) { - return isBooleanLiteral(node) && !node.value; - } - - function getSearchEngine(node: Node) { - let version: string | null; - - if (options.version.valueType === 'string' && isStringLiteral(node)) { - version = `${options.version.property}.${node.value}`; - } else { - version = getFullyQualifiedName(ctx, node); - } - - for (const name of version?.toLowerCase().split('.').reverse() ?? []) { - if (name.includes('opensearch')) { - return OPEN_SEARCH; - } else if (name.includes('elasticsearch')) { - return ELASTIC_SEARCH; - } - } - - return null; - } - }; -} diff --git a/eslint-bridge/src/linting/eslint/rules/aws-rds-unencrypted-databases.ts b/eslint-bridge/src/linting/eslint/rules/aws-rds-unencrypted-databases.ts deleted file mode 100644 index 03b2b36a9fc..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-rds-unencrypted-databases.ts +++ /dev/null @@ -1,133 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6303/javascript - -import { Rule } from 'eslint'; -import { - getFullyQualifiedName, - getProperty, - getUniqueWriteUsageOrNode, - getValueOfExpression, - isFalseLiteral, - isUndefined, -} from './helpers'; - -import * as estree from 'estree'; -import { AwsCdkTemplate, normalizeFQN } from './helpers/aws/cdk'; - -const CfnDBCluster = 'CfnDBCluster'; -const CfnDBInstance = 'CfnDBInstance'; -const DatabaseCluster = 'DatabaseCluster'; -const DatabaseClusterFromSnapshot = 'DatabaseClusterFromSnapshot'; -const DatabaseInstance = 'DatabaseInstance'; -const DatabaseInstanceReadReplica = 'DatabaseInstanceReadReplica'; - -export const rule: Rule.RuleModule = AwsCdkTemplate( - { - 'aws-cdk-lib.aws_rds.CfnDBCluster': checkStorage(CfnDBCluster), - 'aws-cdk-lib.aws_rds.CfnDBInstance': checkStorage(CfnDBInstance), - 'aws-cdk-lib.aws_rds.DatabaseCluster': checkStorage(DatabaseCluster), - 'aws-cdk-lib.aws_rds.DatabaseClusterFromSnapshot': checkStorage(DatabaseClusterFromSnapshot), - 'aws-cdk-lib.aws_rds.DatabaseInstance': checkStorage(DatabaseInstance), - 'aws-cdk-lib.aws_rds.DatabaseInstanceReadReplica': checkStorage(DatabaseInstanceReadReplica), - }, - { - meta: { - messages: { - unsafe: 'Make sure that using unencrypted storage is safe here.', - omitted: 'Omitting storageEncrypted disables RDS encryption. Make sure it is safe here.', - }, - }, - }, -); - -const PROPS_ARGUMENT_POSITION = 2; - -function checkStorage(storage: string) { - return (expr: estree.NewExpression, ctx: Rule.RuleContext) => { - const argument = expr.arguments[PROPS_ARGUMENT_POSITION]; - - const props = getValueOfExpression(ctx, argument, 'ObjectExpression'); - if (isUnresolved(argument, props)) { - return; - } - - if (props === undefined) { - report(expr.callee, 'omitted'); - return; - } - - if (isException(storage, props)) { - return; - } - - const propertyKey = getProperty(props, 'storageEncrypted', ctx); - if (propertyKey === null) { - report(props, 'omitted'); - } - - if (!propertyKey) { - return; - } - - const propertyValue = getUniqueWriteUsageOrNode(ctx, propertyKey.value); - if (isFalseLiteral(propertyValue)) { - report(propertyKey.value, 'unsafe'); - return; - } - - function isUnresolved(node: estree.Node | undefined, value: estree.Node | undefined | null) { - return node?.type === 'Identifier' && !isUndefined(node) && value === undefined; - } - - function isException(storage: string, props: estree.ObjectExpression) { - if ( - ![ - DatabaseCluster, - DatabaseClusterFromSnapshot, - DatabaseInstance, - DatabaseInstanceReadReplica, - ].includes(storage) - ) { - return false; - } - - const exceptionKey = getProperty(props, 'storageEncryptionKey', ctx); - if (exceptionKey == null) { - return false; - } - - const exceptionValue = getUniqueWriteUsageOrNode(ctx, exceptionKey.value); - if (exceptionValue.type !== 'NewExpression') { - return false; - } - - const fqn = normalizeFQN(getFullyQualifiedName(ctx, exceptionValue.callee)); - return fqn === 'aws_cdk_lib.aws_kms.Key' || fqn === 'aws_cdk_lib.aws_kms.Alias'; - } - - function report(node: estree.Node, messageId: string) { - ctx.report({ - messageId, - node, - }); - } - }; -} diff --git a/eslint-bridge/src/linting/eslint/rules/aws-restricted-ip-admin-access.ts b/eslint-bridge/src/linting/eslint/rules/aws-restricted-ip-admin-access.ts deleted file mode 100644 index 0b5bdf8b964..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-restricted-ip-admin-access.ts +++ /dev/null @@ -1,371 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6321/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - AwsCdkCheckArguments, - AwsCdkConsumer, - AwsCdkTemplate, - FullyQualifiedName, - getLiteralValue, - normalizeFQN, -} from './helpers/aws/cdk'; -import { - getFullyQualifiedName, - getProperty, - getUniqueWriteUsageOrNode, - getValueOfExpression, - isUndefined, - isUnresolved, - reduceToIdentifier, -} from './helpers'; - -const TYPES_WITH_CONNECTIONS = [ - 'aws_cdk_lib.aws_docdb.DatabaseCluster.connections', - 'aws_cdk_lib.aws_lambdaPythonAlpha.PythonFunction.connections', - 'aws_cdk_lib.aws_batchAlpha.ComputeEnvironment.connections', - 'aws_cdk_lib.aws_efs.FileSystem.connections', - 'aws_cdk_lib.aws_lambdaGoAlpha.GoFunction.connections', - 'aws_cdk_lib.aws_ecs.ExternalService.connections', - 'aws_cdk_lib.aws_ecs.FargateService.connections', - 'aws_cdk_lib.aws_ecs.Cluster.connections', - 'aws_cdk_lib.aws_ecs.Ec2Service.connections', - 'aws_cdk_lib.aws_elasticsearch.Domain.connections', - 'aws_cdk_lib.aws_neptuneAlpha.DatabaseCluster.connections', - 'aws_cdk_lib.aws_eks.FargateCluster.connections', - 'aws_cdk_lib.aws_eks.Cluster.connections', - 'aws_cdk_lib.aws_codebuild.PipelineProject.connections', - 'aws_cdk_lib.aws_codebuild.Project.connections', - 'aws_cdk_lib.aws_rds.DatabaseInstance.connections', - 'aws_cdk_lib.aws_rds.DatabaseInstanceReadReplica.connections', - 'aws_cdk_lib.aws_rds.DatabaseCluster.connections', - 'aws_cdk_lib.aws_rds.ServerlessClusterFromSnapshot.connections', - 'aws_cdk_lib.aws_rds.DatabaseProxy.connections', - 'aws_cdk_lib.aws_rds.DatabaseInstanceFromSnapshot.connections', - 'aws_cdk_lib.aws_rds.ServerlessCluster.connections', - 'aws_cdk_lib.aws_rds.DatabaseClusterFromSnapshot.connections', - 'aws_cdk_lib.aws_lambdaNodejs.NodejsFunction.connections', - 'aws_cdk_lib.aws_fsx.LustreFileSystem.connections', - 'aws_cdk_lib.aws_ec2.BastionHostLinux.connections', - 'aws_cdk_lib.aws_ec2.ClientVpnEndpoint.connections', - 'aws_cdk_lib.aws_ec2.Instance.connections', - 'aws_cdk_lib.aws_ec2.LaunchTemplate.connections', - 'aws_cdk_lib.aws_ec2.SecurityGroup.connections', - 'aws_cdk_lib.aws_kinesisfirehoseAlpha.DeliveryStream.connections', - 'aws_cdk_lib.aws_stepfunctionsTasks.SageMakerCreateTrainingJob.connections', - 'aws_cdk_lib.aws_stepfunctionsTasks.SageMakerCreateModel.connections', - 'aws_cdk_lib.aws_stepfunctionsTasks.EcsRunTask.connections', - 'aws_cdk_lib.aws_redshiftAlpha.Cluster.connections', - 'aws_cdk_lib.aws_opensearchservice.Domain.connections', - 'aws_cdk_lib.aws_secretsmanager.HostedRotation.connections', - 'aws_cdk_lib.aws_mskAlpha.Cluster.connections', - 'aws_cdk_lib.triggers.TriggerFunction.connections', - 'aws_cdk_lib.aws_autoscaling.AutoScalingGroup.connections', - 'aws_cdk_lib.aws_syntheticsAlpha.Canary.connections', - 'aws_cdk_lib.aws_cloudfront.experimental.EdgeFunction.connections', - 'aws_cdk_lib.aws_lambda.Function.connections', - 'aws_cdk_lib.aws_lambda.DockerImageFunction.connections', - 'aws_cdk_lib.aws_lambda.SingletonFunction.connections', - 'aws_cdk_lib.aws_lambda.Alias.connections', - 'aws_cdk_lib.aws_lambda.Version.connections', - 'aws_cdk_lib.aws_ec2.Connections', -]; - -const badPorts: number[] = [22, 3389]; -const badIpsV4: string[] = ['0.0.0.0/0']; -const badIpsV6: string[] = ['::/0']; -const badFQNProtocols: string[] = [ - 'aws_cdk_lib.aws_ec2.Protocol.ALL', - 'aws_cdk_lib.aws_ec2.Protocol.TCP', -]; -const badProtocols: string[] = ['6', 'tcp', 'TCP']; - -const templateCallback: { [key: FullyQualifiedName]: AwsCdkConsumer } = {}; -for (const type of TYPES_WITH_CONNECTIONS) { - templateCallback[`${type}.allowFrom`] = { callExpression: checkAllowFrom }; - templateCallback[`${type}.allowFromAnyIpv4`] = { callExpression: checkAllowFromAnyIpv4 }; -} - -templateCallback['aws_cdk_lib.aws_ec2.Connections.allowDefaultPortFrom'] = { - callExpression: (expr: estree.CallExpression, ctx: Rule.RuleContext) => { - if (isBadEc2Peer(ctx, expr.arguments[0])) { - checkConstructorDefaultPort(ctx, expr); - } - }, -}; -templateCallback['aws_cdk_lib.aws_ec2.Connections.allowDefaultPortFromAnyIpv4'] = { - callExpression: (expr: estree.CallExpression, ctx: Rule.RuleContext) => { - checkConstructorDefaultPort(ctx, expr); - }, -}; -templateCallback['aws_cdk_lib.aws_ec2.SecurityGroup.addIngressRule'] = { - callExpression: checkAllowFrom, -}; - -templateCallback['aws_cdk_lib.aws_ec2.CfnSecurityGroup'] = ( - expr: estree.NewExpression, - ctx: Rule.RuleContext, -) => { - const params = expr.arguments[2]; - const objExpr = getValueOfExpression(ctx, params, 'ObjectExpression', true); - if (!objExpr) { - return; - } - - const ingressProp = getProperty(objExpr, 'securityGroupIngress', ctx); - - if (!ingressProp) { - return; - } - - const arrExpr = getValueOfExpression(ctx, ingressProp.value, 'ArrayExpression', true); - - if (arrExpr) { - for (const ingressGroup of arrExpr.elements) { - if (ingressGroup) { - checkIngressObject(ctx, ingressGroup); - } - } - } -}; - -templateCallback['aws_cdk_lib.aws_ec2.CfnSecurityGroupIngress'] = ( - expr: estree.NewExpression, - ctx: Rule.RuleContext, -) => { - checkIngressObject(ctx, expr.arguments[2]); -}; - -export const rule: Rule.RuleModule = AwsCdkTemplate(templateCallback, { - meta: { - messages: { - allowFromAnyIpv4: - 'Change this method for "allowFrom" and set "other" to a subset of trusted IP addresses.', - allowFrom: 'Change this IP range to a subset of trusted IP addresses.', - }, - }, -}); - -const invalidDefaultPortChecker = AwsCdkCheckArguments( - 'allowFrom', - false, - 'defaultPort', - { customChecker: isBadEc2Port }, - true, - 0, -); - -function checkConstructorDefaultPort(ctx: Rule.RuleContext, node: estree.CallExpression) { - const newExpr = getValueOfExpression(ctx, reduceToIdentifier(node.callee), 'NewExpression', true); - if (newExpr && invalidDefaultPortChecker(newExpr, ctx)) { - ctx.report({ messageId: 'allowFromAnyIpv4', node: node.callee }); - } -} - -function checkAllowFrom(expr: estree.CallExpression, ctx: Rule.RuleContext) { - const badPeer = isBadEc2Peer(ctx, expr.arguments[0]); - const badPort = isBadEc2Port(ctx, expr.arguments[1]); - - if (badPort && badPeer) { - ctx.report({ messageId: 'allowFrom', node: expr.arguments[0] }); - } -} - -function checkAllowFromAnyIpv4(expr: estree.CallExpression, ctx: Rule.RuleContext) { - const badPort = isBadEc2Port(ctx, expr.arguments[0]); - - if (badPort) { - ctx.report({ messageId: 'allowFromAnyIpv4', node: expr.callee }); - } -} - -function checkIngressObject(ctx: Rule.RuleContext, node: estree.Node) { - const objExpr = getValueOfExpression(ctx, node, 'ObjectExpression', true); - if (!objExpr) { - return; - } - - const ipPropertyV4 = getPropertyValue(ctx, objExpr, 'cidrIp'); - const ipPropertyV6 = getPropertyValue(ctx, objExpr, 'cidrIpv6'); - - const ipProtocol = getPropertyValue(ctx, objExpr, 'ipProtocol')?.value as string; - const cidrIpV4 = ipPropertyV4?.value as string; - const cidrIpV6 = ipPropertyV6?.value as string; - const fromPort = Number.parseInt(getPropertyValue(ctx, objExpr, 'fromPort')?.value as string); - const toPort = Number.parseInt(getPropertyValue(ctx, objExpr, 'toPort')?.value as string); - - if ( - disallowedIpV4(cidrIpV4) && - (ipProtocol === '-1' || (disallowedProtocol(ipProtocol) && disallowedPort(fromPort, toPort))) - ) { - ctx.report({ messageId: 'allowFrom', node: ipPropertyV4! }); - } - - if ( - disallowedIpV6(cidrIpV6) && - (ipProtocol === '-1' || (disallowedProtocol(ipProtocol) && disallowedPort(fromPort, toPort))) - ) { - ctx.report({ messageId: 'allowFrom', node: ipPropertyV6! }); - } -} - -function disallowedPortObject(ctx: Rule.RuleContext, node: estree.Node) { - const objExpr = getValueOfExpression(ctx, node, 'ObjectExpression', true); - if (!objExpr) { - return false; - } - const protocol = getProperty(objExpr, 'protocol', ctx); - - if (!protocol) { - return false; - } - - const protocolValue = getUniqueWriteUsageOrNode(ctx, protocol.value, true); - - if (isUnresolved(protocolValue, ctx) || isUndefined(protocolValue)) { - return false; - } - const protocolFQN = normalizeFQN(getFullyQualifiedName(ctx, protocolValue)); - if (protocolFQN && badFQNProtocols.includes(protocolFQN)) { - const fromPort = Number.parseInt(getPropertyValue(ctx, objExpr, 'fromPort')?.value as string); - const toPort = Number.parseInt(getPropertyValue(ctx, objExpr, 'toPort')?.value as string); - return disallowedPort(fromPort, toPort); - } - return false; -} - -function isBadEc2Peer(ctx: Rule.RuleContext, node: estree.Node): boolean { - const fqn = normalizeFQN(getFullyQualifiedName(ctx, node)); - if (fqn === 'aws_cdk_lib.aws_ec2.Peer.anyIpv4' || fqn === 'aws_cdk_lib.aws_ec2.Peer.anyIpv6') { - return true; - } - if (fqn === 'aws_cdk_lib.aws_ec2.Peer.ipv4') { - return disallowedIpV4(getArgumentValue(ctx, node)?.value as string); - } - if (fqn === 'aws_cdk_lib.aws_ec2.Peer.ipv6') { - return disallowedIpV6(getArgumentValue(ctx, node)?.value as string); - } - return false; -} - -function isBadEc2Port(ctx: Rule.RuleContext, node: estree.Node): boolean { - const fqn = normalizeFQN(getFullyQualifiedName(ctx, node)); - if (fqn === 'aws_cdk_lib.aws_ec2.Port.allTcp' || fqn === 'aws_cdk_lib.aws_ec2.Port.allTraffic') { - return true; - } - if (fqn === 'aws_cdk_lib.aws_ec2.Port.tcp') { - return disallowedPort(getArgumentValue(ctx, node)?.value as number); - } - if (fqn === 'aws_cdk_lib.aws_ec2.Port.tcpRange') { - const startRange = getArgumentValue(ctx, node)?.value as number; - const endRange = getArgumentValue(ctx, node, 1)?.value as number; - return disallowedPort(startRange, endRange); - } - if (fqn === 'aws_cdk_lib.aws_ec2.Port') { - const portParams = getArgument(ctx, node); - if (portParams) { - return disallowedPortObject(ctx, portParams); - } - } - return false; -} - -function getArgument( - ctx: Rule.RuleContext, - node: estree.Node, - position = 0, -): estree.Node | undefined { - if (!node || isUndefined(node) || isUnresolved(node, ctx)) { - return undefined; - } - - const callExpr = getUniqueWriteUsageOrNode(ctx, node, true); - - if ( - isUnresolved(callExpr, ctx) || - isUndefined(callExpr) || - (callExpr.type !== 'CallExpression' && callExpr.type !== 'NewExpression') - ) { - return undefined; - } - - const argument = callExpr.arguments[position]; - - const argumentValue = getUniqueWriteUsageOrNode(ctx, argument, true); - - if (isUnresolved(argumentValue, ctx) || isUndefined(argumentValue)) { - return undefined; - } - - return argumentValue; -} - -function getArgumentValue( - ctx: Rule.RuleContext, - node: estree.Node, - position = 0, -): estree.Literal | undefined { - const argument = getArgument(ctx, node, position); - return argument ? getLiteralValue(ctx, argument) : undefined; -} - -export function getPropertyValue( - ctx: Rule.RuleContext, - node: estree.ObjectExpression, - propertyName: string, -): estree.Literal | undefined { - const property = getProperty(node, propertyName, ctx); - - if (!property) { - return undefined; - } - - const propertyValue = getUniqueWriteUsageOrNode(ctx, property.value, true); - - if (isUnresolved(propertyValue, ctx) || isUndefined(propertyValue)) { - return undefined; - } - - return getLiteralValue(ctx, propertyValue); -} - -function disallowedPort(startRange?: number, endRange?: number): boolean { - if (startRange != null && endRange != null) { - return badPorts.some(port => port >= startRange && port <= endRange); - } - if (startRange != null && endRange == null) { - return badPorts.some(port => port === startRange); - } - return false; -} - -function disallowedIpV4(ip?: string): boolean { - return ip ? badIpsV4.includes(ip) : false; -} - -function disallowedIpV6(ip?: string): boolean { - return ip ? badIpsV6.includes(ip) : false; -} - -function disallowedProtocol(protocol?: string): boolean { - return protocol ? badProtocols.includes(protocol) : false; -} diff --git a/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-granted-access.ts b/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-granted-access.ts deleted file mode 100644 index 5f5a5a53ae3..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-granted-access.ts +++ /dev/null @@ -1,175 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6265/javascript - -import { Rule } from 'eslint'; -import estree from 'estree'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; -import { mergeRules } from './decorators/helpers'; -import { - getFullyQualifiedName, - getUniqueWriteUsageOrNode, - getValueOfExpression, - isIdentifier, - isMethodCall, - toEncodedMessage, -} from './helpers'; -import { normalizeFQN } from './helpers/aws/cdk'; -import { - S3BucketTemplate, - isS3BucketDeploymentConstructor, - findPropagatedSetting, - isS3BucketConstructor, - getProperty, -} from './helpers/aws/s3'; - -const messages = { - accessLevel: (param: string) => `Make sure granting ${param} access is safe here.`, - unrestricted: 'Make sure allowing unrestricted access to objects from this bucket is safe here.', -}; - -const ACCESS_CONTROL_KEY = 'accessControl'; -const INVALID_ACCESS_CONTROL_VALUES = ['PUBLIC_READ', 'PUBLIC_READ_WRITE', 'AUTHENTICATED_READ']; - -const PUBLIC_READ_ACCESS_KEY = 'publicReadAccess'; -const INVALID_PUBLIC_READ_ACCESS_VALUE = true; - -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - return mergeRules( - s3BucketConstructorRule.create(context), - s3BucketDeploymentConstructorRule.create(context), - handleGrantPublicAccess.create(context), - ); - }, - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, -}; - -const s3BucketConstructorRule: Rule.RuleModule = S3BucketTemplate((bucketConstructor, context) => { - for (const value of INVALID_ACCESS_CONTROL_VALUES) { - checkConstantParam(context, bucketConstructor, ACCESS_CONTROL_KEY, [ - 'BucketAccessControl', - value, - ]); - } - checkBooleanParam( - context, - bucketConstructor, - PUBLIC_READ_ACCESS_KEY, - INVALID_PUBLIC_READ_ACCESS_VALUE, - ); -}); - -const s3BucketDeploymentConstructorRule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - return { - NewExpression: (node: estree.NewExpression) => { - if (isS3BucketDeploymentConstructor(context, node)) { - for (const value of INVALID_ACCESS_CONTROL_VALUES) { - checkConstantParam(context, node, ACCESS_CONTROL_KEY, ['BucketAccessControl', value]); - } - } - }, - }; - }, -}; - -function checkBooleanParam( - context: Rule.RuleContext, - bucketConstructor: estree.NewExpression, - propName: string, - propValue: boolean, -) { - const property = getProperty(context, bucketConstructor, propName); - if (property == null) { - return; - } - const propertyLiteralValue = getValueOfExpression(context, property.value, 'Literal'); - if (propertyLiteralValue?.value === propValue) { - const secondary = findPropagatedSetting(property, propertyLiteralValue); - context.report({ - message: toEncodedMessage(messages.unrestricted, secondary.locations, secondary.messages), - node: property, - }); - } -} - -function checkConstantParam( - context: Rule.RuleContext, - bucketConstructor: estree.NewExpression, - propName: string, - paramQualifiers: string[], -) { - const property = getProperty(context, bucketConstructor, propName); - if (property == null) { - return; - } - const propertyLiteralValue = getValueOfExpression(context, property.value, 'MemberExpression'); - if ( - propertyLiteralValue !== undefined && - normalizeFQN(getFullyQualifiedName(context, propertyLiteralValue)) === - `aws_cdk_lib.aws_s3.${paramQualifiers.join('.')}` - ) { - const secondary = findPropagatedSetting(property, propertyLiteralValue); - context.report({ - message: toEncodedMessage( - messages.accessLevel(paramQualifiers[paramQualifiers.length - 1]), - secondary.locations, - secondary.messages, - ), - node: property, - }); - } -} - -const handleGrantPublicAccess: Rule.RuleModule = { - create(context: Rule.RuleContext) { - return { - CallExpression: (node: estree.CallExpression) => { - if (!isMethodCall(node)) { - return; - } - const { object, property } = node.callee; - const isGrantPublicAccessMethodCall = isIdentifier(property, 'grantPublicAccess'); - if (!isGrantPublicAccessMethodCall) { - return; - } - const variableAssignment = getUniqueWriteUsageOrNode(context, object); - const isS3bucketInstance = - variableAssignment.type === 'NewExpression' && - isS3BucketConstructor(context, variableAssignment); - if (!isS3bucketInstance) { - return; - } - context.report({ - message: toEncodedMessage(messages.unrestricted), - node: property, - }); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-insecure-http.ts b/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-insecure-http.ts deleted file mode 100644 index 8fd672677d8..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-insecure-http.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6249/javascript - -import { Rule } from 'eslint'; -import { getValueOfExpression } from './helpers'; -import { getProperty, S3BucketTemplate } from './helpers/aws/s3'; - -const ENFORCE_SSL_KEY = 'enforceSSL'; - -const messages = { - authorized: 'Make sure authorizing HTTP requests is safe here.', - omitted: "Omitting 'enforceSSL' authorizes HTTP requests. Make sure it is safe here.", -}; - -export const rule: Rule.RuleModule = S3BucketTemplate((bucket, context) => { - const enforceSSLProperty = getProperty(context, bucket, ENFORCE_SSL_KEY); - if (enforceSSLProperty == null) { - context.report({ - message: messages['omitted'], - node: bucket.callee, - }); - return; - } - - const enforceSSLValue = getValueOfExpression(context, enforceSSLProperty.value, 'Literal'); - if (enforceSSLValue?.value === false) { - context.report({ - message: messages['authorized'], - node: enforceSSLProperty, - }); - } -}); diff --git a/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-public-access.ts b/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-public-access.ts deleted file mode 100644 index 48b4c58d792..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-public-access.ts +++ /dev/null @@ -1,160 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6281/javascript - -import { Rule } from 'eslint'; -import { NewExpression, ObjectExpression, Property } from 'estree'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; -import { - getFullyQualifiedName, - getValueOfExpression, - isIdentifier, - isProperty, - toEncodedMessage, -} from './helpers'; -import { normalizeFQN } from './helpers/aws/cdk'; -import { findPropagatedSetting, getProperty, S3BucketTemplate } from './helpers/aws/s3'; - -const BLOCK_PUBLIC_ACCESS_KEY = 'blockPublicAccess'; -const BLOCK_PUBLIC_ACCESS_PROPERTY_KEYS = [ - 'blockPublicAcls', - 'blockPublicPolicy', - 'ignorePublicAcls', - 'restrictPublicBuckets', -]; - -const messages = { - omitted: - 'No Public Access Block configuration prevents public ACL/policies ' + - 'to be set on this S3 bucket. Make sure it is safe here.', - public: 'Make sure allowing public ACL/policies to be set is safe here.', -}; - -export const rule: Rule.RuleModule = S3BucketTemplate( - (bucket, context) => { - const blockPublicAccess = getProperty(context, bucket, BLOCK_PUBLIC_ACCESS_KEY); - if (blockPublicAccess == null) { - context.report({ - message: toEncodedMessage(messages['omitted']), - node: bucket.callee, - }); - } else { - checkBlockPublicAccessValue(blockPublicAccess); - checkBlockPublicAccessConstructor(blockPublicAccess); - } - - /** Checks `blockPublicAccess: s3.BlockPublicAccess.BLOCK_ACLS` sensitive pattern */ - function checkBlockPublicAccessValue(blockPublicAccess: Property) { - const blockPublicAccessMember = getValueOfExpression( - context, - blockPublicAccess.value, - 'MemberExpression', - ); - if ( - blockPublicAccessMember !== undefined && - normalizeFQN(getFullyQualifiedName(context, blockPublicAccessMember)) === - 'aws_cdk_lib.aws_s3.BlockPublicAccess.BLOCK_ACLS' - ) { - const propagated = findPropagatedSetting(blockPublicAccess, blockPublicAccessMember); - context.report({ - message: toEncodedMessage(messages['public'], propagated.locations, propagated.messages), - node: blockPublicAccess, - }); - } - } - - /** Checks `blockPublicAccess: new s3.BlockPublicAccess({...})` sensitive pattern */ - function checkBlockPublicAccessConstructor(blockPublicAccess: Property) { - const blockPublicAccessNew = getValueOfExpression( - context, - blockPublicAccess.value, - 'NewExpression', - ); - if ( - blockPublicAccessNew !== undefined && - isS3BlockPublicAccessConstructor(blockPublicAccessNew) - ) { - const blockPublicAccessConfig = getValueOfExpression( - context, - blockPublicAccessNew.arguments[0], - 'ObjectExpression', - ); - if (blockPublicAccessConfig === undefined) { - context.report({ - message: toEncodedMessage(messages['omitted']), - node: blockPublicAccessNew, - }); - } else { - BLOCK_PUBLIC_ACCESS_PROPERTY_KEYS.forEach(key => - checkBlockPublicAccessConstructorProperty(blockPublicAccessConfig, key), - ); - } - } - - function checkBlockPublicAccessConstructorProperty( - blockPublicAccessConfig: ObjectExpression, - key: string, - ) { - const blockPublicAccessProperty = blockPublicAccessConfig.properties.find( - property => isProperty(property) && isIdentifier(property.key, key), - ) as Property | undefined; - if (blockPublicAccessProperty !== undefined) { - const blockPublicAccessValue = getValueOfExpression( - context, - blockPublicAccessProperty.value, - 'Literal', - ); - if (blockPublicAccessValue?.value === false) { - const propagated = findPropagatedSetting( - blockPublicAccessProperty, - blockPublicAccessValue, - ); - context.report({ - message: toEncodedMessage( - messages['public'], - propagated.locations, - propagated.messages, - ), - node: blockPublicAccessProperty, - }); - } - } - } - - function isS3BlockPublicAccessConstructor(expr: NewExpression) { - return ( - expr.callee.type === 'MemberExpression' && - normalizeFQN(getFullyQualifiedName(context, expr.callee)) === - 'aws_cdk_lib.aws_s3.BlockPublicAccess' - ); - } - } - }, - { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - }, -); diff --git a/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-server-encryption.ts b/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-server-encryption.ts deleted file mode 100644 index a8276316208..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-server-encryption.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6245/javascript - -import { Rule } from 'eslint'; -import { MemberExpression } from 'estree'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; -import { getFullyQualifiedName, getValueOfExpression, toEncodedMessage } from './helpers'; -import { normalizeFQN } from './helpers/aws/cdk'; -import { findPropagatedSetting, getProperty, S3BucketTemplate } from './helpers/aws/s3'; - -const ENCRYPTED_KEY = 'encryption'; - -const messages = { - unencrypted: 'Objects in the bucket are not encrypted. Make sure it is safe here.', - omitted: 'Omitting "encryption" disables server-side encryption. Make sure it is safe here.', -}; - -export const rule: Rule.RuleModule = S3BucketTemplate( - (bucket, context) => { - const encryptedProperty = getProperty(context, bucket, ENCRYPTED_KEY); - if (encryptedProperty == null) { - context.report({ - message: toEncodedMessage(messages['omitted'], [], []), - node: bucket.callee, - }); - return; - } - - const encryptedValue = getValueOfExpression( - context, - encryptedProperty.value, - 'MemberExpression', - ); - if (encryptedValue && isUnencrypted(encryptedValue)) { - const propagated = findPropagatedSetting(encryptedProperty, encryptedValue); - context.report({ - message: toEncodedMessage( - messages['unencrypted'], - propagated.locations, - propagated.messages, - ), - node: encryptedProperty, - }); - } - - function isUnencrypted(encrypted: MemberExpression) { - return ( - normalizeFQN(getFullyQualifiedName(context, encrypted)) === - 'aws_cdk_lib.aws_s3.BucketEncryption.UNENCRYPTED' - ); - } - }, - { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - }, -); diff --git a/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-versioning.ts b/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-versioning.ts deleted file mode 100644 index af12f8dfc24..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-s3-bucket-versioning.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6252/javascript - -import { Rule } from 'eslint'; -import { Node } from 'estree'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; -import { getValueOfExpression, toEncodedMessage, getNodeParent } from './helpers'; -import { getProperty, S3BucketTemplate } from './helpers/aws/s3'; - -const VERSIONED_KEY = 'versioned'; - -const messages = { - unversioned: 'Make sure using unversioned S3 bucket is safe here.', - omitted: - 'Omitting the "versioned" argument disables S3 bucket versioning. Make sure it is safe here.', - secondary: 'Propagated setting', -}; - -export const rule: Rule.RuleModule = S3BucketTemplate( - (bucketConstructor, context) => { - const versionedProperty = getProperty(context, bucketConstructor, VERSIONED_KEY); - if (versionedProperty == null) { - context.report({ - message: toEncodedMessage(messages.omitted), - node: bucketConstructor.callee, - }); - return; - } - const propertyLiteralValue = getValueOfExpression(context, versionedProperty.value, 'Literal'); - - if (propertyLiteralValue?.value === false) { - const secondary = { locations: [] as Node[], messages: [] as string[] }; - const isPropagatedProperty = versionedProperty.value !== propertyLiteralValue; - if (isPropagatedProperty) { - secondary.locations = [getNodeParent(propertyLiteralValue)]; - secondary.messages = [messages.secondary]; - } - context.report({ - message: toEncodedMessage(messages.unversioned, secondary.locations, secondary.messages), - node: versionedProperty, - }); - } - }, - { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - }, -); diff --git a/eslint-bridge/src/linting/eslint/rules/aws-sagemaker-unencrypted-notebook.ts b/eslint-bridge/src/linting/eslint/rules/aws-sagemaker-unencrypted-notebook.ts deleted file mode 100644 index 88cc606fda8..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-sagemaker-unencrypted-notebook.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6319/javascript - -import { Rule } from 'eslint'; -import { AwsCdkCheckArguments, AwsCdkTemplate } from './helpers/aws/cdk'; - -export const rule: Rule.RuleModule = AwsCdkTemplate( - { - 'aws-cdk-lib.aws_sagemaker.CfnNotebookInstance': AwsCdkCheckArguments( - 'CfnNotebookInstance', - true, - 'kmsKeyId', - ), - }, - { - meta: { - messages: { - CfnNotebookInstance: - 'Omitting "kmsKeyId" disables encryption of SageMaker notebook instances. Make sure it is safe here.', - }, - }, - }, -); diff --git a/eslint-bridge/src/linting/eslint/rules/aws-sns-unencrypted-topics.ts b/eslint-bridge/src/linting/eslint/rules/aws-sns-unencrypted-topics.ts deleted file mode 100644 index 43a358f615d..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-sns-unencrypted-topics.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6327/javascript - -import { Rule } from 'eslint'; -import { AwsCdkCheckArguments, AwsCdkTemplate } from './helpers/aws/cdk'; - -export const rule: Rule.RuleModule = AwsCdkTemplate( - { - 'aws-cdk-lib.aws_sns.Topic': AwsCdkCheckArguments('SNSTopic', true, 'masterKey'), - 'aws-cdk-lib.aws_sns.CfnTopic': AwsCdkCheckArguments('SNSCfnTopic', true, 'kmsMasterKeyId'), - }, - { - meta: { - messages: { - SNSTopic: 'Omitting "masterKey" disables SNS topics encryption. Make sure it is safe here.', - SNSCfnTopic: - 'Omitting "kmsMasterKeyId" disables SNS topics encryption. Make sure it is safe here.', - }, - }, - }, -); diff --git a/eslint-bridge/src/linting/eslint/rules/aws-sqs-unencrypted-queue.ts b/eslint-bridge/src/linting/eslint/rules/aws-sqs-unencrypted-queue.ts deleted file mode 100644 index d6d10945dd5..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/aws-sqs-unencrypted-queue.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6308/javascript - -import { Rule } from 'eslint'; -import { AwsCdkCheckArguments, AwsCdkTemplate } from './helpers/aws/cdk'; - -export const rule: Rule.RuleModule = AwsCdkTemplate( - { - 'aws-cdk-lib.aws-sqs.Queue': AwsCdkCheckArguments( - ['OmittedQueue', 'DisabledQueue'], - true, - 'encryption', - { fqns: { invalid: ['aws-cdk-lib.aws-sqs.QueueEncryption.UNENCRYPTED'] } }, - ), - 'aws-cdk-lib.aws-sqs.CfnQueue': AwsCdkCheckArguments('CfnQueue', true, 'kmsMasterKeyId'), - }, - { - meta: { - messages: { - CfnQueue: - 'Omitting "kmsMasterKeyId" disables SQS queues encryption. Make sure it is safe here.', - OmittedQueue: - 'Omitting "encryption" disables SQS queues encryption. Make sure it is safe here.', - DisabledQueue: - 'Setting "encryption" to "QueueEncryption.UNENCRYPTED" disables SQS queues encryption.' + - 'Make sure it is safe here.', - }, - }, - }, -); diff --git a/eslint-bridge/src/linting/eslint/rules/bitwise-operators.ts b/eslint-bridge/src/linting/eslint/rules/bitwise-operators.ts deleted file mode 100644 index 5b97aaeb5af..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/bitwise-operators.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1529/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import * as ts from 'typescript'; -import { getTypeFromTreeNode } from './helpers'; - -const BITWISE_AND_OR = ['&', '|']; -const BITWISE_OPERATORS = [ - '&', - '|', - '^', - '~', - '<<', - '>>', - '>>>', - '&=', - '|=', - '^=', - '<<=', - '>>=', - '>>>=', -]; - -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - const isNumeric = getNumericTypeChecker(context); - let lonelyBitwiseAndOr: null | estree.BinaryExpression = null; - let lonelyBitwiseAndOrAncestors: estree.Node[] = []; - let fileContainsSeveralBitwiseOperations = false; - return { - BinaryExpression(node: estree.Node) { - const expression = node as estree.BinaryExpression; - if ( - !lonelyBitwiseAndOr && - BITWISE_AND_OR.includes(expression.operator) && - !isNumeric(expression.left) && - !isNumeric(expression.right) - ) { - lonelyBitwiseAndOr = expression; - lonelyBitwiseAndOrAncestors = [...context.getAncestors()]; - } else if (BITWISE_OPERATORS.includes(expression.operator)) { - fileContainsSeveralBitwiseOperations = true; - } - }, - 'Program:exit': function () { - if ( - !fileContainsSeveralBitwiseOperations && - lonelyBitwiseAndOr && - insideCondition(lonelyBitwiseAndOr, lonelyBitwiseAndOrAncestors) - ) { - const op = lonelyBitwiseAndOr.operator; - const operatorToken = context.getSourceCode().getTokenAfter(lonelyBitwiseAndOr.left); - if (operatorToken) { - context.report({ - loc: operatorToken.loc, - message: `Review this use of bitwise "${op}" operator; conditional "${op}${op}" might have been intended.`, - }); - } - } - }, - }; - }, -}; - -function insideCondition(node: estree.Node, ancestors: estree.Node[]) { - let child = node; - for (let i = ancestors.length - 1; i >= 0; i--) { - const parent = ancestors[i]; - if ( - parent.type === 'IfStatement' || - parent.type === 'ForStatement' || - parent.type === 'WhileStatement' || - parent.type === 'DoWhileStatement' || - parent.type === 'ConditionalExpression' - ) { - return parent.test === child; - } - child = parent; - } - return false; -} - -type NumericTypeChecker = (node: estree.Node) => boolean; - -function getNumericTypeChecker(context: Rule.RuleContext): NumericTypeChecker { - const services = context.parserServices; - if (!!services && !!services.program && !!services.esTreeNodeToTSNodeMap) { - return (node: estree.Node) => isNumericType(getTypeFromTreeNode(node, services)); - } else { - const numericTypes = ['number', 'bigint']; - return (node: estree.Node) => - node.type === 'Literal' ? numericTypes.includes(typeof node.value) : false; - } - - function isNumericType(type: ts.Type): boolean { - return ( - (type.getFlags() & (ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike)) !== 0 || - (type.isUnionOrIntersection() && !!type.types.find(isNumericType)) - ); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/bool-param-default.ts b/eslint-bridge/src/linting/eslint/rules/bool-param-default.ts deleted file mode 100644 index 543f571e4a8..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/bool-param-default.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4798/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -type FunctionLike = - | TSESTree.FunctionDeclaration - | TSESTree.FunctionExpression - | TSESTree.ArrowFunctionExpression; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - provideDefault: - "Provide a default value for '{{parameter}}' so that " + - 'the logic of the function is more evident when this parameter is missing. ' + - 'Consider defining another function if providing default value is not possible.', - }, - }, - create(context: Rule.RuleContext) { - return { - 'FunctionDeclaration, FunctionExpression, ArrowFunctionExpression': (node: estree.Node) => { - const functionLike = node as FunctionLike; - for (const param of functionLike.params) { - if (param.type === 'Identifier' && isOptionalBoolean(param)) { - context.report({ - messageId: 'provideDefault', - data: { - parameter: param.name, - }, - node: param as estree.Node, - }); - } - } - }, - }; - }, -}; - -function isOptionalBoolean(node: TSESTree.Identifier): boolean { - return usesQuestionOptionalSyntax(node) || usesUnionUndefinedOptionalSyntax(node); -} - -/** - * Matches "param?: boolean" - */ -function usesQuestionOptionalSyntax(node: TSESTree.Identifier): boolean { - return ( - !!node.optional && - !!node.typeAnnotation && - node.typeAnnotation.typeAnnotation.type === 'TSBooleanKeyword' - ); -} - -/** - * Matches "boolean | undefined" - */ -function usesUnionUndefinedOptionalSyntax(node: TSESTree.Identifier): boolean { - if (!!node.typeAnnotation && node.typeAnnotation.typeAnnotation.type === 'TSUnionType') { - const types = node.typeAnnotation.typeAnnotation.types; - return ( - types.length === 2 && - types.some(tp => tp.type === 'TSBooleanKeyword') && - types.some(tp => tp.type === 'TSUndefinedKeyword') - ); - } - return false; -} diff --git a/eslint-bridge/src/linting/eslint/rules/call-argument-line.ts b/eslint-bridge/src/linting/eslint/rules/call-argument-line.ts deleted file mode 100644 index e0d40ee05b4..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/call-argument-line.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1472/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - moveArguments: 'Make those call arguments start on line {{line}}.', - }, - }, - create(context: Rule.RuleContext) { - return { - CallExpression: (node: estree.Node) => { - const call = node as estree.CallExpression; - if (call.callee.type !== 'CallExpression' && call.arguments.length === 1) { - const sourceCode = context.getSourceCode(); - const parenthesis = sourceCode.getLastTokenBetween( - call.callee, - call.arguments[0], - token => token.type === 'Punctuator' && token.value === ')', - ); - const calleeLastLine = (parenthesis ? parenthesis : sourceCode.getLastToken(call.callee))! - .loc.end.line; - const { start } = sourceCode.getTokenAfter(call.callee)!.loc; - if (calleeLastLine !== start.line) { - const { end } = sourceCode.getLastToken(call)!.loc; - if (end.line !== start.line) { - //If arguments span multiple lines, we only report the first one - reportIssue(start, calleeLastLine, context); - } else { - reportIssue({ start, end }, calleeLastLine, context); - } - } - } - }, - }; - }, -}; - -function reportIssue( - loc: { start: estree.Position; end: estree.Position } | estree.Position, - line: number, - context: Rule.RuleContext, -) { - context.report({ - messageId: 'moveArguments', - data: { - line: line.toString(), - }, - loc, - }); -} diff --git a/eslint-bridge/src/linting/eslint/rules/certificate-transparency.ts b/eslint-bridge/src/linting/eslint/rules/certificate-transparency.ts deleted file mode 100644 index b820f808c91..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/certificate-transparency.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5742/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { Express, getFullyQualifiedName, getPropertyWithValue } from './helpers'; - -const HELMET = 'helmet'; -const EXPECT_CERTIFICATE_TRANSPARENCY = 'expectCt'; - -export const rule: Rule.RuleModule = Express.SensitiveMiddlewarePropertyRule( - findFalseCertificateTransparencyPropertyFromHelmet, - `Make sure disabling Certificate Transparency monitoring is safe here.`, -); - -/** - * Looks for property `expectCt: false` in node looking - * somewhat similar to `helmet(?)`, and returns it. - */ -function findFalseCertificateTransparencyPropertyFromHelmet( - context: Rule.RuleContext, - node: estree.CallExpression, -): estree.Property[] { - let sensitive: estree.Property | undefined; - const { callee, arguments: args } = node; - if ( - getFullyQualifiedName(context, callee) === HELMET && - args.length === 1 && - args[0].type === 'ObjectExpression' - ) { - sensitive = getPropertyWithValue(context, args[0], EXPECT_CERTIFICATE_TRANSPARENCY, false); - } - return sensitive ? [sensitive] : []; -} diff --git a/eslint-bridge/src/linting/eslint/rules/chai-determinate-assertion.ts b/eslint-bridge/src/linting/eslint/rules/chai-determinate-assertion.ts deleted file mode 100644 index 9a53add244e..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/chai-determinate-assertion.ts +++ /dev/null @@ -1,179 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6092/javascript - -import { Rule } from 'eslint'; -import { Chai, isDotNotation, isIdentifier } from './helpers'; -import * as estree from 'estree'; - -const message = 'Refactor this uncertain assertion; it can succeed for multiple reasons.'; - -type ChainElement = { - identifier: estree.Identifier; - arguments?: estree.Node[]; -}; - -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - if (!Chai.isImported(context)) { - return {}; - } - return { - ExpressionStatement: (node: estree.ExpressionStatement) => { - const elements: ChainElement[] = retrieveAssertionChainElements(node.expression); - - if ( - elements.length > 1 && - (isIdentifier(elements[0].identifier, 'expect') || - getElementIndex(elements, 'should') >= 0) - ) { - checkNotThrow(context, elements); - checkNotInclude(context, elements); - checkNotHaveProperty(context, elements); - checkNotHaveOwnPropertyDescriptor(context, elements); - checkNotHaveMembers(context, elements); - checkChangeBy(context, elements); - checkNotIncDec(context, elements); - checkNotBy(context, elements); - checkNotFinite(context, elements); - } - }, - }; - }, -}; - -function checkNotThrow(context: Rule.RuleContext, elements: ChainElement[]) { - checkWithCondition(context, elements, 'not', 'throw', args => !!args && args.length > 0); -} - -function checkNotInclude(context: Rule.RuleContext, elements: ChainElement[]) { - checkWithCondition( - context, - elements, - 'not', - 'include', - args => !!args && args.length > 0 && args[0].type === 'ObjectExpression', - ); -} - -function checkNotHaveProperty(context: Rule.RuleContext, elements: ChainElement[]) { - checkWithCondition(context, elements, 'not', 'property', args => !!args && args.length > 1); -} - -function checkNotHaveOwnPropertyDescriptor(context: Rule.RuleContext, elements: ChainElement[]) { - checkWithCondition( - context, - elements, - 'not', - 'ownPropertyDescriptor', - args => !!args && args.length > 1, - ); -} - -function checkNotHaveMembers(context: Rule.RuleContext, elements: ChainElement[]) { - checkWithCondition(context, elements, 'not', 'members'); -} - -function checkChangeBy(context: Rule.RuleContext, elements: ChainElement[]) { - checkWithCondition(context, elements, 'change', 'by'); -} - -function checkNotIncDec(context: Rule.RuleContext, elements: ChainElement[]) { - checkWithCondition(context, elements, 'not', 'increase'); - checkWithCondition(context, elements, 'not', 'decrease'); -} - -function checkNotBy(context: Rule.RuleContext, elements: ChainElement[]) { - checkWithCondition(context, elements, 'not', 'by'); -} - -function checkNotFinite(context: Rule.RuleContext, elements: ChainElement[]) { - checkWithCondition(context, elements, 'not', 'finite'); -} - -function checkWithCondition( - context: Rule.RuleContext, - elements: ChainElement[], - first: string, - second: string, - condition: (args?: estree.Node[]) => boolean = () => true, -) { - const firstIndex = getElementIndex(elements, first); - const firstElement = elements[firstIndex]; - - const secondIndex = getElementIndex(elements, second); - const secondElement = elements[secondIndex]; - - if ( - firstElement && - secondElement && - neighborIndexes(firstIndex, secondIndex, elements) && - condition(secondElement.arguments) - ) { - context.report({ - message, - loc: locFromTwoNodes(firstElement.identifier, secondElement.identifier), - }); - } -} - -// first element is not applied to second if between them function call (e.g. fist.foo().second()) -function neighborIndexes(firstIndex: number, secondIndex: number, elements: ChainElement[]) { - if (firstIndex === secondIndex - 2) { - return !elements[firstIndex + 1].arguments; - } - - return firstIndex === secondIndex - 1; -} - -function retrieveAssertionChainElements(node: estree.Expression) { - let currentNode: estree.Node = node; - const result: ChainElement[] = []; - let currentArguments: estree.Node[] | undefined = undefined; - - while (true) { - if (isDotNotation(currentNode)) { - result.push({ identifier: currentNode.property, arguments: currentArguments }); - currentNode = currentNode.object; - currentArguments = undefined; - } else if (currentNode.type === 'CallExpression') { - currentArguments = currentNode.arguments; - currentNode = currentNode.callee; - } else if (isIdentifier(currentNode)) { - result.push({ identifier: currentNode, arguments: currentArguments }); - break; - } else { - break; - } - } - - return result.reverse(); -} - -function getElementIndex(elements: ChainElement[], name: string) { - return elements.findIndex(element => isIdentifier(element.identifier, name)); -} - -function locFromTwoNodes(start: estree.Node, end: estree.Node) { - return { - start: start.loc!.start, - end: end.loc!.end, - }; -} diff --git a/eslint-bridge/src/linting/eslint/rules/class-name.ts b/eslint-bridge/src/linting/eslint/rules/class-name.ts deleted file mode 100644 index c92cee8d2a1..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/class-name.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S101/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -type ClassOrInterfaceDeclaration = TSESTree.ClassDeclaration | TSESTree.TSInterfaceDeclaration; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - renameClass: 'Rename {{symbolType}} "{{symbol}}" to match the regular expression {{format}}.', - }, - }, - create(context: Rule.RuleContext) { - return { - ClassDeclaration: (node: estree.Node) => - checkName(node as ClassOrInterfaceDeclaration, 'class', context), - TSInterfaceDeclaration: (node: estree.Node) => - checkName(node as ClassOrInterfaceDeclaration, 'interface', context), - }; - }, -}; - -function checkName( - node: ClassOrInterfaceDeclaration, - declarationType: string, - context: Rule.RuleContext, -) { - const [{ format }] = context.options; - if (node.id) { - const name = node.id.name; - if (!name.match(format)) { - context.report({ - messageId: 'renameClass', - data: { - symbol: name, - symbolType: declarationType, - format, - }, - node: node.id, - }); - } - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/class-prototype.ts b/eslint-bridge/src/linting/eslint/rules/class-prototype.ts deleted file mode 100644 index 83e0c6a6f56..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/class-prototype.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3525/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import * as ts from 'typescript'; -import { getTypeFromTreeNode, isRequiredParserServices, RequiredParserServices } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - declareClass: - 'Declare a "{{class}}" class and move this declaration of "{{declaration}}" into it.', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - const isFunction = isRequiredParserServices(services) ? isFunctionType : isFunctionLike; - return { - AssignmentExpression: (node: estree.Node) => { - const { left, right } = node as estree.AssignmentExpression; - if (left.type === 'MemberExpression' && isFunction(right, services)) { - const [member, prototype] = [left.object, left.property]; - if (member.type === 'MemberExpression' && prototype.type === 'Identifier') { - const [klass, property] = [member.object, member.property]; - if ( - klass.type === 'Identifier' && - property.type === 'Identifier' && - property.name === 'prototype' - ) { - context.report({ - messageId: 'declareClass', - data: { - class: klass.name, - declaration: prototype.name, - }, - node: left, - }); - } - } - } - }, - }; - }, -}; - -function isFunctionType(node: estree.Node, services: RequiredParserServices) { - const type = getTypeFromTreeNode(node, services); - return type.symbol && (type.symbol.flags & ts.SymbolFlags.Function) !== 0; -} - -function isFunctionLike(node: estree.Node, _services: RequiredParserServices) { - return ['FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'].includes( - node.type, - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/code-eval.ts b/eslint-bridge/src/linting/eslint/rules/code-eval.ts deleted file mode 100644 index 324a5e8616d..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/code-eval.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1523/javascript -// SQ key 'eval' - -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - safeCode: 'Make sure that this dynamic injection or execution of code is safe.', - }, - }, - create(context: Rule.RuleContext) { - return { - CallExpression: (node: estree.Node) => - checkCallExpression(node as estree.CallExpression, context), - NewExpression: (node: estree.Node) => - checkCallExpression(node as estree.CallExpression, context), - }; - }, -}; - -function checkCallExpression(node: estree.CallExpression, context: Rule.RuleContext) { - if (node.callee.type === 'Identifier') { - const { name } = node.callee; - if ((name === 'eval' || name === 'Function') && hasAtLeastOneVariableArgument(node.arguments)) { - context.report({ - messageId: 'safeCode', - node: node.callee, - }); - } - } -} - -function hasAtLeastOneVariableArgument(args: Array) { - return !!args.find(arg => !isLiteral(arg)); -} - -function isLiteral(node: estree.Node) { - if (node.type === 'Literal') { - return true; - } - - if (node.type === 'TemplateLiteral') { - return node.expressions.length === 0; - } - - return false; -} diff --git a/eslint-bridge/src/linting/eslint/rules/comma-or-logical-or-case.ts b/eslint-bridge/src/linting/eslint/rules/comma-or-logical-or-case.ts deleted file mode 100644 index ab7c9d525a2..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/comma-or-logical-or-case.ts +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3616/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isLiteral } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - specifyCase: `Explicitly specify {{nesting}} separate cases that fall through; currently this case clause only works for "{{expression}}".`, - }, - }, - create(context: Rule.RuleContext) { - function reportIssue(node: estree.Node, clause: estree.Node, nestingLvl: number) { - context.report({ - messageId: 'specifyCase', - data: { - nesting: nestingLvl.toString(), - expression: String(getTextFromNode(clause)), - }, - node, - }); - } - - function getTextFromNode(node: estree.Node) { - if (node.type === 'Literal') { - return node.value; - } else { - return context.getSourceCode().getText(node); - } - } - - return { - 'SwitchCase > SequenceExpression': function (node: estree.Node) { - const expressions = (node as estree.SequenceExpression).expressions; - reportIssue(node, expressions[expressions.length - 1], expressions.length); - }, - 'SwitchCase > LogicalExpression': function (node: estree.Node) { - if (!isSwitchTrue(getEnclosingSwitchStatement(context))) { - const firstElemAndNesting = getFirstElementAndNestingLevel( - node as estree.LogicalExpression, - 0, - ); - if (firstElemAndNesting) { - reportIssue(node, firstElemAndNesting[0], firstElemAndNesting[1] + 1); - } - } - }, - }; - }, -}; - -function getEnclosingSwitchStatement(context: Rule.RuleContext): estree.SwitchStatement { - const ancestors = context.getAncestors(); - for (let i = ancestors.length - 1; i >= 0; i--) { - if (ancestors[i].type === 'SwitchStatement') { - return ancestors[i] as estree.SwitchStatement; - } - } - throw new Error('A switch case should have an enclosing switch statement'); -} - -function isSwitchTrue(node: estree.SwitchStatement) { - return isLiteral(node.discriminant) && node.discriminant.value === true; -} - -function getFirstElementAndNestingLevel( - logicalExpression: estree.LogicalExpression, - currentLvl: number, -): [estree.Node, number] | undefined { - if (logicalExpression.operator === '||') { - if (logicalExpression.left.type === 'LogicalExpression') { - return getFirstElementAndNestingLevel(logicalExpression.left, currentLvl + 1); - } else { - return [logicalExpression.left, currentLvl + 1]; - } - } - return undefined; -} diff --git a/eslint-bridge/src/linting/eslint/rules/comment-regex.ts b/eslint-bridge/src/linting/eslint/rules/comment-regex.ts deleted file mode 100644 index 0197ec9f3d8..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/comment-regex.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S124/javascript - -import { Rule } from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - type: 'object', - properties: { - regularExpression: { - type: 'string', - }, - message: { - type: 'string', - }, - flags: { - type: 'string', - }, - }, - additionalProperties: false, - }, - ], - }, - - create(context: Rule.RuleContext) { - const options = context.options[0] || {}; - const flags = options.flags || ''; - const cleanedFlags = 'gimusy' - .split('') - .filter(c => flags.includes(c)) - .join(''); - const pattern = options.regularExpression - ? new RegExp(options.regularExpression, cleanedFlags) - : undefined; - const message = options.message || 'The regular expression matches this comment.'; - - return { - 'Program:exit': () => { - (context.getSourceCode().getAllComments() as TSESTree.Comment[]).forEach(comment => { - const rawTextTrimmed = comment.value.trim(); - if (pattern && pattern.test(rawTextTrimmed)) { - context.report({ - message, - loc: comment.loc, - }); - } - }); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/concise-regex.ts b/eslint-bridge/src/linting/eslint/rules/concise-regex.ts deleted file mode 100644 index cc35e7abd8d..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/concise-regex.ts +++ /dev/null @@ -1,158 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6353/javascript - -import { Rule } from 'eslint'; -import { CharacterClass, Flags, Quantifier, RegExpLiteral } from 'regexpp/ast'; -import { createRegExpRule, RegexRuleContext } from './helpers/regex'; - -export const rule: Rule.RuleModule = createRegExpRule(context => { - let flags: Flags; - return { - onRegExpLiteralEnter: (node: RegExpLiteral) => { - ({ flags } = node); - }, - onCharacterClassEnter: (node: CharacterClass) => { - checkBulkyAnyCharacterClass(node, flags, context); - checkBulkyNumericCharacterClass(node, context); - checkBulkyAlphaNumericCharacterClass(node, context); - }, - onQuantifierEnter: (node: Quantifier) => { - checkBulkyQuantifier(node, context); - }, - }; -}); - -function checkBulkyAnyCharacterClass( - node: CharacterClass, - flags: Flags, - context: RegexRuleContext, -) { - if (node.negate || node.elements.length !== 2) { - return; - } - let hasLowerEscapeW = false; - let hasUpperEscapeW = false; - let hasLowerEscapeD = false; - let hasUpperEscapeD = false; - let hasLowerEscapeS = false; - let hasUpperEscapeS = false; - node.elements.forEach(element => { - hasLowerEscapeW ||= - element.type === 'CharacterSet' && element.kind === 'word' && !element.negate; - hasUpperEscapeW ||= - element.type === 'CharacterSet' && element.kind === 'word' && element.negate; - hasLowerEscapeD ||= - element.type === 'CharacterSet' && element.kind === 'digit' && !element.negate; - hasUpperEscapeD ||= - element.type === 'CharacterSet' && element.kind === 'digit' && element.negate; - hasLowerEscapeS ||= - element.type === 'CharacterSet' && element.kind === 'space' && !element.negate; - hasUpperEscapeS ||= - element.type === 'CharacterSet' && element.kind === 'space' && element.negate; - }); - const isBulkyAnyCharacterClass = - (hasLowerEscapeW && hasUpperEscapeW) || - (hasLowerEscapeD && hasUpperEscapeD) || - (hasLowerEscapeS && hasUpperEscapeS && flags.dotAll); - if (isBulkyAnyCharacterClass) { - context.reportRegExpNode({ - message: `Use concise character class syntax '.' instead of '${node.raw}'.`, - node: context.node, - regexpNode: node, - }); - } -} - -function checkBulkyNumericCharacterClass(node: CharacterClass, context: RegexRuleContext) { - if (node.elements.length === 1) { - const [element] = node.elements; - const hasDigit = element.type === 'CharacterClassRange' && element.raw === '0-9'; - if (hasDigit) { - const expected = node.negate ? '\\D' : '\\d'; - const actual = node.raw; - context.reportRegExpNode({ - message: `Use concise character class syntax '${expected}' instead of '${actual}'.`, - node: context.node, - regexpNode: node, - }); - } - } -} - -function checkBulkyAlphaNumericCharacterClass(node: CharacterClass, context: RegexRuleContext) { - if (node.elements.length === 4) { - let hasDigit = false, - hasLowerCase = false, - hasUpperCase = false, - hasUnderscore = false; - for (const element of node.elements) { - hasDigit ||= element.type === 'CharacterClassRange' && element.raw === '0-9'; - hasLowerCase ||= element.type === 'CharacterClassRange' && element.raw === 'a-z'; - hasUpperCase ||= element.type === 'CharacterClassRange' && element.raw === 'A-Z'; - hasUnderscore ||= element.type === 'Character' && element.raw === '_'; - } - if (hasDigit && hasLowerCase && hasUpperCase && hasUnderscore) { - const expected = node.negate ? '\\W' : '\\w'; - const actual = node.raw; - context.reportRegExpNode({ - message: `Use concise character class syntax '${expected}' instead of '${actual}'.`, - node: context.node, - regexpNode: node, - }); - } - } -} - -function checkBulkyQuantifier(node: Quantifier, context: RegexRuleContext) { - const { raw } = node; - let message: string | undefined; - let bulkyQuantifier: { concise: string; verbose: string } | undefined; - - if (/\{0,1\}\??$/.test(raw)) { - bulkyQuantifier = { concise: '?', verbose: '{0,1}' }; - } else if (/\{0,0\}\??$/.test(raw)) { - message = `Remove redundant ${node.element.raw}{0,0}.`; - } else if (/\{0\}\??$/.test(raw)) { - message = `Remove redundant ${node.element.raw}{0}.`; - } else if (/\{1,1\}\??$/.test(raw)) { - message = 'Remove redundant quantifier {1,1}.'; - } else if (/\{1\}\??$/.test(raw)) { - message = 'Remove redundant quantifier {1}.'; - } else if (/\{0,\}\??$/.test(raw)) { - bulkyQuantifier = { concise: '*', verbose: '{0,}' }; - } else if (/\{1,\}\??$/.test(raw)) { - bulkyQuantifier = { concise: '+', verbose: '{1,}' }; - } else if (/\{(\d+),\1\}\??$/.test(raw)) { - bulkyQuantifier = { concise: `{${node.min}}`, verbose: `{${node.min},${node.min}}` }; - } - - if (bulkyQuantifier) { - message = `Use concise quantifier syntax '${bulkyQuantifier.concise}' instead of '${bulkyQuantifier.verbose}'.`; - } - - if (message) { - context.reportRegExpNode({ - message, - node: context.node, - regexpNode: node, - }); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/conditional-indentation.ts b/eslint-bridge/src/linting/eslint/rules/conditional-indentation.ts deleted file mode 100644 index 55107474c17..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/conditional-indentation.ts +++ /dev/null @@ -1,110 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3973/javascript - -import { Rule, AST, SourceCode } from 'eslint'; -import * as estree from 'estree'; -import { getParent, LoopLike, toEncodedMessage } from './helpers'; -import { TSESLint } from '@typescript-eslint/experimental-utils'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - - create(context: Rule.RuleContext) { - const sourceCode = context.getSourceCode(); - return { - IfStatement: (node: estree.Node) => { - const ifStatement = node as estree.IfStatement; - const parent = getParent(context); - if (parent && parent.type !== 'IfStatement') { - const firstToken = sourceCode.getFirstToken(node); - checkIndentation(firstToken, ifStatement.consequent, context); - } - - if (ifStatement.alternate) { - const elseToken = sourceCode.getTokenBefore( - ifStatement.alternate, - token => token.type === 'Keyword' && token.value === 'else', - ); - const alternate = ifStatement.alternate; - if (alternate.type === 'IfStatement') { - //case with "else if", we have to check the consequent of the next if - checkIndentation(elseToken, alternate.consequent, context); - } else { - checkIndentation( - getPrecedingBrace(elseToken, sourceCode) || elseToken, - alternate, - context, - elseToken, - ); - } - } - }, - 'WhileStatement, ForStatement, ForInStatement, ForOfStatement': (node: estree.Node) => { - const firstToken = sourceCode.getFirstToken(node); - checkIndentation(firstToken, (node as LoopLike).body, context); - }, - }; - }, -}; - -function checkIndentation( - firstToken: AST.Token | null, - statement: estree.Statement, - context: Rule.RuleContext, - tokenToReport = firstToken, -) { - if (firstToken && tokenToReport && statement.type !== 'BlockStatement') { - const firstStatementToken = context.getSourceCode().getFirstToken(statement); - if ( - firstStatementToken && - firstToken.loc.start.column >= firstStatementToken.loc.start.column - ) { - const message = - `Use curly braces or indentation to denote the code conditionally ` + - `executed by this "${tokenToReport.value}".`; - context.report({ - message: toEncodedMessage(message, [firstStatementToken as TSESLint.AST.Token]), - loc: tokenToReport.loc, - }); - } - } -} - -function getPrecedingBrace(elseToken: AST.Token | null, sourceCode: SourceCode) { - if (elseToken) { - const tokenBeforeElse = sourceCode.getTokenBefore(elseToken); - if ( - tokenBeforeElse?.value === '}' && - tokenBeforeElse.loc.start.line === elseToken.loc.start.line - ) { - return tokenBeforeElse; - } - } - return undefined; -} diff --git a/eslint-bridge/src/linting/eslint/rules/confidential-information-logging.ts b/eslint-bridge/src/linting/eslint/rules/confidential-information-logging.ts deleted file mode 100644 index fd9d062f268..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/confidential-information-logging.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5757/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { - getValueOfExpression, - getObjectExpressionProperty, - toEncodedMessage, - getFullyQualifiedName, -} from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -const MESSAGE = 'Make sure confidential information is not logged here.'; -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - return { - NewExpression: (node: estree.Node) => { - const newExpression = node as estree.NewExpression; - const { callee } = newExpression; - if (getFullyQualifiedName(context, callee) !== 'signale.Signale') { - return; - } - if (newExpression.arguments.length === 0) { - context.report({ node: callee, message: toEncodedMessage(MESSAGE, []) }); - return; - } - const firstArgument = getValueOfExpression( - context, - newExpression.arguments[0], - 'ObjectExpression', - ); - if (!firstArgument) { - // Argument exists but its value is unknown - return; - } - const secrets = getObjectExpressionProperty(firstArgument, 'secrets'); - if ( - secrets && - secrets.value.type === 'ArrayExpression' && - secrets.value.elements.length === 0 - ) { - context.report({ - node: callee, - message: toEncodedMessage(MESSAGE, [secrets as TSESTree.Node]), - }); - } else if (!secrets) { - context.report({ - node: callee, - message: toEncodedMessage(MESSAGE, [firstArgument as TSESTree.Node]), - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/constructor-for-side-effects.ts b/eslint-bridge/src/linting/eslint/rules/constructor-for-side-effects.ts deleted file mode 100644 index 99a5c8292f3..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/constructor-for-side-effects.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1848/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getFullyQualifiedName, isTestCode } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeInstantiationOf: - 'Either remove this useless object instantiation of "{{constructor}}" or use it.', - removeInstantiation: 'Either remove this useless object instantiation or use it.', - }, - }, - create(context: Rule.RuleContext) { - const sourceCode = context.getSourceCode(); - return { - 'ExpressionStatement > NewExpression': (node: estree.NewExpression) => { - if (isTestCode(context) || isTryable(node, context)) { - return; - } - const callee = (node as estree.NewExpression).callee; - if (callee.type === 'Identifier' || callee.type === 'MemberExpression') { - const calleeText = sourceCode.getText(callee); - if (isException(context, callee, calleeText)) { - return; - } - const reportLocation = { - start: node.loc!.start, - end: callee.loc!.end, - }; - reportIssue(reportLocation, `${calleeText}`, 'removeInstantiationOf', context); - } else { - const newToken = sourceCode.getFirstToken(node); - reportIssue(newToken!.loc, '', 'removeInstantiation', context); - } - }, - }; - }, -}; - -function isTryable(node: estree.Node, context: Rule.RuleContext) { - const ancestors = context.getAncestors(); - let parent = undefined; - let child = node; - while ((parent = ancestors.pop()) !== undefined) { - if (parent.type === 'TryStatement' && parent.block === child) { - return true; - } - child = parent; - } - return false; -} - -function reportIssue( - loc: { start: estree.Position; end: estree.Position }, - objectText: string, - messageId: string, - context: Rule.RuleContext, -) { - context.report({ - messageId, - data: { - constructor: objectText, - }, - loc, - }); -} - -/** - * These exceptions are based on community requests and Peach - */ -function isException( - context: Rule.RuleContext, - node: estree.Identifier | estree.MemberExpression, - name: string, -) { - if (name === 'Notification') { - return true; - } - - const fqn = getFullyQualifiedName(context, node); - return fqn === 'vue' || fqn === '@ag-grid-community.core.Grid'; -} diff --git a/eslint-bridge/src/linting/eslint/rules/content-length.ts b/eslint-bridge/src/linting/eslint/rules/content-length.ts deleted file mode 100644 index 77ece6e449b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/content-length.ts +++ /dev/null @@ -1,228 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5693/javascript - -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { getVariablePropertyFromAssignment } from './file-uploads'; -import { parse } from 'bytes'; -import { - getLhsVariable, - getValueOfExpression, - getObjectExpressionProperty, - getFullyQualifiedName, -} from './helpers'; - -const FORMIDABLE_MODULE = 'formidable'; -const MAX_FILE_SIZE = 'maxFileSize'; -const FORMIDABLE_DEFAULT_SIZE = 200 * 1024 * 1024; - -const MULTER_MODULE = 'multer'; -const LIMITS_OPTION = 'limits'; -const FILE_SIZE_OPTION = 'fileSize'; - -const BODY_PARSER_MODULE = 'body-parser'; -const BODY_PARSER_DEFAULT_SIZE = parse('100kb'); - -const formidableObjects: Map = - new Map(); - -export const rule: Rule.RuleModule = { - meta: { - messages: { - safeLimit: 'Make sure the content length limit is safe here.', - }, - }, - create(context: Rule.RuleContext) { - return { - NewExpression(node: estree.Node) { - checkCallExpression(context, node as estree.NewExpression); - }, - CallExpression(node: estree.Node) { - checkCallExpression(context, node as estree.CallExpression); - }, - AssignmentExpression(node: estree.Node) { - visitAssignment(context, node as estree.AssignmentExpression); - }, - Program() { - formidableObjects.clear(); - }, - 'Program:exit'() { - formidableObjects.forEach(value => report(context, value.nodeToReport, value.maxFileSize)); - }, - }; - }, -}; - -function checkCallExpression(context: Rule.RuleContext, callExpression: estree.CallExpression) { - const { callee } = callExpression; - let identifierFromModule: estree.Identifier; - if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier') { - identifierFromModule = callee.object; - } else if (callee.type === 'Identifier') { - identifierFromModule = callee; - } else { - return; - } - - const fqn = getFullyQualifiedName(context, identifierFromModule); - if (!fqn) { - return; - } - const [moduleName] = fqn.split('.'); - - if (moduleName === FORMIDABLE_MODULE) { - checkFormidable(context, callExpression); - } - - if (moduleName === MULTER_MODULE) { - checkMulter(context, callExpression); - } - - if (moduleName === BODY_PARSER_MODULE) { - checkBodyParser(context, callExpression); - } -} - -function checkFormidable(context: Rule.RuleContext, callExpression: estree.CallExpression) { - if (callExpression.arguments.length === 0) { - // options will be set later through member assignment - const formVariable = getLhsVariable(context); - if (formVariable) { - formidableObjects.set(formVariable, { - maxFileSize: FORMIDABLE_DEFAULT_SIZE, - nodeToReport: callExpression, - }); - } - return; - } - - const options = getValueOfExpression(context, callExpression.arguments[0], 'ObjectExpression'); - if (options) { - const property = getObjectExpressionProperty(options, MAX_FILE_SIZE); - checkSize(context, callExpression, property, FORMIDABLE_DEFAULT_SIZE); - } -} - -function checkMulter(context: Rule.RuleContext, callExpression: estree.CallExpression) { - if (callExpression.arguments.length === 0) { - report(context, callExpression.callee); - return; - } - const multerOptions = getValueOfExpression( - context, - callExpression.arguments[0], - 'ObjectExpression', - ); - - if (!multerOptions) { - return; - } - - const limitsPropertyValue = getObjectExpressionProperty(multerOptions, LIMITS_OPTION)?.value; - if (limitsPropertyValue && limitsPropertyValue.type === 'ObjectExpression') { - const fileSizeProperty = getObjectExpressionProperty(limitsPropertyValue, FILE_SIZE_OPTION); - checkSize(context, callExpression, fileSizeProperty); - } - - if (!limitsPropertyValue) { - report(context, callExpression.callee); - } -} - -function checkBodyParser(context: Rule.RuleContext, callExpression: estree.CallExpression) { - if (callExpression.arguments.length === 0) { - checkSize(context, callExpression, undefined, BODY_PARSER_DEFAULT_SIZE, true); - return; - } - const options = getValueOfExpression(context, callExpression.arguments[0], 'ObjectExpression'); - - if (!options) { - return; - } - - const limitsProperty = getObjectExpressionProperty(options, LIMITS_OPTION); - checkSize(context, callExpression, limitsProperty, BODY_PARSER_DEFAULT_SIZE, true); -} - -function checkSize( - context: Rule.RuleContext, - callExpr: estree.CallExpression, - property?: estree.Property, - defaultLimit?: number, - useStandardSizeLimit = false, -) { - if (property) { - const maxFileSizeValue = getSizeValue(context, property.value); - if (maxFileSizeValue) { - report(context, property, maxFileSizeValue, useStandardSizeLimit); - } - } else { - report(context, callExpr, defaultLimit, useStandardSizeLimit); - } -} - -function visitAssignment(context: Rule.RuleContext, assignment: estree.AssignmentExpression) { - const variableProperty = getVariablePropertyFromAssignment(context, assignment); - if (!variableProperty) { - return; - } - - const { objectVariable, property } = variableProperty; - - if (formidableObjects.has(objectVariable) && property === MAX_FILE_SIZE) { - const formOptions = formidableObjects.get(objectVariable)!; - const rhsValue = getSizeValue(context, assignment.right); - if (rhsValue !== undefined) { - formOptions.maxFileSize = rhsValue; - formOptions.nodeToReport = assignment; - } else { - formidableObjects.delete(objectVariable); - } - } -} - -function getSizeValue(context: Rule.RuleContext, node: estree.Node): number | undefined { - const literal = getValueOfExpression(context, node, 'Literal'); - if (literal) { - if (typeof literal.value === 'number') { - return literal.value; - } else if (typeof literal.value === 'string') { - return parse(literal.value); - } - } - return undefined; -} - -function report( - context: Rule.RuleContext, - nodeToReport: estree.Node, - size?: number, - useStandardSizeLimit = false, -) { - const [fileUploadSizeLimit, standardSizeLimit] = context.options; - const limitToCompare = useStandardSizeLimit ? standardSizeLimit : fileUploadSizeLimit; - if (!size || size > limitToCompare) { - context.report({ - messageId: 'safeLimit', - node: nodeToReport, - }); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/content-security-policy.ts b/eslint-bridge/src/linting/eslint/rules/content-security-policy.ts deleted file mode 100644 index 6dd6d9cca8b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/content-security-policy.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5728/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { Express, getFullyQualifiedName, getPropertyWithValue } from './helpers'; - -const HELMET = 'helmet'; -const CONTENT_SECURITY_POLICY = 'contentSecurityPolicy'; - -export const rule: Rule.RuleModule = Express.SensitiveMiddlewarePropertyRule( - findFalseContentSecurityPolicyPropertyFromHelmet, - `Make sure not enabling content security policy fetch directives is safe here.`, -); - -/** - * Looks for property `contentSecurityPolicy: false` in node looking - * somewhat similar to `helmet(?)`, and returns it. - */ -function findFalseContentSecurityPolicyPropertyFromHelmet( - context: Rule.RuleContext, - node: estree.CallExpression, -): estree.Property[] { - let sensitive: estree.Property | undefined; - const { callee, arguments: args } = node; - if ( - getFullyQualifiedName(context, callee) === HELMET && - args.length === 1 && - args[0].type === 'ObjectExpression' - ) { - sensitive = getPropertyWithValue(context, args[0], CONTENT_SECURITY_POLICY, false); - } - return sensitive ? [sensitive] : []; -} diff --git a/eslint-bridge/src/linting/eslint/rules/cookie-flag-check.ts b/eslint-bridge/src/linting/eslint/rules/cookie-flag-check.ts deleted file mode 100644 index 4fef5edf676..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/cookie-flag-check.ts +++ /dev/null @@ -1,178 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - isIdentifier, - getValueOfExpression, - getObjectExpressionProperty, - toEncodedMessage, - getFullyQualifiedName, -} from './helpers'; - -export class CookieFlagCheck { - issueMessage: string; - - constructor(readonly context: Rule.RuleContext, readonly flag: 'httpOnly' | 'secure') { - this.issueMessage = `Make sure creating this cookie without the "${flag}" flag is safe.`; - } - - private checkCookieSession(callExpression: estree.CallExpression) { - // Sensitive argument for cookie session is first one - this.checkSensitiveCookieArgument(callExpression, 0); - } - - private checkCookiesMethodCall(callExpression: estree.CallExpression) { - if (!isIdentifier((callExpression.callee as estree.MemberExpression).property, 'set')) { - return; - } - // Sensitive argument is third argument for "cookies.set" calls - this.checkSensitiveCookieArgument(callExpression, 2); - } - - private checkCsurf(callExpression: estree.CallExpression) { - // Sensitive argument is first for csurf - const cookieProperty = this.checkSensitiveObjectArgument(callExpression, 0); - if (cookieProperty) { - // csurf cookie property can be passed as a boolean literal, - // in which case neither "secure" nor "httponly" are enabled by default - const cookiePropertyLiteral = getValueOfExpression( - this.context, - cookieProperty.value, - 'Literal', - ); - if (cookiePropertyLiteral?.value === true) { - this.context.report({ - node: callExpression.callee, - message: toEncodedMessage(this.issueMessage, [cookiePropertyLiteral as TSESTree.Node]), - }); - } - } - } - - private checkExpressSession(callExpression: estree.CallExpression) { - // Sensitive argument is first for express-session - this.checkSensitiveObjectArgument(callExpression, 0); - } - - private checkSensitiveCookieArgument( - callExpression: estree.CallExpression, - sensitiveArgumentIndex: number, - ) { - if (callExpression.arguments.length < sensitiveArgumentIndex + 1) { - return; - } - const sensitiveArgument = callExpression.arguments[sensitiveArgumentIndex]; - const cookieObjectExpression = getValueOfExpression( - this.context, - sensitiveArgument, - 'ObjectExpression', - ); - if (!cookieObjectExpression) { - return; - } - this.checkFlagOnCookieExpression( - cookieObjectExpression, - sensitiveArgument, - cookieObjectExpression, - callExpression, - ); - } - - private checkSensitiveObjectArgument( - callExpression: estree.CallExpression, - argumentIndex: number, - ): estree.Property | undefined { - if (callExpression.arguments.length < argumentIndex + 1) { - return; - } - const firstArgument = callExpression.arguments[argumentIndex]; - const objectExpression = getValueOfExpression(this.context, firstArgument, 'ObjectExpression'); - if (!objectExpression) { - return; - } - const cookieProperty = getObjectExpressionProperty(objectExpression, 'cookie'); - if (!cookieProperty) { - return; - } - const cookiePropertyValue = getValueOfExpression( - this.context, - cookieProperty.value, - 'ObjectExpression', - ); - if (cookiePropertyValue) { - this.checkFlagOnCookieExpression( - cookiePropertyValue, - firstArgument, - objectExpression, - callExpression, - ); - return; - } - return cookieProperty; - } - - private checkFlagOnCookieExpression( - cookiePropertyValue: estree.ObjectExpression, - firstArgument: estree.Node, - objectExpression: estree.ObjectExpression, - callExpression: estree.CallExpression, - ) { - const flagProperty = getObjectExpressionProperty(cookiePropertyValue, this.flag); - if (flagProperty) { - const flagPropertyValue = getValueOfExpression(this.context, flagProperty.value, 'Literal'); - if (flagPropertyValue?.value === false) { - const secondaryLocations: estree.Node[] = [flagPropertyValue]; - if (firstArgument !== objectExpression) { - secondaryLocations.push(objectExpression); - } - this.context.report({ - node: callExpression.callee, - message: toEncodedMessage(this.issueMessage, secondaryLocations as TSESTree.Node[]), - }); - } - } - } - - public checkCookiesFromCallExpression(node: estree.Node) { - const callExpression = node as estree.CallExpression; - const { callee } = callExpression; - const fqn = getFullyQualifiedName(this.context, callee); - if (fqn === 'cookie-session') { - this.checkCookieSession(callExpression); - return; - } - if (fqn === 'csurf') { - this.checkCsurf(callExpression); - return; - } - if (fqn === 'express-session') { - this.checkExpressSession(callExpression); - return; - } - if (callee.type === 'MemberExpression') { - const objectValue = getValueOfExpression(this.context, callee.object, 'NewExpression'); - if (objectValue && getFullyQualifiedName(this.context, objectValue.callee) === 'cookies') { - this.checkCookiesMethodCall(callExpression); - } - } - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/cookie-no-httponly.ts b/eslint-bridge/src/linting/eslint/rules/cookie-no-httponly.ts deleted file mode 100644 index 0e860136e09..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/cookie-no-httponly.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3330/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { CookieFlagCheck } from './cookie-flag-check'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - return { - CallExpression: (node: estree.Node) => - new CookieFlagCheck(context, 'httpOnly').checkCookiesFromCallExpression(node), - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/cookies.ts b/eslint-bridge/src/linting/eslint/rules/cookies.ts deleted file mode 100644 index 5ef57939a96..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/cookies.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2255/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isIdentifier } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - safeCookie: 'Make sure that cookie is written safely here.', - }, - }, - create(context: Rule.RuleContext) { - let usingExpressFramework = false; - - return { - Program() { - // init flag for each file - usingExpressFramework = false; - }, - - Literal(node: estree.Node) { - if ((node as estree.Literal).value === 'express') { - usingExpressFramework = true; - } - }, - - AssignmentExpression(node: estree.Node) { - const { left } = node as estree.AssignmentExpression; - if (left.type === 'MemberExpression') { - const { object, property } = left; - if (isIdentifier(object, 'document') && isIdentifier(property, 'cookie')) { - context.report({ - messageId: 'safeCookie', - node: left, - }); - } - } - }, - - CallExpression(node: estree.Node) { - const { callee, arguments: args } = node as estree.CallExpression; - if ( - callee.type === 'MemberExpression' && - usingExpressFramework && - isIdentifier(callee.property, 'cookie', 'cookies') - ) { - context.report({ - messageId: 'safeCookie', - node, - }); - } - - if ( - callee.type === 'MemberExpression' && - isIdentifier(callee.property, 'setHeader') && - isLiteral(args[0], 'Set-Cookie') - ) { - context.report({ - messageId: 'safeCookie', - node: callee, - }); - } - }, - }; - }, -}; - -function isLiteral(node: estree.Node | undefined, value: string) { - return node && node.type === 'Literal' && node.value === value; -} diff --git a/eslint-bridge/src/linting/eslint/rules/core/index.ts b/eslint-bridge/src/linting/eslint/rules/core/index.ts deleted file mode 100755 index 707660a7281..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/core/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Linter } from 'eslint'; -/** - * ESLint core rules. - */ -export const eslintRules = Object.fromEntries(new Linter().getRules()); diff --git a/eslint-bridge/src/linting/eslint/rules/cors.ts b/eslint-bridge/src/linting/eslint/rules/cors.ts deleted file mode 100644 index dc4f2656a4f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/cors.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5122/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - getUniqueWriteUsage, - getObjectExpressionProperty, - toEncodedMessage, - getFullyQualifiedName, -} from './helpers'; -import { isLiteral } from 'eslint-plugin-sonarjs/lib/utils/nodes'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -const MESSAGE = `Make sure that enabling CORS is safe here.`; - -const CORS_HEADER = 'Access-Control-Allow-Origin'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - function report(node: estree.Node, ...secondaryLocations: estree.Node[]) { - const message = toEncodedMessage(MESSAGE, secondaryLocations as TSESTree.Node[]); - context.report({ message, node }); - } - - function isCorsCall(call: estree.CallExpression) { - return getFullyQualifiedName(context, call) === 'cors'; - } - - return { - CallExpression(node: estree.Node) { - const call = node as estree.CallExpression; - - if (isCorsCall(call)) { - if (call.arguments.length === 0) { - report(call); - return; - } - const [arg] = call.arguments; - let sensitiveCorsProperty = getSensitiveCorsProperty(arg); - if (sensitiveCorsProperty) { - report(sensitiveCorsProperty); - } - if (arg?.type === 'Identifier') { - const usage = getUniqueWriteUsage(context, arg.name); - sensitiveCorsProperty = getSensitiveCorsProperty(usage); - if (sensitiveCorsProperty) { - report(sensitiveCorsProperty, arg); - } - } - } - - if (isSettingCorsHeader(call)) { - report(call); - } - }, - - ObjectExpression(node: estree.Node) { - const objProperty = getObjectExpressionProperty(node, CORS_HEADER); - if (objProperty && isAnyDomain(objProperty.value)) { - report(objProperty); - } - }, - }; - }, -}; - -function isCorsHeader(node: estree.Node) { - const header = node as TSESTree.Node; - return isLiteral(header) && header.value === CORS_HEADER; -} - -function isAnyDomain(node: estree.Node) { - const domain = node as TSESTree.Node; - return isLiteral(domain) && domain.value === '*'; -} - -function getSensitiveCorsProperty( - node: estree.Node | undefined | null, -): estree.Property | undefined { - const originProperty = getObjectExpressionProperty(node, 'origin'); - if (originProperty && isAnyDomain(originProperty.value)) { - return originProperty; - } - return undefined; -} - -function isSettingCorsHeader(call: estree.CallExpression) { - return isCorsHeader(call.arguments[0]) && isAnyDomain(call.arguments[1]); -} diff --git a/eslint-bridge/src/linting/eslint/rules/csrf.ts b/eslint-bridge/src/linting/eslint/rules/csrf.ts deleted file mode 100644 index 2dc9f76935e..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/csrf.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4502/javascript - -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - isIdentifier, - isLiteral, - getObjectExpressionProperty, - flattenArgs, - toEncodedMessage, - getFullyQualifiedName, - isRequireModule, -} from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -const CSURF_MODULE = 'csurf'; -const SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - let globalCsrfProtection = false; - let importedCsrfMiddleware = false; - - function checkIgnoredMethods(node: estree.Property) { - if (node.value.type === 'ArrayExpression') { - const arrayExpr = node.value; - const unsafeMethods = arrayExpr.elements - .filter(isLiteral) - .filter(e => typeof e.value === 'string' && !SAFE_METHODS.includes(e.value)); - if (unsafeMethods.length > 0) { - const [first, ...rest] = unsafeMethods; - context.report({ - message: toEncodedMessage( - 'Make sure disabling CSRF protection is safe here.', - rest as TSESTree.Node[], - ), - node: first, - }); - } - } - } - - function isCsurfMiddleware(node: estree.Node | undefined) { - return node && getFullyQualifiedName(context, node) === CSURF_MODULE; - } - - function checkCallExpression(callExpression: estree.CallExpression) { - const { callee } = callExpression; - - // require('csurf') - if (isRequireModule(callExpression, CSURF_MODULE)) { - importedCsrfMiddleware = true; - } - - // csurf(...) - if (getFullyQualifiedName(context, callee) === CSURF_MODULE) { - const [args] = callExpression.arguments; - const ignoredMethods = getObjectExpressionProperty(args, 'ignoreMethods'); - if (ignoredMethods) { - checkIgnoredMethods(ignoredMethods); - } - } - - // app.use(csurf(...)) - if (callee.type === 'MemberExpression') { - if ( - isIdentifier(callee.property, 'use') && - flattenArgs(context, callExpression.arguments).find(isCsurfMiddleware) - ) { - globalCsrfProtection = true; - } - if ( - isIdentifier(callee.property, 'post', 'put', 'delete', 'patch') && - !globalCsrfProtection && - importedCsrfMiddleware && - !callExpression.arguments.some(arg => isCsurfMiddleware(arg)) - ) { - context.report({ - message: toEncodedMessage('Make sure not using CSRF protection is safe here.', []), - node: callee, - }); - } - } - } - - return { - Program() { - globalCsrfProtection = false; - }, - CallExpression(node: estree.Node) { - checkCallExpression(node as estree.CallExpression); - }, - ImportDeclaration(node: estree.Node) { - if ((node as estree.ImportDeclaration).source.value === CSURF_MODULE) { - importedCsrfMiddleware = true; - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/cyclomatic-complexity.ts b/eslint-bridge/src/linting/eslint/rules/cyclomatic-complexity.ts deleted file mode 100644 index 5d31485f931..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/cyclomatic-complexity.ts +++ /dev/null @@ -1,204 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1541/javascript - -import { Rule, AST } from 'eslint'; -import * as estree from 'estree'; -import { - EncodedMessage, - IssueLocation, - getMainFunctionTokenLocation, -} from 'eslint-plugin-sonarjs/lib/utils/locations'; -import { FunctionNodeType, isFunctionNode, getParent, RuleContext } from './helpers'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; -import { childrenOf } from 'linting/eslint'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { type: 'integer' }, - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - - create(context: Rule.RuleContext) { - const [threshold] = context.options; - let functionsWithParent: Map; - let functionsDefiningModule: estree.Node[]; - let functionsImmediatelyInvoked: estree.Node[]; - return { - Program: () => { - functionsWithParent = new Map(); - functionsDefiningModule = []; - functionsImmediatelyInvoked = []; - }, - 'Program:exit': () => { - functionsWithParent.forEach((parent, func) => { - if ( - !functionsDefiningModule.includes(func) && - !functionsImmediatelyInvoked.includes(func) - ) { - raiseOnUnauthorizedComplexity(func as FunctionNodeType, parent, threshold, context); - } - }); - }, - 'FunctionDeclaration, FunctionExpression, ArrowFunctionExpression': (node: estree.Node) => - functionsWithParent.set(node, getParent(context)), - "CallExpression[callee.type='Identifier'][callee.name='define'] FunctionExpression": ( - node: estree.Node, - ) => functionsDefiningModule.push(node), - "NewExpression[callee.type='FunctionExpression'], CallExpression[callee.type='FunctionExpression']": - (node: estree.Node) => - functionsImmediatelyInvoked.push((node as estree.NewExpression).callee), - }; - }, -}; - -function raiseOnUnauthorizedComplexity( - node: FunctionNodeType, - parent: estree.Node | undefined, - threshold: number, - context: Rule.RuleContext, -): void { - const tokens = computeCyclomaticComplexity(node, parent, context); - const complexity = tokens.length; - if (complexity > threshold) { - context.report({ - message: toEncodedMessage(complexity, threshold, tokens), - loc: getMainFunctionTokenLocation( - node as TSESTree.FunctionLike, - parent as TSESTree.Node, - context as unknown as RuleContext, - ), - }); - } -} - -function toEncodedMessage( - complexity: number, - threshold: number, - tokens: ComplexityToken[], -): string { - const encodedMessage: EncodedMessage = { - message: `Function has a complexity of ${complexity} which is greater than ${threshold} authorized.`, - cost: complexity - threshold, - secondaryLocations: tokens.map(toSecondaryLocation), - }; - return JSON.stringify(encodedMessage); -} - -function toSecondaryLocation(token: ComplexityToken): IssueLocation { - return { - line: token.loc.start.line, - column: token.loc.start.column, - endLine: token.loc.end.line, - endColumn: token.loc.end.column, - message: '+1', - }; -} - -function computeCyclomaticComplexity( - node: estree.Node, - parent: estree.Node | undefined, - context: Rule.RuleContext, -): ComplexityToken[] { - const visitor = new FunctionComplexityVisitor(node, parent, context); - visitor.visit(); - return visitor.getComplexityTokens(); -} - -interface ComplexityToken { - loc: AST.SourceLocation; -} - -class FunctionComplexityVisitor { - private readonly tokens: ComplexityToken[] = []; - - constructor( - private readonly root: estree.Node, - private readonly parent: estree.Node | undefined, - private readonly context: Rule.RuleContext, - ) {} - - visit() { - const visitNode = (node: estree.Node) => { - let token: ComplexityToken | undefined | null; - - if (isFunctionNode(node)) { - if (node !== this.root) { - return; - } else { - token = { - loc: getMainFunctionTokenLocation( - node as TSESTree.FunctionLike, - this.parent as TSESTree.Node, - this.context as unknown as RuleContext, - ), - }; - } - } else { - switch (node.type) { - case 'ConditionalExpression': - token = this.context - .getSourceCode() - .getFirstTokenBetween(node.test, node.consequent, token => token.value === '?'); - break; - case 'SwitchCase': - // ignore default case - if (!node.test) { - break; - } - case 'IfStatement': - case 'ForStatement': - case 'ForInStatement': - case 'ForOfStatement': - case 'WhileStatement': - case 'DoWhileStatement': - token = this.context.getSourceCode().getFirstToken(node); - break; - case 'LogicalExpression': - token = this.context - .getSourceCode() - .getTokenAfter( - node.left, - token => ['||', '&&'].includes(token.value) && token.type === 'Punctuator', - ); - break; - } - } - - if (token) { - this.tokens.push(token); - } - - childrenOf(node, this.context.getSourceCode().visitorKeys).forEach(visitNode); - }; - - visitNode(this.root); - } - - getComplexityTokens() { - return this.tokens; - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/declarations-in-global-scope.ts b/eslint-bridge/src/linting/eslint/rules/declarations-in-global-scope.ts deleted file mode 100644 index c02b11fa68e..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/declarations-in-global-scope.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3798/javascript -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isIdentifier } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - defineLocally: - 'Define this declaration in a local scope or bind explicitly the property to the global object.', - }, - }, - create(context: Rule.RuleContext) { - return { - Program() { - const scope = context.getScope(); - // As we parse every file with "module" source type, we find user defined global variables in the module scope - const moduleScope = findModuleScope(context); - moduleScope?.variables.forEach(variable => { - if (scope.variables.find(global => global.name === variable.name)) { - // Avoid reporting on redefinitions of actual global variables - return; - } - for (const def of variable.defs) { - const defNode = def.node; - if ( - def.type === 'FunctionName' || - (def.type === 'Variable' && def.parent?.kind === 'var' && !isRequire(def.node.init)) - ) { - context.report({ - node: defNode, - messageId: 'defineLocally', - }); - return; - } - } - }); - }, - }; - }, -}; - -function findModuleScope(context: Rule.RuleContext) { - return context.getSourceCode().scopeManager.scopes.find(s => s.type === 'module'); -} - -function isRequire(node: estree.Node | null | undefined) { - return ( - node?.type === 'CallExpression' && - node.arguments.length === 1 && - isIdentifier(node.callee, 'require') - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/accessor-pairs-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/accessor-pairs-decorator.ts deleted file mode 100644 index 8de06202c0c..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/accessor-pairs-decorator.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { interceptReport } from './helpers'; - -export function decorateAccessorPairs(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReport(rule, reportExempting(isDecoratedSetterWithAngularInput)); -} - -function reportExempting( - exemptionCondition: (def: TSESTree.MethodDefinition) => boolean, -): (context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) => void { - return (context, reportDescriptor) => { - if ('node' in reportDescriptor) { - const def = reportDescriptor['node'] as TSESTree.MethodDefinition; - if (!exemptionCondition(def)) { - context.report(reportDescriptor); - } - } - }; -} - -function isDecoratedSetterWithAngularInput(def: TSESTree.MethodDefinition) { - const { kind, decorators } = def; - return ( - kind === 'set' && - decorators !== undefined && - decorators.some( - decorator => - decorator.expression.type === 'CallExpression' && - decorator.expression.callee.type === 'Identifier' && - decorator.expression.callee.name === 'Input', - ) - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/brace-style-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/brace-style-decorator.ts deleted file mode 100644 index 0fbd4e925a5..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/brace-style-decorator.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1105/javascript - -import { Rule } from 'eslint'; -import { interceptReport } from './helpers'; - -export function decorateBraceStyle(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReport(rule, reportExempting(isOpeningBracket)); -} - -function reportExempting( - exemptionCondition: (messageId: string) => boolean, -): (context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) => void { - return (context, reportDescriptor) => { - if (exemptionCondition((reportDescriptor as any).messageId)) { - context.report(reportDescriptor); - } - }; -} - -function isOpeningBracket(messageId: string) { - return messageId !== 'nextLineClose'; -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/default-param-last-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/default-param-last-decorator.ts deleted file mode 100644 index 0f44fbebe50..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/default-param-last-decorator.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1788/javascript - -import { Rule } from 'eslint'; -import { AssignmentPattern, BaseFunction } from 'estree'; -import { isIdentifier } from 'linting/eslint/rules/helpers'; -import { interceptReport } from './helpers'; - -const NUM_ARGS_REDUX_REDUCER = 2; - -export function decorateDefaultParamLast(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReport(rule, reportExempting(isReduxReducer)); -} - -function reportExempting( - exemptionCondition: (enclosingFunction: BaseFunction) => boolean, -): (context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) => void { - return (context, reportDescriptor) => { - if ('node' in reportDescriptor) { - const node = reportDescriptor['node'] as AssignmentPattern; - const scope = context.getScope(); - const variable = scope.variables.find(value => isIdentifier(node.left, value.name)); - const enclosingFunction = variable?.defs?.[0]?.node as BaseFunction; - if (enclosingFunction && !exemptionCondition(enclosingFunction)) { - context.report(reportDescriptor); - } - } - }; -} - -function isReduxReducer(enclosingFunction: BaseFunction) { - if (enclosingFunction.params.length === NUM_ARGS_REDUX_REDUCER) { - const [firstParam, secondParam] = enclosingFunction.params; - return ( - firstParam.type === 'AssignmentPattern' && - isIdentifier(firstParam.left, 'state') && - isIdentifier(secondParam, 'action') - ); - } - return false; -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/helpers/index.ts b/eslint-bridge/src/linting/eslint/rules/decorators/helpers/index.ts deleted file mode 100644 index 8fcece92051..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/helpers/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './interceptor'; -export * from './merger'; diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/helpers/interceptor.ts b/eslint-bridge/src/linting/eslint/rules/decorators/helpers/interceptor.ts deleted file mode 100644 index c05b143674f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/helpers/interceptor.ts +++ /dev/null @@ -1,138 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -const NUM_ARGS_NODE_MESSAGE = 2; - -export type ReportOverrider = ( - context: Rule.RuleContext, - reportDescriptor: Rule.ReportDescriptor, -) => void; -export type ContextOverrider = ( - context: Rule.RuleContext, - onReport: ReportOverrider, -) => Rule.RuleContext; - -/** - * Modifies the behavior of `context.report(descriptor)` for a given rule. - * - * Useful for performing additional checks before reporting an issue. - * - * @param rule the original rule - * @param onReport replacement for `context.report(descr)` - * invocations used inside of the rule - * @param contextOverrider optional function to change the default context overridding mechanism - */ -export function interceptReport( - rule: Rule.RuleModule, - onReport: ReportOverrider, - contextOverrider?: ContextOverrider, -): Rule.RuleModule { - return { - // meta should be defined only when it's defined on original rule, otherwise RuleTester will fail - ...(!!rule.meta && { meta: rule.meta }), - create(originalContext: Rule.RuleContext) { - let interceptingContext: Rule.RuleContext; - if (contextOverrider == null) { - interceptingContext = { - id: originalContext.id, - options: originalContext.options, - settings: originalContext.settings, - parserPath: originalContext.parserPath, - parserOptions: originalContext.parserOptions, - parserServices: originalContext.parserServices, - - getCwd(): string { - return originalContext.getCwd(); - }, - - getPhysicalFilename(): string { - return originalContext.getPhysicalFilename(); - }, - - getAncestors() { - return originalContext.getAncestors(); - }, - - getDeclaredVariables(node: estree.Node) { - return originalContext.getDeclaredVariables(node); - }, - - getFilename() { - return originalContext.getFilename(); - }, - - getScope() { - return originalContext.getScope(); - }, - - getSourceCode() { - return originalContext.getSourceCode(); - }, - - markVariableAsUsed(name: string) { - return originalContext.markVariableAsUsed(name); - }, - - report(...args: any[]): void { - let descr: Rule.ReportDescriptor | undefined = undefined; - if (args.length === 1) { - descr = args[0] as Rule.ReportDescriptor; - } else if (args.length === NUM_ARGS_NODE_MESSAGE && typeof args[1] === 'string') { - // not declared in the `.d.ts`, but used in practice by rules written in JS - descr = { - node: args[0] as estree.Node, - message: args[1], - }; - } - if (descr) { - onReport(originalContext, descr); - } - }, - }; - } else { - interceptingContext = contextOverrider(originalContext, onReport); - } - return rule.create(interceptingContext); - }, - }; -} - -// interceptReport() by default doesn't work with the React plugin -// as the rules fail to find the context getFirstTokens() function. -export function interceptReportForReact(rule: Rule.RuleModule, onReport: ReportOverrider) { - return interceptReport(rule, onReport, contextOverriderForReact); -} - -function contextOverriderForReact( - context: Rule.RuleContext, - onReport: (context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) => void, -): Rule.RuleContext { - const overriddenReportContext = { - report(reportDescriptor: Rule.ReportDescriptor) { - onReport(context, reportDescriptor); - }, - }; - - Object.setPrototypeOf(overriddenReportContext, context); - - return overriddenReportContext as Rule.RuleContext; -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/helpers/merger.ts b/eslint-bridge/src/linting/eslint/rules/decorators/helpers/merger.ts deleted file mode 100644 index db8457ee83f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/helpers/merger.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; - -/** - * Merges the listeners of an arbitrary number of ESLint-based rules - * - * The purpose of this helper function is to merge the behaviour of a - * variable number of rules. An ESLint rule "listens to" node visits based - * on a node selector. If the node selector matches, the listener then - * invokes a callback to proceed further with the node being visited. - * - * One needs to pay special attention when merging multiple rules that - * their respective listeners don't overlap with one another, e.g., two - * rules listen to `CallExpression` node vists. Unexpected behaviours - * could happen otherwise. - * - * @param rules rules to merge - * @returns the merge of the rules' listeners - */ -export function mergeRules(...rules: Rule.RuleListener[]): Rule.RuleListener { - const merged = Object.assign({}, ...rules); - - for (const listener of Object.keys(merged)) { - merged[listener] = mergeListeners(...rules.map(rule => rule[listener])); - } - return merged; -} - -function mergeListeners(...listeners: (Function | undefined)[]) { - return (...args: any[]) => { - for (const listener of listeners) { - if (listener) { - listener(...args); - } - } - }; -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/index.ts b/eslint-bridge/src/linting/eslint/rules/decorators/index.ts deleted file mode 100644 index 17812ba32a3..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/index.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; - -import { decorateAccessorPairs } from './accessor-pairs-decorator'; -import { decorateBraceStyle } from './brace-style-decorator'; -import { decorateDefaultParamLast } from './default-param-last-decorator'; -import { decorateJsxKey } from './jsx-key-decorator'; -import { decorateJsxNoConstructedContextValues } from './jsx-no-constructed-context-values'; -import { decorateNoDupeKeys } from './no-dupe-keys-decorator'; -import { decorateNoDuplicateImports } from './no-duplicate-imports-decorator'; -import { decorateNoEmpty } from './no-empty-decorator'; -import { decorateNoEmptyFunction } from './no-empty-function-decorator'; -import { decorateNoExtraSemi } from './no-extra-semi-decorator'; -import { decorateNoRedeclare } from './no-redeclare-decorator'; -import { decorateNoThisAlias } from './no-this-alias-decorator'; -import { decorateNoThrowLiteral } from './no-throw-literal-decorator'; -import { decorateNoUnreachable } from './no-unreachable-decorator'; -import { decorateNoUnstableNestedComponents } from './no-unstable-nested-components'; -import { decorateNoUnusedExpressions } from './no-unused-expressions-decorator'; -import { decorateObjectShorthand } from './object-shorthand-decorator'; -import { decoratePreferForOf } from './prefer-for-of-decorator'; -import { decoratePreferTemplate } from './prefer-template-decorator'; -import { decorateSemi } from './semi-decorator'; -import { decorateUseIsNan } from './use-isnan-decorator'; -import { decorateNoVar } from './no-var-decorator'; - -/** - * A decorator of an ESLint rule - * - * The purpose of a decorator is to refine the behaviour of external - * ESLint rules. These refinements can include reducing the noise by - * adding exceptions, extending the scope of the rule, adding quick fixes, etc. - */ -export type RuleDecorator = (rule: Rule.RuleModule) => Rule.RuleModule; - -/** - * The set of internal ESLint rule decorators - * - * Once declared here, these decorators are automatically applied - * to the corresponding rule definitions by the linter's wrapper. - * There is no further setup required to enable them, except when - * one needs to test them using ESLint's rule tester. - */ -export const decorators: Record = { - 'accessor-pairs': decorateAccessorPairs, - 'brace-style': decorateBraceStyle, - 'default-param-last': decorateDefaultParamLast, - 'jsx-key': decorateJsxKey, - 'jsx-no-constructed-context-values': decorateJsxNoConstructedContextValues, - 'no-dupe-keys': decorateNoDupeKeys, - 'no-duplicate-imports': decorateNoDuplicateImports, - 'no-empty': decorateNoEmpty, - 'no-empty-function': decorateNoEmptyFunction, - 'no-extra-semi': decorateNoExtraSemi, - 'no-redeclare': decorateNoRedeclare, - 'no-this-alias': decorateNoThisAlias, - 'no-throw-literal': decorateNoThrowLiteral, - 'no-unreachable': decorateNoUnreachable, - 'no-unstable-nested-components': decorateNoUnstableNestedComponents, - 'no-unused-expressions': decorateNoUnusedExpressions, - 'no-var': decorateNoVar, - 'object-shorthand': decorateObjectShorthand, - 'prefer-for-of': decoratePreferForOf, - 'prefer-template': decoratePreferTemplate, - semi: decorateSemi, - 'use-isnan': decorateUseIsNan, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/jsx-key-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/jsx-key-decorator.ts deleted file mode 100644 index 239e901ef4c..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/jsx-key-decorator.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { Rule } from 'eslint'; -import { interceptReportForReact } from './helpers'; - -export function decorateJsxKey(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReportForReact(rule, reportExempting(hasSpreadOperator)); -} - -function reportExempting(exemptionCondition: (property: TSESTree.Node) => boolean) { - return (context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) => { - // check if node has attribute containing spread operator - if ('node' in reportDescriptor) { - const { node, ...rest } = reportDescriptor; - if (exemptionCondition(node as TSESTree.Node)) { - return; - } - context.report({ - node, - ...rest, - }); - } - }; -} - -function hasSpreadOperator(node: TSESTree.Node) { - return ( - node.type === 'JSXElement' && - node.openingElement.attributes.some(attribute => attribute.type === 'JSXSpreadAttribute') - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/jsx-no-constructed-context-values.ts b/eslint-bridge/src/linting/eslint/rules/decorators/jsx-no-constructed-context-values.ts deleted file mode 100644 index 58e67575c78..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/jsx-no-constructed-context-values.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6481/javascript - -import { Rule } from 'eslint'; - -export function decorateJsxNoConstructedContextValues(rule: Rule.RuleModule): Rule.RuleModule { - return changeRuleMessagesWith(rule, lineRemover()); -} - -function changeRuleMessagesWith( - rule: Rule.RuleModule, - messageChanger: (message: string) => string, -) { - if (rule.meta?.messages) { - const messages = rule.meta.messages; - const newMessages = Object.fromEntries( - Object.entries(messages).map(([key, value]) => [key, messageChanger(value)]), - ); - rule.meta.messages = newMessages; - } - return rule; -} - -function lineRemover() { - const lineRegexp = / \(at line [^)]+\)/g; - return (message: string) => message.replace(lineRegexp, ''); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/no-dupe-keys-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/no-dupe-keys-decorator.ts deleted file mode 100644 index 38a049f953e..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/no-dupe-keys-decorator.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1534/javascript - -import { Rule, AST } from 'eslint'; -import { interceptReport } from './helpers'; -import * as estree from 'estree'; - -// core implementation of this rule does not provide quick fixes -export function decorateNoDupeKeys(rule: Rule.RuleModule): Rule.RuleModule { - rule.meta!.hasSuggestions = true; - return interceptReport(rule, (context, reportDescriptor) => { - context.report({ - ...reportDescriptor, - suggest: [ - { - desc: 'Remove this duplicate property', - fix(fixer) { - const propertyToRemove = getPropertyNode(reportDescriptor, context)!; - const commaAfter = context - .getSourceCode() - .getTokenAfter(propertyToRemove, token => token.value === ','); - const commaBefore = context - .getSourceCode() - .getTokenBefore(propertyToRemove, token => token.value === ',')!; - - let start = commaBefore.range[1]; - let end = propertyToRemove.range![1]; - if (commaAfter) { - end = commaAfter.range[1]; - } else { - start = commaBefore.range[0]; - } - return fixer.removeRange([start, end]); - }, - }, - ], - }); - }); -} - -function getPropertyNode(reportDescriptor: Rule.ReportDescriptor, context: Rule.RuleContext) { - if ('node' in reportDescriptor && 'loc' in reportDescriptor) { - const objectLiteral = reportDescriptor['node'] as estree.ObjectExpression; - const loc = reportDescriptor['loc'] as AST.SourceLocation; - - const transformPosToIndex = (p: estree.Position) => context.getSourceCode().getIndexFromLoc(p); - return objectLiteral.properties.find( - property => - transformPosToIndex(property.loc?.start!) <= transformPosToIndex(loc?.start) && - transformPosToIndex(property.loc?.end!) >= transformPosToIndex(loc?.end), - ); - } else { - throw new Error('Missing properties in report descriptor for rule S1534'); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/no-duplicate-imports-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/no-duplicate-imports-decorator.ts deleted file mode 100644 index ec922734ff2..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/no-duplicate-imports-decorator.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3863/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { interceptReport } from './helpers'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { removeNodeWithLeadingWhitespaces } from 'linting/eslint/rules/helpers'; - -// core implementation of this rule does not provide quick fixes -export function decorateNoDuplicateImports(rule: Rule.RuleModule): Rule.RuleModule { - rule.meta!.hasSuggestions = true; - return interceptReport(rule, (context, reportDescriptor) => { - const duplicateDecl = (reportDescriptor as any).node as estree.ImportDeclaration; - context.report({ - ...reportDescriptor, - suggest: getSuggestion(duplicateDecl, context), - }); - }); -} - -function getSuggestion( - duplicateDecl: estree.ImportDeclaration, - context: Rule.RuleContext, -): Rule.SuggestionReportDescriptor[] { - const module = getModule(duplicateDecl); - const importDecl = getFirstMatchingImportDeclaration(module, context); - if (!importDecl) { - return []; - } - const newSpecifiersText = mergeSpecifiers(importDecl, duplicateDecl, context); - const oldSpecifiersRange = getSpecifiersRange(importDecl, context); - return [ - { - desc: `Merge this import into the first import from "${module}"`, - fix: fixer => [ - fixer.replaceTextRange(oldSpecifiersRange, newSpecifiersText), - removeNodeWithLeadingWhitespaces(context, duplicateDecl, fixer), - ], - }, - ]; -} - -function mergeSpecifiers( - toDecl: estree.ImportDeclaration, - fromDecl: estree.ImportDeclaration, - context: Rule.RuleContext, -) { - const specifiers = [...toDecl.specifiers, ...fromDecl.specifiers]; - if (specifiers.length === 0) { - return ''; - } - - let defaultSpecifierText = ''; - let namespaceSpecifierText = ''; - const importSpecifiersTexts: string[] = []; - for (const specifier of specifiers) { - const specifierText = context.getSourceCode().getText(specifier); - switch (specifier.type) { - case 'ImportDefaultSpecifier': - defaultSpecifierText = specifierText; - break; - case 'ImportNamespaceSpecifier': - namespaceSpecifierText = specifierText; - break; - case 'ImportSpecifier': - importSpecifiersTexts.push(specifierText); - break; - } - } - - let importSpecifiersText = ''; - if (importSpecifiersTexts.length > 0) { - const multiline = isMultiline(toDecl) || isMultiline(fromDecl); - const [separator, prefix, suffix] = multiline ? [',\n', '{\n', '\n}'] : [', ', '{ ', ' }']; - importSpecifiersText = importSpecifiersTexts - .map(text => (multiline ? ' ' + text : text)) - .join(separator); - importSpecifiersText = `${prefix}${importSpecifiersText}${suffix}`; - } - - return [defaultSpecifierText, namespaceSpecifierText, importSpecifiersText] - .filter(text => text.length > 0) - .join(', '); -} - -function getSpecifiersRange( - decl: estree.ImportDeclaration, - context: Rule.RuleContext, -): [number, number] { - const sourceCode = context.getSourceCode(); - const importDecl = decl as TSESTree.ImportDeclaration; - const importOrType = importDecl.importKind === 'type' ? 'type' : 'import'; - const importOrTypeToken = sourceCode.getFirstToken(decl, token => token.value === importOrType)!; - const fromToken = sourceCode.getLastToken(decl, token => token.value === 'from'); - const begin = importOrTypeToken.range[1] + 1; - const end = fromToken ? fromToken.range[0] - 1 : importOrTypeToken.range[1] + 1; - return [begin, end]; -} - -function isMultiline(node: estree.Node): boolean { - return node.loc!.start.line !== node.loc!.end.line; -} - -function getModule(decl: estree.ImportDeclaration): string { - return (decl.source.value as string).trim(); -} - -function getFirstMatchingImportDeclaration( - module: string, - context: Rule.RuleContext, -): estree.ImportDeclaration | undefined { - return context - .getSourceCode() - .ast.body.find(node => node.type === 'ImportDeclaration' && module === getModule(node)) as - | estree.ImportDeclaration - | undefined; -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/no-empty-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/no-empty-decorator.ts deleted file mode 100644 index 0a403fe51ad..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/no-empty-decorator.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S108/javascript - -import { Rule, AST } from 'eslint'; -import * as estree from 'estree'; -import { interceptReport } from './helpers'; - -// core implementation of this rule does not provide quick fixes -export function decorateNoEmpty(rule: Rule.RuleModule): Rule.RuleModule { - rule.meta!.hasSuggestions = true; - return interceptReport(rule, (context, reportDescriptor) => { - const node = (reportDescriptor as any).node as estree.Node; - const type = reportDescriptor.data!.type; - let openingBrace: AST.Token; - if (node.type === 'SwitchStatement') { - openingBrace = context - .getSourceCode() - .getTokenAfter(node.discriminant, token => token.value === '{')!; - } /* BlockStatement */ else { - openingBrace = context.getSourceCode().getFirstToken(node)!; - } - const closingBrace = context.getSourceCode().getLastToken(node)!; - suggestEmptyBlockQuickFix(context, reportDescriptor, type, openingBrace, closingBrace); - }); -} - -export function suggestEmptyBlockQuickFix( - context: Rule.RuleContext, - descriptor: Rule.ReportDescriptor, - blockType: string, - openingBrace: AST.Token, - closingBrace: AST.Token, -) { - let commentPlaceholder: string; - if (openingBrace.loc.start.line === closingBrace.loc.start.line) { - commentPlaceholder = ` /* TODO document why this ${blockType} is empty */ `; - } else { - const columnOffset = closingBrace.loc.start.column; - const padding = ' '.repeat(columnOffset); - commentPlaceholder = `\n${padding} // TODO document why this ${blockType} is empty\n${padding}`; - } - context.report({ - ...descriptor, - suggest: [ - { - desc: 'Insert placeholder comment', - fix: fixer => fixer.insertTextAfter(openingBrace, commentPlaceholder), - }, - ], - }); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/no-empty-function-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/no-empty-function-decorator.ts deleted file mode 100644 index 92fb85ff7da..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/no-empty-function-decorator.ts +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1186/javascript - -import * as estree from 'estree'; -import { Rule } from 'eslint'; -import { interceptReport } from './helpers'; -import { suggestEmptyBlockQuickFix } from './no-empty-decorator'; -import { FunctionNodeType, isFunctionNode, isIdentifier } from '../helpers'; - -type RuleFunctionNode = FunctionNodeType & Rule.Node; - -function isRuleFunctionNode(node: estree.Node): node is RuleFunctionNode { - return isFunctionNode(node) && 'parent' in node; -} - -// core implementation of this rule does not provide quick fixes -export function decorateNoEmptyFunction(rule: Rule.RuleModule): Rule.RuleModule { - rule.meta!.hasSuggestions = true; - return interceptReport(rule, reportWithQuickFixIfApplicable); -} - -export function reportWithQuickFixIfApplicable( - context: Rule.RuleContext, - reportDescriptor: Rule.ReportDescriptor, -) { - if (!('node' in reportDescriptor) || !isRuleFunctionNode(reportDescriptor.node)) { - return; - } - - const functionNode = reportDescriptor.node; - if (isApplicable(functionNode)) { - reportWithQuickFix(context, reportDescriptor, functionNode); - } -} - -// This function limits the issues to variable/function/method declarations which name is not like /^on[A-Z]. -// Any lambda expression or arrow function is thus ignored. -function isApplicable(functionNode: RuleFunctionNode) { - // Matches identifiers like onClick and more generally onXxx - function isCallbackIdentifier(node: estree.Node | null) { - return node !== null && isIdentifier(node) && /^on[A-Z]/.test(node.name); - } - - // Matches: function foo() {} - // But not: function onClose() {} - function isFunctionDeclaration() { - return functionNode.type === 'FunctionDeclaration' && !isCallbackIdentifier(functionNode.id); - } - - // Matches: class A { foo() {} } - // But not: class A { onClose() {} } - function isMethodDefinition() { - const methodNode = functionNode.parent; - return ( - methodNode.type === 'MethodDefinition' && - methodNode.value === functionNode && - !isCallbackIdentifier(methodNode.key) - ); - } - - // Matches: const foo = () => {}; - // But not: const onClose = () => {}; - function isVariableDeclarator() { - const variableNode = functionNode.parent; - return ( - variableNode.type === 'VariableDeclarator' && - variableNode.init === functionNode && - !isCallbackIdentifier(variableNode.id) - ); - } - - return isFunctionDeclaration() || isMethodDefinition() || isVariableDeclarator(); -} - -function reportWithQuickFix( - context: Rule.RuleContext, - reportDescriptor: Rule.ReportDescriptor, - func: FunctionNodeType, -) { - const name = reportDescriptor.data!.name; - const openingBrace = context.getSourceCode().getFirstToken(func.body)!; - const closingBrace = context.getSourceCode().getLastToken(func.body)!; - suggestEmptyBlockQuickFix(context, reportDescriptor, name, openingBrace, closingBrace); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/no-extra-semi-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/no-extra-semi-decorator.ts deleted file mode 100644 index da5f4a88289..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/no-extra-semi-decorator.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { AST, Rule } from 'eslint'; -import * as estree from 'estree'; -import { interceptReport } from './helpers'; - -type NullableToken = AST.Token | null | undefined; -type NodeCondition = (context: Rule.RuleContext, node: estree.Node) => boolean; - -// core implementation of this rule raises issues when using semicolon-free style and -// using semicolon to protect code on purpose. -export function decorateNoExtraSemi(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReport(rule, reportExempting(isProtectionSemicolon)); -} - -function reportExempting(exemptionCondition: NodeCondition) { - return (context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor): void => { - if ('node' in reportDescriptor && !exemptionCondition(context, reportDescriptor.node)) { - context.report(reportDescriptor); - } - }; -} - -// Checks that a node is a semicolon inserted to prevent the compiler from merging the -// following statement with the previous. -export function isProtectionSemicolon(context: Rule.RuleContext, node: estree.Node): boolean { - if (node.type !== 'EmptyStatement') { - return false; - } - - // This checks the semicolon is on a new line compared to the previous token if it exists. - const previousToken = context.getSourceCode().getTokenBefore(node); - if (!isNodeOnNewLineAfterToken(node, previousToken)) { - return false; - } - - const nextToken = context.getSourceCode().getTokenAfter(node); - return isParenOrBracket(nextToken); -} - -function isNodeOnNewLineAfterToken(node: estree.Node, token: NullableToken): boolean { - if (node.loc == null) { - return false; - } else if (token == null) { - return true; - } else { - return token.loc.end.line < node.loc.start.line; - } -} - -function isParenOrBracket(token: NullableToken): boolean { - return token?.type === 'Punctuator' && (token.value === '[' || token.value === '('); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/no-redeclare-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/no-redeclare-decorator.ts deleted file mode 100644 index f3ca24b3306..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/no-redeclare-decorator.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { interceptReport } from './helpers'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -// core implementation of this rule raises issues on type exports -export function decorateNoRedeclare(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReport(rule, reportExempting(isTypeDeclaration)); -} - -function reportExempting( - exemptionCondition: (node: estree.Identifier) => boolean, -): (context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) => void { - return (context, reportDescriptor) => { - if ('node' in reportDescriptor) { - const node = reportDescriptor['node']; - if (node.type === 'Identifier' && !exemptionCondition(node)) { - context.report(reportDescriptor); - } - } - }; -} - -function isTypeDeclaration(node: estree.Identifier) { - return (node as TSESTree.Node).parent?.type === 'TSTypeAliasDeclaration'; -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/no-this-alias-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/no-this-alias-decorator.ts deleted file mode 100644 index afcb6b6e419..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/no-this-alias-decorator.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { getVariableFromName } from '../helpers'; -import { interceptReport } from './helpers'; - -// core implementation of this rule raises false positives for generators -export function decorateNoThisAlias(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReport(rule, reportExempting(isReferencedInsideGenerators)); -} - -function reportExempting( - exemptionCondition: (context: Rule.RuleContext, node: estree.Identifier) => boolean, -): (context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) => void { - return (context, reportDescriptor) => { - if ('node' in reportDescriptor) { - const node = reportDescriptor['node'] as estree.Identifier; - if (!exemptionCondition(context, node)) { - context.report(reportDescriptor); - } - } - }; -} - -function isReferencedInsideGenerators(context: Rule.RuleContext, node: estree.Identifier) { - const variable = getVariableFromName(context, node.name); - if (variable) { - for (const reference of variable.references) { - let scope: Scope.Scope | null = reference.from; - while (scope !== null && !scope.variables.includes(variable)) { - if (isGenerator(scope.block)) { - return true; - } - scope = scope.upper; - } - } - } - return false; - - function isGenerator(node: estree.Node) { - return ( - (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') && - node.generator === true - ); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/no-throw-literal-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/no-throw-literal-decorator.ts deleted file mode 100644 index a22235c3ab5..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/no-throw-literal-decorator.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3696/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isBinaryPlus, isStringLiteral } from 'linting/eslint/rules/helpers'; -import { interceptReport } from './helpers'; - -// core implementation of this rule does not provide quick fixes -export function decorateNoThrowLiteral(rule: Rule.RuleModule): Rule.RuleModule { - rule.meta!.hasSuggestions = true; - return interceptReport(rule, (context, reportDescriptor) => { - const suggest: Rule.SuggestionReportDescriptor[] = []; - if ('node' in reportDescriptor) { - const { argument: thrown } = reportDescriptor.node as estree.ThrowStatement; - if (isStringLike(thrown)) { - const thrownText = context.getSourceCode().getText(thrown); - suggest.push({ - desc: 'Throw an error object', - fix: fixer => fixer.replaceText(thrown, `new Error(${thrownText})`), - }); - } - } - context.report({ - ...reportDescriptor, - suggest, - }); - }); -} - -function isStringLike(node: estree.Node): boolean { - return isStringLiteral(node) || isStringConcatenation(node); -} - -function isStringConcatenation(node: estree.Node): boolean { - return isBinaryPlus(node) && (isStringLike(node.left) || isStringLike(node.right)); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/no-unreachable-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/no-unreachable-decorator.ts deleted file mode 100644 index d6abdaa6d7c..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/no-unreachable-decorator.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1763/javascript - -import { Rule, AST } from 'eslint'; -import * as estree from 'estree'; -import { interceptReport } from './helpers'; -import { removeNodeWithLeadingWhitespaces } from 'linting/eslint/rules/helpers'; - -// core implementation of this rule does not provide quick fixes -export function decorateNoUnreachable(rule: Rule.RuleModule): Rule.RuleModule { - rule.meta!.hasSuggestions = true; - return interceptReport(rule, (context, reportDescriptor) => { - const loc = (reportDescriptor as any).loc as AST.SourceLocation; - const node = (reportDescriptor as any).node as estree.Node; - context.report({ - ...reportDescriptor, - suggest: [ - { - desc: 'Remove unreachable code', - fix: fixer => - removeNodeWithLeadingWhitespaces( - context, - node, - fixer, - context.getSourceCode().getIndexFromLoc(loc.end), - ), - }, - ], - }); - }); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/no-unstable-nested-components.ts b/eslint-bridge/src/linting/eslint/rules/decorators/no-unstable-nested-components.ts deleted file mode 100644 index ba2c94ea740..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/no-unstable-nested-components.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6478/javascript - -import { Rule } from 'eslint'; -import { interceptReportForReact } from './helpers'; - -export function decorateNoUnstableNestedComponents(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReportForReact(rule, changeMessageWith(urlRemover())); -} - -function changeMessageWith(messageChanger: (message: string) => string) { - return (context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) => { - const report = reportDescriptor as { message?: string }; - if (report.message) { - report.message = messageChanger(report.message); - } - context.report(reportDescriptor); - }; -} - -function urlRemover() { - const urlRegexp = / \(https:[^)]+\)/; - return (message: string) => message.replace(urlRegexp, ''); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/no-unused-expressions-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/no-unused-expressions-decorator.ts deleted file mode 100644 index 227b9cdefc5..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/no-unused-expressions-decorator.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { interceptReport } from './helpers'; - -export function decorateNoUnusedExpressions(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReport( - rule, - reportExempting( - expr => - isNegatedIife(expr) || - containsChaiExpect(expr) || - containsValidChaiShould(expr) || - isAuraLightningComponent(expr) || - isSequenceWithSideEffects(expr), - ), - ); -} - -function reportExempting( - exemptionCondition: (expr: estree.Expression) => boolean, -): (context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) => void { - return (context, reportDescriptor) => { - if ('node' in reportDescriptor) { - const n: estree.Node = reportDescriptor['node']; - const expr = (n as estree.ExpressionStatement).expression; - if (!exemptionCondition(expr)) { - context.report(reportDescriptor); - } - } - }; -} - -function containsChaiExpect(node: estree.Node): boolean { - if (node.type === 'CallExpression') { - if (node.callee.type === 'Identifier' && node.callee.name === 'expect') { - return true; - } else { - return containsChaiExpect(node.callee); - } - } else if (node.type === 'MemberExpression') { - return containsChaiExpect(node.object); - } - return false; -} - -function containsValidChaiShould(node: estree.Node, isSubexpr = false): boolean { - if (node.type === 'CallExpression') { - return containsValidChaiShould(node.callee, true); - } else if (node.type === 'MemberExpression') { - if (node.property && node.property.type === 'Identifier' && node.property.name === 'should') { - // Expressions like `x.should` are valid only as subexpressions, not on top level - return isSubexpr; - } else { - return containsValidChaiShould(node.object, true); - } - } - return false; -} - -function isNegatedIife(node: estree.Node): boolean { - return node.type === 'UnaryExpression' && node.operator === '!' && isIife(node.argument); -} - -function isIife(node: estree.Node): boolean { - return ( - node.type === 'CallExpression' && - (node.callee.type === 'FunctionExpression' || node.callee.type === 'ArrowFunctionExpression') - ); -} - -function isSequenceWithSideEffects(node: estree.Node): boolean { - return ( - node.type === 'SequenceExpression' && - node.expressions[node.expressions.length - 1].type === 'AssignmentExpression' - ); -} - -function isAuraLightningComponent(node: estree.Node): boolean { - return ( - node.type === 'ObjectExpression' && - node.properties.length > 0 && - (node as TSESTree.Node).parent?.parent?.type === 'Program' - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/no-var-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/no-var-decorator.ts deleted file mode 100644 index 4ecf5cea96b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/no-var-decorator.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import { interceptReport } from './helpers'; -import estree from 'estree'; - -export function decorateNoVar(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReport(rule, (context, reportDescriptor) => { - if ('node' in reportDescriptor) { - const { node, ...rest } = reportDescriptor; - const { - declarations: [firstDecl, ..._], - } = node as estree.VariableDeclaration; - - const varToken = context.getSourceCode().getTokenBefore(firstDecl.id); - const identifierEnd = firstDecl.id.loc!.end; - if (varToken == null) { - // impossible - return; - } - context.report({ - loc: { - start: varToken.loc.start, - end: identifierEnd, - }, - ...rest, - }); - } - }); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/object-shorthand-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/object-shorthand-decorator.ts deleted file mode 100644 index e4a326debfa..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/object-shorthand-decorator.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3498/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { interceptReport } from './helpers'; - -// core implementation of this rule raises issues on aura lightning components -export function decorateObjectShorthand(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReport(rule, reportExempting(isAuraLightningComponent)); -} - -function reportExempting( - exemptionCondition: (property: TSESTree.Property) => boolean, -): (context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) => void { - return (context, reportDescriptor) => { - if ('node' in reportDescriptor) { - const property = reportDescriptor['node'] as TSESTree.Property; - if (!exemptionCondition(property)) { - context.report({ ...reportDescriptor, node: property.key as estree.Node }); - } - } - }; -} - -function isAuraLightningComponent(property: TSESTree.Property) { - const { parent, value } = property; - return ( - parent!.parent!.type === 'ExpressionStatement' && - parent!.parent!.parent!.type === 'Program' && - value.type === 'FunctionExpression' - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/prefer-for-of-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/prefer-for-of-decorator.ts deleted file mode 100644 index 8d135b90541..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/prefer-for-of-decorator.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4138/javascript - -import { Rule, AST, Scope } from 'eslint'; -import { interceptReport } from './helpers'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -const element = 'element'; - -// core implementation of this rule does not provide quick fixes -export function decoratePreferForOf(rule: Rule.RuleModule): Rule.RuleModule { - rule.meta!.hasSuggestions = true; - return interceptReport(rule, (context, reportDescriptor) => { - const forStmt = (reportDescriptor as any).node as estree.ForStatement; - const suggest: Rule.SuggestionReportDescriptor[] = []; - if (isFixable(context.getScope())) { - suggest.push({ - desc: 'Replace with "for of" loop', - fix: fixer => rewriteForStatement(forStmt, context, fixer), - }); - } - context.report({ - ...reportDescriptor, - suggest, - }); - }); -} - -function isFixable(scope: Scope.Scope): boolean { - return ( - scope.references.every(reference => reference.identifier.name !== element) && - scope.childScopes.every(isFixable) - ); -} - -function rewriteForStatement( - forStmt: estree.ForStatement, - context: Rule.RuleContext, - fixer: Rule.RuleFixer, -) { - const fixes: Rule.Fix[] = []; - - /* rewrite `for` header: `(init; test; update)` -> `(const element of ) ` */ - const openingParenthesis = context - .getSourceCode() - .getFirstToken(forStmt, token => token.value === '(')!; - const closingParenthesis = context - .getSourceCode() - .getTokenBefore(forStmt.body, token => token.value === ')')!; - - const arrayExpr = extractArrayExpression(forStmt); - const arrayText = context.getSourceCode().getText(arrayExpr); - - const headerRange: AST.Range = [openingParenthesis.range[1], closingParenthesis.range[0]]; - const headerText = `const ${element} of ${arrayText}`; - fixes.push(fixer.replaceTextRange(headerRange, headerText)); - - /* rewrite `for` body: `[]` -> `element` */ - const [indexVar] = context.getDeclaredVariables(forStmt.init!); - for (const reference of indexVar.references) { - const id = reference.identifier; - if (contains(forStmt.body, id)) { - const arrayAccess = (id as TSESTree.Node).parent as estree.Node; - fixes.push(fixer.replaceText(arrayAccess, element)); - } - } - - return fixes; -} - -function extractArrayExpression(forStmt: estree.ForStatement) { - return ((forStmt.test as estree.BinaryExpression).right as estree.MemberExpression).object; -} - -function contains(outer: estree.Node, inner: estree.Node) { - return outer.range![0] <= inner.range![0] && outer.range![1] >= inner.range![1]; -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/prefer-template-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/prefer-template-decorator.ts deleted file mode 100644 index 59475b6c7b2..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/prefer-template-decorator.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { interceptReport } from './helpers'; - -// core implementation of this rule raises issues on binary expressions with string literal operand(s) -export function decoratePreferTemplate(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReport(rule, reportExempting(isTwoOperands)); -} - -function reportExempting( - exemptionCondition: (node: estree.BinaryExpression) => boolean, -): (context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) => void { - return (context, reportDescriptor) => { - if ('node' in reportDescriptor) { - const expr = reportDescriptor['node'] as estree.BinaryExpression; - if (!exemptionCondition(expr)) { - context.report(reportDescriptor); - } - } - }; -} - -function isTwoOperands(node: estree.BinaryExpression) { - return node.right.type !== 'BinaryExpression' && node.left.type !== 'BinaryExpression'; -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/semi-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/semi-decorator.ts deleted file mode 100644 index a51510e4a6c..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/semi-decorator.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1438/javascript - -import { Rule } from 'eslint'; -import { interceptReport } from './helpers'; - -export function decorateSemi(rule: Rule.RuleModule): Rule.RuleModule { - return interceptReport(rule, fixLocation); -} - -function fixLocation(context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) { - const report = reportDescriptor as any; - if (report.loc?.start && report.messageId === 'missingSemi') { - report.loc = report.loc.start; - } - context.report(reportDescriptor); -} diff --git a/eslint-bridge/src/linting/eslint/rules/decorators/use-isnan-decorator.ts b/eslint-bridge/src/linting/eslint/rules/decorators/use-isnan-decorator.ts deleted file mode 100644 index 1a89bc85663..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/decorators/use-isnan-decorator.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2688/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isIdentifier, isMemberExpression } from 'linting/eslint/rules/helpers'; -import { interceptReport } from './helpers'; - -// core implementation of this rule does not provide quick fixes -export function decorateUseIsNan(rule: Rule.RuleModule): Rule.RuleModule { - rule.meta!.hasSuggestions = true; - return interceptReport(rule, (context, reportDescriptor) => { - const suggest: Rule.SuggestionReportDescriptor[] = []; - const node = (reportDescriptor as any).node as estree.Node; - if (node.type === 'BinaryExpression') { - const { left, operator, right } = node; - let negate: boolean | null = null; - switch (operator) { - case '!=': - case '!==': - negate = true; - break; - case '==': - case '===': - negate = false; - break; - } - if (negate !== null) { - const arg = isNaNIdentifier(left) ? right : left; - const argText = context.getSourceCode().getText(arg); - const prefix = negate ? '!' : ''; - suggest.push( - { - desc: 'Use "isNaN()"', - fix: fixer => fixer.replaceText(node, `${prefix}isNaN(${argText})`), - }, - { - desc: 'Use "Number.isNaN()"', - fix: fixer => fixer.replaceText(node, `${prefix}Number.isNaN(${argText})`), - }, - ); - } - } - context.report({ ...reportDescriptor, suggest }); - }); -} - -function isNaNIdentifier(node: estree.Node) { - return isIdentifier(node, 'NaN') || isMemberExpression(node, 'Number', 'NaN'); -} diff --git a/eslint-bridge/src/linting/eslint/rules/deprecation.ts b/eslint-bridge/src/linting/eslint/rules/deprecation.ts deleted file mode 100644 index bb1c051d960..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/deprecation.ts +++ /dev/null @@ -1,238 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1874/javascript - -import { Rule } from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import * as estree from 'estree'; -import { getParent, isRequiredParserServices, RequiredParserServices } from './helpers'; -import * as ts from 'typescript'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - deprecation: "'{{symbol}}' is deprecated. {{reason}}", - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - return { - Identifier: (node: estree.Node) => { - const parent = getParent(context); - if (isShortHandProperty(parent) && parent.key === node) { - // to not report twice - return; - } - if (isObjectExpressionProperty(node, context)) { - return; - } - const id = node as estree.Identifier; - const insideImportExport = context.getAncestors().some(anc => anc.type.includes('Import')); - if (insideImportExport || isDeclaration(id, context)) { - return; - } - - const deprecation = getDeprecation(id, services, context); - if (deprecation) { - context.report({ - node, - messageId: 'deprecation', - data: { - symbol: id.name, - reason: deprecation.reason, - }, - }); - } - }, - }; - }, -}; - -function isDeclaration(id: estree.Identifier, context: Rule.RuleContext) { - const parent = getParent(context); - if (isShortHandProperty(parent) && parent.value === id) { - return false; - } - - const variable = context.getScope().variables.find(v => v.name === id.name); - if (variable) { - return variable.defs.some(def => def.name === id); - } - - const declarationTypes = [ - 'PropertyDefinition', - 'TSPropertySignature', - 'TSDeclareFunction', - 'FunctionDeclaration', - 'MethodDefinition', - 'TSMethodSignature', - ]; - return parent && declarationTypes.includes(parent.type); -} - -function getDeprecation( - id: estree.Identifier, - services: RequiredParserServices, - context: Rule.RuleContext, -): Deprecation | undefined { - const tc = services.program.getTypeChecker(); - const callExpression = getCallExpression(context, id); - - if (callExpression) { - const tsCallExpression = services.esTreeNodeToTSNodeMap.get(callExpression as TSESTree.Node); - const signature = tc.getResolvedSignature(tsCallExpression as ts.CallLikeExpression); - if (signature) { - const deprecation = getJsDocDeprecation(signature.getJsDocTags()); - if (deprecation) { - return deprecation; - } - } - } - const symbol = getSymbol(id, services, context, tc); - - if (!symbol) { - return undefined; - } - if (callExpression && isFunction(symbol)) { - return undefined; - } - - return getJsDocDeprecation(symbol.getJsDocTags()); -} - -function getSymbol( - id: estree.Identifier, - services: RequiredParserServices, - context: Rule.RuleContext, - tc: ts.TypeChecker, -) { - let symbol: ts.Symbol | undefined; - const tsId = services.esTreeNodeToTSNodeMap.get(id as TSESTree.Node) as ts.Identifier; - const parent = services.esTreeNodeToTSNodeMap.get(getParent(context) as TSESTree.Node) as ts.Node; - if (parent.kind === ts.SyntaxKind.BindingElement) { - symbol = tc.getTypeAtLocation(parent.parent).getProperty(tsId.text); - } else if ( - (isPropertyAssignment(parent) && parent.name === tsId) || - (isShorthandPropertyAssignment(parent) && parent.name === tsId) - ) { - try { - symbol = tc.getPropertySymbolOfDestructuringAssignment(tsId); - } catch (e) { - // do nothing, we are in object literal, not destructuring - // no obvious easy way to check that in advance - } - } else { - symbol = tc.getSymbolAtLocation(tsId); - } - - if (symbol && (symbol.flags & ts.SymbolFlags.Alias) !== 0) { - return tc.getAliasedSymbol(symbol); - } - return symbol; -} - -function getCallExpression( - context: Rule.RuleContext, - id: estree.Node, -): estree.CallExpression | estree.TaggedTemplateExpression | undefined { - const ancestors = context.getAncestors(); - let callee = id; - let parent = ancestors.length > 0 ? ancestors[ancestors.length - 1] : undefined; - - if (parent && parent.type === 'MemberExpression' && parent.property === id) { - callee = parent; - parent = ancestors.length > 1 ? ancestors[ancestors.length - 2] : undefined; - } - - if (isCallExpression(parent, callee)) { - return parent; - } -} - -function isCallExpression( - node: estree.Node | undefined, - callee: estree.Node, -): node is estree.CallExpression | estree.TaggedTemplateExpression { - if (node) { - if (node.type === 'NewExpression' || node.type === 'CallExpression') { - return node.callee === callee; - } else if (node.type === 'TaggedTemplateExpression') { - return node.tag === callee; - } - } - return false; -} - -function getJsDocDeprecation(tags: ts.JSDocTagInfo[]): Deprecation | undefined { - for (const tag of tags) { - if (tag.name === 'deprecated') { - return tag.text ? { reason: tag.text.map(e => e.text).join(' ') } : new Deprecation(); - } - } - return undefined; -} - -function isFunction(symbol: ts.Symbol) { - const { declarations } = symbol; - if (declarations === undefined || declarations.length === 0) { - return false; - } - switch (declarations[0].kind) { - case ts.SyntaxKind.MethodDeclaration: - case ts.SyntaxKind.FunctionDeclaration: - case ts.SyntaxKind.FunctionExpression: - case ts.SyntaxKind.MethodSignature: - return true; - default: - return false; - } -} - -function isPropertyAssignment(node: ts.Node): node is ts.PropertyAssignment { - return node.kind === ts.SyntaxKind.PropertyAssignment; -} - -function isShorthandPropertyAssignment(node: ts.Node): node is ts.ShorthandPropertyAssignment { - return node.kind === ts.SyntaxKind.ShorthandPropertyAssignment; -} - -function isShortHandProperty(parent: estree.Node | undefined): parent is estree.Property { - return !!parent && parent.type === 'Property' && parent.shorthand; -} - -function isObjectExpressionProperty(node: estree.Node, context: Rule.RuleContext) { - const ancestors = context.getAncestors(); - const parent = ancestors.pop(); - const grandparent = ancestors.pop(); - return ( - parent?.type === 'Property' && - !parent.computed && - !parent.shorthand && - parent.key === node && - grandparent?.type === 'ObjectExpression' - ); -} - -class Deprecation { - reason = ''; -} diff --git a/eslint-bridge/src/linting/eslint/rules/destructuring-assignment-syntax.ts b/eslint-bridge/src/linting/eslint/rules/destructuring-assignment-syntax.ts deleted file mode 100644 index f0d18677510..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/destructuring-assignment-syntax.ts +++ /dev/null @@ -1,137 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3514/javascript - -import { Rule } from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import * as estree from 'estree'; -import { findFirstMatchingAncestor, toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -const MAX_INDEX = 4; -const isAllowedIndex = (idx: number) => idx >= 0 && idx <= MAX_INDEX; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - - create(context: Rule.RuleContext) { - function visitStatements(statements: Array) { - const declarationsByObject: Map = new Map(); - - for (const statement of statements) { - if (statement.type === 'VariableDeclaration') { - visitDeclarations(declarationsByObject, statement.declarations); - } else { - checkDeclarationsBlock(declarationsByObject); - declarationsByObject.clear(); - } - } - checkDeclarationsBlock(declarationsByObject); - } - - function visitDeclarations( - declarationsByObject: Map, - declarations: Array, - ) { - for (const declaration of declarations) { - const id = declaration.id; - if (declaration.init && id.type === 'Identifier') { - const varName = id.name; - const expression = declaration.init; - if (expression.type !== 'MemberExpression') { - continue; - } - const property = expression.property; - if (property.type === 'Identifier' && property.name === varName) { - addDeclaration(declarationsByObject, expression.object, declaration); - } else if ( - property.type === 'Literal' && - typeof property.value === 'number' && - isAllowedIndex(property.value) - ) { - addDeclaration(declarationsByObject, expression.object, declaration); - } - } - } - } - - function addDeclaration( - declarationsByObject: Map, - object: estree.Node, - declaration: estree.VariableDeclarator, - ) { - const key = context.getSourceCode().getText(object); - const value = declarationsByObject.get(key); - if (value) { - value.push(declaration); - } else { - declarationsByObject.set(key, [declaration]); - } - } - - function checkDeclarationsBlock( - declarationsByObject: Map, - ) { - declarationsByObject.forEach((declarations: estree.VariableDeclarator[], key: string) => { - if (declarations.length > 1) { - const firstKind = getKind(declarations[0]); - const tail = declarations.slice(1); - if (tail.every(decl => getKind(decl) === firstKind)) { - context.report({ - node: declarations[0], - message: toEncodedMessage( - `Use destructuring syntax for these assignments from "${key}".`, - tail as TSESTree.Node[], - Array(tail.length).fill('Replace this assignment.'), - ), - }); - } - } - }); - } - - return { - BlockStatement: (node: estree.Node) => { - visitStatements((node as estree.BlockStatement).body); - }, - SwitchCase: (node: estree.Node) => { - visitStatements((node as estree.SwitchCase).consequent); - }, - Program: (node: estree.Node) => { - visitStatements((node as estree.Program).body); - }, - }; - }, -}; - -function getKind(declarator: estree.VariableDeclarator) { - const declaration = findFirstMatchingAncestor( - declarator as TSESTree.Node, - n => n.type === 'VariableDeclaration', - ) as estree.VariableDeclaration | undefined; - return declaration && declaration.kind; -} diff --git a/eslint-bridge/src/linting/eslint/rules/different-types-comparison.ts b/eslint-bridge/src/linting/eslint/rules/different-types-comparison.ts deleted file mode 100644 index 21da76613c4..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/different-types-comparison.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3403/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isRequiredParserServices, getTypeFromTreeNode, toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - hasSuggestions: true, - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - - function isComparableTo(lhs: estree.Node, rhs: estree.Node) { - const checker = services.program.getTypeChecker(); - const lhsType = checker.getBaseTypeOfLiteralType(getTypeFromTreeNode(lhs, services)); - const rhsType = checker.getBaseTypeOfLiteralType(getTypeFromTreeNode(rhs, services)); - // @ts-ignore private API - return ( - checker.isTypeAssignableTo(lhsType, rhsType) || checker.isTypeAssignableTo(rhsType, lhsType) - ); - } - - return { - BinaryExpression: (node: estree.Node) => { - const { left, operator, right } = node as estree.BinaryExpression; - if (['===', '!=='].includes(operator) && !isComparableTo(left, right)) { - const [actual, expected, outcome] = - operator === '===' ? ['===', '==', 'false'] : ['!==', '!=', 'true']; - const operatorToken = context - .getSourceCode() - .getTokensBetween(left, right) - .find(token => token.type === 'Punctuator' && token.value === operator)!; - context.report({ - message: toEncodedMessage( - `Remove this "${actual}" check; it will always be ${outcome}. Did you mean to use "${expected}"?`, - [left, right], - ), - loc: operatorToken.loc, - suggest: [ - { - desc: `Replace "${actual}" with "${expected}"`, - fix: fixer => fixer.replaceText(operatorToken, expected), - }, - ], - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/disabled-auto-escaping.ts b/eslint-bridge/src/linting/eslint/rules/disabled-auto-escaping.ts deleted file mode 100644 index c37c1c3db31..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/disabled-auto-escaping.ts +++ /dev/null @@ -1,150 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5247/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - isIdentifier, - getValueOfExpression, - isRequiredParserServices, - resolveFromFunctionReference, - checkSensitiveCall, - toEncodedMessage, - getFullyQualifiedName, -} from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -const MESSAGE = 'Make sure disabling auto-escaping feature is safe here.'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - - function isEmptySanitizerFunction( - sanitizerFunction: - | estree.FunctionExpression - | estree.FunctionDeclaration - | estree.ArrowFunctionExpression, - ) { - if (sanitizerFunction.params.length !== 1) { - return false; - } - const firstParam = sanitizerFunction.params[0]; - if (firstParam.type !== 'Identifier') { - return false; - } - const firstParamName = firstParam.name; - if (sanitizerFunction.body.type !== 'BlockStatement') { - return ( - sanitizerFunction.body.type === 'Identifier' && - sanitizerFunction.body.name === firstParamName - ); - } - const { body } = sanitizerFunction.body; - if (body.length !== 1) { - return false; - } - const onlyStatement = body[0]; - if ( - onlyStatement.type === 'ReturnStatement' && - onlyStatement.argument && - isIdentifier(onlyStatement.argument, firstParamName) - ) { - return true; - } - return false; - } - - function isInvalidSanitizerFunction(node: estree.Node) { - type AssignedFunction = - | estree.FunctionDeclaration - | estree.FunctionExpression - | estree.ArrowFunctionExpression - | undefined - | null; - let assignedFunction: AssignedFunction = - getValueOfExpression(context, node, 'FunctionExpression') ?? - getValueOfExpression(context, node, 'ArrowFunctionExpression'); - if (!assignedFunction && node.type === 'Identifier' && isRequiredParserServices(services)) { - assignedFunction = resolveFromFunctionReference(context, node); - } - if (!!assignedFunction) { - return isEmptySanitizerFunction(assignedFunction); - } - return false; - } - - return { - CallExpression: (node: estree.Node) => { - const callExpression = node as estree.CallExpression; - const fqn = getFullyQualifiedName(context, callExpression); - if (fqn === 'handlebars.compile') { - checkSensitiveCall(context, callExpression, 1, 'noEscape', true, MESSAGE); - } - if (fqn === 'marked.setOptions') { - checkSensitiveCall(context, callExpression, 0, 'sanitize', false, MESSAGE); - } - if (fqn === 'markdown-it') { - checkSensitiveCall(context, callExpression, 0, 'html', true, MESSAGE); - } - }, - NewExpression: (node: estree.Node) => { - const newExpression = node as estree.NewExpression; - if (getFullyQualifiedName(context, newExpression) === 'kramed.Renderer') { - checkSensitiveCall(context, newExpression, 0, 'sanitize', false, MESSAGE); - } - }, - AssignmentExpression: (node: estree.Node) => { - const assignmentExpression = node as estree.AssignmentExpression; - const { left, right } = assignmentExpression; - if (left.type !== 'MemberExpression') { - return; - } - if ( - !( - getFullyQualifiedName(context, left) === 'mustache.escape' || - (isMustacheIdentifier(left.object) && isIdentifier(left.property, 'escape')) - ) - ) { - return; - } - if (isInvalidSanitizerFunction(right)) { - context.report({ - node: left, - message: toEncodedMessage(MESSAGE), - }); - } - }, - }; - }, -}; - -function isMustacheIdentifier(node: estree.Node) { - return isIdentifier(node, 'Mustache'); -} diff --git a/eslint-bridge/src/linting/eslint/rules/disabled-resource-integrity.ts b/eslint-bridge/src/linting/eslint/rules/disabled-resource-integrity.ts deleted file mode 100644 index 0812601be90..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/disabled-resource-integrity.ts +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5725/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { Variable } from 'eslint-scope'; -import { isIdentifier, isRequiredParserServices, getTypeAsString } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - safeResource: 'Make sure not using resource integrity feature is safe here.', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - function shouldReport(assignedVariable: Variable) { - let nbSrcAssignment = 0; - let hasUnsafeSrcAssignment = false; - let hasIntegrityAssignment = false; - assignedVariable.references.forEach(ref => { - const parentNode = (ref.identifier as TSESTree.Node).parent; - if (!parentNode) { - return; - } - nbSrcAssignment += isSrcAssignment(parentNode) ? 1 : 0; - hasUnsafeSrcAssignment = hasUnsafeSrcAssignment || isUnsafeSrcAssignment(parentNode); - hasIntegrityAssignment = hasIntegrityAssignment || isIntegrityAssignment(parentNode); - }); - return nbSrcAssignment === 1 && hasUnsafeSrcAssignment && !hasIntegrityAssignment; - } - - function isIntegrityAssignment(memberExpression: TSESTree.Node): boolean { - if (memberExpression.type !== 'MemberExpression') { - return false; - } - return ( - memberExpression.property.type === 'Identifier' && - memberExpression.property.name === 'integrity' - ); - } - - function isSrcAssignment(memberExpression: TSESTree.Node): boolean { - if (memberExpression.type !== 'MemberExpression') { - return false; - } - if ( - memberExpression.property.type !== 'Identifier' || - memberExpression.property.name !== 'src' - ) { - return false; - } - const assignmentExpression = memberExpression.parent; - if (assignmentExpression?.type !== 'AssignmentExpression') { - return false; - } - return true; - } - - function isUnsafeSrcAssignment(memberExpression: TSESTree.Node): boolean { - if (!isSrcAssignment(memberExpression)) { - return false; - } - const right = (memberExpression.parent as estree.AssignmentExpression).right; - if (right.type !== 'Literal') { - return false; - } - return !!right.raw && (!!right.raw.match('^"http') || !!right.raw.match('^"//')); - } - - return { - 'VariableDeclarator[init.type="CallExpression"]': (node: estree.Node) => { - const variableDeclarator = node as estree.VariableDeclarator; - const callExpression = variableDeclarator.init as estree.CallExpression; - const left = variableDeclarator.id; - const { callee } = callExpression; - if (left.type !== 'Identifier') { - return; - } - if (callee.type !== 'MemberExpression') { - return; - } - const typeName = getTypeAsString(left, services); - if ( - !isIdentifier(callee.object, 'document') || - !isIdentifier(callee.property, 'createElement') || - typeName !== 'HTMLScriptElement' - ) { - return; - } - const scope = context.getScope(); - const assignedVariable = scope.variables.find(v => v.name === left.name); - if (!assignedVariable) { - return; - } - if (shouldReport(assignedVariable)) { - context.report({ - node: variableDeclarator, - messageId: 'safeResource', - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/disabled-timeout.ts b/eslint-bridge/src/linting/eslint/rules/disabled-timeout.ts deleted file mode 100644 index ed496012f3f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/disabled-timeout.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6080/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - Chai, - getUniqueWriteUsageOrNode, - isIdentifier, - isMethodCall, - isNumberLiteral, - isThisExpression, - Mocha, -} from './helpers'; - -const MESSAGE = - 'Set this timeout to 0 if you want to disable it, otherwise use a value lower than 2147483648.'; -const MAX_DELAY_VALUE = 2_147_483_647; - -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - if (!Chai.isImported(context)) { - return {}; - } - const constructs: estree.Node[] = []; - return { - CallExpression: (node: estree.Node) => { - if (Mocha.isTestConstruct(node)) { - constructs.push(node); - return; - } - if (constructs.length > 0) { - checkTimeoutDisabling(node as estree.CallExpression, context); - } - }, - 'CallExpression:exit': (node: estree.Node) => { - if (Mocha.isTestConstruct(node)) { - constructs.pop(); - } - }, - }; - }, -}; - -function checkTimeoutDisabling(node: estree.CallExpression, context: Rule.RuleContext) { - if (isMethodCall(node) && node.arguments.length > 0) { - const { - callee: { object, property }, - arguments: [value], - } = node; - if ( - isThisExpression(object) && - isIdentifier(property, 'timeout') && - isDisablingTimeout(value, context) - ) { - context.report({ - message: MESSAGE, - node: value, - }); - } - } -} - -function isDisablingTimeout(timeout: estree.Node, context: Rule.RuleContext) { - const usage = getUniqueWriteUsageOrNode(context, timeout); - return isNumberLiteral(usage) && usage.value > MAX_DELAY_VALUE; -} diff --git a/eslint-bridge/src/linting/eslint/rules/dns-prefetching.ts b/eslint-bridge/src/linting/eslint/rules/dns-prefetching.ts deleted file mode 100644 index 12e18784745..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/dns-prefetching.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5743/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { checkSensitiveCall, getFullyQualifiedName } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -const MESSAGE = 'Make sure allowing browsers to perform DNS prefetching is safe here.'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - return { - CallExpression: (node: estree.Node) => { - const callExpression = node as estree.CallExpression; - const fqn = getFullyQualifiedName(context, callExpression); - if (fqn === 'helmet.dnsPrefetchControl') { - checkSensitiveCall(context, callExpression, 0, 'allow', true, MESSAGE); - } - if (fqn === 'helmet') { - checkSensitiveCall(context, callExpression, 0, 'dnsPrefetchControl', false, MESSAGE); - } - if (fqn === 'dns-prefetch-control') { - checkSensitiveCall(context, callExpression, 0, 'allow', true, MESSAGE); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/duplicates-in-character-class.ts b/eslint-bridge/src/linting/eslint/rules/duplicates-in-character-class.ts deleted file mode 100644 index 61fd9f33306..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/duplicates-in-character-class.ts +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5869/javascript - -import { Rule } from 'eslint'; -import { CharacterClass, Flags, Node, RegExpLiteral } from 'regexpp/ast'; -import { toEncodedMessage } from './helpers'; -import { - createRegExpRule, - getRegexpLocation, - SimplifiedRegexCharacterClass, -} from './helpers/regex'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = createRegExpRule( - context => { - let flags: Flags; - return { - onRegExpLiteralEnter: (node: RegExpLiteral) => { - flags = node.flags; - }, - onCharacterClassEnter: (node: CharacterClass) => { - const duplicates = new Set(); - const characterClass = new SimplifiedRegexCharacterClass(flags); - node.elements.forEach(element => { - const intersections = new SimplifiedRegexCharacterClass(flags, element).findIntersections( - characterClass, - ); - if (intersections.length > 0) { - intersections.forEach(intersection => duplicates.add(intersection)); - duplicates.add(element); - } - characterClass.add(element); - }); - if (duplicates.size > 0) { - const [primary, ...secondaries] = duplicates; - context.reportRegExpNode({ - message: toEncodedMessage( - 'Remove duplicates in this character class.', - secondaries.map(snd => ({ loc: getRegexpLocation(context.node, snd, context) })), - secondaries.map(_ => 'Additional duplicate'), - ), - node: context.node, - regexpNode: primary, - }); - } - }, - }; - }, - { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - }, -); diff --git a/eslint-bridge/src/linting/eslint/rules/empty-string-repetition.ts b/eslint-bridge/src/linting/eslint/rules/empty-string-repetition.ts deleted file mode 100644 index d591133569b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/empty-string-repetition.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5842/javascript - -import { Rule } from 'eslint'; -import { Node, Quantifier } from 'regexpp/ast'; -import { createRegExpRule } from './helpers/regex'; - -export const rule: Rule.RuleModule = createRegExpRule(context => { - return { - onQuantifierEnter: (node: Quantifier) => { - const { element } = node; - if (matchEmptyString(element)) { - context.reportRegExpNode({ - message: `Rework this part of the regex to not match the empty string.`, - node: context.node, - regexpNode: element, - }); - } - }, - }; -}); - -function matchEmptyString(node: Node): boolean { - switch (node.type) { - case 'Alternative': - return node.elements.every(matchEmptyString); - case 'Assertion': - return true; - case 'CapturingGroup': - case 'Group': - case 'Pattern': - return node.alternatives.some(matchEmptyString); - case 'Quantifier': - return node.min === 0; - default: - return false; - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/encryption-secure-mode.ts b/eslint-bridge/src/linting/eslint/rules/encryption-secure-mode.ts deleted file mode 100644 index efb9cb1b581..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/encryption-secure-mode.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5542/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getFullyQualifiedName, getValueOfExpression } from './helpers'; - -const aliases: string[] = [ - 'AES128', - 'AES192', - 'AES256', - 'BF', - 'blowfish', - 'CAMELLIA128', - 'CAMELLIA192', - 'CAMELLIA256', - 'CAST', - 'DES', - 'DES-EDE', - 'DES-EDE3', - 'DES3', - 'DESX', - 'RC2', - 'RC2-40', - 'RC2-64', - 'RC2-128', - 'SEED', -]; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - useSecureMode: 'Use a secure mode and padding scheme.', - }, - }, - create(context: Rule.RuleContext) { - const patterns: RegExp[] = [new RegExp('CBC', 'i'), new RegExp('ECB', 'i')]; - aliases.forEach(alias => patterns.push(new RegExp(`^${alias}$`, 'i'))); - return { - CallExpression: (node: estree.Node) => { - const callExpression = node as estree.CallExpression; - if (getFullyQualifiedName(context, callExpression) !== 'crypto.createCipheriv') { - return; - } - const sensitiveArgument = callExpression.arguments[0]; - const sensitiveArgumentValue = getValueOfExpression(context, sensitiveArgument, 'Literal'); - if (!sensitiveArgumentValue) { - return; - } - const { value } = sensitiveArgumentValue; - if (typeof value !== 'string') { - return; - } - if (patterns.some(pattern => pattern.test(value))) { - context.report({ - messageId: 'useSecureMode', - node: sensitiveArgument, - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/encryption.ts b/eslint-bridge/src/linting/eslint/rules/encryption.ts deleted file mode 100644 index 500daf82d28..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/encryption.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4787/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isIdentifier, isMemberWithProperty, getFullyQualifiedName } from './helpers'; - -const getEncryptionRuleModule = ( - clientSideMethods: string[], - serverSideMethods: string[], -): Rule.RuleModule => ({ - meta: { - messages: { - safeEncryption: 'Make sure that encrypting data is safe here.', - }, - }, - create(context: Rule.RuleContext) { - // for client side - let usingCryptoInFile = false; - - return { - Program() { - // init flag for each file - usingCryptoInFile = false; - }, - - MemberExpression(node: estree.Node) { - // detect 'SubtleCrypto' object - // which can be retrieved by 'crypto.subtle' or 'window.crypto.subtle' - const { object, property } = node as estree.MemberExpression; - if ( - isIdentifier(property, 'subtle') && - (isIdentifier(object, 'crypto') || isMemberWithProperty(object, 'crypto')) - ) { - usingCryptoInFile = true; - } - }, - - 'CallExpression:exit'(node: estree.Node) { - const { callee } = node as estree.CallExpression; - - if (usingCryptoInFile) { - // e.g.: crypto.subtle.encrypt() - checkForClientSide(callee, context, clientSideMethods); - } - - // e.g. - // const crypto = require("crypto"); - // const cipher = crypto.createCipher(alg, key); - checkForServerSide(callee, context, serverSideMethods); - }, - }; - }, -}); - -function checkForServerSide( - callee: estree.Node, - context: Rule.RuleContext, - serverSideMethods: string[], -) { - const fqn = getFullyQualifiedName(context, callee); - if (serverSideMethods.some(method => fqn === `crypto.${method}`)) { - context.report({ - messageId: 'safeEncryption', - node: callee, - }); - } -} - -function checkForClientSide( - callee: estree.Node, - context: Rule.RuleContext, - clientSideMethods: string[], -) { - if ( - isIdentifier(callee, ...clientSideMethods) || - isMemberWithProperty(callee, ...clientSideMethods) - ) { - context.report({ - messageId: 'safeEncryption', - node: callee, - }); - } -} - -const clientSideEncryptMethods = ['encrypt', 'decrypt']; -const serverSideEncryptMethods = [ - 'createCipher', - 'createCipheriv', - 'createDecipher', - 'createDecipheriv', - 'publicEncrypt', - 'publicDecrypt', - 'privateEncrypt', - 'privateDecrypt', -]; - -export const rule: Rule.RuleModule = getEncryptionRuleModule( - clientSideEncryptMethods, - serverSideEncryptMethods, -); diff --git a/eslint-bridge/src/linting/eslint/rules/existing-groups.ts b/eslint-bridge/src/linting/eslint/rules/existing-groups.ts deleted file mode 100644 index f708a7af298..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/existing-groups.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6328/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import * as regexpp from 'regexpp'; -import { RegExpLiteral } from 'regexpp/ast'; -import { isRequiredParserServices } from './helpers'; -import { - GroupReference, - extractReferences, - getParsedRegex, - isStringReplaceCall, -} from './helpers/regex'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - nonExistingGroup: 'Referencing non-existing group{{groups}}.', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - return { - CallExpression: (call: estree.CallExpression) => { - if (isStringReplaceCall(call, services)) { - const [pattern, substr] = call.arguments; - const regex = getParsedRegex(pattern, context); - if (regex !== null) { - const groups = extractGroups(regex); - const references = extractReferences(substr); - const invalidReferences = references.filter( - ref => !isReferencingExistingGroup(ref, groups), - ); - if (invalidReferences.length > 0) { - const groups = `${invalidReferences.length > 1 ? 's' : ''}: ${invalidReferences - .map(ref => ref.raw) - .join(', ')}`; - context.report({ - node: substr, - messageId: 'nonExistingGroup', - data: { - groups, - }, - }); - } - } - } - }, - }; - }, -}; - -class CapturingGroups { - private readonly names = new Set(); - private groups = 0; - - public add(name: string | null): void { - if (name !== null) { - this.names.add(name); - } - this.groups++; - } - - public has(name: string): boolean { - return this.names.has(name); - } - - public count(): number { - return this.groups; - } -} - -function extractGroups(regex: RegExpLiteral) { - const groups = new CapturingGroups(); - regexpp.visitRegExpAST(regex, { - onCapturingGroupEnter: group => groups.add(group.name), - }); - return groups; -} - -function isReferencingExistingGroup(reference: GroupReference, groups: CapturingGroups) { - if (!isNaN(Number(reference.value))) { - const index = Number(reference.value); - return index >= 1 && index <= groups.count(); - } else { - const name = reference.value; - return groups.has(name); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/expression-complexity.ts b/eslint-bridge/src/linting/eslint/rules/expression-complexity.ts deleted file mode 100644 index 8adad043fc8..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/expression-complexity.ts +++ /dev/null @@ -1,146 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1067/javascript - -import { Rule, AST } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { type: 'integer' }, - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - const [max] = context.options; - const statementLevel: ExpressionComplexity[] = [new ExpressionComplexity()]; - return { - '*': (node: estree.Node) => { - const tree = node as TSESTree.Node; - if (isConditionalLike(tree)) { - const expr = statementLevel[statementLevel.length - 1]; - expr.incrementNestedExprLevel(); - expr.addOperator(getOperatorToken(tree, context)); - } else if (isScopeLike(tree)) { - statementLevel.push(new ExpressionComplexity()); - } - }, - '*:exit': (node: estree.Node) => { - const tree = node as TSESTree.Node; - if (isConditionalLike(tree)) { - const expr = statementLevel[statementLevel.length - 1]; - expr.decrementNestedExprLevel(); - if (expr.isOnFirstExprLevel()) { - const operators = expr.getComplexityOperators(); - if (operators.length > max) { - reportIssue(tree, operators, max, context); - } - expr.resetExpressionComplexityOperators(); - } - } else if (isScopeLike(tree)) { - statementLevel.pop(); - } - }, - }; - }, -}; - -class ExpressionComplexity { - nestedLevel = 0; - operators: AST.Token[] = []; - - addOperator(operator: AST.Token) { - this.operators.push(operator); - } - - incrementNestedExprLevel() { - this.nestedLevel++; - } - - decrementNestedExprLevel() { - this.nestedLevel--; - } - - isOnFirstExprLevel() { - return this.nestedLevel === 0; - } - - getComplexityOperators() { - return this.operators; - } - - resetExpressionComplexityOperators() { - this.operators = []; - } -} - -function isScopeLike(node: TSESTree.Node) { - return ( - node.type === 'FunctionExpression' || - (node.type === 'FunctionDeclaration' && node.generator) || - node.type === 'ObjectExpression' || - node.type === 'CallExpression' || - node.type === 'JSXElement' - ); -} - -function isConditionalLike(node: TSESTree.Node) { - return node.type === 'ConditionalExpression' || node.type === 'LogicalExpression'; -} - -function getOperatorToken(node: TSESTree.Node, context: Rule.RuleContext) { - const sourceCode = context.getSourceCode(); - if (node.type === 'ConditionalExpression') { - return sourceCode.getTokenAfter( - node.test as estree.Node, - token => token.type === 'Punctuator' && token.value === '?', - )!; - } else { - const expr = node as estree.LogicalExpression; - return sourceCode.getTokenAfter( - expr.left, - token => token.type === 'Punctuator' && token.value === expr.operator, - )!; - } -} - -function reportIssue( - node: TSESTree.Node, - operators: AST.Token[], - max: number, - context: Rule.RuleContext, -) { - const complexity = operators.length; - const message = `Reduce the number of conditional operators (${complexity}) used in the expression (maximum allowed ${max}).`; - const secondaryLocationsHolder = operators; - const secondaryMessages = Array(complexity).fill('+1'); - const cost = complexity - max; - context.report({ - node: node as estree.Node, - message: toEncodedMessage(message, secondaryLocationsHolder, secondaryMessages, cost), - }); -} diff --git a/eslint-bridge/src/linting/eslint/rules/file-header.ts b/eslint-bridge/src/linting/eslint/rules/file-header.ts deleted file mode 100644 index 20cd5df41bc..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/file-header.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1451/javascript - -import { Rule } from 'eslint'; - -let cached: { - headerFormat: string; - isRegularExpression: boolean; - expectedLines?: string[]; - searchPattern?: RegExp; - failedToCompile?: boolean; -}; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - fixHeader: 'Add or update the header of this file.', - }, - }, - create(context: Rule.RuleContext) { - updateCache(context.options); - - if (cached.failedToCompile) { - // don't visit anything - return {}; - } - - return { - 'Program:exit': function () { - if (cached.isRegularExpression) { - checkRegularExpression(cached.searchPattern!, context); - } else { - checkPlainText(cached.expectedLines!, context); - } - }, - }; - }, -}; - -function checkPlainText(expectedLines: string[], context: Rule.RuleContext) { - let matches = false; - const lines = context.getSourceCode().lines; - - if (expectedLines.length <= lines.length) { - matches = true; - - let i = 0; - for (const expectedLine of expectedLines) { - const line = lines[i]; - i++; - if (line !== expectedLine) { - matches = false; - break; - } - } - } - - if (!matches) { - addFileIssue(context); - } -} - -function checkRegularExpression(searchPattern: RegExp, context: Rule.RuleContext) { - const fileContent = context.getSourceCode().getText(); - const match = searchPattern.exec(fileContent); - if (!match || match.index !== 0) { - addFileIssue(context); - } -} - -function addFileIssue(context: Rule.RuleContext) { - context.report({ - messageId: 'fixHeader', - loc: { line: 0, column: 0 }, - }); -} - -function updateCache(options: any[]) { - const [{ headerFormat, isRegularExpression }] = options; - - if ( - !cached || - cached.headerFormat !== headerFormat || - cached.isRegularExpression !== isRegularExpression - ) { - cached = { - headerFormat, - isRegularExpression, - }; - - if (isRegularExpression) { - try { - cached.searchPattern = new RegExp(headerFormat, 's'); - cached.failedToCompile = false; - } catch (e) { - console.error(`Failed to compile regular expression for rule S1451 (${e.message})`); - cached.failedToCompile = true; - } - } else { - cached.expectedLines = headerFormat.split(/(?:\r)?\n|\r/); - } - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/file-name-differ-from-class.ts b/eslint-bridge/src/linting/eslint/rules/file-name-differ-from-class.ts deleted file mode 100644 index 8f0bdb7d1c0..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/file-name-differ-from-class.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3317/javascript - -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import path from 'path'; -import { getVariableFromName } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - renameFile: 'Rename this file to "{{exported}}"', - }, - }, - create(context: Rule.RuleContext) { - let isOnlyExport = true; - let nameOfExported: string | undefined = undefined; - - return { - ExportDefaultDeclaration: (node: estree.Node) => { - const declaration = (node as estree.ExportDefaultDeclaration).declaration; - if (declaration.type === 'Identifier') { - const variable = getVariableFromName(context, declaration.name); - if (variable && variable.defs.length === 1) { - const def = variable.defs[0]; - if (def.type === 'ClassName' || def.type === 'FunctionName' || isConst(def)) { - nameOfExported = declaration.name; - } - } - } else if ( - declaration.type === 'ClassDeclaration' || - declaration.type === 'FunctionDeclaration' - ) { - if (declaration.id) { - nameOfExported = declaration.id.name; - } - } - }, - 'ExportAllDeclaration, ExportNamedDeclaration': () => { - isOnlyExport = false; - }, - 'Program:exit': () => { - if (isOnlyExport && nameOfExported) { - const fileName = path.parse(context.getFilename()).name; - if ( - 'index' !== fileName && - !sameName(nameOfExported, fileName) && - !sameName(nameOfExported, sliceOffPostfix(fileName)) - ) { - context.report({ - messageId: 'renameFile', - data: { - exported: nameOfExported, - }, - loc: { line: 0, column: 0 }, - }); - } - } - }, - }; - }, -}; - -function sameName(nameOfExported: string, fileName: string) { - const normalizedFileName = fileName.replace(/_/g, '').replace(/-/g, '').replace(/\./g, ''); - const normalizedNameOfExported = nameOfExported.replace(/_/g, '').replace(/-/g, ''); - return normalizedNameOfExported.toLowerCase() === normalizedFileName.toLowerCase(); -} - -function isConst(def: Scope.Definition) { - return def.type === 'Variable' && def.parent && def.parent.kind === 'const'; -} - -function sliceOffPostfix(fileName: string) { - return fileName.slice(0, fileName.lastIndexOf('.')); -} diff --git a/eslint-bridge/src/linting/eslint/rules/file-permissions.ts b/eslint-bridge/src/linting/eslint/rules/file-permissions.ts deleted file mode 100644 index 0c4659fbafd..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/file-permissions.ts +++ /dev/null @@ -1,143 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2612/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - isIdentifier, - isMemberExpression, - getUniqueWriteUsage, - getFullyQualifiedName, -} from './helpers'; - -const chmodLikeFunction = ['chmod', 'chmodSync', 'fchmod', 'fchmodSync', 'lchmod', 'lchmodSync']; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - safePermission: 'Make sure this permission is safe.', - }, - }, - create(context: Rule.RuleContext) { - function isChmodLikeFunction(node: estree.CallExpression) { - const { callee } = node; - if (callee.type !== 'MemberExpression') { - return false; - } - // to support fs promises we are only checking the name of the function - return isIdentifier(callee.property, ...chmodLikeFunction); - } - - function modeFromLiteral(modeExpr: estree.Literal) { - const modeValue = modeExpr.value; - let mode = null; - if (typeof modeValue === 'string') { - mode = Number.parseInt(modeValue, 8); - } else if (typeof modeValue === 'number') { - const raw = modeExpr.raw; - // ts parser interprets number starting with 0 as decimal, we need to parse it as octal value - if (raw && raw.startsWith('0') && !raw.startsWith('0o')) { - mode = Number.parseInt(raw, 8); - } else { - mode = modeValue; - } - } - return mode; - } - - // fs.constants have these value only when running on linux, we need to hardcode them to be able to test on win - const FS_CONST: Record = { - S_IRWXU: 0o700, - S_IRUSR: 0o400, - S_IWUSR: 0o200, - S_IXUSR: 0o100, - S_IRWXG: 0o70, - S_IRGRP: 0o40, - S_IWGRP: 0o20, - S_IXGRP: 0o10, - S_IRWXO: 0o7, - S_IROTH: 0o4, - S_IWOTH: 0o2, - S_IXOTH: 0o1, - }; - - function modeFromMemberExpression(modeExpr: estree.MemberExpression): number | null { - const { object, property } = modeExpr; - if (isMemberExpression(object, 'fs', 'constants') && property.type === 'Identifier') { - return FS_CONST[property.name]; - } - return null; - } - - function modeFromExpression( - expr: estree.Node | undefined, - visited: Set, - ): number | null { - if (!expr) { - return null; - } - if (expr.type === 'MemberExpression') { - return modeFromMemberExpression(expr); - } else if (expr.type === 'Literal') { - return modeFromLiteral(expr); - } else if (expr.type === 'Identifier') { - const usage = getUniqueWriteUsage(context, expr.name); - if (usage && !visited.has(usage)) { - visited.add(usage); - return modeFromExpression(usage, visited); - } - } else if (expr.type === 'BinaryExpression') { - const { left, operator, right } = expr; - if (operator === '|') { - const leftValue = modeFromExpression(left, visited); - const rightValue = modeFromExpression(right, visited); - if (leftValue && rightValue) { - return leftValue | rightValue; - } - } - } - return null; - } - - function checkModeArgument(node: estree.Node, moduloTest: number) { - const visited = new Set(); - const mode = modeFromExpression(node, visited); - if (mode !== null && !isNaN(mode) && mode % 8 !== moduloTest) { - context.report({ - node, - messageId: 'safePermission', - }); - } - } - - return { - CallExpression: (node: estree.Node) => { - const callExpression = node as estree.CallExpression; - if (isChmodLikeFunction(callExpression)) { - checkModeArgument(callExpression.arguments[0], 0); - checkModeArgument(callExpression.arguments[1], 0); - } else if (getFullyQualifiedName(context, callExpression) === 'process.umask') { - checkModeArgument(callExpression.arguments[0], 7); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/file-uploads.ts b/eslint-bridge/src/linting/eslint/rules/file-uploads.ts deleted file mode 100644 index 9e84af887fb..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/file-uploads.ts +++ /dev/null @@ -1,265 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2598/javascript - -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { - getLhsVariable, - getValueOfExpression, - getObjectExpressionProperty, - getVariableFromName, - toEncodedMessage, - getFullyQualifiedName, -} from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -const FORMIDABLE_MODULE = 'formidable'; -const KEEP_EXTENSIONS = 'keepExtensions'; -const UPLOAD_DIR = 'uploadDir'; - -const MULTER_MODULE = 'multer'; -const STORAGE_OPTION = 'storage'; -const DESTINATION_OPTION = 'destination'; - -const formidableObjects: Map< - Scope.Variable, - { uploadDirSet: boolean; keepExtensions: boolean; callExpression: estree.CallExpression } -> = new Map(); - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - return { - NewExpression(node: estree.Node) { - checkCallExpression(context, node as estree.NewExpression); - }, - CallExpression(node: estree.Node) { - checkCallExpression(context, node as estree.CallExpression); - }, - AssignmentExpression(node: estree.Node) { - visitAssignment(context, node as estree.AssignmentExpression); - }, - Program() { - formidableObjects.clear(); - }, - 'Program:exit'() { - formidableObjects.forEach(value => - report(context, value.uploadDirSet, value.keepExtensions, value.callExpression), - ); - }, - }; - }, -}; - -function checkCallExpression(context: Rule.RuleContext, callExpression: estree.CallExpression) { - const { callee } = callExpression; - if (callee.type !== 'Identifier') { - return; - } - - const fqn = getFullyQualifiedName(context, callee); - if (!fqn) { - return; - } - const [moduleName] = fqn.split('.'); - - if (moduleName === FORMIDABLE_MODULE) { - checkFormidable(context, callExpression); - } - - if (moduleName === MULTER_MODULE) { - checkMulter(context, callExpression); - } -} - -function checkFormidable(context: Rule.RuleContext, callExpression: estree.CallExpression) { - if (callExpression.arguments.length === 0) { - const formVariable = getLhsVariable(context); - if (formVariable) { - formidableObjects.set(formVariable, { - uploadDirSet: false, - keepExtensions: false, - callExpression, - }); - } - return; - } - - const options = getValueOfExpression(context, callExpression.arguments[0], 'ObjectExpression'); - if (options) { - report( - context, - !!getObjectExpressionProperty(options, UPLOAD_DIR), - keepExtensionsValue(getObjectExpressionProperty(options, KEEP_EXTENSIONS)?.value), - callExpression, - ); - } -} - -function checkMulter(context: Rule.RuleContext, callExpression: estree.CallExpression) { - if (callExpression.arguments.length === 0) { - return; - } - const multerOptions = getValueOfExpression( - context, - callExpression.arguments[0], - 'ObjectExpression', - ); - - if (!multerOptions) { - return; - } - - const storagePropertyValue = getObjectExpressionProperty(multerOptions, STORAGE_OPTION)?.value; - if (storagePropertyValue) { - const storageValue = getValueOfExpression(context, storagePropertyValue, 'CallExpression'); - - if (storageValue) { - const diskStorageCallee = getDiskStorageCalleeIfUnsafeStorage(context, storageValue); - if (diskStorageCallee) { - report(context, false, false, callExpression, { - node: diskStorageCallee, - message: 'no destination specified', - }); - } - } - } -} - -function getDiskStorageCalleeIfUnsafeStorage( - context: Rule.RuleContext, - storageCreation: estree.CallExpression, -) { - const { arguments: args, callee } = storageCreation; - if (args.length > 0 && isMemberWithProperty(callee, 'diskStorage')) { - const storageOptions = getValueOfExpression(context, args[0], 'ObjectExpression'); - if (storageOptions && !getObjectExpressionProperty(storageOptions, DESTINATION_OPTION)) { - return callee; - } - } - - return false; -} - -function isMemberWithProperty(expr: estree.Node, property: string) { - return ( - expr.type === 'MemberExpression' && - expr.property.type === 'Identifier' && - expr.property.name === property - ); -} - -function keepExtensionsValue(extensionValue?: estree.Node): boolean { - if ( - extensionValue && - extensionValue.type === 'Literal' && - typeof extensionValue.value === 'boolean' - ) { - return extensionValue.value; - } - - return false; -} - -function visitAssignment(context: Rule.RuleContext, assignment: estree.AssignmentExpression) { - const variableProperty = getVariablePropertyFromAssignment(context, assignment); - if (!variableProperty) { - return; - } - - const { objectVariable, property } = variableProperty; - - if (formidableObjects.has(objectVariable)) { - const formOptions = formidableObjects.get(objectVariable)!; - if (property === UPLOAD_DIR) { - formOptions.uploadDirSet = true; - } - - if (property === KEEP_EXTENSIONS) { - formOptions.keepExtensions = keepExtensionsValue(assignment.right); - } - } -} - -/** - * for `x.foo = 42` returns 'x' variable and 'foo' property string - */ -export function getVariablePropertyFromAssignment( - context: Rule.RuleContext, - assignment: estree.AssignmentExpression, -): { objectVariable: Scope.Variable; property: string } | undefined { - if (assignment.left.type !== 'MemberExpression') { - return undefined; - } - - const memberExpr = assignment.left; - if (memberExpr.object.type === 'Identifier' && memberExpr.property.type === 'Identifier') { - const objectVariable = getVariableFromName(context, memberExpr.object.name); - if (objectVariable) { - return { objectVariable, property: memberExpr.property.name }; - } - } - - return undefined; -} - -function report( - context: Rule.RuleContext, - uploadDirSet: boolean, - keepExtensions: boolean, - callExpression: estree.CallExpression, - secondaryLocation?: { node: estree.Node; message: string }, -) { - let message; - - if (keepExtensions && uploadDirSet) { - message = 'Restrict the extension of uploaded files.'; - } else if (!keepExtensions && !uploadDirSet) { - message = 'Restrict folder destination of uploaded files.'; - } else if (keepExtensions && !uploadDirSet) { - message = 'Restrict the extension and folder destination of uploaded files.'; - } - - if (message) { - if (secondaryLocation) { - message = toEncodedMessage( - message, - [secondaryLocation.node as TSESTree.Node], - [secondaryLocation.message], - ); - } else { - message = toEncodedMessage(message, []); - } - - context.report({ - message, - node: callExpression.callee, - }); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/fixme-tag.ts b/eslint-bridge/src/linting/eslint/rules/fixme-tag.ts deleted file mode 100644 index 636e9f65764..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/fixme-tag.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1134/javascript - -import { Rule } from 'eslint'; -import { reportPatternInComment } from './todo-tag'; - -const fixmePattern = 'fixme'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - fixme: 'Take the required action to fix the issue indicated by this comment.', - }, - }, - create(context: Rule.RuleContext) { - return { - 'Program:exit': () => { - reportPatternInComment(context, fixmePattern, 'fixme'); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/for-in.ts b/eslint-bridge/src/linting/eslint/rules/for-in.ts deleted file mode 100644 index 4ed5fd64635..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/for-in.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1535/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - restrictLoop: 'Restrict what this loop acts on by testing each property.', - }, - }, - create(context: Rule.RuleContext) { - function isAttrCopy(statement: estree.Node) { - if (statement.type !== 'ExpressionStatement') { - return false; - } - const expression = statement.expression; - return ( - expression.type === 'AssignmentExpression' && - expression.left.type === 'MemberExpression' && - expression.left.computed - ); - } - - return { - ForInStatement(node) { - const forInStatement = node as estree.ForInStatement; - const body = forInStatement.body; - - if (body.type === 'BlockStatement') { - if (body.body.length === 0) { - return; - } - const firstStatement = body.body[0]; - if (firstStatement.type === 'IfStatement' || isAttrCopy(firstStatement)) { - return; - } - } - - if (body.type === 'EmptyStatement' || body.type === 'IfStatement' || isAttrCopy(body)) { - return; - } - - context.report({ - node: forInStatement, - messageId: 'restrictLoop', - }); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/for-loop-increment-sign.ts b/eslint-bridge/src/linting/eslint/rules/for-loop-increment-sign.ts deleted file mode 100644 index a51339565cb..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/for-loop-increment-sign.ts +++ /dev/null @@ -1,191 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2251/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { toEncodedMessage } from './helpers'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - return { - ForStatement: (node: estree.Node) => { - const forStatement: estree.ForStatement = node as estree.ForStatement; - const test = forStatement.test; - const loopIncrement: ForLoopIncrement | null = - ForLoopIncrement.findInLoopUpdate(forStatement); - if (test == null || loopIncrement == null || forStatement.update == null) { - return; - } - const wrongDirection = getWrongDirection(test, loopIncrement); - if (wrongDirection !== 0 && wrongDirection === loopIncrement.direction) { - const movement: string = wrongDirection > 0 ? 'incremented' : 'decremented'; - const message = toEncodedMessage( - `"${loopIncrement.identifier.name}" is ${movement} and will never reach its stop condition.`, - [test as TSESTree.Node], - ); - context.report({ - message, - node: forStatement.update, - }); - } - }, - }; - }, -}; - -class ForLoopIncrement { - increment: estree.Expression; - identifier: estree.Identifier; - direction: number; - - constructor(increment: estree.Expression, identifier: estree.Identifier, direction: number) { - this.increment = increment; - this.identifier = identifier; - this.direction = direction; - } - - static findInLoopUpdate(forStatement: estree.ForStatement) { - let result = null; - const expression = forStatement.update; - if (!expression) { - return null; - } - if (expression.type === 'UpdateExpression') { - const updateExpression: estree.UpdateExpression = expression; - const direction: number = updateExpression.operator === '++' ? 1 : -1; - result = ForLoopIncrement.increment(updateExpression, updateExpression.argument, direction); - } - if (expression.type === 'AssignmentExpression') { - const assignmentExpression: estree.AssignmentExpression = expression; - if ( - assignmentExpression.operator === '+=' && - assignmentExpression.left.type === 'Identifier' - ) { - result = ForLoopIncrement.increment( - expression, - assignmentExpression.left, - directionFromValue(assignmentExpression.right), - ); - } - if ( - assignmentExpression.operator === '-=' && - assignmentExpression.left.type === 'Identifier' - ) { - result = ForLoopIncrement.increment( - expression, - assignmentExpression.left, - -directionFromValue(assignmentExpression.right), - ); - } - if (assignmentExpression.operator === '=') { - result = ForLoopIncrement.assignmentIncrement(assignmentExpression); - } - } - return result; - } - - private static increment( - increment: estree.Expression, - expression: estree.Expression, - direction: number, - ) { - if (expression.type === 'Identifier') { - return new ForLoopIncrement(increment, expression, direction); - } - return null; - } - - private static assignmentIncrement(assignmentExpression: estree.AssignmentExpression) { - const lhs = assignmentExpression.left; - const rhs = assignmentExpression.right; - if ( - lhs.type === 'Identifier' && - rhs.type === 'BinaryExpression' && - (rhs.operator === '+' || rhs.operator === '-') - ) { - let incrementDirection = directionFromValue(rhs.right); - if (incrementDirection !== null && isSameIdentifier(rhs.left, lhs)) { - incrementDirection = rhs.operator === '-' ? -incrementDirection : incrementDirection; - return ForLoopIncrement.increment(assignmentExpression, lhs, incrementDirection); - } - } - return null; - } -} - -function directionFromValue(expression: estree.Expression): number { - if (expression.type === 'Literal') { - const value = Number(expression.raw); - if (isNaN(value) || value === 0) { - return 0; - } - return value > 0 ? 1 : -1; - } - if (expression.type === 'UnaryExpression') { - const unaryExpression: estree.UnaryExpression = expression; - if (unaryExpression.operator === '+') { - return directionFromValue(unaryExpression.argument); - } - if (unaryExpression.operator === '-') { - return -directionFromValue(unaryExpression.argument); - } - } - return 0; -} - -function getWrongDirection( - condition: estree.Expression, - forLoopIncrement: ForLoopIncrement, -): number { - if (condition.type !== 'BinaryExpression') { - return 0; - } - if (isSameIdentifier(condition.left, forLoopIncrement.identifier)) { - if (condition.operator === '<' || condition.operator === '<=') { - return -1; - } - if (condition.operator === '>' || condition.operator === '>=') { - return +1; - } - } else if (isSameIdentifier(condition.right, forLoopIncrement.identifier)) { - if (condition.operator === '<' || condition.operator === '<=') { - return +1; - } - if (condition.operator === '>' || condition.operator === '>=') { - return -1; - } - } - return 0; -} - -function isSameIdentifier(expression: estree.Expression, identifier: estree.Identifier) { - return expression.type === 'Identifier' && expression.name === identifier.name; -} diff --git a/eslint-bridge/src/linting/eslint/rules/frame-ancestors.ts b/eslint-bridge/src/linting/eslint/rules/frame-ancestors.ts deleted file mode 100644 index 7eb840db629..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/frame-ancestors.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5732/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { Express, getFullyQualifiedName, getObjectExpressionProperty } from './helpers'; - -const HELMET = 'helmet'; -const HELMET_CSP = 'helmet-csp'; -const DIRECTIVES = 'directives'; -const NONE = "'none'"; -const CONTENT_SECURITY_POLICY = 'contentSecurityPolicy'; -const FRAME_ANCESTORS_CAMEL = 'frameAncestors'; -const FRAME_ANCESTORS_HYPHEN = 'frame-ancestors'; - -export const rule: Rule.RuleModule = Express.SensitiveMiddlewarePropertyRule( - findDirectivesWithSensitiveFrameAncestorsPropertyFromHelmet, - `Make sure disabling content security policy frame-ancestors directive is safe here.`, -); - -function findDirectivesWithSensitiveFrameAncestorsPropertyFromHelmet( - context: Rule.RuleContext, - node: estree.CallExpression, -): estree.Property[] { - const { arguments: args } = node; - if (isValidHelmetModuleCall(context, node) && args.length === 1) { - const [options] = args; - const maybeDirectives = getObjectExpressionProperty(options, DIRECTIVES); - if (maybeDirectives) { - const maybeFrameAncestors = getFrameAncestorsProperty(maybeDirectives); - if (!maybeFrameAncestors) { - return [maybeDirectives]; - } - if (isSetNoneFrameAncestorsProperty(maybeFrameAncestors)) { - return [maybeFrameAncestors]; - } - } - } - return []; -} - -function isValidHelmetModuleCall(context: Rule.RuleContext, callExpr: estree.CallExpression) { - /* csp(options) or helmet.contentSecurityPolicy(options) */ - const fqn = getFullyQualifiedName(context, callExpr); - return fqn === HELMET_CSP || fqn === `${HELMET}.${CONTENT_SECURITY_POLICY}`; -} - -function isSetNoneFrameAncestorsProperty(frameAncestors: estree.Property): boolean { - const { value } = frameAncestors; - return ( - value.type === 'ArrayExpression' && - Boolean( - value.elements.find( - v => v?.type === 'Literal' && typeof v.value === 'string' && v.value === NONE, - ), - ) - ); -} - -function getFrameAncestorsProperty(directives: estree.Property): estree.Property | undefined { - const propertyKeys = [FRAME_ANCESTORS_CAMEL, FRAME_ANCESTORS_HYPHEN]; - for (const propertyKey of propertyKeys) { - const maybeProperty = getObjectExpressionProperty(directives.value, propertyKey); - if (maybeProperty) { - return maybeProperty; - } - } - return undefined; -} diff --git a/eslint-bridge/src/linting/eslint/rules/function-inside-loop.ts b/eslint-bridge/src/linting/eslint/rules/function-inside-loop.ts deleted file mode 100644 index a11e02ebd93..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/function-inside-loop.ts +++ /dev/null @@ -1,189 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1515/javascript - -import { AST, Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { getMainFunctionTokenLocation } from 'eslint-plugin-sonarjs/lib/utils/locations'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { - findFirstMatchingAncestor, - getParent, - LoopLike, - RuleContext, - toEncodedMessage, -} from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -const message = 'Make sure this function is not called after the loop completes.'; - -const loopLike = 'WhileStatement,DoWhileStatement,ForStatement,ForOfStatement,ForInStatement'; - -const functionLike = 'FunctionDeclaration,FunctionExpression,ArrowFunctionExpression'; - -const allowedCallbacks = [ - 'replace', - 'forEach', - 'filter', - 'map', - 'find', - 'findIndex', - 'every', - 'some', - 'reduce', - 'reduceRight', - 'sort', - 'each', -]; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - function getLocalEnclosingLoop(node: estree.Node) { - return findFirstMatchingAncestor(node as TSESTree.Node, n => loopLike.includes(n.type)); - } - - return { - [functionLike]: (node: estree.Node) => { - const loopNode = getLocalEnclosingLoop(node) as LoopLike; - if (loopNode) { - if ( - !isIIEF(node, context) && - !isAllowedCallbacks(context) && - context.getScope().through.some(ref => !isSafe(ref, loopNode)) - ) { - context.report({ - message: toEncodedMessage(message, [getMainLoopToken(loopNode, context)]), - loc: getMainFunctionTokenLocation( - node as TSESTree.FunctionLike, - getParent(context) as TSESTree.Node, - context as unknown as RuleContext, - ), - }); - } - } - }, - }; - }, -}; - -function isIIEF(node: estree.Node, context: Rule.RuleContext) { - const parent = getParent(context); - return ( - parent && - ((parent.type === 'CallExpression' && parent.callee === node) || - (parent.type === 'MemberExpression' && parent.object === node)) - ); -} - -function isAllowedCallbacks(context: Rule.RuleContext) { - const parent = getParent(context); - if (parent && parent.type === 'CallExpression') { - const callee = parent.callee; - if (callee.type === 'MemberExpression') { - return ( - callee.property.type === 'Identifier' && allowedCallbacks.includes(callee.property.name) - ); - } - } - return false; -} - -function isSafe(ref: Scope.Reference, loopNode: LoopLike) { - const variable = ref.resolved; - if (variable) { - const definition = variable.defs[0]; - const declaration = definition && definition.parent; - const kind = declaration && declaration.type === 'VariableDeclaration' ? declaration.kind : ''; - - if (kind !== 'let' && kind !== 'const') { - return hasConstValue(variable, loopNode); - } - } - - return true; -} - -function hasConstValue(variable: Scope.Variable, loopNode: LoopLike): boolean { - for (const ref of variable.references) { - if (ref.isWrite()) { - //Check if write is in the scope of the loop - if (ref.from.type === 'block' && ref.from.block === loopNode.body) { - return false; - } - - const refRange = ref.identifier.range; - const range = getLoopTestRange(loopNode); - //Check if value change in the header of the loop - if (refRange && range && refRange[0] >= range[0] && refRange[1] <= range[1]) { - return false; - } - } - } - return true; -} - -function getLoopTestRange(loopNode: LoopLike) { - const bodyRange = loopNode.body.range; - if (bodyRange) { - switch (loopNode.type) { - case 'ForStatement': - if (loopNode.test && loopNode.test.range) { - return [loopNode.test.range[0], bodyRange[0]]; - } - break; - case 'WhileStatement': - case 'DoWhileStatement': - return loopNode.test.range; - case 'ForOfStatement': - case 'ForInStatement': - const leftRange = loopNode.range; - if (leftRange) { - return [leftRange[0], bodyRange[0]]; - } - } - } -} - -function getMainLoopToken(loop: LoopLike, context: Rule.RuleContext): AST.Token { - const sourceCode = context.getSourceCode(); - let token: AST.Token | null; - switch (loop.type) { - case 'WhileStatement': - case 'DoWhileStatement': - token = sourceCode.getTokenBefore( - loop.test, - t => t.type === 'Keyword' && t.value === 'while', - ); - break; - case 'ForStatement': - case 'ForOfStatement': - default: - token = sourceCode.getFirstToken(loop, t => t.type === 'Keyword' && t.value === 'for'); - } - return token!; -} diff --git a/eslint-bridge/src/linting/eslint/rules/function-name.ts b/eslint-bridge/src/linting/eslint/rules/function-name.ts deleted file mode 100644 index 1693054e631..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/function-name.ts +++ /dev/null @@ -1,138 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S100/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { last, functionLike } from './helpers'; - -interface FunctionKnowledge { - node: estree.Identifier; - func: estree.Function; - returnsJSX: boolean; -} - -const functionExitSelector = [ - ':matches(', - ['FunctionExpression', 'ArrowFunctionExpression', 'FunctionDeclaration'].join(','), - ')', - ':exit', -].join(''); - -const functionExpressionProperty = [ - 'Property', - '[key.type="Identifier"]', - ':matches(', - ['[value.type="FunctionExpression"]', '[value.type="ArrowFunctionExpression"]'].join(','), - ')', -].join(''); - -const functionExpressionVariable = [ - 'VariableDeclarator', - '[id.type="Identifier"]', - ':matches(', - ['[init.type="FunctionExpression"]', '[init.type="ArrowFunctionExpression"]'].join(','), - ')', -].join(''); - -export const rule: Rule.RuleModule = { - meta: { - messages: { - renameFunction: - "Rename this '{{function}}' function to match the regular expression '{{format}}'.", - }, - }, - create(context: Rule.RuleContext) { - const [{ format }] = context.options; - const knowledgeStack: FunctionKnowledge[] = []; - return { - [functionExpressionProperty]: (node: estree.Property) => { - knowledgeStack.push({ - node: node.key as estree.Identifier, - func: node.value as estree.Function, - returnsJSX: returnsJSX(node.value as estree.Function), - }); - }, - [functionExpressionVariable]: (node: estree.VariableDeclarator) => { - knowledgeStack.push({ - node: node.id as estree.Identifier, - func: node.init as estree.Function, - returnsJSX: returnsJSX(node.init as estree.Function), - }); - }, - 'MethodDefinition[key.type="Identifier"]': (node: estree.MethodDefinition) => { - knowledgeStack.push({ - node: node.key as estree.Identifier, - func: node.value as estree.Function, - returnsJSX: false, - }); - }, - 'FunctionDeclaration[id.type="Identifier"]': (node: estree.FunctionDeclaration) => { - knowledgeStack.push({ - node: node.id as estree.Identifier, - func: node as estree.Function, - returnsJSX: false, - }); - }, - [functionExitSelector]: (func: estree.Function) => { - if (func === last(knowledgeStack)?.func) { - const knowledge = knowledgeStack.pop(); - if (knowledge && !knowledge.returnsJSX) { - const { node } = knowledge; - if (!node.name.match(format)) { - context.report({ - messageId: 'renameFunction', - data: { - function: node.name, - format, - }, - node, - }); - } - } - } - }, - ReturnStatement: (node: estree.ReturnStatement) => { - const knowledge = last(knowledgeStack); - const ancestors = context.getAncestors(); - - for (let i = ancestors.length - 1; i >= 0; i--) { - if (functionLike.has(ancestors[i].type)) { - const enclosingFunction = ancestors[i]; - if ( - knowledge && - knowledge.func === enclosingFunction && - node.argument && - (node.argument as any).type.startsWith('JSX') - ) { - knowledge.returnsJSX = true; - } - return; - } - } - }, - }; - }, -}; - -//handling arrow functions without return statement -function returnsJSX(node: estree.Function) { - return (node.body as any).type.startsWith('JSX'); -} diff --git a/eslint-bridge/src/linting/eslint/rules/function-return-type.ts b/eslint-bridge/src/linting/eslint/rules/function-return-type.ts deleted file mode 100644 index eec00ff9d32..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/function-return-type.ts +++ /dev/null @@ -1,177 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3800/javascript - -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { Rule } from 'eslint'; -import { getMainFunctionTokenLocation } from 'eslint-plugin-sonarjs/lib/utils/locations'; -import * as estree from 'estree'; -import * as ts from 'typescript'; -import { - getParent, - getTypeFromTreeNode, - isAny, - isRequiredParserServices, - RuleContext, - toEncodedMessage, -} from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -class FunctionScope { - private readonly returnStatements: estree.ReturnStatement[] = []; - - getReturnStatements() { - return this.returnStatements.slice(); - } - - addReturnStatement(node: estree.ReturnStatement) { - this.returnStatements.push(node); - } -} - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - let scopes: FunctionScope[] = []; - - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - - const checker = services.program.getTypeChecker(); - - function onFunctionExit(node: estree.Node) { - const returnStatements = scopes.pop()!.getReturnStatements(); - if (returnStatements.every(retStmt => retStmt.argument?.type === 'ThisExpression')) { - return; - } - const signature = checker.getSignatureFromDeclaration( - services.esTreeNodeToTSNodeMap.get(node as TSESTree.Node) as ts.SignatureDeclaration, - ); - if (signature && hasMultipleReturnTypes(signature, checker)) { - const stmts = returnStatements.filter( - retStmt => !isNullLike(getTypeFromTreeNode(retStmt.argument!, services)), - ); - const stmtsTypes = stmts.map(retStmt => getTypeFromTreeNode(retStmt.argument!, services)); - if (stmtsTypes.every(isAny)) { - return; - } - context.report({ - message: toEncodedMessage( - 'Refactor this function to always return the same type.', - stmts, - stmtsTypes.map(stmtType => `Returns ${prettyPrint(stmtType, checker)}`), - ), - loc: getMainFunctionTokenLocation( - node as TSESTree.FunctionLike, - getParent(context) as TSESTree.Node, - context as unknown as RuleContext, - ), - }); - } - } - - return { - ReturnStatement: (node: estree.Node) => { - const retStmt = node as estree.ReturnStatement; - if (scopes.length > 0 && retStmt.argument) { - scopes[scopes.length - 1].addReturnStatement(retStmt); - } - }, - ':function': () => { - scopes.push(new FunctionScope()); - }, - ':function:exit': onFunctionExit, - 'Program:exit': () => { - scopes = []; - }, - }; - }, -}; - -function hasMultipleReturnTypes(signature: ts.Signature, checker: ts.TypeChecker) { - const returnType = checker.getBaseTypeOfLiteralType(checker.getReturnTypeOfSignature(signature)); - return isMixingTypes(returnType, checker) && !hasReturnTypeJSDoc(signature); -} - -function isMixingTypes(type: ts.Type, checker: ts.TypeChecker): boolean { - return ( - type.isUnion() && - type.types - .filter(tp => !isNullLike(tp)) - .map(tp => prettyPrint(tp, checker)) - .filter(distinct).length > 1 - ); -} - -function hasReturnTypeJSDoc(signature: ts.Signature) { - return signature.getJsDocTags().some(tag => ['return', 'returns'].includes(tag.name)); -} - -function isObjectLikeType(type: ts.Type) { - return !!(type.getFlags() & ts.TypeFlags.Object); -} - -function distinct(value: T, index: number, self: T[]) { - return self.indexOf(value) === index; -} - -function prettyPrint(type: ts.Type, checker: ts.TypeChecker): string { - if (type.isUnionOrIntersection()) { - const delimiter = type.isUnion() ? ' | ' : ' & '; - return type.types - .map(tp => prettyPrint(tp, checker)) - .filter(distinct) - .join(delimiter); - } - const typeNode = checker.typeToTypeNode(type, undefined, undefined); - if (typeNode !== undefined) { - if (ts.isFunctionTypeNode(typeNode)) { - return 'function'; - } - if (ts.isArrayTypeNode(typeNode) || isTypedArray(type, checker)) { - return 'array'; - } - } - if (isObjectLikeType(type)) { - return 'object'; - } - return checker.typeToString(checker.getBaseTypeOfLiteralType(type)); -} - -function isTypedArray(type: ts.Type, checker: ts.TypeChecker) { - return checker.typeToString(type).endsWith('Array'); -} - -function isNullLike(type: ts.Type) { - return ( - (type.flags & ts.TypeFlags.Null) !== 0 || - (type.flags & ts.TypeFlags.Void) !== 0 || - (type.flags & ts.TypeFlags.Undefined) !== 0 - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/future-reserved-words.ts b/eslint-bridge/src/linting/eslint/rules/future-reserved-words.ts deleted file mode 100644 index 354ab9170ee..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/future-reserved-words.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1527/javascript - -import { Rule, Scope } from 'eslint'; - -const futureReservedWords = [ - 'implements', - 'interface', - 'package', - 'private', - 'protected', - 'public', - 'enum', - 'class', - 'const', - 'export', - 'extends', - 'import', - 'super', - 'let', - 'static', - 'yield', - 'await', -]; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - renameReserved: - 'Rename "{{reserved}}" identifier to prevent potential conflicts with future evolutions of the JavaScript language.', - }, - }, - create(context: Rule.RuleContext) { - function checkVariable(variable: Scope.Variable) { - if (variable.defs.length > 0) { - const def = variable.defs[0].name; - context.report({ - node: def, - messageId: 'renameReserved', - data: { - reserved: variable.name, - }, - }); - } - } - - function checkVariablesByScope(scope: Scope.Scope) { - scope.variables.filter(v => futureReservedWords.includes(v.name)).forEach(checkVariable); - - scope.childScopes.forEach(childScope => { - checkVariablesByScope(childScope); - }); - } - - return { - 'Program:exit': () => { - checkVariablesByScope(context.getScope()); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/generator-without-yield.ts b/eslint-bridge/src/linting/eslint/rules/generator-without-yield.ts deleted file mode 100644 index fc43a6a5f7e..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/generator-without-yield.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3531/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getMainFunctionTokenLocation } from 'eslint-plugin-sonarjs/lib/utils/locations'; -import { getParent, RuleContext } from './helpers'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - addYield: 'Add a "yield" statement to this generator.', - }, - }, - create(context: Rule.RuleContext) { - const yieldStack: number[] = []; - - function enterFunction() { - yieldStack.push(0); - } - - function exitFunction(node: estree.Node) { - const functionNode = node as estree.FunctionExpression | estree.FunctionDeclaration; - const countYield = yieldStack.pop(); - if (countYield === 0 && functionNode.body.body.length > 0) { - context.report({ - messageId: 'addYield', - loc: getMainFunctionTokenLocation( - functionNode as TSESTree.FunctionLike, - getParent(context) as TSESTree.Node, - context as unknown as RuleContext, - ), - }); - } - } - - return { - ':function[generator=true]': enterFunction, - ':function[generator=true]:exit': exitFunction, - YieldExpression() { - if (yieldStack.length > 0) { - yieldStack[yieldStack.length - 1] += 1; - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/hashing.ts b/eslint-bridge/src/linting/eslint/rules/hashing.ts deleted file mode 100644 index 73fa8e0f797..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/hashing.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4790/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getFullyQualifiedName, getUniqueWriteUsageOrNode, isStringLiteral } from './helpers'; - -const message = 'Make sure this weak hash algorithm is not used in a sensitive context here.'; -const CRYPTO_UNSECURE_HASH_ALGORITHMS = new Set([ - 'md2', - 'md4', - 'md5', - 'md6', - 'haval128', - 'hmacmd5', - 'dsa', - 'ripemd', - 'ripemd128', - 'ripemd160', - 'hmacripemd160', - 'sha1', -]); -const SUBTLE_UNSECURE_HASH_ALGORITHMS = new Set(['sha-1']); - -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - function checkNodejsCrypto(fqn: string | null, node: estree.CallExpression) { - // crypto#createHash - const { callee, arguments: args } = node; - if (fqn === 'crypto.createHash') { - checkUnsecureAlgorithm(callee, args[0], CRYPTO_UNSECURE_HASH_ALGORITHMS); - } - } - - function checkSubtleCrypto(fqn: string | null, node: estree.CallExpression) { - // crypto.subtle#digest - const { callee, arguments: args } = node; - if (fqn === 'crypto.subtle.digest') { - checkUnsecureAlgorithm(callee, args[0], SUBTLE_UNSECURE_HASH_ALGORITHMS); - } - } - - function checkUnsecureAlgorithm( - method: estree.Node, - hash: estree.Node, - unsecureAlgorithms: Set, - ) { - const hashAlgorithm = getUniqueWriteUsageOrNode(context, hash); - if ( - isStringLiteral(hashAlgorithm) && - unsecureAlgorithms.has(hashAlgorithm.value.toLocaleLowerCase()) - ) { - context.report({ - message, - node: method, - }); - } - } - - return { - 'CallExpression[arguments.length > 0]': (node: estree.Node) => { - const callExpr = node as estree.CallExpression; - const fqn = getFullyQualifiedName(context, callExpr); - checkNodejsCrypto(fqn, callExpr); - checkSubtleCrypto(fqn, callExpr); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/ancestor.ts b/eslint-bridge/src/linting/eslint/rules/helpers/ancestor.ts deleted file mode 100644 index f682abb7e4d..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/ancestor.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { Rule } from 'eslint'; -import { Node } from 'estree'; -import { functionLike } from './ast'; - -export function findFirstMatchingLocalAncestor( - node: TSESTree.Node, - predicate: (node: TSESTree.Node) => boolean, -) { - return localAncestorsChain(node).find(predicate); -} - -export function findFirstMatchingAncestor( - node: TSESTree.Node, - predicate: (node: TSESTree.Node) => boolean, -) { - return ancestorsChain(node, new Set()).find(predicate); -} - -export function localAncestorsChain(node: TSESTree.Node) { - return ancestorsChain(node, functionLike); -} - -export function ancestorsChain(node: TSESTree.Node, boundaryTypes: Set) { - const chain: TSESTree.Node[] = []; - - let currentNode = node.parent; - while (currentNode) { - chain.push(currentNode); - if (boundaryTypes.has(currentNode.type)) { - break; - } - currentNode = currentNode.parent; - } - return chain; -} - -export function getParent(context: Rule.RuleContext) { - const ancestors = context.getAncestors(); - return ancestors.length > 0 ? ancestors[ancestors.length - 1] : undefined; -} - -/** - * Returns the parent of an ESLint node - * - * This function assumes that an ESLint node exposes a parent property, - * which is always defined. However, it's better to use `getParent` if - * it is possible to retrieve the parent based on the rule context. - * - * It should eventually disappear once we come up with a proper solution - * against the conflicting typings between ESLint and TypeScript ESLint - * when it comes to the parent of a node. - * - * @param node an ESLint node - * @returns the parent node - */ -export function getNodeParent(node: Node) { - return (node as TSESTree.Node).parent as Node; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/ast.ts b/eslint-bridge/src/linting/eslint/rules/helpers/ast.ts deleted file mode 100644 index ebe1046432b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/ast.ts +++ /dev/null @@ -1,619 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { flatMap, getFullyQualifiedName, toEncodedMessage } from '.'; - -export type Node = estree.Node | TSESTree.Node; - -export type LoopLike = - | estree.WhileStatement - | estree.DoWhileStatement - | estree.ForStatement - | estree.ForOfStatement - | estree.ForInStatement; - -export type FunctionNodeType = - | estree.FunctionDeclaration - | estree.FunctionExpression - | estree.ArrowFunctionExpression; - -export type StringLiteral = estree.Literal & { value: string }; - -export const FUNCTION_NODES = [ - 'FunctionDeclaration', - 'FunctionExpression', - 'ArrowFunctionExpression', -]; - -export const functionLike = new Set([ - 'FunctionDeclaration', - 'FunctionExpression', - 'ArrowFunctionExpression', - 'MethodDefinition', -]); - -export function isIdentifier( - node: Node | undefined, - ...values: string[] -): node is estree.Identifier { - return ( - node?.type === 'Identifier' && - (values.length === 0 || values.some(value => value === node.name)) - ); -} - -export function isMemberWithProperty(node: estree.Node, ...values: string[]) { - return node.type === 'MemberExpression' && isIdentifier(node.property, ...values); -} - -export function isMemberExpression( - node: estree.Node, - objectValue: string, - ...propertyValue: string[] -) { - if (node.type === 'MemberExpression') { - const { object, property } = node; - if (isIdentifier(object, objectValue) && isIdentifier(property, ...propertyValue)) { - return true; - } - } - - return false; -} - -export function isBinaryPlus( - node: estree.Node, -): node is estree.BinaryExpression & { operator: '+' } { - return node.type === 'BinaryExpression' && node.operator === '+'; -} - -export function isUnaryExpression(node: estree.Node | undefined): node is estree.UnaryExpression { - return node !== undefined && node.type === 'UnaryExpression'; -} - -export function isArrayExpression(node: estree.Node | undefined): node is estree.ArrayExpression { - return node !== undefined && node.type === 'ArrayExpression'; -} - -export function isRequireModule(node: estree.CallExpression, ...moduleNames: string[]) { - if (isIdentifier(node.callee, 'require') && node.arguments.length === 1) { - const argument = node.arguments[0]; - if (argument.type === 'Literal') { - return moduleNames.includes(String(argument.value)); - } - } - - return false; -} - -export function isMethodInvocation( - callExpression: estree.CallExpression, - objectIdentifierName: string, - methodName: string, - minArgs: number, -): boolean { - return ( - callExpression.callee.type === 'MemberExpression' && - isIdentifier(callExpression.callee.object, objectIdentifierName) && - isIdentifier(callExpression.callee.property, methodName) && - callExpression.callee.property.type === 'Identifier' && - callExpression.arguments.length >= minArgs - ); -} - -export function isFunctionInvocation( - callExpression: estree.CallExpression, - functionName: string, - minArgs: number, -): boolean { - return ( - callExpression.callee.type === 'Identifier' && - isIdentifier(callExpression.callee, functionName) && - callExpression.arguments.length >= minArgs - ); -} - -export function isFunctionCall( - node: estree.Node, -): node is estree.CallExpression & { callee: estree.Identifier } { - return node.type === 'CallExpression' && node.callee.type === 'Identifier'; -} - -export function isMethodCall(callExpr: estree.CallExpression): callExpr is estree.CallExpression & { - callee: estree.MemberExpression & { property: estree.Identifier }; -} { - return ( - callExpr.callee.type === 'MemberExpression' && - !callExpr.callee.computed && - callExpr.callee.property.type === 'Identifier' - ); -} - -export function isCallingMethod( - callExpr: estree.CallExpression, - arity: number, - ...methodNames: string[] -): callExpr is estree.CallExpression & { - callee: estree.MemberExpression & { property: estree.Identifier }; -} { - return ( - isMethodCall(callExpr) && - callExpr.arguments.length === arity && - methodNames.includes(callExpr.callee.property.name) - ); -} - -export function isNamespaceSpecifier(importDeclaration: estree.ImportDeclaration, name: string) { - return importDeclaration.specifiers.some( - ({ type, local }) => type === 'ImportNamespaceSpecifier' && local.name === name, - ); -} - -export function isDefaultSpecifier(importDeclaration: estree.ImportDeclaration, name: string) { - return importDeclaration.specifiers.some( - ({ type, local }) => type === 'ImportDefaultSpecifier' && local.name === name, - ); -} - -export function isModuleExports(node: estree.Node): boolean { - return ( - node.type === 'MemberExpression' && - node.object.type === 'Identifier' && - node.object.name === 'module' && - node.property.type === 'Identifier' && - node.property.name === 'exports' - ); -} - -export function isFunctionNode(node: estree.Node): node is FunctionNodeType { - return FUNCTION_NODES.includes(node.type); -} - -// we have similar function in eslint-plugin-sonarjs, however this one accepts null -// eventually we should update eslint-plugin-sonarjs -export function isLiteral(n: estree.Node | null): n is estree.Literal { - return n != null && n.type === 'Literal'; -} - -export function isNullLiteral(n: estree.Node): boolean { - return isLiteral(n) && n.value === null; -} - -export function isFalseLiteral(n: estree.Node): boolean { - return isLiteral(n) && n.value === false; -} - -export function isUndefined(node: Node): boolean { - return node.type === 'Identifier' && node.name === 'undefined'; -} - -/** - * Detect expression statements like the following: - * myArray[1] = 42; - * myArray[1] += 42; - * myObj.prop1 = 3; - * myObj.prop1 += 3; - */ -export function isElementWrite(statement: estree.ExpressionStatement, ref: Scope.Reference) { - if (statement.expression.type === 'AssignmentExpression') { - const assignmentExpression = statement.expression; - const lhs = assignmentExpression.left; - return isMemberExpressionReference(lhs, ref); - } - return false; -} - -function isMemberExpressionReference(lhs: estree.Node, ref: Scope.Reference): boolean { - return ( - lhs.type === 'MemberExpression' && - (isReferenceTo(ref, lhs.object) || isMemberExpressionReference(lhs.object, ref)) - ); -} - -export function isReferenceTo(ref: Scope.Reference, node: estree.Node) { - return node.type === 'Identifier' && node === ref.identifier; -} - -export function getUniqueWriteUsage(context: Rule.RuleContext, name: string) { - const variable = getVariableFromName(context, name); - return getUniqueWriteReference(variable); -} - -export function getUniqueWriteReference( - variable: Scope.Variable | undefined, -): estree.Node | undefined { - if (variable) { - const writeReferences = variable.references.filter(reference => reference.isWrite()); - if (writeReferences.length === 1 && writeReferences[0].writeExpr) { - return writeReferences[0].writeExpr; - } - } - return undefined; -} - -export function getUniqueWriteUsageOrNode( - context: Rule.RuleContext, - node: estree.Node, - recursive = false, -): estree.Node { - if (node.type === 'Identifier') { - const usage = getUniqueWriteUsage(context, node.name); - if (usage) { - return recursive ? getUniqueWriteUsageOrNode(context, usage, recursive) : usage; - } else { - return node; - } - } else { - return node; - } -} - -export function getValueOfExpression( - context: Rule.RuleContext, - expr: estree.Node | undefined | null, - type: T, - recursive = false, -): Extract | undefined { - if (!expr) { - return undefined; - } - if (isNodeType(expr, type)) { - return expr; - } - if (expr.type === 'Identifier') { - const usage = getUniqueWriteUsage(context, expr.name); - if (usage) { - if (isNodeType(usage, type)) { - return usage; - } - if (recursive) { - return getValueOfExpression(context, usage, type, true); - } - } - } - - return undefined; -} - -// see https://stackoverflow.com/questions/64262105/narrowing-return-value-of-function-based-on-argument -function isNodeType( - node: Node, - type: T, -): node is Extract { - return node.type === type; -} - -/** - * for `x = 42` or `let x = 42` when visiting '42' returns 'x' variable - */ -export function getLhsVariable(context: Rule.RuleContext): Scope.Variable | undefined { - const parent = context.getAncestors()[context.getAncestors().length - 1]; - let formIdentifier: estree.Identifier | undefined; - if (parent.type === 'VariableDeclarator' && parent.id.type === 'Identifier') { - formIdentifier = parent.id; - } else if (parent.type === 'AssignmentExpression' && parent.left.type === 'Identifier') { - formIdentifier = parent.left; - } - if (formIdentifier) { - return getVariableFromName(context, formIdentifier.name); - } - - return undefined; -} - -export function getVariableFromScope(scope: Scope.Scope | null, name: string) { - let variable; - while (variable == null && scope != null) { - variable = scope.variables.find(value => value.name === name); - scope = scope.upper; - } - return variable; -} - -export function getVariableFromName(context: Rule.RuleContext, name: string) { - const scope: Scope.Scope | null = context.getScope(); - return getVariableFromScope(scope, name); -} - -/** - * Takes array of arguments. Keeps following variable definitions - * and unpacking arrays as long as possible. Returns flattened - * array with all collected nodes. - * - * A usage example should clarify why this might be useful. - * According to ExpressJs `app.use` spec, the arguments can be: - * - * - A middleware function. - * - A series of middleware functions (separated by commas). - * - An array of middleware functions. - * - A combination of all of the above. - * - * This means that methods like `app.use` accept variable arguments, - * but also arrays, or combinations thereof. This methods helps - * to flatten out such complicated composed argument lists. - */ -export function flattenArgs(context: Rule.RuleContext, args: estree.Node[]): estree.Node[] { - // Invokes `getUniqueWriteUsageOrNode` at most once, from then on - // only flattens arrays. - function recHelper(nodePossiblyIdentifier: estree.Node): estree.Node[] { - const n = getUniqueWriteUsageOrNode(context, nodePossiblyIdentifier); - if (n.type === 'ArrayExpression') { - return flatMap(n.elements as estree.Node[], recHelper); - } else { - return [n]; - } - } - - return flatMap(args, recHelper); -} - -export function resolveIdentifiers( - node: TSESTree.Node, - acceptShorthand = false, -): TSESTree.Identifier[] { - const identifiers: TSESTree.Identifier[] = []; - resolveIdentifiersAcc(node, identifiers, acceptShorthand); - return identifiers; -} - -function resolveIdentifiersAcc( - node: TSESTree.Node, - identifiers: TSESTree.Identifier[], - acceptShorthand: boolean, -): void { - if (!node) { - return; - } - switch (node.type) { - case 'Identifier': - identifiers.push(node); - break; - case 'ObjectPattern': - node.properties.forEach(prop => resolveIdentifiersAcc(prop, identifiers, acceptShorthand)); - break; - case 'ArrayPattern': - node.elements.forEach( - elem => elem && resolveIdentifiersAcc(elem, identifiers, acceptShorthand), - ); - break; - case 'Property': - if (acceptShorthand || !node.shorthand) { - resolveIdentifiersAcc(node.value, identifiers, acceptShorthand); - } - break; - case 'RestElement': - resolveIdentifiersAcc(node.argument, identifiers, acceptShorthand); - break; - case 'AssignmentPattern': - resolveIdentifiersAcc(node.left, identifiers, acceptShorthand); - break; - case 'TSParameterProperty': - resolveIdentifiersAcc(node.parameter, identifiers, acceptShorthand); - break; - } -} - -// TODO Drop this function and replace it with `getProperty` -export function getObjectExpressionProperty( - node: estree.Node | undefined | null, - propertyKey: string, -): estree.Property | undefined { - if (node?.type === 'ObjectExpression') { - const properties = node.properties.filter( - p => - p.type === 'Property' && - (isIdentifier(p.key, propertyKey) || (isLiteral(p.key) && p.key.value === propertyKey)), - ) as estree.Property[]; - // if property is duplicated, we return the last defined - return properties[properties.length - 1]; - } - return undefined; -} - -export function getPropertyWithValue( - context: Rule.RuleContext, - objectExpression: estree.ObjectExpression, - propertyName: string, - propertyValue: estree.Literal['value'], -): estree.Property | undefined { - const maybeProperty = getObjectExpressionProperty(objectExpression, propertyName); - if (maybeProperty) { - const maybePropertyValue = getValueOfExpression(context, maybeProperty.value, 'Literal'); - if (maybePropertyValue?.value === propertyValue) { - return maybeProperty; - } - } - return undefined; -} - -export function getProperty( - expr: estree.ObjectExpression, - key: string, - ctx: Rule.RuleContext, -): estree.Property | null | undefined { - let unresolvedSpreadElement = false; - for (let i = expr.properties.length - 1; i >= 0; --i) { - const property = expr.properties[i]; - if (isProperty(property, key)) { - return property; - } - if (property.type === 'SpreadElement') { - const props = getValueOfExpression(ctx, property.argument, 'ObjectExpression'); - if (props !== undefined) { - const prop = getProperty(props, key, ctx); - if (prop !== null) { - return prop; - } - } else { - unresolvedSpreadElement = true; - } - } - } - if (unresolvedSpreadElement) { - return undefined; - } - return null; - - function isProperty(node: estree.Node, key: string): node is estree.Property { - return ( - node.type === 'Property' && - (isIdentifier(node.key, key) || (isStringLiteral(node.key) && node.key.value === key)) - ); - } -} - -export function resolveFromFunctionReference( - context: Rule.RuleContext, - functionIdentifier: estree.Identifier, -) { - const { scopeManager } = context.getSourceCode(); - for (const scope of scopeManager.scopes) { - const reference = scope.references.find(r => r.identifier === functionIdentifier); - if ( - reference?.resolved && - reference.resolved.defs.length === 1 && - reference.resolved.defs[0].type === 'FunctionName' - ) { - return reference.resolved.defs[0].node; - } - } - return null; -} - -export function resolveFunction( - context: Rule.RuleContext, - node: estree.Node, -): estree.Function | null { - if (isFunctionNode(node)) { - return node; - } else if (node.type === 'Identifier') { - return resolveFromFunctionReference(context, node); - } else { - return null; - } -} - -export function checkSensitiveCall( - context: Rule.RuleContext, - callExpression: estree.CallExpression, - sensitiveArgumentIndex: number, - sensitiveProperty: string, - sensitivePropertyValue: boolean, - message: string, -) { - if (callExpression.arguments.length < sensitiveArgumentIndex + 1) { - return; - } - const sensitiveArgument = callExpression.arguments[sensitiveArgumentIndex]; - const options = getValueOfExpression(context, sensitiveArgument, 'ObjectExpression'); - if (!options) { - return; - } - const unsafeProperty = getPropertyWithValue( - context, - options, - sensitiveProperty, - sensitivePropertyValue, - ); - if (unsafeProperty) { - context.report({ - node: callExpression.callee, - message: toEncodedMessage(message, [unsafeProperty]), - }); - } -} - -export function isStringLiteral(node: estree.Node): node is StringLiteral { - return isLiteral(node) && typeof node.value === 'string'; -} - -export function isBooleanLiteral(node: estree.Node): node is estree.Literal & { value: boolean } { - return isLiteral(node) && typeof node.value === 'boolean'; -} - -export function isNumberLiteral(node: estree.Node): node is estree.Literal & { value: number } { - return isLiteral(node) && typeof node.value === 'number'; -} - -export function isRegexLiteral(node: estree.Node): node is estree.RegExpLiteral { - return node.type === 'Literal' && node.value instanceof RegExp; -} - -export function isDotNotation( - node: estree.Node, -): node is estree.MemberExpression & { property: estree.Identifier } { - return node.type === 'MemberExpression' && !node.computed && node.property.type === 'Identifier'; -} - -export function isObjectDestructuring( - node: estree.Node, -): node is - | (estree.VariableDeclarator & { id: estree.ObjectPattern }) - | (estree.AssignmentExpression & { left: estree.ObjectPattern }) { - return ( - (node.type === 'VariableDeclarator' && node.id.type === 'ObjectPattern') || - (node.type === 'AssignmentExpression' && node.left.type === 'ObjectPattern') - ); -} - -export function isStaticTemplateLiteral(node: estree.Node): node is estree.TemplateLiteral { - return ( - node.type === 'TemplateLiteral' && node.expressions.length === 0 && node.quasis.length === 1 - ); -} - -export function isThisExpression(node: estree.Node): node is estree.ThisExpression { - return node.type === 'ThisExpression'; -} - -export function isProperty(node: estree.Node): node is estree.Property { - return node.type === 'Property'; -} - -/** - * Check if an identifier has no known value, meaning: - * - * - It's not imported/required - * - Defined variable without any write references (function parameter?) - * - Non-defined variable (a possible global?) - * - * @param node Node to check - * @param ctx Rule context - */ -export function isUnresolved(node: estree.Node | undefined | null, ctx: Rule.RuleContext): boolean { - if (!node || getFullyQualifiedName(ctx, node) || isUndefined(node)) { - return false; - } - let nodeToCheck: estree.Node = node; - while (nodeToCheck.type === 'MemberExpression') { - nodeToCheck = nodeToCheck.object; - } - - if (nodeToCheck.type === 'Identifier') { - const variable = getVariableFromName(ctx, nodeToCheck.name); - const writeReferences = variable?.references.filter(reference => reference.isWrite()); - if (!variable || !writeReferences?.length) { - return true; - } - } - return false; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/aws/cdk.ts b/eslint-bridge/src/linting/eslint/rules/helpers/aws/cdk.ts deleted file mode 100644 index 25fb9759f84..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/aws/cdk.ts +++ /dev/null @@ -1,414 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getFullyQualifiedName } from '../module'; -import { - getProperty, - getUniqueWriteUsage, - getUniqueWriteUsageOrNode, - isIdentifier, - isLiteral, - isUndefined, - isUnresolved, - getValueOfExpression, -} from '../ast'; - -const AWS_OPTIONS_ARGUMENT_POSITION = 2; - -/** - * A symbol fully qualified name, e.g. `aws-cdk-lib.aws_sns.Topic`. - */ -export type FullyQualifiedName = string; -export type AwsCdkCallback = { - functionName?: string; - methods?: string[]; - callExpression(expr: estree.CallExpression, ctx: Rule.RuleContext, fqn?: string): void; - newExpression?(expr: estree.NewExpression, ctx: Rule.RuleContext): void; -}; -export type AwsCdkConsumer = - | ((expr: estree.NewExpression, ctx: Rule.RuleContext) => void) - | AwsCdkCallback; -type AwsCdkNode = estree.NewExpression | estree.CallExpression; - -type Values = { invalid?: any[]; valid?: any[]; case_insensitive?: boolean }; -type ValuesByType = { - primitives?: Values; - fqns?: Values; - customChecker?: (ctx: Rule.RuleContext, node: estree.Node) => boolean; -}; -type NodeAndReport = { - node: estree.Node; - nodeToReport: estree.Node; -}; - -export type AwsCdkConsumerMap = { [key: FullyQualifiedName]: AwsCdkConsumer }; - -/** - * A rule template for AWS CDK resources - * - * @param mapOrFactory callbacks to invoke when a new expression or a call expression matches a fully qualified name - * @param metadata the rule metadata - * @returns the instantiated rule module - */ -export function AwsCdkTemplate( - mapOrFactory: AwsCdkConsumerMap | ((ctx: Rule.RuleContext) => AwsCdkConsumerMap), - metadata: { meta: Rule.RuleMetaData } = { meta: {} }, -): Rule.RuleModule { - return { - ...metadata, - create(ctx: Rule.RuleContext) { - const consumers = typeof mapOrFactory === 'function' ? mapOrFactory(ctx) : mapOrFactory; - return { - 'NewExpression, CallExpression'(node: AwsCdkNode) { - if (node.arguments.some(arg => arg.type === 'SpreadElement')) { - return; - } - for (const fqn in consumers) { - const normalizedExpectedFQN = normalizeFQN(fqn); - const callback = consumers[fqn]; - if (typeof callback === 'object' || node.type === 'CallExpression') { - executeIfMatching(node, normalizedExpectedFQN!, callback); - continue; - } - const normalizedActualFQN = normalizeFQN(getFullyQualifiedName(ctx, node.callee)); - if (normalizedActualFQN === normalizedExpectedFQN) { - callback(node, ctx); - } - } - }, - }; - - function executeIfMatching(node: AwsCdkNode, expected: string, callback: AwsCdkConsumer) { - if (typeof callback === 'function') { - return; - } - - const fqn = normalizeFQN(getFullyQualifiedName(ctx, node.callee)); - if (node.type === 'NewExpression' && fqn === expected) { - callback.newExpression?.(node, ctx); - } else if (isMethodCall(callback, fqn, expected)) { - callback.callExpression(node, ctx, fqn); - } - } - - function isMethodCall(callback: AwsCdkCallback, fqn: string | undefined, expected: string) { - if (callback.functionName) { - return fqn === `${expected}.${callback.functionName}`; - } else if (callback.methods && fqn?.startsWith(expected)) { - const methodNames = fqn.substring(expected.length).split('.'); - const methods = callback.methods; - return methodNames.every(name => name === '' || methods.includes(name)); - } else { - return fqn === expected; - } - } - }, - }; -} - -/** - * Get the messageId at the given position from an array. If a string is used - * instead of an array, return it - * @param messageId Array of messageIds or single string if only one messageId is used - * @param pos - */ -function getMessageAtPos(messageId: string | string[], pos = 0): string { - if (typeof messageId === 'string') { - return messageId; - } - return messageId[pos]; -} - -/** - * Function to analyse arguments in a function and check for correct values. It will report if the - * conditions are not met unless `silent = true`, in which case it will return boolean `true` - * indicating conditions are not met. - * - * @param messageId Array of messageIds or single string if only one messageId is used. When an array is passed, - * first messageId is used for omitted values and second for invalid values. - * @param needsProps whether default (undefined) values are allowed or if it must be set - * @param propertyName property name to search in the object (Array of strings for nested props) - * @param values allowed or disallowed values - * @param silent whether the function must report or just return conflicting Node when conditions are not met - * @param position position of the argument to be analysed (3rd argument by default) - */ -export function AwsCdkCheckArguments( - messageId: string | string[], - needsProps: boolean, - propertyName: string | string[], - values?: ValuesByType, - silent = false, - position = AWS_OPTIONS_ARGUMENT_POSITION, -) { - return (expr: estree.NewExpression, ctx: Rule.RuleContext): estree.Node | undefined => { - const argument = expr.arguments[position]; - - // Argument not found or undefined - if (!argument || isUndefined(argument)) { - if (needsProps) { - if (silent) { - return expr.callee; - } - ctx.report({ messageId: getMessageAtPos(messageId, 0), node: expr.callee }); - } - return; - } - - const properties = traverseProperties( - { node: argument, nodeToReport: argument }, - typeof propertyName === 'string' ? [propertyName] : propertyName, - ctx, - getMessageAtPos(messageId, 0), - needsProps, - silent, - ); - - if (!Array.isArray(properties)) { - return properties; - } - - if (!properties?.length) { - return; - } - - for (const property of properties) { - const propertyValue = getUniqueWriteUsageOrNode( - ctx, - (property.node as estree.Property).value, - true, - ); - - if (isUnresolved(propertyValue, ctx)) { - continue; - } - - /* Property is undefined or an empty array, which is the undefined equivalent - for properties with an array-form where we expect multiple nested values */ - if ( - isUndefined(propertyValue) || - (propertyValue.type === 'ArrayExpression' && !propertyValue.elements.length) - ) { - if (needsProps) { - if (silent) { - return getNodeToReport(property); - } - ctx.report({ messageId: getMessageAtPos(messageId, 0), node: getNodeToReport(property) }); - } - continue; - } - - // Value is expected to be a primitive (string, number) - if (values?.primitives && disallowedValue(ctx, propertyValue, values.primitives)) { - if (silent) { - return getNodeToReport(property); - } - ctx.report({ messageId: getMessageAtPos(messageId, 1), node: getNodeToReport(property) }); - } - // Value is expected to be an Identifier following a specific FQN - if (values?.fqns && disallowedFQNs(ctx, propertyValue, values.fqns)) { - if (silent) { - return getNodeToReport(property); - } - ctx.report({ messageId: getMessageAtPos(messageId, 1), node: getNodeToReport(property) }); - } - // The value needs to be validated with a customized function - if (values?.customChecker && values.customChecker(ctx, propertyValue)) { - if (silent) { - return getNodeToReport(property); - } - ctx.report({ messageId: getMessageAtPos(messageId, 1), node: getNodeToReport(property) }); - } - } - }; -} - -function getNodeToReport(property: NodeAndReport): estree.Node { - if (property.nodeToReport.type === 'Property') { - return property.nodeToReport.value; - } - return property.nodeToReport; -} - -/** - * Given an object expression, check for [nested] attributes. If at some level an - * array is found, the search for next level properties will be performed on each element - * of the array. - * - * @returns an array of Nodes which have the given property path. - * - * @param node node to look for the next property. - * @param propertyPath pending property paths to traverse - * @param ctx rule context - * @param messageId messageId to report when path cannot be met and silent = `false` - * @param needsProp whether missing (undefined) values are allowed or if it must be set - * @param silent whether the function must report or just return conflicting Node when conditions are not met - */ - -function traverseProperties( - node: NodeAndReport, - propertyPath: string[], - ctx: Rule.RuleContext, - messageId: string, - needsProp: boolean, - silent: boolean, -): NodeAndReport[] | estree.Node { - const [propertyName, ...nextElements] = propertyPath; - const properties: NodeAndReport[] = []; - const children: NodeAndReport[] = []; - - if (isUnresolved(node.node, ctx)) { - return []; - } - - const objExpr = getValueOfExpression(ctx, node.node, 'ObjectExpression', true); - - if (objExpr === undefined) { - const arrayExpr = getValueOfExpression(ctx, node.node, 'ArrayExpression', true); - - if (arrayExpr === undefined || !arrayExpr.elements.length) { - if (needsProp) { - if (silent) { - return node.nodeToReport; - } - ctx.report({ messageId, node: node.nodeToReport }); - } - return []; - } - - for (const element of arrayExpr.elements) { - const elemObjExpr = getValueOfExpression(ctx, element, 'ObjectExpression', true); - if (elemObjExpr && element) { - children.push({ node: elemObjExpr, nodeToReport: element }); - } - } - } else { - children.push({ node: objExpr, nodeToReport: node.nodeToReport }); - } - - for (const child of children) { - const property = getProperty(child.node as estree.ObjectExpression, propertyName, ctx); - if (property === undefined) { - continue; - } - - if (!property) { - if (needsProp) { - if (silent) { - return node.nodeToReport; - } - ctx.report({ messageId, node: node.nodeToReport }); - } - continue; - } - - if (nextElements.length) { - if ( - child.node === child.nodeToReport && - (child.node as estree.ObjectExpression).properties.includes(property) - ) { - child.nodeToReport = property.value; - } - child.node = property.value; - const nextElementChildren = traverseProperties( - child, - nextElements, - ctx, - messageId, - needsProp, - silent, - ); - if (!Array.isArray(nextElementChildren)) { - return nextElementChildren; - } - properties.push(...nextElementChildren); - } else { - if ( - child.node === child.nodeToReport && - (child.node as estree.ObjectExpression).properties.includes(property) - ) { - child.nodeToReport = property; - } - child.node = property; - properties.push(child); - } - } - return properties; -} - -function disallowedValue(ctx: Rule.RuleContext, node: estree.Node, values: Values): boolean { - const literal = getLiteralValue(ctx, node); - if (literal) { - if (values.valid?.length) { - const found = values.valid.some(value => { - if (values.case_insensitive && typeof literal.value === 'string') { - return value.toLowerCase() === literal.value.toLowerCase(); - } - return value === literal.value; - }); - if (!found) { - return true; - } - } - if (values.invalid?.length) { - const found = values.invalid.some(value => { - if (values.case_insensitive && typeof literal.value === 'string') { - return value.toLowerCase() === literal.value.toLowerCase(); - } - return value === literal.value; - }); - if (found) { - return true; - } - } - } - return false; -} - -export function getLiteralValue( - ctx: Rule.RuleContext, - node: estree.Node, -): estree.Literal | undefined { - if (isLiteral(node)) { - return node; - } else if (isIdentifier(node)) { - const usage = getUniqueWriteUsage(ctx, node.name); - if (usage) { - return getLiteralValue(ctx, usage); - } - } - return undefined; -} - -function disallowedFQNs(ctx: Rule.RuleContext, node: estree.Node, values: Values) { - const normalizedFQN = normalizeFQN(getFullyQualifiedName(ctx, node)); - - if ( - values.valid?.length && - (!normalizedFQN || !values.valid.map(normalizeFQN).includes(normalizedFQN)) - ) { - return true; - } - return normalizedFQN && values.invalid?.map(normalizeFQN).includes(normalizedFQN); -} - -export function normalizeFQN(fqn?: string | null) { - return fqn?.replace(/-/g, '_'); -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/aws/iam.ts b/eslint-bridge/src/linting/eslint/rules/helpers/aws/iam.ts deleted file mode 100644 index d3810463d62..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/aws/iam.ts +++ /dev/null @@ -1,175 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { CallExpression, NewExpression, Node } from 'estree'; -import { Rule } from 'eslint'; -import { AwsCdkTemplate, normalizeFQN } from './cdk'; -import { SONAR_RUNTIME } from '../../../linter/parameters'; -import { getResultOfExpression, Result } from '../result'; -import { flattenArgs, isStringLiteral, StringLiteral } from '../ast'; -import { getFullyQualifiedName } from '../module'; - -export interface PolicyCheckerOptions { - effect: { - property: string; - type: 'FullyQualifiedName' | 'string'; - allowValue: string; - }; - actions: { - property: string; - anyValues?: string[]; - }; - resources: { - property: string; - }; - conditions: { - property: string; - }; - principals: { - property: string; - type: 'FullyQualifiedName' | 'json'; - anyValues?: string[]; - }; -} - -type StatementChecker = (expr: Node, ctx: Rule.RuleContext, options: PolicyCheckerOptions) => void; - -const PROPERTIES_POSITION = 0; - -const POLICY_DOCUMENT_STATEMENT_PROPERTY = 'Statement'; - -const ARN_PRINCIPAL = 'aws_cdk_lib.aws_iam.ArnPrincipal'; -const STAR_PRINCIPAL = 'aws_cdk_lib.aws_iam.StarPrincipal'; -const ANY_PRINCIPAL = 'aws_cdk_lib.aws_iam.AnyPrincipal'; - -const ANY_LITERAL = '*'; - -const PROPERTIES_OPTIONS: PolicyCheckerOptions = { - effect: { - property: 'effect', - type: 'FullyQualifiedName', - allowValue: 'aws_cdk_lib.aws_iam.Effect.ALLOW', - }, - actions: { - property: 'actions', - }, - resources: { - property: 'resources', - }, - conditions: { - property: 'conditions', - }, - principals: { - property: 'principals', - type: 'FullyQualifiedName', - anyValues: [STAR_PRINCIPAL, ANY_PRINCIPAL, ARN_PRINCIPAL], - }, -}; - -const JSON_OPTIONS: PolicyCheckerOptions = { - effect: { - property: 'Effect', - type: 'string', - allowValue: 'Allow', - }, - actions: { - property: 'Action', - }, - resources: { - property: 'Resource', - }, - conditions: { - property: 'Condition', - }, - principals: { - property: 'Principal', - type: 'json', - }, -}; - -export function AwsIamPolicyTemplate(statementChecker: StatementChecker) { - return AwsCdkTemplate( - { - 'aws-cdk-lib.aws-iam.PolicyStatement': { - newExpression: policyStatementChecker(statementChecker, PROPERTIES_OPTIONS), - functionName: 'fromJson', - callExpression: policyStatementChecker(statementChecker, JSON_OPTIONS), - }, - 'aws-cdk-lib.aws-iam.PolicyDocument': { - functionName: 'fromJson', - callExpression: policyDocumentChecker(statementChecker, JSON_OPTIONS), - }, - }, - { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - }, - ); -} - -export function getSensitiveEffect( - properties: Result, - ctx: Rule.RuleContext, - options: PolicyCheckerOptions, -) { - const effect = properties.getProperty(options.effect.property); - return effect.filter(node => { - if (options.effect.type === 'FullyQualifiedName') { - const fullyQualifiedName = normalizeFQN(getFullyQualifiedName(ctx, node)); - return fullyQualifiedName === options.effect.allowValue; - } else { - return isStringLiteral(node) && node.value === options.effect.allowValue; - } - }); -} - -export function isAnyLiteral(literal: StringLiteral) { - return literal.value === ANY_LITERAL; -} - -function policyDocumentChecker(statementChecker: StatementChecker, options: PolicyCheckerOptions) { - return (expr: CallExpression, ctx: Rule.RuleContext) => { - const call = getResultOfExpression(ctx, expr); - const properties = call.getArgument(PROPERTIES_POSITION); - const statements = properties.getProperty(POLICY_DOCUMENT_STATEMENT_PROPERTY); - - if (statements.isFound) { - for (const node of flattenArgs(ctx, [statements.node])) { - statementChecker(node, ctx, options); - } - } - }; -} - -function policyStatementChecker(statementChecker: StatementChecker, options: PolicyCheckerOptions) { - return (expr: CallExpression | NewExpression, ctx: Rule.RuleContext) => { - const call = getResultOfExpression(ctx, expr); - const properties = call.getArgument(PROPERTIES_POSITION); - - if (properties.isFound) { - statementChecker(properties.node, ctx, options); - } - }; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/aws/s3.ts b/eslint-bridge/src/linting/eslint/rules/helpers/aws/s3.ts deleted file mode 100644 index 8fc839fffbd..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/aws/s3.ts +++ /dev/null @@ -1,130 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - getFullyQualifiedName, - getNodeParent, - getValueOfExpression, - isIdentifier, - isProperty, -} from '..'; -import { normalizeFQN } from './cdk'; - -/** - * A rule template for AWS S3 Buckets - * - * The rule template allows to detect sensitive configuration passed on - * the invocation of S3 Bucket's constructor from AWS CDK: - * - * ```new s3.Bucket(...)``` - * - * @param callback the callback invoked on visiting S3 Bucket's instantiation - * @param metadata the instantiated rule metadata - * @returns the instantiated rule definition - */ -export function S3BucketTemplate( - callback: (bucketConstructor: estree.NewExpression, context: Rule.RuleContext) => void, - metadata: { meta: Rule.RuleMetaData } = { meta: {} }, -): Rule.RuleModule { - return { - ...metadata, - create(context: Rule.RuleContext) { - return { - NewExpression: (node: estree.NewExpression) => { - if (isS3BucketConstructor(context, node)) { - callback(node, context); - } - }, - }; - }, - }; -} - -/** - * Detects S3 Bucket's constructor invocation from 'aws-cdk-lib/aws-s3': - * - * const s3 = require('aws-cdk-lib/aws-s3'); - * new s3.Bucket(); - */ -export function isS3BucketConstructor(context: Rule.RuleContext, node: estree.NewExpression) { - return normalizeFQN(getFullyQualifiedName(context, node)) === 'aws_cdk_lib.aws_s3.Bucket'; -} - -/** - * Detects S3 BucketDeployment's constructor invocation from 'aws-cdk-lib/aws-s3': - * - * const s3 = require('aws-cdk-lib/aws-s3'); - * new s3.BucketDeployment(); - */ -export function isS3BucketDeploymentConstructor( - context: Rule.RuleContext, - node: estree.NewExpression, -) { - return ( - normalizeFQN(getFullyQualifiedName(context, node)) === 'aws_cdk_lib.aws_s3.BucketDeployment' - ); -} - -/** - * Extracts a property from the configuration argument of S3 Bucket's constructor - * - * ``` - * new s3.Bucket(_, _, { // config - * key1: value1, - * ... - * keyN: valueN - * }); - * ``` - * - * @param context the rule context - * @param bucket the invocation of S3 Bucket's constructor - * @param key the key of the property to extract - * @returns the extracted property - */ -export function getProperty(context: Rule.RuleContext, bucket: estree.NewExpression, key: string) { - const args = bucket.arguments as estree.Expression[]; - - const optionsArg = args[2]; - const options = getValueOfExpression(context, optionsArg, 'ObjectExpression'); - if (options == null) { - return null; - } - - return options.properties.find( - property => isProperty(property) && isIdentifier(property.key, key), - ) as estree.Property | undefined; -} - -/** - * Finds the propagated setting of a sensitive property - */ -export function findPropagatedSetting( - sensitiveProperty: estree.Property, - propagatedValue: estree.Node, -) { - const propagated = { locations: [] as estree.Node[], messages: [] as string[] }; - const isPropagatedProperty = sensitiveProperty.value !== propagatedValue; - if (isPropagatedProperty) { - propagated.locations = [getNodeParent(propagatedValue)]; - propagated.messages = ['Propagated setting.']; - } - return propagated; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/chai.ts b/eslint-bridge/src/linting/eslint/rules/helpers/chai.ts deleted file mode 100644 index 23811fe9584..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/chai.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - getImportDeclarations, - getRequireCalls, - isFunctionInvocation, - isIdentifier, - isMethodCall, - isMethodInvocation, -} from '.'; - -export namespace Chai { - export function isImported(context: Rule.RuleContext): boolean { - return ( - getRequireCalls(context).some( - r => r.arguments[0].type === 'Literal' && r.arguments[0].value === 'chai', - ) || getImportDeclarations(context).some(i => i.source.value === 'chai') - ); - } - - export function isAssertion(node: estree.Node): boolean { - return isAssertUsage(node) || isExpectUsage(node) || isShouldUsage(node); - } - - function isAssertUsage(node: estree.Node) { - // assert(), assert.(), chai.assert(), chai.assert.() - return ( - node.type === 'CallExpression' && - (isMethodInvocation(node, 'chai', 'assert', 1) || - isFunctionInvocation(node, 'assert', 1) || - (isMethodCall(node) && isIdentifier(node.callee.object, 'assert')) || - (isMethodCall(node) && - node.callee.object.type === 'MemberExpression' && - isIdentifier(node.callee.object.object, 'chai') && - isIdentifier(node.callee.object.property, 'assert'))) - ); - } - - function isExpectUsage(node: estree.Node) { - // expect(), chai.expect() - return ( - node.type === 'CallExpression' && - (isMethodInvocation(node, 'chai', 'expect', 1) || isFunctionInvocation(node, 'expect', 1)) - ); - } - - function isShouldUsage(node: estree.Node) { - // .should. - return node.type === 'MemberExpression' && isIdentifier(node.property, 'should'); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/collection.ts b/eslint-bridge/src/linting/eslint/rules/helpers/collection.ts deleted file mode 100644 index 8638f2ae118..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/collection.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export const collectionConstructor = ['Array', 'Map', 'Set', 'WeakSet', 'WeakMap']; - -export const writingMethods = [ - // array methods - 'copyWithin', - 'fill', - 'pop', - 'push', - 'reverse', - 'set', - 'shift', - 'sort', - 'splice', - 'unshift', - // map, set methods - 'add', - 'clear', - 'delete', -]; - -export const sortLike = ['sort', '"sort"', "'sort'"]; - -export function flatMap(xs: A[], f: (e: A) => B[]): B[] { - const acc: B[] = []; - for (const x of xs) { - acc.push(...f(x)); - } - return acc; -} - -export function last(arr: Array) { - return arr[arr.length - 1]; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/express.ts b/eslint-bridge/src/linting/eslint/rules/helpers/express.ts deleted file mode 100644 index 53288fb99e5..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/express.ts +++ /dev/null @@ -1,205 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - getFullyQualifiedName, - isModuleExports, - isMethodInvocation, - flattenArgs, - getParent, - toEncodedMessage, -} from '.'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -/** - * This modules provides utilities for writing rules about Express.js. - */ -export namespace Express { - const EXPRESS = 'express'; - - /** - * Checks whether the declaration looks somewhat like ` = express()` - * and returns `` if it matches. - */ - export function attemptFindAppInstantiation( - varDecl: estree.VariableDeclarator, - context: Rule.RuleContext, - ): estree.Identifier | undefined { - const rhs = varDecl.init; - if (rhs && rhs.type === 'CallExpression' && getFullyQualifiedName(context, rhs) === EXPRESS) { - const pattern = varDecl.id; - return pattern.type === 'Identifier' ? pattern : undefined; - } - return undefined; - } - - /** - * Checks whether the function injects an instantiated app and is exported like `module.exports = function(app) {}` - * or `module.exports.property = function(app) {}`, and returns app if it matches. - */ - export function attemptFindAppInjection( - functionDef: estree.Function, - context: Rule.RuleContext, - ): estree.Identifier | undefined { - const app = functionDef.params.find( - param => param.type === 'Identifier' && param.name === 'app', - ) as estree.Identifier | undefined; - if (app) { - const parent = getParent(context); - if (parent?.type === 'AssignmentExpression') { - const { left } = parent; - if ( - left.type === 'MemberExpression' && - (isModuleExports(left) || isModuleExports(left.object)) - ) { - return app; - } - } - } - return undefined; - } - - /** - * Checks whether the expression looks somewhat like `app.use(m1, [m2, m3], ..., mN)`, - * where one of `mK`-nodes satisfies the given predicate. - */ - export function isUsingMiddleware( - context: Rule.RuleContext, - callExpression: estree.CallExpression, - app: estree.Identifier, - middlewareNodePredicate: (n: estree.Node) => boolean, - ): boolean { - if (isMethodInvocation(callExpression, app.name, 'use', 1)) { - const flattenedArgs = flattenArgs(context, callExpression.arguments); - return Boolean(flattenedArgs.find(middlewareNodePredicate)); - } - return false; - } - - /** - * Checks whether a node looks somewhat like `require('m')()` for - * some middleware `m` from the list of middlewares. - */ - export function isMiddlewareInstance( - context: Rule.RuleContext, - middlewares: string[], - n: estree.Node, - ): boolean { - if (n.type === 'CallExpression') { - const fqn = getFullyQualifiedName(context, n); - return middlewares.some(middleware => middleware === fqn); - } - return false; - } - - /** - * Rule factory for detecting sensitive settings that are passed to - * middlewares eventually used by Express.js applications: - * - * app.use( - * middleware(settings) - * ) - * - * or - * - * app.use( - * middleware.method(settings) - * ) - * - * @param sensitivePropertyFinder - a function looking for a sensitive setting on a middleware call - * @param message - the reported message when an issue is raised - * @returns a rule module that raises issues when a sensitive property is found - */ - export function SensitiveMiddlewarePropertyRule( - sensitivePropertyFinder: ( - context: Rule.RuleContext, - middlewareCall: estree.CallExpression, - ) => estree.Property[], - message: string, - ): Rule.RuleModule { - return { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - let app: estree.Identifier | null; - let sensitiveProperties: estree.Property[]; - - function isExposing(middlewareNode: estree.Node): boolean { - return Boolean(sensitiveProperties.push(...findSensitiveProperty(middlewareNode))); - } - - function findSensitiveProperty(middlewareNode: estree.Node): estree.Property[] { - if (middlewareNode.type === 'CallExpression') { - return sensitivePropertyFinder(context, middlewareNode); - } - return []; - } - - return { - Program: () => { - app = null; - sensitiveProperties = []; - }, - CallExpression: (node: estree.Node) => { - if (app) { - const callExpr = node as estree.CallExpression; - const isSafe = !isUsingMiddleware(context, callExpr, app, isExposing); - if (!isSafe) { - for (const sensitive of sensitiveProperties) { - context.report({ - node: callExpr, - message: toEncodedMessage(message, [sensitive as TSESTree.Property]), - }); - } - sensitiveProperties = []; - } - } - }, - VariableDeclarator: (node: estree.Node) => { - if (!app) { - const varDecl = node as estree.VariableDeclarator; - const instantiatedApp = attemptFindAppInstantiation(varDecl, context); - if (instantiatedApp) { - app = instantiatedApp; - } - } - }, - ':function': (node: estree.Node) => { - if (!app) { - const functionDef = node as estree.Function; - const injectedApp = attemptFindAppInjection(functionDef, context); - if (injectedApp) { - app = injectedApp; - } - } - }, - }; - }, - }; - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/file.ts b/eslint-bridge/src/linting/eslint/rules/helpers/file.ts deleted file mode 100644 index ad73dc61656..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/file.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import { FileType } from 'helpers'; - -export function isMainCode(context: Rule.RuleContext) { - return !isTestCode(context); -} - -export function isTestCode(context: Rule.RuleContext) { - return getFileType(context) === 'TEST'; -} - -function getFileType(context: Rule.RuleContext): FileType { - return context.settings['fileType']; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/globals.ts b/eslint-bridge/src/linting/eslint/rules/helpers/globals.ts deleted file mode 100644 index aff753a80d1..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/globals.ts +++ /dev/null @@ -1,1205 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// copied from javascript-frontend/src/main/resources/org/sonar/javascript/tree/symbols/globals.json , -// which should be deleted once the frontend migration is over -export const globalsByLibraries = { - builtin: [ - 'Array', - 'ArrayBuffer', - 'Boolean', - 'DataView', - 'Date', - 'Error', - 'EvalError', - 'Float32Array', - 'Float64Array', - 'Function', - 'Infinity', - 'Int16Array', - 'Int32Array', - 'Int8Array', - 'JSON', - 'Map', - 'Math', - 'NaN', - 'Number', - 'Object', - 'Promise', - 'Proxy', - 'RangeError', - 'ReferenceError', - 'Reflect', - 'RegExp', - 'Set', - 'String', - 'Symbol', - 'SyntaxError', - 'TypeError', - 'URIError', - 'Uint16Array', - 'Uint32Array', - 'Uint8Array', - 'Uint8ClampedArray', - 'WeakMap', - 'WeakSet', - 'constructor', - 'decodeURI', - 'decodeURIComponent', - 'encodeURI', - 'encodeURIComponent', - 'escape', - 'eval', - 'hasOwnProperty', - 'isFinite', - 'isNaN', - 'isPrototypeOf', - 'parseFloat', - 'parseInt', - 'propertyIsEnumerable', - 'toLocaleString', - 'toString', - 'unescape', - 'valueOf', - ], - - // https://developer.mozilla.org/en-US/docs/Web/API/Window - // https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model - browser: [ - 'addEventListener', - 'alert', - 'AnalyserNode', - 'Animation', - 'AnimationEffectReadOnly', - 'AnimationEffectTiming', - 'AnimationEffectTimingReadOnly', - 'AnimationEvent', - 'AnimationPlaybackEvent', - 'AnimationTimeline', - 'applicationCache', - 'ApplicationCache', - 'ApplicationCacheErrorEvent', - 'atob', - 'Attr', - 'Audio', - 'AudioBuffer', - 'AudioBufferSourceNode', - 'AudioContext', - 'AudioDestinationNode', - 'AudioListener', - 'AudioNode', - 'AudioParam', - 'AudioProcessingEvent', - 'AutocompleteErrorEvent', - 'BarProp', - 'BatteryManager', - 'BeforeUnloadEvent', - 'BiquadFilterNode', - 'Blob', - 'blur', - 'btoa', - 'Cache', - 'caches', - 'CacheStorage', - 'cancelAnimationFrame', - 'CanvasGradient', - 'CanvasPattern', - 'CanvasRenderingContext2D', - 'CDATASection', - 'ChannelMergerNode', - 'ChannelSplitterNode', - 'CharacterData', - 'clearInterval', - 'clearTimeout', - 'clientInformation', - 'ClientRect', - 'ClientRectList', - 'ClipboardEvent', - 'close', - 'closed', - 'CloseEvent', - 'Comment', - 'CompositionEvent', - 'confirm', - 'console', - 'ConvolverNode', - 'Credential', - 'CredentialsContainer', - 'crypto', - 'Crypto', - 'CryptoKey', - 'CSS', - 'CSSAnimation', - 'CSSFontFaceRule', - 'CSSImportRule', - 'CSSKeyframeRule', - 'CSSKeyframesRule', - 'CSSMediaRule', - 'CSSPageRule', - 'CSSRule', - 'CSSRuleList', - 'CSSStyleDeclaration', - 'CSSStyleRule', - 'CSSStyleSheet', - 'CSSSupportsRule', - 'CSSTransition', - 'CSSUnknownRule', - 'CSSViewportRule', - 'customElements', - 'CustomEvent', - 'DataTransfer', - 'DataTransferItem', - 'DataTransferItemList', - 'Debug', - 'defaultStatus', - 'defaultstatus', - 'DelayNode', - 'DeviceMotionEvent', - 'DeviceOrientationEvent', - 'devicePixelRatio', - 'dispatchEvent', - 'document', - 'Document', - 'DocumentFragment', - 'DocumentTimeline', - 'DocumentType', - 'DOMError', - 'DOMException', - 'DOMImplementation', - 'DOMParser', - 'DOMSettableTokenList', - 'DOMStringList', - 'DOMStringMap', - 'DOMTokenList', - 'DragEvent', - 'DynamicsCompressorNode', - 'Element', - 'ElementTimeControl', - 'ErrorEvent', - 'event', - 'Event', - 'EventSource', - 'EventTarget', - 'external', - 'FederatedCredential', - 'fetch', - 'File', - 'FileError', - 'FileList', - 'FileReader', - 'find', - 'focus', - 'FocusEvent', - 'FontFace', - 'FormData', - 'frameElement', - 'frames', - 'GainNode', - 'Gamepad', - 'GamepadButton', - 'GamepadEvent', - 'getComputedStyle', - 'getSelection', - 'HashChangeEvent', - 'Headers', - 'history', - 'History', - 'HTMLAllCollection', - 'HTMLAnchorElement', - 'HTMLAppletElement', - 'HTMLAreaElement', - 'HTMLAudioElement', - 'HTMLBaseElement', - 'HTMLBlockquoteElement', - 'HTMLBodyElement', - 'HTMLBRElement', - 'HTMLButtonElement', - 'HTMLCanvasElement', - 'HTMLCollection', - 'HTMLContentElement', - 'HTMLDataListElement', - 'HTMLDetailsElement', - 'HTMLDialogElement', - 'HTMLDirectoryElement', - 'HTMLDivElement', - 'HTMLDListElement', - 'HTMLDocument', - 'HTMLElement', - 'HTMLEmbedElement', - 'HTMLFieldSetElement', - 'HTMLFontElement', - 'HTMLFormControlsCollection', - 'HTMLFormElement', - 'HTMLFrameElement', - 'HTMLFrameSetElement', - 'HTMLHeadElement', - 'HTMLHeadingElement', - 'HTMLHRElement', - 'HTMLHtmlElement', - 'HTMLIFrameElement', - 'HTMLImageElement', - 'HTMLInputElement', - 'HTMLIsIndexElement', - 'HTMLKeygenElement', - 'HTMLLabelElement', - 'HTMLLayerElement', - 'HTMLLegendElement', - 'HTMLLIElement', - 'HTMLLinkElement', - 'HTMLMapElement', - 'HTMLMarqueeElement', - 'HTMLMediaElement', - 'HTMLMenuElement', - 'HTMLMetaElement', - 'HTMLMeterElement', - 'HTMLModElement', - 'HTMLObjectElement', - 'HTMLOListElement', - 'HTMLOptGroupElement', - 'HTMLOptionElement', - 'HTMLOptionsCollection', - 'HTMLOutputElement', - 'HTMLParagraphElement', - 'HTMLParamElement', - 'HTMLPictureElement', - 'HTMLPreElement', - 'HTMLProgressElement', - 'HTMLQuoteElement', - 'HTMLScriptElement', - 'HTMLSelectElement', - 'HTMLShadowElement', - 'HTMLSourceElement', - 'HTMLSpanElement', - 'HTMLStyleElement', - 'HTMLTableCaptionElement', - 'HTMLTableCellElement', - 'HTMLTableColElement', - 'HTMLTableElement', - 'HTMLTableRowElement', - 'HTMLTableSectionElement', - 'HTMLTemplateElement', - 'HTMLTextAreaElement', - 'HTMLTitleElement', - 'HTMLTrackElement', - 'HTMLUListElement', - 'HTMLUnknownElement', - 'HTMLVideoElement', - 'IDBCursor', - 'IDBCursorWithValue', - 'IDBDatabase', - 'IDBEnvironment', - 'IDBFactory', - 'IDBIndex', - 'IDBKeyRange', - 'IDBObjectStore', - 'IDBOpenDBRequest', - 'IDBRequest', - 'IDBTransaction', - 'IDBVersionChangeEvent', - 'Image', - 'ImageBitmap', - 'ImageData', - 'indexedDB', - 'innerHeight', - 'innerWidth', - 'InputEvent', - 'InputMethodContext', - 'IntersectionObserver', - 'IntersectionObserverEntry', - 'Intl', - 'KeyboardEvent', - 'KeyframeEffect', - 'KeyframeEffectReadOnly', - 'length', - 'localStorage', - 'location', - 'Location', - 'locationbar', - 'matchMedia', - 'MediaElementAudioSourceNode', - 'MediaEncryptedEvent', - 'MediaError', - 'MediaKeyError', - 'MediaKeyEvent', - 'MediaKeyMessageEvent', - 'MediaKeys', - 'MediaKeySession', - 'MediaKeyStatusMap', - 'MediaKeySystemAccess', - 'MediaList', - 'MediaQueryList', - 'MediaQueryListEvent', - 'MediaSource', - 'MediaStream', - 'MediaStreamAudioDestinationNode', - 'MediaStreamAudioSourceNode', - 'MediaStreamEvent', - 'MediaStreamTrack', - 'menubar', - 'MessageChannel', - 'MessageEvent', - 'MessagePort', - 'MIDIAccess', - 'MIDIConnectionEvent', - 'MIDIInput', - 'MIDIInputMap', - 'MIDIMessageEvent', - 'MIDIOutput', - 'MIDIOutputMap', - 'MIDIPort', - 'MimeType', - 'MimeTypeArray', - 'MouseEvent', - 'moveBy', - 'moveTo', - 'MutationEvent', - 'MutationObserver', - 'MutationRecord', - 'name', - 'NamedNodeMap', - 'navigator', - 'Navigator', - 'Node', - 'NodeFilter', - 'NodeIterator', - 'NodeList', - 'Notification', - 'OfflineAudioCompletionEvent', - 'OfflineAudioContext', - 'offscreenBuffering', - 'onbeforeunload', - 'onblur', - 'onerror', - 'onfocus', - 'onload', - 'onresize', - 'onunload', - 'open', - 'openDatabase', - 'opener', - 'opera', - 'Option', - 'OscillatorNode', - 'outerHeight', - 'outerWidth', - 'PageTransitionEvent', - 'pageXOffset', - 'pageYOffset', - 'parent', - 'PasswordCredential', - 'Path2D', - 'performance', - 'Performance', - 'PerformanceEntry', - 'PerformanceMark', - 'PerformanceMeasure', - 'PerformanceNavigation', - 'PerformanceResourceTiming', - 'PerformanceTiming', - 'PeriodicWave', - 'Permissions', - 'PermissionStatus', - 'personalbar', - 'Plugin', - 'PluginArray', - 'PopStateEvent', - 'postMessage', - 'print', - 'ProcessingInstruction', - 'ProgressEvent', - 'PromiseRejectionEvent', - 'prompt', - 'PushManager', - 'PushSubscription', - 'RadioNodeList', - 'Range', - 'ReadableByteStream', - 'ReadableStream', - 'removeEventListener', - 'Request', - 'requestAnimationFrame', - 'requestIdleCallback', - 'resizeBy', - 'resizeTo', - 'Response', - 'RTCIceCandidate', - 'RTCSessionDescription', - 'RTCPeerConnection', - 'screen', - 'Screen', - 'screenLeft', - 'ScreenOrientation', - 'screenTop', - 'screenX', - 'screenY', - 'ScriptProcessorNode', - 'scroll', - 'scrollbars', - 'scrollBy', - 'scrollTo', - 'scrollX', - 'scrollY', - 'SecurityPolicyViolationEvent', - 'Selection', - 'self', - 'ServiceWorker', - 'ServiceWorkerContainer', - 'ServiceWorkerRegistration', - 'sessionStorage', - 'setInterval', - 'setTimeout', - 'ShadowRoot', - 'SharedKeyframeList', - 'SharedWorker', - 'showModalDialog', - 'SiteBoundCredential', - 'speechSynthesis', - 'SpeechSynthesisEvent', - 'SpeechSynthesisUtterance', - 'status', - 'statusbar', - 'stop', - 'Storage', - 'StorageEvent', - 'styleMedia', - 'StyleSheet', - 'StyleSheetList', - 'SubtleCrypto', - 'SVGAElement', - 'SVGAltGlyphDefElement', - 'SVGAltGlyphElement', - 'SVGAltGlyphItemElement', - 'SVGAngle', - 'SVGAnimateColorElement', - 'SVGAnimatedAngle', - 'SVGAnimatedBoolean', - 'SVGAnimatedEnumeration', - 'SVGAnimatedInteger', - 'SVGAnimatedLength', - 'SVGAnimatedLengthList', - 'SVGAnimatedNumber', - 'SVGAnimatedNumberList', - 'SVGAnimatedPathData', - 'SVGAnimatedPoints', - 'SVGAnimatedPreserveAspectRatio', - 'SVGAnimatedRect', - 'SVGAnimatedString', - 'SVGAnimatedTransformList', - 'SVGAnimateElement', - 'SVGAnimateMotionElement', - 'SVGAnimateTransformElement', - 'SVGAnimationElement', - 'SVGCircleElement', - 'SVGClipPathElement', - 'SVGColor', - 'SVGColorProfileElement', - 'SVGColorProfileRule', - 'SVGComponentTransferFunctionElement', - 'SVGCSSRule', - 'SVGCursorElement', - 'SVGDefsElement', - 'SVGDescElement', - 'SVGDiscardElement', - 'SVGDocument', - 'SVGElement', - 'SVGElementInstance', - 'SVGElementInstanceList', - 'SVGEllipseElement', - 'SVGEvent', - 'SVGExternalResourcesRequired', - 'SVGFEBlendElement', - 'SVGFEColorMatrixElement', - 'SVGFEComponentTransferElement', - 'SVGFECompositeElement', - 'SVGFEConvolveMatrixElement', - 'SVGFEDiffuseLightingElement', - 'SVGFEDisplacementMapElement', - 'SVGFEDistantLightElement', - 'SVGFEDropShadowElement', - 'SVGFEFloodElement', - 'SVGFEFuncAElement', - 'SVGFEFuncBElement', - 'SVGFEFuncGElement', - 'SVGFEFuncRElement', - 'SVGFEGaussianBlurElement', - 'SVGFEImageElement', - 'SVGFEMergeElement', - 'SVGFEMergeNodeElement', - 'SVGFEMorphologyElement', - 'SVGFEOffsetElement', - 'SVGFEPointLightElement', - 'SVGFESpecularLightingElement', - 'SVGFESpotLightElement', - 'SVGFETileElement', - 'SVGFETurbulenceElement', - 'SVGFilterElement', - 'SVGFilterPrimitiveStandardAttributes', - 'SVGFitToViewBox', - 'SVGFontElement', - 'SVGFontFaceElement', - 'SVGFontFaceFormatElement', - 'SVGFontFaceNameElement', - 'SVGFontFaceSrcElement', - 'SVGFontFaceUriElement', - 'SVGForeignObjectElement', - 'SVGGElement', - 'SVGGeometryElement', - 'SVGGlyphElement', - 'SVGGlyphRefElement', - 'SVGGradientElement', - 'SVGGraphicsElement', - 'SVGHKernElement', - 'SVGICCColor', - 'SVGImageElement', - 'SVGLangSpace', - 'SVGLength', - 'SVGLengthList', - 'SVGLinearGradientElement', - 'SVGLineElement', - 'SVGLocatable', - 'SVGMarkerElement', - 'SVGMaskElement', - 'SVGMatrix', - 'SVGMetadataElement', - 'SVGMissingGlyphElement', - 'SVGMPathElement', - 'SVGNumber', - 'SVGNumberList', - 'SVGPaint', - 'SVGPathElement', - 'SVGPathSeg', - 'SVGPathSegArcAbs', - 'SVGPathSegArcRel', - 'SVGPathSegClosePath', - 'SVGPathSegCurvetoCubicAbs', - 'SVGPathSegCurvetoCubicRel', - 'SVGPathSegCurvetoCubicSmoothAbs', - 'SVGPathSegCurvetoCubicSmoothRel', - 'SVGPathSegCurvetoQuadraticAbs', - 'SVGPathSegCurvetoQuadraticRel', - 'SVGPathSegCurvetoQuadraticSmoothAbs', - 'SVGPathSegCurvetoQuadraticSmoothRel', - 'SVGPathSegLinetoAbs', - 'SVGPathSegLinetoHorizontalAbs', - 'SVGPathSegLinetoHorizontalRel', - 'SVGPathSegLinetoRel', - 'SVGPathSegLinetoVerticalAbs', - 'SVGPathSegLinetoVerticalRel', - 'SVGPathSegList', - 'SVGPathSegMovetoAbs', - 'SVGPathSegMovetoRel', - 'SVGPatternElement', - 'SVGPoint', - 'SVGPointList', - 'SVGPolygonElement', - 'SVGPolylineElement', - 'SVGPreserveAspectRatio', - 'SVGRadialGradientElement', - 'SVGRect', - 'SVGRectElement', - 'SVGRenderingIntent', - 'SVGScriptElement', - 'SVGSetElement', - 'SVGStopElement', - 'SVGStringList', - 'SVGStylable', - 'SVGStyleElement', - 'SVGSVGElement', - 'SVGSwitchElement', - 'SVGSymbolElement', - 'SVGTests', - 'SVGTextContentElement', - 'SVGTextElement', - 'SVGTextPathElement', - 'SVGTextPositioningElement', - 'SVGTitleElement', - 'SVGTransform', - 'SVGTransformable', - 'SVGTransformList', - 'SVGTRefElement', - 'SVGTSpanElement', - 'SVGUnitTypes', - 'SVGURIReference', - 'SVGUseElement', - 'SVGViewElement', - 'SVGViewSpec', - 'SVGVKernElement', - 'SVGZoomAndPan', - 'SVGZoomEvent', - 'Text', - 'TextDecoder', - 'TextEncoder', - 'TextEvent', - 'TextMetrics', - 'TextTrack', - 'TextTrackCue', - 'TextTrackCueList', - 'TextTrackList', - 'TimeEvent', - 'TimeRanges', - 'toolbar', - 'top', - 'Touch', - 'TouchEvent', - 'TouchList', - 'TrackEvent', - 'TransitionEvent', - 'TreeWalker', - 'UIEvent', - 'URL', - 'URLSearchParams', - 'ValidityState', - 'VTTCue', - 'WaveShaperNode', - 'WebGLActiveInfo', - 'WebGLBuffer', - 'WebGLContextEvent', - 'WebGLFramebuffer', - 'WebGLProgram', - 'WebGLRenderbuffer', - 'WebGLRenderingContext', - 'WebGLShader', - 'WebGLShaderPrecisionFormat', - 'WebGLTexture', - 'WebGLUniformLocation', - 'WebSocket', - 'WheelEvent', - 'window', - 'Window', - 'Worker', - 'XDomainRequest', - 'XMLDocument', - 'XMLHttpRequest', - 'XMLHttpRequestEventTarget', - 'XMLHttpRequestProgressEvent', - 'XMLHttpRequestUpload', - 'XMLSerializer', - 'XPathEvaluator', - 'XPathException', - 'XPathExpression', - 'XPathNamespace', - 'XPathNSResolver', - 'XPathResult', - 'XSLTProcessor', - ], - worker: [ - 'applicationCache', - 'atob', - 'Blob', - 'BroadcastChannel', - 'btoa', - 'Cache', - 'caches', - 'clearInterval', - 'clearTimeout', - 'close', - 'console', - 'fetch', - 'FileReaderSync', - 'FormData', - 'Headers', - 'IDBCursor', - 'IDBCursorWithValue', - 'IDBDatabase', - 'IDBFactory', - 'IDBIndex', - 'IDBKeyRange', - 'IDBObjectStore', - 'IDBOpenDBRequest', - 'IDBRequest', - 'IDBTransaction', - 'IDBVersionChangeEvent', - 'ImageData', - 'importScripts', - 'indexedDB', - 'location', - 'MessageChannel', - 'MessagePort', - 'name', - 'navigator', - 'Notification', - 'onclose', - 'onconnect', - 'onerror', - 'onlanguagechange', - 'onmessage', - 'onoffline', - 'ononline', - 'onrejectionhandled', - 'onunhandledrejection', - 'performance', - 'Performance', - 'PerformanceEntry', - 'PerformanceMark', - 'PerformanceMeasure', - 'PerformanceNavigation', - 'PerformanceResourceTiming', - 'PerformanceTiming', - 'postMessage', - 'Promise', - 'Request', - 'Response', - 'self', - 'ServiceWorkerRegistration', - 'setInterval', - 'setTimeout', - 'TextDecoder', - 'TextEncoder', - 'URL', - 'URLSearchParams', - 'WebSocket', - 'Worker', - 'XMLHttpRequest', - ], - - // https://nodejs.org/api/globals.html - node: [ - '__dirname', - '__filename', - 'Buffer', - 'clearImmediate', - 'clearInterval', - 'clearTimeout', - 'console', - 'exports', - 'global', - 'module', - 'process', - 'require', - 'setImmediate', - 'setInterval', - 'setTimeout', - ], - commonjs: ['exports', 'module', 'require', 'global'], - amd: ['define', 'require'], - - // https://mochajs.org/ - mocha: [ - 'after', - 'afterEach', - 'before', - 'beforeEach', - 'context', - 'describe', - 'it', - 'mocha', - 'run', - 'setup', - 'specify', - 'suite', - 'suiteSetup', - 'suiteTeardown', - 'teardown', - 'test', - 'xcontext', - 'xdescribe', - 'xit', - 'xspecify', - ], - - // https://jasmine.github.io/2.0/introduction.html - jasmine: [ - 'afterAll', - 'afterEach', - 'beforeAll', - 'beforeEach', - 'describe', - 'expect', - 'fail', - 'fdescribe', - 'fit', - 'it', - 'jasmine', - 'pending', - 'runs', - 'spyOn', - 'waits', - 'waitsFor', - 'xdescribe', - 'xit', - ], - jest: [ - 'afterAll', - 'afterEach', - 'beforeAll', - 'beforeEach', - 'check', - 'describe', - 'expect', - 'gen', - 'it', - 'fit', - 'jest', - 'pit', - 'require', - 'test', - 'xdescribe', - 'xit', - 'xtest', - ], - qunit: [ - 'asyncTest', - 'deepEqual', - 'equal', - 'expect', - 'module', - 'notDeepEqual', - 'notEqual', - 'notOk', - 'notPropEqual', - 'notStrictEqual', - 'ok', - 'propEqual', - 'QUnit', - 'raises', - 'start', - 'stop', - 'strictEqual', - 'test', - 'throws', - ], - phantomjs: ['console', 'exports', 'phantom', 'require', 'WebPage'], - couch: [ - 'emit', - 'exports', - 'getRow', - 'log', - 'module', - 'provides', - 'require', - 'respond', - 'send', - 'start', - 'sum', - ], - rhino: [ - 'defineClass', - 'deserialize', - 'gc', - 'help', - 'importClass', - 'importPackage', - 'java', - 'load', - 'loadClass', - 'Packages', - 'print', - 'quit', - 'readFile', - 'readUrl', - 'runCommand', - 'seal', - 'serialize', - 'spawn', - 'sync', - 'toint32', - 'version', - ], - nashorn: [ - '__DIR__', - '__FILE__', - '__LINE__', - 'com', - 'edu', - 'exit', - 'Java', - 'java', - 'javafx', - 'JavaImporter', - 'javax', - 'JSAdapter', - 'load', - 'loadWithNewGlobal', - 'org', - 'Packages', - 'print', - 'quit', - ], - wsh: [ - 'ActiveXObject', - 'Enumerator', - 'GetObject', - 'ScriptEngine', - 'ScriptEngineBuildVersion', - 'ScriptEngineMajorVersion', - 'ScriptEngineMinorVersion', - 'VBArray', - 'WScript', - 'WSH', - 'XDomainRequest', - ], - jquery: ['$', 'jQuery'], - yui: ['Y', 'YUI', 'YUI_config'], - shelljs: [ - 'cat', - 'cd', - 'chmod', - 'config', - 'cp', - 'dirs', - 'echo', - 'env', - 'error', - 'exec', - 'exit', - 'find', - 'grep', - 'ls', - 'ln', - 'mkdir', - 'mv', - 'popd', - 'pushd', - 'pwd', - 'rm', - 'sed', - 'set', - 'target', - 'tempdir', - 'test', - 'touch', - 'which', - ], - prototypejs: [ - '$', - '$$', - '$A', - '$break', - '$continue', - '$F', - '$H', - '$R', - '$w', - 'Abstract', - 'Ajax', - 'Autocompleter', - 'Builder', - 'Class', - 'Control', - 'Draggable', - 'Draggables', - 'Droppables', - 'Effect', - 'Element', - 'Enumerable', - 'Event', - 'Field', - 'Form', - 'Hash', - 'Insertion', - 'ObjectRange', - 'PeriodicalExecuter', - 'Position', - 'Prototype', - 'Scriptaculous', - 'Selector', - 'Sortable', - 'SortableObserver', - 'Sound', - 'Template', - 'Toggle', - 'Try', - ], - meteor: [ - '$', - '_', - 'Accounts', - 'AccountsClient', - 'AccountsServer', - 'AccountsCommon', - 'App', - 'Assets', - 'Blaze', - 'check', - 'Cordova', - 'DDP', - 'DDPServer', - 'DDPRateLimiter', - 'Deps', - 'EJSON', - 'Email', - 'HTTP', - 'Log', - 'Match', - 'Meteor', - 'Mongo', - 'MongoInternals', - 'Npm', - 'Package', - 'Plugin', - 'process', - 'Random', - 'ReactiveDict', - 'ReactiveVar', - 'Router', - 'ServiceConfiguration', - 'Session', - 'share', - 'Spacebars', - 'Template', - 'Tinytest', - 'Tracker', - 'UI', - 'Utils', - 'WebApp', - 'WebAppInternals', - ], - mongo: [ - '_isWindows', - '_rand', - 'BulkWriteResult', - 'cat', - 'cd', - 'connect', - 'db', - 'getHostName', - 'getMemInfo', - 'hostname', - 'ISODate', - 'listFiles', - 'load', - 'ls', - 'md5sumFile', - 'mkdir', - 'Mongo', - 'NumberInt', - 'NumberLong', - 'ObjectId', - 'PlanCache', - 'print', - 'printjson', - 'pwd', - 'quit', - 'removeFile', - 'rs', - 'sh', - 'UUID', - 'version', - 'WriteResult', - ], - applescript: [ - '$', - 'Application', - 'Automation', - 'console', - 'delay', - 'Library', - 'ObjC', - 'ObjectSpecifier', - 'Path', - 'Progress', - 'Ref', - ], - serviceworker: [ - 'caches', - 'Cache', - 'CacheStorage', - 'Client', - 'clients', - 'Clients', - 'ExtendableEvent', - 'ExtendableMessageEvent', - 'FetchEvent', - 'importScripts', - 'registration', - 'self', - 'ServiceWorker', - 'ServiceWorkerContainer', - 'ServiceWorkerGlobalScope', - 'ServiceWorkerMessageEvent', - 'ServiceWorkerRegistration', - 'skipWaiting', - 'WindowClient', - ], - atomtest: [ - 'advanceClock', - 'fakeClearInterval', - 'fakeClearTimeout', - 'fakeSetInterval', - 'fakeSetTimeout', - 'resetTimeouts', - 'waitsForPromise', - ], - - // https://guides.emberjs.com/v1.10.0/testing/test-helpers/ - embertest: [ - 'andThen', - 'click', - 'currentPath', - 'currentRouteName', - 'currentURL', - 'fillIn', - 'find', - 'findWithAssert', - 'keyEvent', - 'pauseTest', - 'triggerEvent', - 'visit', - ], - protractor: ['$', '$$', 'browser', 'By', 'by', 'DartObject', 'element', 'protractor'], - 'shared-node-browser': ['clearInterval', 'clearTimeout', 'console', 'setInterval', 'setTimeout'], - webextensions: ['browser', 'chrome', 'opr'], - greasemonkey: [ - 'GM_addStyle', - 'GM_deleteValue', - 'GM_getResourceText', - 'GM_getResourceURL', - 'GM_getValue', - 'GM_info', - 'GM_listValues', - 'GM_log', - 'GM_openInTab', - 'GM_registerMenuCommand', - 'GM_setClipboard', - 'GM_setValue', - 'GM_xmlhttpRequest', - 'unsafeWindow', - ], - flow: [ - 'boolean', - 'number', - 'string', - 'null', - 'void', - 'mixed', - 'any', - 'empty', - 'Array', - 'Class', - '$Call', - '$TupleMap', - '$ObjMap', - '$ElementType', - '$PropertyType', - '$Rest', - '$Diff', - '$Exact', - '$ReadOnly', - '$ReadOnlyArray', - '$Values', - '$Keys', - '$SuperType', - '$Subtype', - 'RegExp$flags', - 'stream$Writable', - 'stream$Readable', - 'tty$WriteStream', - 'tty$ReadStream', - ], -}; diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/index.ts b/eslint-bridge/src/linting/eslint/rules/helpers/index.ts deleted file mode 100644 index da3d26e2c1b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './ancestor'; -export * from './ast'; -export * from './chai'; -export * from './collection'; -export * from './express'; -export * from './file'; -export * from './globals'; -export * from './location'; -export * from './lva'; -export * from './mocha'; -export * from './module'; -export * from './quickfix'; -export * from './reaching-definitions'; -export * from './rule-detect-react'; -export * from './type'; - -export * from 'eslint-plugin-sonarjs/lib/utils/parser-services'; diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/location.ts b/eslint-bridge/src/linting/eslint/rules/helpers/location.ts deleted file mode 100644 index 0bb9f1d4f36..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/location.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as estree from 'estree'; -import { AST } from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { EncodedMessage, IssueLocation } from 'eslint-plugin-sonarjs/lib/utils/locations'; - -export type LocationHolder = AST.Token | TSESTree.Node | estree.Node | { loc: AST.SourceLocation }; - -/** - * Encodes an ESLint descriptor message with secondary locations - * - * The encoding consists in stringifying a JavaScript object with - * `JSON.stringify` that includes the ESLint's descriptor message - * along with second location information: message and location. - * - * This encoded message is eventually decoded by the linter wrapper - * on the condition that the rule definition of the flagged problem - * defines the internal `sonar-runtime` parameter in its schema. - * - * @param message the ESLint descriptor message - * @param secondaryLocationsHolder the secondary locations - * @param secondaryMessages the messages for each secondary location - * @param cost the optional cost to fix - * @returns the encoded message with secondary locations - */ -export function toEncodedMessage( - message: string, - secondaryLocationsHolder: Array = [], - secondaryMessages?: (string | undefined)[], - cost?: number, -): string { - const encodedMessage: EncodedMessage = { - message, - cost, - secondaryLocations: secondaryLocationsHolder.map((locationHolder, index) => - toSecondaryLocation( - locationHolder, - !!secondaryMessages ? secondaryMessages[index] : undefined, - ), - ), - }; - return JSON.stringify(encodedMessage); -} - -function toSecondaryLocation(locationHolder: LocationHolder, message?: string): IssueLocation { - if (!locationHolder.loc) { - throw new Error('Invalid secondary location'); - } - return { - message, - column: locationHolder.loc.start.column, - line: locationHolder.loc.start.line, - endColumn: locationHolder.loc.end.column, - endLine: locationHolder.loc.end.line, - }; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/lva.ts b/eslint-bridge/src/linting/eslint/rules/helpers/lva.ts deleted file mode 100644 index 227da767262..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/lva.ts +++ /dev/null @@ -1,139 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule, Scope } from 'eslint'; -import Variable = Scope.Variable; -import CodePathSegment = Rule.CodePathSegment; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/typescript-estree'; - -export function lva(liveVariablesMap: Map) { - const worklist = Array.from(liveVariablesMap.values(), lva => lva.segment); - while (worklist.length > 0) { - const current = worklist.pop()!; - const liveVariables = liveVariablesMap.get(current.id)!; - const liveInHasChanged = liveVariables.propagate(liveVariablesMap); - if (liveInHasChanged) { - current.prevSegments.forEach(prev => worklist.push(prev)); - } - } -} - -export interface ReferenceLike { - identifier: estree.Identifier | TSESTree.JSXIdentifier; - from: Scope.Scope; - resolved: Scope.Variable | null; - writeExpr: estree.Node | null; - init: boolean; - - isWrite(): boolean; - - isRead(): boolean; - - isWriteOnly(): boolean; - - isReadOnly(): boolean; - - isReadWrite(): boolean; -} - -export class LiveVariables { - constructor(segment: Rule.CodePathSegment) { - this.segment = segment; - } - - segment: CodePathSegment; - - /** - * variables that are being read in the block - */ - gen = new Set(); - /** - * variables that are being written in the block - */ - kill = new Set(); - /** - * variables needed by this or a successor block and are not killed in this block - */ - in = new Set(); - /** - * variables needed by successors - */ - out: Variable[] = []; - - /** - * collects references in order they are evaluated, set in JS maintains insertion order - */ - references = new Set(); - - add(ref: ReferenceLike) { - const variable = ref.resolved; - if (variable) { - if (ref.isRead()) { - this.gen.add(variable); - } - if (ref.isWrite()) { - this.kill.add(variable); - } - this.references.add(ref); - } - } - - propagate(liveVariablesMap: Map) { - const out: Variable[] = []; - this.segment.nextSegments.forEach(next => { - out.push(...liveVariablesMap.get(next.id)!.in); - }); - const diff = difference(out, this.kill); - this.out = out; - if (shouldUpdate(this.in, this.gen, diff)) { - this.in = new Set([...this.gen, ...diff]); - return true; - } else { - return false; - } - } -} - -function difference(a: T[], b: Set): T[] { - if (b.size === 0) { - return a; - } - const diff = []; - for (const e of a) { - if (!b.has(e)) { - diff.push(e); - } - } - return diff; -} - -function shouldUpdate(inSet: Set, gen: Set, diff: Variable[]): boolean { - for (const e of gen) { - if (!inSet.has(e)) { - return true; - } - } - for (const e of diff) { - if (!inSet.has(e)) { - return true; - } - } - return false; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/mocha.ts b/eslint-bridge/src/linting/eslint/rules/helpers/mocha.ts deleted file mode 100644 index 25a887c9f72..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/mocha.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as estree from 'estree'; -import { FUNCTION_NODES, isIdentifier } from '.'; - -export namespace Mocha { - const TEST_CONSTRUCTS = [ - 'describe', - 'context', - 'it', - 'specify', - 'before', - 'after', - 'beforeEach', - 'afterEach', - ]; - - export interface TestCase { - node: estree.Node; - callback: estree.Function; - } - - export function isTestConstruct( - node: estree.Node, - constructs: string[] = TEST_CONSTRUCTS, - ): boolean { - return constructs.some(construct => { - return ( - node.type === 'CallExpression' && - (isIdentifier(node.callee, construct) || - (node.callee.type === 'MemberExpression' && - isIdentifier(node.callee.object, construct) && - isIdentifier(node.callee.property, 'only', 'skip'))) - ); - }); - } - - export function extractTestCase(node: estree.Node): TestCase | null { - if (isTestCase(node)) { - const callExpr = node as estree.CallExpression; - const [, callback] = callExpr.arguments; - if (callback && FUNCTION_NODES.includes(callback.type)) { - return { node: callExpr.callee, callback: callback as estree.Function }; - } - } - return null; - } - - export function isTestCase(node: estree.Node): boolean { - return isTestConstruct(node, ['it', 'specify']); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/module.ts b/eslint-bridge/src/linting/eslint/rules/helpers/module.ts deleted file mode 100644 index a71c4bb7f66..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/module.ts +++ /dev/null @@ -1,337 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { Node, isIdentifier, getVariableFromScope, getUniqueWriteReference } from './ast'; -import Variable = Scope.Variable; - -export function getImportDeclarations(context: Rule.RuleContext) { - const program = context.getSourceCode().ast; - if (program.sourceType === 'module') { - return program.body.filter( - node => node.type === 'ImportDeclaration', - ) as estree.ImportDeclaration[]; - } - return []; -} - -export function getRequireCalls(context: Rule.RuleContext) { - const required: estree.CallExpression[] = []; - const { scopeManager } = context.getSourceCode(); - scopeManager.scopes.forEach(scope => - scope.variables.forEach(variable => - variable.defs.forEach(def => { - if (def.type === 'Variable' && def.node.init) { - if (isRequire(def.node.init)) { - required.push(def.node.init as estree.CallExpression); - } else if (def.node.init.type === 'MemberExpression' && isRequire(def.node.init.object)) { - required.push(def.node.init.object as estree.CallExpression); - } - } - }), - ), - ); - return required; -} - -function isRequire(node: Node) { - return ( - node.type === 'CallExpression' && - node.callee.type === 'Identifier' && - node.callee.name === 'require' && - node.arguments.length === 1 - ); -} - -/** - * Returns 'module' if `node` is a `require('module')` CallExpression - * - * For usage inside rules, prefer getFullyQualifiedName() - * - * @param node - * @returns the module name or undefined - */ -function getModuleNameFromRequire(node: Node): estree.Literal | undefined { - if (isRequire(node)) { - const moduleName = (node as estree.CallExpression).arguments[0]; - if (moduleName.type === 'Literal') { - return moduleName; - } - } - return undefined; -} - -/** - * Returns the fully qualified name of ESLint node - * - * This function filters out the `node:` prefix - * - * A fully qualified name here denotes a value that is accessed through an imported - * symbol, e.g., `foo.bar.baz` where `foo` was imported either from a require call - * or an import statement: - * - * ``` - * const foo = require('lib'); - * foo.bar.baz.qux; // matches the fully qualified name 'lib.bar.baz.qux' (not 'foo.bar.baz.qux') - * const foo2 = require('lib').bar; - * foo2.baz.qux; // matches the fully qualified name 'lib.bar.baz.qux' - * ``` - * - * Returns null when an FQN could not be found. - * - * @param context the rule context - * @param node the node - * @param fqn the already traversed FQN (for recursive calls) - * @param scope scope to look for the variable definition, used in recursion not to - * loop over same variable always in the lower scope - */ -export function getFullyQualifiedName( - context: Rule.RuleContext, - node: estree.Node, - fqn: string[] = [], - scope?: Scope.Scope, -): string | null { - return removeNodePrefixIfExists(getFullyQualifiedNameRaw(context, node, fqn, scope)); -} - -/** - * Just like getFullyQualifiedName(), but does not filter out the `node:` prefix. - * - * To be used for rules that need to work with the `node:` prefix. - */ -export function getFullyQualifiedNameRaw( - context: Rule.RuleContext, - node: estree.Node, - fqn: string[], - scope?: Scope.Scope, - visitedVars: Variable[] = [], -): string | null { - let nodeToCheck = reduceToIdentifier(node, fqn); - - if (!isIdentifier(nodeToCheck)) { - // require chaining, e.g. `require('lib')()` or `require('lib').prop()` - if (node.type === 'CallExpression') { - const qualifiers: string[] = []; - const maybeRequire = reduceTo('CallExpression', node.callee, qualifiers); - const module = getModuleNameFromRequire(maybeRequire); - if (typeof module?.value === 'string') { - qualifiers.unshift(module.value); - return qualifiers.join('.'); - } - } - return null; - } - - const variable = getVariableFromScope(scope || context.getScope(), nodeToCheck.name); - - if (!variable || variable.defs.length > 1) { - return null; - } - - // built-in variable - // ESLint marks built-in global variables with an undocumented hidden `writeable` property that should equal `false`. - // @see https://github.com/eslint/eslint/blob/6380c87c563be5dc78ce0ddd5c7409aaf71692bb/lib/linter/linter.js#L207 - // @see https://github.com/eslint/eslint/blob/6380c87c563be5dc78ce0ddd5c7409aaf71692bb/lib/rules/no-global-assign.js#L81 - if ((variable as any).writeable === false || visitedVars.includes(variable)) { - fqn.unshift(nodeToCheck.name); - return fqn.join('.'); - } - - const definition = variable.defs.find(({ type }) => ['ImportBinding', 'Variable'].includes(type)); - - if (!definition) { - return null; - } - - // imports - const fqnFromImport = checkFqnFromImport(variable, definition, context, fqn, visitedVars); - if (fqnFromImport !== null) { - return fqnFromImport; - } - - // requires - const fqnFromRequire = checkFqnFromRequire(variable, definition, context, fqn, visitedVars); - if (fqnFromRequire !== null) { - return fqnFromRequire; - } - - return null; -} - -function checkFqnFromImport( - variable: Scope.Variable, - definition: Scope.Definition, - context: Rule.RuleContext, - fqn: string[], - visitedVars: Variable[], -) { - if (definition.type === 'ImportBinding') { - const specifier = definition.node; - const importDeclaration = definition.parent; - // import {default as cdk} from 'aws-cdk-lib'; - // vs. - // import { aws_s3 as s3 } from 'aws-cdk-lib'; - if (specifier.type === 'ImportSpecifier' && specifier.imported?.name !== 'default') { - fqn.unshift(specifier.imported?.name); - } - if (typeof importDeclaration.source?.value === 'string') { - const importedQualifiers = importDeclaration.source.value.split('/'); - fqn.unshift(...importedQualifiers); - return fqn.join('.'); - } - // import s3 = require('aws-cdk-lib/aws-s3'); - if ((importDeclaration as TSESTree.Node).type === 'TSImportEqualsDeclaration') { - const importedModule = (importDeclaration as unknown as TSESTree.TSImportEqualsDeclaration) - .moduleReference; - if ( - importedModule.type === 'TSExternalModuleReference' && - importedModule.expression.type === 'Literal' && - typeof importedModule.expression.value === 'string' - ) { - const importedQualifiers = importedModule.expression.value.split('/'); - fqn.unshift(...importedQualifiers); - return fqn.join('.'); - } - //import s3 = cdk.aws_s3; - if (importedModule.type === 'TSQualifiedName') { - visitedVars.push(variable); - return getFullyQualifiedNameRaw( - context, - importedModule as unknown as estree.Node, - fqn, - variable.scope, - visitedVars, - ); - } - } - } - return null; -} - -function checkFqnFromRequire( - variable: Scope.Variable, - definition: Scope.Definition, - context: Rule.RuleContext, - fqn: string[], - visitedVars: Variable[], -) { - const value = getUniqueWriteReference(variable); - // requires - if (definition.type === 'Variable' && value) { - // case for `const {Bucket} = require('aws-cdk-lib/aws-s3');` - // case for `const {Bucket: foo} = require('aws-cdk-lib/aws-s3');` - if (definition.node.id.type === 'ObjectPattern') { - for (const property of definition.node.id.properties) { - if ((property as estree.Property).value === definition.name) { - fqn.unshift(((property as estree.Property).key as estree.Identifier).name); - } - } - } - const nodeToCheck = reduceTo('CallExpression', value, fqn); - const module = getModuleNameFromRequire(nodeToCheck)?.value; - if (typeof module === 'string') { - const importedQualifiers = module.split('/'); - fqn.unshift(...importedQualifiers); - return fqn.join('.'); - } else { - visitedVars.push(variable); - return getFullyQualifiedNameRaw(context, nodeToCheck, fqn, variable.scope, visitedVars); - } - } - return null; -} - -/** - * Removes `node:` prefix if such exists - * - * Node.js builtin modules can be referenced with a `node:` prefix (eg.: node:fs/promises) - * - * https://nodejs.org/api/esm.html#node-imports - * - * @param fqn Fully Qualified Name (ex.: `node:https.request`) - * @returns `fqn` sanitized from `node:` prefix (ex.: `https.request`) - */ -function removeNodePrefixIfExists(fqn: string | null) { - if (fqn === null) { - return null; - } - const NODE_NAMESPACE = 'node:'; - if (fqn.startsWith(NODE_NAMESPACE)) { - return fqn.substring(NODE_NAMESPACE.length); - } - return fqn; -} - -/** - * Helper function for getFullyQualifiedName to handle Member expressions - * filling in the FQN array with the accessed properties. - * @param node the Node to traverse - * @param fqn the array with the qualifiers - */ -export function reduceToIdentifier(node: estree.Node, fqn: string[] = []): estree.Node { - return reduceTo('Identifier', node, fqn); -} - -/** - * Reduce a given node through its ancestors until a given node type is found - * filling in the FQN array with the accessed properties. - * @param type the type of node you are looking for to be returned. Returned node still needs to be - * checked as its type it's not guaranteed to match the passed type. - * @param node the Node to traverse - * @param fqn the array with the qualifiers - */ -export function reduceTo( - type: T, - node: estree.Node, - fqn: string[] = [], -): estree.Node { - let nodeToCheck: estree.Node = node; - - while (nodeToCheck.type !== type) { - if (nodeToCheck.type === 'MemberExpression') { - const { property } = nodeToCheck; - if (property.type === 'Literal' && typeof property.value === 'string') { - fqn.unshift(property.value); - } else if (property.type === 'Identifier') { - fqn.unshift(property.name); - } - nodeToCheck = nodeToCheck.object; - } else if (nodeToCheck.type === 'CallExpression' && !getModuleNameFromRequire(nodeToCheck)) { - nodeToCheck = nodeToCheck.callee; - } else if (nodeToCheck.type === 'NewExpression') { - nodeToCheck = nodeToCheck.callee; - } else if (nodeToCheck.type === 'ChainExpression') { - nodeToCheck = nodeToCheck.expression; - } else if ((nodeToCheck as TSESTree.Node).type === 'TSNonNullExpression') { - // we should migrate to use only TSESTree types everywhere to avoid casting - nodeToCheck = (nodeToCheck as unknown as TSESTree.TSNonNullExpression) - .expression as estree.Expression; - } else if ((nodeToCheck as TSESTree.Node).type === 'TSQualifiedName') { - const qualified = nodeToCheck as unknown as TSESTree.TSQualifiedName; - fqn.unshift(qualified.right.name); - nodeToCheck = qualified.left as estree.Node; - } else { - break; - } - } - - return nodeToCheck; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/quickfix.ts b/eslint-bridge/src/linting/eslint/rules/helpers/quickfix.ts deleted file mode 100644 index f8d5c74bdcb..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/quickfix.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as estree from 'estree'; -import { Rule } from 'eslint'; - -export function removeNodeWithLeadingWhitespaces( - context: Rule.RuleContext, - node: estree.Node, - fixer: Rule.RuleFixer, - removeUntil?: number, -) { - const previousComments = context.getSourceCode().getCommentsBefore(node); - let start = 0; - if (previousComments.length === 0) { - const previousToken = context.getSourceCode().getTokenBefore(node); - if (previousToken) { - start = previousToken.range[1]; - } - } else { - start = previousComments[previousComments.length - 1].range![1]; - } - - const end = removeUntil ? removeUntil : node.range![1]; - return fixer.removeRange([start, end]); -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/reaching-definitions.ts b/eslint-bridge/src/linting/eslint/rules/helpers/reaching-definitions.ts deleted file mode 100644 index b1bb2f390ab..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/reaching-definitions.ts +++ /dev/null @@ -1,173 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import Variable = Scope.Variable; -import CodePathSegment = Rule.CodePathSegment; -import Reference = Scope.Reference; - -type LiteralValue = string; - -class AssignedValues extends Set { - type: 'AssignedValues' = 'AssignedValues'; -} - -const assignedValues = (val: LiteralValue) => new AssignedValues([val]); -interface UnknownValue { - type: 'UnknownValue'; -} -export const unknownValue: UnknownValue = { - type: 'UnknownValue', -}; - -export type Values = AssignedValues | UnknownValue; - -export function reachingDefinitions(reachingDefinitionsMap: Map) { - const worklist = Array.from(reachingDefinitionsMap.values(), defs => defs.segment); - - while (worklist.length > 0) { - const current = worklist.pop()!; - const reachingDefs = reachingDefinitionsMap.get(current.id)!; - const outHasChanged = reachingDefs.propagate(reachingDefinitionsMap); - if (outHasChanged) { - current.nextSegments.forEach(next => worklist.push(next)); - } - } -} - -export class ReachingDefinitions { - constructor(segment: Rule.CodePathSegment) { - this.segment = segment; - } - - segment: CodePathSegment; - - in = new Map(); - - out = new Map(); - - /** - * collects references in order they are evaluated, set in JS maintains insertion order - */ - references = new Set(); - - add(ref: Reference) { - const variable = ref.resolved; - if (variable) { - this.references.add(ref); - } - } - - propagate(reachingDefinitionsMap: Map) { - this.in.clear(); - this.segment.prevSegments.forEach(prev => { - this.join(reachingDefinitionsMap.get(prev.id)!.out); - }); - const newOut = new Map(this.in); - this.references.forEach(ref => this.updateProgramState(ref, newOut)); - if (!equals(this.out, newOut)) { - this.out = newOut; - return true; - } else { - return false; - } - } - - updateProgramState(ref: Reference, programState: Map) { - const variable = ref.resolved; - if (!variable || !ref.isWrite()) { - return; - } - if (!ref.writeExpr) { - programState.set(variable, unknownValue); - return; - } - const rhsValues = resolveAssignedValues(variable, ref.writeExpr, programState, ref.from); - programState.set(variable, rhsValues); - } - - join(previousOut: Map) { - for (const [key, values] of previousOut.entries()) { - const inValues = this.in.get(key) || new AssignedValues(); - if (inValues.type === 'AssignedValues' && values.type === 'AssignedValues') { - values.forEach(val => inValues.add(val)); - this.in.set(key, inValues); - } else { - this.in.set(key, unknownValue); - } - } - } -} - -export function resolveAssignedValues( - lhsVariable: Variable, - writeExpr: estree.Node | null, - assignedValuesMap: Map, - scope: Scope.Scope, -): Values { - if (!writeExpr) { - return unknownValue; - } - switch (writeExpr.type) { - case 'Literal': - return writeExpr.raw ? assignedValues(writeExpr.raw) : unknownValue; - case 'Identifier': - const resolvedVar = getVariableFromIdentifier(writeExpr, scope); - if (resolvedVar && resolvedVar !== lhsVariable) { - const resolvedAssignedValues = assignedValuesMap.get(resolvedVar); - return resolvedAssignedValues || unknownValue; - } - return unknownValue; - default: - return unknownValue; - } -} - -function equals(ps1: Map, ps2: Map) { - if (ps1.size !== ps2.size) { - return false; - } - for (const [variable, values1] of ps1) { - const values2 = ps2.get(variable); - if (!values2 || !valuesEquals(values2, values1)) { - return false; - } - } - return true; -} - -function valuesEquals(a: Values, b: Values) { - if (a.type === 'AssignedValues' && b.type === 'AssignedValues') { - return setEquals(a, b); - } - return a === b; -} - -function setEquals(a: Set, b: Set): boolean { - return a.size === b.size && [...a].every(e => b.has(e)); -} - -export function getVariableFromIdentifier(identifier: estree.Identifier, scope: Scope.Scope) { - let variable = scope.variables.find(value => value.name === identifier.name); - if (!variable && scope.upper) { - variable = scope.upper.variables.find(value => value.name === identifier.name); - } - return variable; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/regex/alternation.ts b/eslint-bridge/src/linting/eslint/rules/helpers/regex/alternation.ts deleted file mode 100644 index 36773c6d134..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/regex/alternation.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { CapturingGroup, Group, LookaroundAssertion, Pattern } from 'regexpp/ast'; - -/** - * An alternation is a regexpp node that has an `alternatives` field. - */ -export type Alternation = Pattern | CapturingGroup | Group | LookaroundAssertion; diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/regex/ast.ts b/eslint-bridge/src/linting/eslint/rules/helpers/regex/ast.ts deleted file mode 100644 index 7983e4f7685..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/regex/ast.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { ParserServices } from '@typescript-eslint/experimental-utils'; -import * as estree from 'estree'; -import { isIdentifier, isString } from 'linting/eslint/rules/helpers'; - -export function isRegExpConstructor(node: estree.Node): node is estree.CallExpression { - return ( - ((node.type === 'CallExpression' || node.type === 'NewExpression') && - node.callee.type === 'Identifier' && - node.callee.name === 'RegExp' && - node.arguments.length > 0) || - isRegExpWithGlobalThis(node) - ); -} - -export function isStringReplaceCall(call: estree.CallExpression, services: ParserServices) { - return ( - call.callee.type === 'MemberExpression' && - call.callee.property.type === 'Identifier' && - !call.callee.computed && - ['replace', 'replaceAll'].includes(call.callee.property.name) && - call.arguments.length > 1 && - isString(call.callee.object, services) - ); -} - -export function isStringRegexMethodCall(call: estree.CallExpression, services: ParserServices) { - return ( - call.callee.type === 'MemberExpression' && - call.callee.property.type === 'Identifier' && - !call.callee.computed && - ['match', 'matchAll', 'search'].includes(call.callee.property.name) && - call.arguments.length > 0 && - isString(call.callee.object, services) && - isString(call.arguments[0], services) - ); -} - -function isRegExpWithGlobalThis(node: estree.Node) { - return ( - node.type === 'NewExpression' && - node.callee.type === 'MemberExpression' && - isIdentifier(node.callee.object, 'globalThis') && - isIdentifier(node.callee.property, 'RegExp') && - node.arguments.length > 0 - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/regex/extract.ts b/eslint-bridge/src/linting/eslint/rules/helpers/regex/extract.ts deleted file mode 100644 index f6061821b07..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/regex/extract.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as estree from 'estree'; -import * as regexpp from 'regexpp'; -import { Rule } from 'eslint'; -import { - getUniqueWriteUsage, - isBinaryPlus, - isIdentifier, - isRegexLiteral, - isStaticTemplateLiteral, - isStringLiteral, -} from 'linting/eslint/rules/helpers'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { isRegExpConstructor } from './ast'; -import { getFlags } from './flags'; - -export function getParsedRegex( - node: estree.Node, - context: Rule.RuleContext, -): regexpp.AST.RegExpLiteral | null { - const patternAndFlags = getPatternFromNode(node, context); - if (patternAndFlags) { - try { - return regexpp.parseRegExpLiteral(new RegExp(patternAndFlags.pattern, patternAndFlags.flags)); - } catch { - // do nothing for invalid regex - } - } - - return null; -} - -function getPatternFromNode( - node: estree.Node, - context: Rule.RuleContext, -): { pattern: string; flags: string } | null { - if (isRegExpConstructor(node)) { - const patternOnly = getPatternFromNode(node.arguments[0], context); - const flags = getFlags(node); - if (patternOnly && flags !== null) { - return { pattern: patternOnly.pattern, flags }; - } - } else if (isRegexLiteral(node)) { - return node.regex; - } else if (isStringLiteral(node)) { - return { pattern: node.value as string, flags: '' }; - } else if (isStaticTemplateLiteral(node)) { - return { pattern: node.quasis[0].value.raw, flags: '' }; - } else if (isIdentifier(node)) { - const assignedExpression = getUniqueWriteUsage(context, node.name); - if ( - assignedExpression && - (assignedExpression as TSESTree.Node).parent?.type === 'VariableDeclarator' - ) { - return getPatternFromNode(assignedExpression, context); - } - } else if (isBinaryPlus(node)) { - const left = getPatternFromNode(node.left, context); - const right = getPatternFromNode(node.right, context); - if (left && right) { - return { pattern: left.pattern + right.pattern, flags: '' }; - } - } - - return null; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/regex/flags.ts b/eslint-bridge/src/linting/eslint/rules/helpers/regex/flags.ts deleted file mode 100644 index b973cbc0872..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/regex/flags.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as estree from 'estree'; - -export function getFlags(callExpr: estree.CallExpression): string | null { - if (callExpr.arguments.length < 2) { - return ''; - } - const flags = callExpr.arguments[1]; - if (flags.type === 'Literal' && typeof flags.value === 'string') { - return flags.value; - } - return null; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/regex/group.ts b/eslint-bridge/src/linting/eslint/rules/helpers/regex/group.ts deleted file mode 100644 index 00ead43999b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/regex/group.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as estree from 'estree'; -import { isStringLiteral } from 'linting/eslint/rules/helpers'; - -export interface GroupReference { - raw: string; - value: string; -} - -export function extractReferences(node: estree.Node) { - const references: GroupReference[] = []; - if (isStringLiteral(node)) { - const str = node.value as string; - const reg = /\$(\d+)|\$\<([a-zA-Z][a-zA-Z0-9_]*)\>/g; - let match: RegExpExecArray | null; - while ((match = reg.exec(str)) !== null) { - const [raw, index, name] = match; - const value = index || name; - references.push({ raw, value }); - } - } - return references; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/regex/index.ts b/eslint-bridge/src/linting/eslint/rules/helpers/regex/index.ts deleted file mode 100644 index 439a3775213..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/regex/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export * from './alternation'; -export * from './ast'; -export * from './extract'; -export * from './flags'; -export * from './group'; -export * from './location'; -export * from './range'; -export * from './rule-template'; -export * from './simplified-regex-character-class'; -export * from './tokenizer'; diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/regex/location.ts b/eslint-bridge/src/linting/eslint/rules/helpers/regex/location.ts deleted file mode 100644 index b3358eb2d60..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/regex/location.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { AST, Rule } from 'eslint'; -import * as estree from 'estree'; -import * as regexpp from 'regexpp'; -import { isRegexLiteral, isStringLiteral } from 'linting/eslint/rules/helpers'; -import { getRegexpRange } from './range'; - -/** - * Gets the regexp node location in the ESLint referential - * @param node the ESLint regex node - * @param regexpNode the regexp regex node - * @param context the rule context - * @param offset an offset to apply on the location - * @returns the regexp node location in the ESLint referential - */ -export function getRegexpLocation( - node: estree.Node, - regexpNode: regexpp.AST.Node, - context: Rule.RuleContext, - offset = [0, 0], -): AST.SourceLocation { - let loc: AST.SourceLocation; - if (isRegexLiteral(node) || isStringLiteral(node)) { - const source = context.getSourceCode(); - const [start] = node.range!; - const [reStart, reEnd] = getRegexpRange(node, regexpNode); - loc = { - start: source.getLocFromIndex(start + reStart + offset[0]), - end: source.getLocFromIndex(start + reEnd + offset[1]), - }; - } else { - loc = node.loc!; - } - return loc; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/regex/range.ts b/eslint-bridge/src/linting/eslint/rules/helpers/regex/range.ts deleted file mode 100644 index ce9e5002901..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/regex/range.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { AST } from 'eslint'; -import * as estree from 'estree'; -import * as regexpp from 'regexpp'; -import { last, isRegexLiteral, isStringLiteral } from 'linting/eslint/rules/helpers'; -import { tokenizeString } from './tokenizer'; - -/** - * Returns the location of regexpNode relative to the node, which is regexp string or literal. If the computation - * of location fails, it returns the range of the whole node. - */ -export function getRegexpRange(node: estree.Node, regexpNode: regexpp.AST.Node): AST.Range { - if (isRegexLiteral(node)) { - return [regexpNode.start, regexpNode.end]; - } - if (isStringLiteral(node)) { - if (node.value === '') { - return [0, 2]; - } - const s = node.raw!; - const tokens = tokenizeString(unquote(s)); - if (regexpNode.start === regexpNode.end) { - // this happens in case of empty alternative node like '|' - if (regexpNode.start - 1 < tokens.length) { - // '|' first empty alternative will have start = 1, end = 1 - // +1 is to account for string quote - return [ - tokens[regexpNode.start - 1].range[0] + 1, - tokens[regexpNode.start - 1].range[0] + 1, - ]; - } else { - // '|' second empty alternative regex node will have start = 2, end = 2 - // +1 is to account for string quote - return [last(tokens).range[1] + 1, last(tokens).range[1] + 1]; - } - } - // regexpNode positions are 1 - based, we need to -1 to report as 0 - based - // it's possible for node start to be outside of range, e.g. `a` in new RegExp('//a') - const startToken = regexpNode.start - 1; - if (tokens[startToken] === undefined) { - // fallback when something is broken - return nodeRange(node); - } - const start = tokens[startToken].range[0]; - // it's possible for node end to be outside of range, e.g. new RegExp('\n(|)') - const endToken = Math.min(regexpNode.end - 2, tokens.length - 1); - if (tokens[endToken] === undefined) { - // fallback when something is broken - return nodeRange(node); - } - const end = tokens[endToken].range[1]; - // +1 is needed to account for string quotes - return [start + 1, end + 1]; - } - if (node.type === 'TemplateLiteral') { - // we don't support these properly - return nodeRange(node); - } - throw new Error(`Expected regexp or string literal, got ${node.type}`); -} - -function nodeRange(node: estree.Node): [number, number] { - return [0, node.range![1] - node.range![0]]; -} - -function unquote(s: string): string { - if (s.charAt(0) !== "'" && s.charAt(0) !== '"') { - throw new Error(`invalid string to unquote: ${s}`); - } - return s.substring(1, s.length - 1); -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/regex/rule-template.ts b/eslint-bridge/src/linting/eslint/rules/helpers/regex/rule-template.ts deleted file mode 100644 index cb4a9d6ad99..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/regex/rule-template.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import * as regexpp from 'regexpp'; -import type { RegExpVisitor } from 'regexpp/visitor'; -import { isStringRegexMethodCall } from './ast'; -import { getParsedRegex } from './extract'; -import { getRegexpLocation } from './location'; -import { isRequiredParserServices } from '..'; - -/** - * Rule context for regex rules that also includes the original ESLint node - * denoting the regular expression (string) literal. - */ -export type RegexRuleContext = Rule.RuleContext & { - node: estree.Node; - reportRegExpNode: (descriptor: RegexReportDescriptor) => void; -}; - -type RegexReportMessage = { message: string } | { messageId: string }; -type RegexReportData = { - regexpNode: regexpp.AST.Node; - node: estree.Node; - offset?: [number, number]; -}; -type RegexReportDescriptor = RegexReportData & RegexReportMessage; - -/** - * Rule template to create regex rules. - * @param handlers - the regexpp node handlers - * @param meta - the (optional) rule metadata - * @returns the resulting rule module - */ -export function createRegExpRule( - handlers: (context: RegexRuleContext) => RegExpVisitor.Handlers, - metadata: { meta: Rule.RuleMetaData } = { meta: {} }, -): Rule.RuleModule { - return { - ...metadata, - create(context: Rule.RuleContext) { - const services = isRequiredParserServices(context.parserServices) - ? context.parserServices - : null; - - function checkRegex(node: estree.Node, regExpAST: regexpp.AST.Node | null) { - if (!regExpAST) { - return; - } - const ctx = Object.create(context) as RegexRuleContext; - ctx.node = node; - ctx.reportRegExpNode = reportRegExpNode; - regexpp.visitRegExpAST(regExpAST, handlers(ctx)); - } - - function reportRegExpNode(descriptor: RegexReportDescriptor) { - const { node, regexpNode, offset = [0, 0] } = descriptor; - const loc = getRegexpLocation(node, regexpNode, context, offset); - if ('message' in descriptor) { - context.report({ message: descriptor.message, loc }); - } else if ('messageId' in descriptor) { - context.report({ messageId: descriptor.messageId, loc }); - } - } - - function checkLiteral(literal: estree.Literal) { - checkRegex(literal, getParsedRegex(literal, context)); - } - - function checkCallExpression(callExpr: estree.CallExpression) { - let parsedRegex = getParsedRegex(callExpr, context); - if (!parsedRegex && services && isStringRegexMethodCall(callExpr, services)) { - const [implicitRegex] = callExpr.arguments; - parsedRegex = getParsedRegex(implicitRegex, context); - } - checkRegex(callExpr.arguments[0], parsedRegex); - } - - return { - 'Literal[regex]': checkLiteral, - NewExpression: checkCallExpression, - CallExpression: checkCallExpression, - }; - }, - }; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/regex/simplified-regex-character-class.ts b/eslint-bridge/src/linting/eslint/rules/helpers/regex/simplified-regex-character-class.ts deleted file mode 100644 index e444abf6d84..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/regex/simplified-regex-character-class.ts +++ /dev/null @@ -1,258 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { - Character, - CharacterClassElement, - CharacterClassRange, - CharacterSet, - Flags, - Node, -} from 'regexpp/ast'; -import * as regexpp from 'regexpp'; -import createTree from 'functional-red-black-tree'; - -const MAX_CODE_POINT = 0x10ffff; - -export class SimplifiedRegexCharacterClass { - /** - * This map defines the contents of the character class in the following way:
- * For any entry {@code codepoint -> tree}, all the codepoints from {@code codepoint} up to (and excluding) the next - * entry are in the character class and belong to the given tree.
- * For any entry {@code codepoint -> null}, all the codepoints from {@code codepoint} up to (and excluding) the next - * entry are not part of the character class.
- * So a codepoint is contained in this class if and only if {@code contents.le(codePoint).value} is - * non-null and the tree returned by {@code value} will be the element of the character class which matches that - * code point. - */ - private contents = createTree(); - - constructor(private readonly flags: Flags, element?: CharacterClassElement) { - if (element) { - this.add(element); - } - } - - public add(element: CharacterClassElement) { - new SimplifiedRegexCharacterClass.Builder(this).visit(element); - } - - public findIntersections(that: SimplifiedRegexCharacterClass) { - const iter = that.contents.begin; - const intersections: Node[] = []; - if (iter.key === undefined) { - return intersections; - } - while (iter.hasNext) { - const { key, value } = iter; - iter.next(); - const to = iter.value ? iter.key : iter.key - 1; - if (value && this.hasEntryBetween(key, to)) { - intersections.push(value); - } - } - if (iter.value && this.hasEntryBetween(iter.key, MAX_CODE_POINT)) { - intersections.push(iter.value); - } - return intersections; - } - - hasEntryBetween(from: number, to: number) { - const before = this.contents.le(from); - return (before.key !== undefined && before.value) || !this.isRangeEmpty(from + 1, to + 1); - } - - isRangeEmpty(from: number, to: number) { - let isEmpty = true; - this.contents.forEach(() => (isEmpty = false), from, to); - return isEmpty; - } - - addRange(from: number, to: number, element: CharacterClassElement) { - const oldEntry = this.contents.le(to); - const oldEnd = oldEntry.key === undefined ? undefined : this.contents.gt(oldEntry.key).key; - this.contents = this.put(from, element, this.contents); - const iterator = this.contents.begin; - while (iterator.key !== undefined) { - if (iterator.key > from && iterator.key <= to && iterator.value === undefined) { - this.contents = iterator.update(element); - } - iterator.next(); - } - const next = to + 1; - if (next <= MAX_CODE_POINT) { - if (oldEntry.key !== undefined && oldEntry.value && (oldEnd === undefined || oldEnd > next)) { - this.contents = this.put(next, oldEntry.value, this.contents); - } else if (this.contents.find(next).key === undefined) { - this.contents = this.put(next, undefined, this.contents); - } - } - } - - put( - key: number, - value: Node | undefined, - tree: createTree.Tree, - ) { - const entry = tree.find(key); - if (entry.valid) { - return entry.update(value); - } - return tree.insert(key, value); - } - - private static readonly Builder = class { - constructor(private readonly characters: SimplifiedRegexCharacterClass) {} - - public visit(element: CharacterClassElement) { - switch (element.type) { - case 'Character': - this.visitCharacter(element); - break; - case 'CharacterClassRange': - this.visitCharacterClassRange(element); - break; - case 'CharacterSet': - this.visitCharacterSet(element); - break; - } - } - - visitCharacter(character: Character) { - this.addRange(character.value, character.value, character); - } - - visitCharacterClassRange(characterRange: CharacterClassRange) { - this.addRange(characterRange.min.value, characterRange.max.value, characterRange); - } - - visitCharacterSet(characterSet: CharacterSet) { - switch (characterSet.kind) { - case 'digit': - if (characterSet.negate) { - this.characters.addRange(0x00, this.codePoint('0') - 1, characterSet); - if (this.characters.flags.unicode) { - this.characters.addRange(this.codePoint('9') + 1, 0xff, characterSet); - } else { - this.characters.addRange(this.codePoint('9') + 1, MAX_CODE_POINT, characterSet); - } - } else { - this.characters.addRange(this.codePoint('0'), this.codePoint('9'), characterSet); - } - break; - case 'space': - if (characterSet.negate) { - this.characters.addRange(0x00, this.codePoint('\t') - 1, characterSet); - this.characters.addRange( - this.codePoint('\r') + 1, - this.codePoint(' ') - 1, - characterSet, - ); - if (this.characters.flags.unicode) { - this.characters.addRange(this.codePoint(' ') + 1, 0x84, characterSet); - this.characters.addRange(0x86, 0x9f, characterSet); - this.characters.addRange(0xa1, 0x167f, characterSet); - this.characters.addRange(0x1681, 0x1fff, characterSet); - this.characters.addRange(0x200b, 0x2027, characterSet); - this.characters.addRange(0x202a, 0x202e, characterSet); - this.characters.addRange(0x2030, 0x205e, characterSet); - this.characters.addRange(0x2060, 0x2fff, characterSet); - this.characters.addRange(0x3001, MAX_CODE_POINT, characterSet); - } else { - this.characters.addRange(this.codePoint(' ') + 1, MAX_CODE_POINT, characterSet); - } - } else { - this.characters.addRange(this.codePoint('\t'), this.codePoint('\r'), characterSet); - this.characters.addRange(this.codePoint(' '), this.codePoint(' '), characterSet); - if (this.characters.flags.unicode) { - this.characters.addRange(0x85, 0x85, characterSet); - this.characters.addRange(0xa0, 0xa0, characterSet); - this.characters.addRange(0x1680, 0x1680, characterSet); - this.characters.addRange(0x2000, 0x200a, characterSet); - this.characters.addRange(0x2028, 0x2029, characterSet); - this.characters.addRange(0x202f, 0x202f, characterSet); - this.characters.addRange(0x205f, 0x205f, characterSet); - this.characters.addRange(0x3000, 0x3000, characterSet); - } - } - break; - case 'word': - if (characterSet.negate) { - this.characters.addRange(0x00, this.codePoint('0') - 1, characterSet); - this.characters.addRange( - this.codePoint('9') + 1, - this.codePoint('A') - 1, - characterSet, - ); - this.characters.addRange( - this.codePoint('Z') + 1, - this.codePoint('_') - 1, - characterSet, - ); - this.characters.addRange(this.codePoint('`'), this.codePoint('`'), characterSet); - if (this.characters.flags.unicode) { - this.characters.addRange( - this.codePoint('z') + 1, - this.codePoint('µ') - 1, - characterSet, - ); - } else { - this.characters.addRange(this.codePoint('z') + 1, MAX_CODE_POINT, characterSet); - } - } else { - this.characters.addRange(this.codePoint('0'), this.codePoint('9'), characterSet); - this.characters.addRange(this.codePoint('A'), this.codePoint('Z'), characterSet); - this.characters.addRange(this.codePoint('_'), this.codePoint('_'), characterSet); - this.characters.addRange(this.codePoint('a'), this.codePoint('z'), characterSet); - } - break; - } - } - - addRange(from: number, to: number, element: CharacterClassElement) { - const upperCaseFrom = this.codePoint(String.fromCodePoint(from).toUpperCase()); - const upperCaseTo = this.codePoint(String.fromCodePoint(to).toUpperCase()); - const lowerCaseFrom = this.codePoint(String.fromCodePoint(upperCaseFrom).toLowerCase()); - const lowerCaseTo = this.codePoint(String.fromCodePoint(upperCaseTo).toLowerCase()); - if ( - this.characters.flags.ignoreCase && - lowerCaseFrom !== upperCaseFrom && - lowerCaseTo !== upperCaseTo && - ((this.isAscii(from) && this.isAscii(to)) || this.characters.flags.unicode) - ) { - this.characters.addRange(upperCaseFrom, upperCaseTo, element); - this.characters.addRange(lowerCaseFrom, lowerCaseTo, element); - } else { - this.characters.addRange(from, to, element); - } - } - - isAscii(c: number) { - return c < 128; - } - - codePoint(c: string) { - const cp = c.codePointAt(0); - if (cp === undefined) { - throw new Error(`failed to compute code point for: ${c}`); - } - return cp; - } - }; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/regex/tokenizer.ts b/eslint-bridge/src/linting/eslint/rules/helpers/regex/tokenizer.ts deleted file mode 100644 index 74ce59cc0a1..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/regex/tokenizer.ts +++ /dev/null @@ -1,170 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export interface StringLiteralToken { - value: string; - range: [number, number]; -} - -const UNICODE_ESCAPE_LENGTH = 4; -const HEX_ESCAPE_LENGTH = 2; - -const CP_BACK_SLASH = cp('\\'); -const CP_FORWARD_SLASH = cp('/'); -const CP_CR = cp('\r'); -const CP_LF = cp('\n'); -const CP_n = cp('n'); -const CP_r = cp('r'); -const CP_t = cp('t'); -const CP_b = cp('b'); -const CP_v = cp('v'); -const CP_f = cp('f'); -const CP_u = cp('u'); -const CP_x = cp('x'); - -/** - * Parse 's' and return array of tokens with range. We assume 's' is correctly terminated because it was already parsed - * into AST. - * - * Inspired by https://github.com/ota-meshi/eslint-plugin-regexp/blob/61ae9424e0f3bde62569718b597cdc036fec9f71/lib/utils/string-literal-parser/tokenizer.ts - */ -export function tokenizeString(s: string): StringLiteralToken[] { - const tokens: StringLiteralToken[] = []; - let pos = 0; - - function next() { - const c = cp(s, pos); - pos = inc(pos, c); - return c; - } - - function readEscape(): string { - const c = next(); - switch (c) { - case CP_n: - return '\n'; - case CP_r: - return '\r'; - case CP_t: - return '\t'; - case CP_b: - return '\b'; - case CP_v: - return '\v'; - case CP_f: - return '\f'; - case CP_BACK_SLASH: - return '\\'; - case CP_CR: - if (cp(s, pos) === CP_LF) { - pos++; // \r\n - } - return ''; - case CP_LF: - return ''; - case CP_u: - return String.fromCodePoint(readUnicode()); - case CP_x: - return String.fromCodePoint(readHex()); - default: - if (isOctalDigit(c)) { - return readOctal(c); - } - return String.fromCodePoint(c); - } - } - - /** - * read unicode escape like \u0061 or \u{61} - */ - function readUnicode(): number { - let u; - if (s.charAt(pos) === '{') { - pos++; - const close = s.indexOf('}', pos); - u = s.substring(pos, close); - pos = close + 1; - } else { - u = s.substring(pos, pos + UNICODE_ESCAPE_LENGTH); - pos += UNICODE_ESCAPE_LENGTH; - } - return Number.parseInt(u, 16); - } - - /** - * read hex escape like \xA9 - */ - function readHex(): number { - const x = Number.parseInt(s.substring(pos, pos + HEX_ESCAPE_LENGTH), 16); - pos += HEX_ESCAPE_LENGTH; - return x; - } - - /** - * read octal escapes like \251. Octal escape sequences can have 1 - 3 digits - * and can be padded with 0 - * - * @param firstDigit digit on the current 'pos' position - */ - function readOctal(firstDigit: number): string { - let octal = String.fromCodePoint(firstDigit); - let i = pos; - while (isOctalDigit(cp(s, i)) && i - pos < 2) { - octal += s.charAt(i); - i++; - } - const res = Number.parseInt(octal, 8); - pos = i; - return String.fromCodePoint(res); - } - - while (pos < s.length) { - const start = pos; - const c = next(); - if (c === CP_BACK_SLASH) { - const value = readEscape(); - if (value !== '') { - tokens.push({ value, range: [start, pos] }); - } - } else if (c === CP_FORWARD_SLASH) { - const forwardSlash: StringLiteralToken = { - value: String.fromCodePoint(c), - range: [start, pos], - }; - tokens.push(forwardSlash); - tokens.push(forwardSlash); - } else { - tokens.push({ value: String.fromCodePoint(c), range: [start, pos] }); - } - } - return tokens; -} - -function inc(pos: number, c: number): number { - // account for UTF-16 low surrogate - return pos + (c >= 0x10000 ? 2 : 1); -} - -function isOctalDigit(c: number | undefined): boolean { - return c !== undefined && cp('0') <= c && c <= cp('7'); -} - -function cp(s: string, i = 0): number { - return s.codePointAt(i)!; -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/result.ts b/eslint-bridge/src/linting/eslint/rules/helpers/result.ts deleted file mode 100644 index ed1b072bd5d..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/result.ts +++ /dev/null @@ -1,184 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Node } from 'estree'; -import { - getProperty, - getUniqueWriteUsageOrNode, - isArrayExpression, - isBooleanLiteral, - isStringLiteral, - isUndefined, - StringLiteral, -} from './ast'; -import { Rule } from 'eslint'; - -export class Result { - constructor( - readonly ctx: Rule.RuleContext, - readonly node: Node, - readonly status: 'missing' | 'unknown' | 'found', - ) {} - - get isFound() { - return this.status === 'found'; - } - - get isMissing() { - return this.status === 'missing'; - } - - get isTrue() { - return this.isFound && isBooleanLiteral(this.node) && this.node.value; - } - - ofType(type: Node['type']) { - return this.isFound && this.node.type === type; - } - - getArgument(position: number): Result { - if (!this.isFound) { - return this; - } else if (this.node.type !== 'NewExpression' && this.node.type !== 'CallExpression') { - return unknown(this.ctx, this.node); - } - - const argument = this.node.arguments[position]; - if (argument == null) { - return missing(this.ctx, this.node); - } else { - return getResultOfExpression(this.ctx, argument); - } - } - - getProperty(propertyName: string): Result { - if (!this.isFound) { - return this; - } else if (this.node.type !== 'ObjectExpression') { - return unknown(this.ctx, this.node); - } - - const property = getProperty(this.node, propertyName, this.ctx); - if (property === undefined) { - return unknown(this.ctx, this.node); - } else if (property === null) { - return missing(this.ctx, this.node); - } else { - return getResultOfExpression(this.ctx, property.value); - } - } - - getMemberObject(): Result { - if (!this.isFound) { - return this; - } else if (this.node.type !== 'MemberExpression') { - return unknown(this.ctx, this.node); - } else { - return getResultOfExpression(this.ctx, this.node.object).filter(n => n.type !== 'Super'); - } - } - - findInArray(closure: (item: Result) => Result | null | undefined) { - if (!this.isFound) { - return this; - } else if (!isArrayExpression(this.node)) { - return unknown(this.ctx, this.node); - } - - let isMissing = true; - - for (const element of this.node.elements) { - const result = element != null ? closure(getResultOfExpression(this.ctx, element)) : null; - if (result?.isFound) { - return result; - } - isMissing &&= result?.isMissing ?? true; - } - - return isMissing ? missing(this.ctx, this.node) : unknown(this.ctx, this.node); - } - - everyStringLiteral(closure: (item: StringLiteral) => boolean) { - if (!this.isFound) { - return false; - } else if (isStringLiteral(this.node)) { - return closure(this.node); - } else if (!isArrayExpression(this.node)) { - return false; - } - - for (const element of this.node.elements) { - const child = element == null ? null : getResultOfExpression(this.ctx, element); - if (!child?.isFound || !isStringLiteral(child.node) || !closure(child.node)) { - return false; - } - } - - return true; - } - - asStringLiterals() { - if (!this.isFound) { - return []; - } - - const values: StringLiteral[] = []; - - if (isArrayExpression(this.node)) { - for (const arg of this.node.elements) { - const result = arg == null ? null : getResultOfExpression(this.ctx, arg); - if (result?.isFound && isStringLiteral(result.node)) { - values.push(result.node); - } - } - } else if (isStringLiteral(this.node)) { - values.push(this.node); - } - - return values; - } - - map(closure: (node: N) => V | null): V | null { - return !this.isFound ? null : closure(this.node as N); - } - - filter(closure: (node: N, ctx: Rule.RuleContext) => boolean): Result { - if (!this.isFound) { - return this; - } - return !closure(this.node as N, this.ctx) ? unknown(this.ctx, this.node) : this; - } -} - -function unknown(ctx: Rule.RuleContext, node: Node): Result { - return new Result(ctx, node, 'unknown'); -} - -function missing(ctx: Rule.RuleContext, node: Node): Result { - return new Result(ctx, node, 'missing'); -} - -function found(ctx: Rule.RuleContext, node: Node): Result { - return new Result(ctx, node, 'found'); -} - -export function getResultOfExpression(ctx: Rule.RuleContext, node: Node): Result { - const value = getUniqueWriteUsageOrNode(ctx, node, true); - return isUndefined(value) ? missing(ctx, value) : found(ctx, value); -} diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/rule-detect-react.ts b/eslint-bridge/src/linting/eslint/rules/helpers/rule-detect-react.ts deleted file mode 100644 index eb87d5e9b1f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/rule-detect-react.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; -import { Node } from 'estree'; - -const detectReactSelector = [ - ':matches(', - [ - 'CallExpression[callee.name="require"][arguments.0.value="react"]', - 'CallExpression[callee.name="require"][arguments.0.value="create-react-class"]', - 'ImportDeclaration[source.value="react"]', - ].join(','), - ')', -].join(''); - -export const rule: Rule.RuleModule = { - meta: { - messages: { - reactDetected: 'React detected', - }, - }, - create(context: Rule.RuleContext) { - return { - [detectReactSelector](node: Node) { - context.report({ - messageId: 'reactDetected', - node, - }); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/type.ts b/eslint-bridge/src/linting/eslint/rules/helpers/type.ts deleted file mode 100644 index a0e829185dd..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/helpers/type.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as estree from 'estree'; -import ts from 'typescript'; -import { TSESTree, TSESLint } from '@typescript-eslint/experimental-utils'; -import { RequiredParserServices } from 'eslint-plugin-sonarjs/lib/utils/parser-services'; - -export type RuleContext = TSESLint.RuleContext; - -export function isArray(node: estree.Node, services: RequiredParserServices) { - const type = getTypeFromTreeNode(node, services); - return type.symbol && type.symbol.name === 'Array'; -} - -export function isString(node: estree.Node, services: RequiredParserServices) { - const checker = services.program.getTypeChecker(); - const typ = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node as TSESTree.Node)); - return (typ.getFlags() & ts.TypeFlags.StringLike) !== 0; -} - -export function isNumber(node: estree.Node, services: RequiredParserServices) { - const checker = services.program.getTypeChecker(); - const typ = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node as TSESTree.Node)); - return (typ.getFlags() & ts.TypeFlags.NumberLike) !== 0; -} - -export function isBigIntType(type: ts.Type) { - return (type.getFlags() & ts.TypeFlags.BigIntLike) !== 0; -} - -export function isNumberType(type: ts.Type) { - return (type.getFlags() & ts.TypeFlags.NumberLike) !== 0; -} - -export function isStringType(type: ts.Type) { - return (type.flags & ts.TypeFlags.StringLike) > 0 || type.symbol?.name === 'String'; -} - -export function isFunction(node: estree.Node, services: RequiredParserServices) { - const checker = services.program.getTypeChecker(); - const type = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node as TSESTree.Node)); - return type.symbol && (type.symbol.flags & ts.SymbolFlags.Function) !== 0; -} - -export function isUndefinedOrNull(node: estree.Node, services: RequiredParserServices) { - const checker = services.program.getTypeChecker(); - const typ = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node as TSESTree.Node)); - return ( - (typ.getFlags() & ts.TypeFlags.Undefined) !== 0 || (typ.getFlags() & ts.TypeFlags.Null) !== 0 - ); -} - -export function isThenable(node: estree.Node, services: RequiredParserServices) { - const mapped = services.esTreeNodeToTSNodeMap.get(node as TSESTree.Node); - const tp = services.program.getTypeChecker().getTypeAtLocation(mapped); - const thenProperty = tp.getProperty('then'); - return Boolean(thenProperty && thenProperty.flags & ts.SymbolFlags.Method); -} - -export function isAny(type: ts.Type) { - return type.flags === ts.TypeFlags.Any; -} - -export function getTypeFromTreeNode(node: estree.Node, services: RequiredParserServices) { - const checker = services.program.getTypeChecker(); - return checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node as TSESTree.Node)); -} - -export function getTypeAsString(node: estree.Node, services: RequiredParserServices) { - const { typeToString, getBaseTypeOfLiteralType } = services.program.getTypeChecker(); - return typeToString(getBaseTypeOfLiteralType(getTypeFromTreeNode(node, services))); -} - -export function getSymbolAtLocation(node: estree.Node, services: RequiredParserServices) { - const checker = services.program.getTypeChecker(); - return checker.getSymbolAtLocation(services.esTreeNodeToTSNodeMap.get(node as TSESTree.Node)); -} - -export function getSignatureFromCallee(node: estree.Node, services: RequiredParserServices) { - const checker = services.program.getTypeChecker(); - return checker.getResolvedSignature( - services.esTreeNodeToTSNodeMap.get(node as TSESTree.Node) as ts.CallLikeExpression, - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/hidden-files.ts b/eslint-bridge/src/linting/eslint/rules/hidden-files.ts deleted file mode 100644 index 9197011354f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/hidden-files.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5691/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getUniqueWriteUsage, getObjectExpressionProperty, getFullyQualifiedName } from './helpers'; - -const SERVE_STATIC = 'serve-static'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - safeHiddenFile: 'Make sure serving hidden files is safe here.', - }, - }, - create(context: Rule.RuleContext) { - return { - CallExpression(node: estree.Node) { - // serveStatic(...) - const { callee, arguments: args } = node as estree.CallExpression; - if (getFullyQualifiedName(context, callee) === SERVE_STATIC && args.length > 1) { - let options: estree.Node | undefined = args[1]; - if (options.type === 'Identifier') { - options = getUniqueWriteUsage(context, options.name); - } - - const dotfilesProperty = getObjectExpressionProperty(options, 'dotfiles'); - if ( - dotfilesProperty?.value.type === 'Literal' && - dotfilesProperty.value.value === 'allow' - ) { - context.report({ node: dotfilesProperty, messageId: 'safeHiddenFile' }); - } - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/in-operator-type-error.ts b/eslint-bridge/src/linting/eslint/rules/in-operator-type-error.ts deleted file mode 100644 index fe85aa3c9af..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/in-operator-type-error.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3785/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import * as ts from 'typescript'; -import { isRequiredParserServices, getTypeFromTreeNode, toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - function isPrimitive(node: estree.Node) { - const type = getTypeFromTreeNode(node, services); - return ( - (type.flags & ts.TypeFlags.StringLike) !== 0 || - (type.flags & ts.TypeFlags.NumberLike) !== 0 || - (type.flags & ts.TypeFlags.BooleanLike) !== 0 || - (type.flags & ts.TypeFlags.Null) !== 0 || - (type.flags & ts.TypeFlags.Undefined) !== 0 - ); - } - return { - 'BinaryExpression[operator="in"]': (node: estree.Node) => { - const { left, right, operator } = node as estree.BinaryExpression; - if (isPrimitive(right)) { - const opToken = context - .getSourceCode() - .getTokensBetween(left, right) - .find(token => token.type === 'Keyword' && token.value === operator)!; - context.report({ - message: toEncodedMessage( - 'TypeError can be thrown as this operand might have primitive type.', - [opToken], - ), - node: right, - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/inconsistent-function-call.ts b/eslint-bridge/src/linting/eslint/rules/inconsistent-function-call.ts deleted file mode 100644 index 6d840687cec..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/inconsistent-function-call.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3686/javascript - -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { getVariableFromName, toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - - create(context: Rule.RuleContext) { - const usedInNew: Map = new Map(); - const usedInCall: Map = new Map(); - const hasIssue: Scope.Variable[] = []; - - return { - NewExpression: (node: estree.Node) => { - checkExpression( - node as estree.SimpleCallExpression, - usedInNew, - usedInCall, - hasIssue, - 'out', - context, - ); - }, - CallExpression: (node: estree.Node) => { - checkExpression( - node as estree.SimpleCallExpression, - usedInCall, - usedInNew, - hasIssue, - '', - context, - ); - }, - }; - }, -}; - -function checkExpression( - callExpression: estree.SimpleCallExpression, - thisTypeUsageMap: Map, - otherTypeUsageMap: Map, - hasIssue: Scope.Variable[], - tail: string, - context: Rule.RuleContext, -) { - const variable = getVariable(callExpression, context); - if (variable && variable.defs.length !== 0) { - const otherTypeUsage = otherTypeUsageMap.get(variable); - if (otherTypeUsage && otherTypeUsage.loc && !hasIssue.includes(variable)) { - const message = - `Correct the use of this function; ` + - `on line ${otherTypeUsage.loc.start.line} it was called with${tail} "new".`; - - context.report({ - node: callExpression.callee, - message: toEncodedMessage(message, [otherTypeUsage.callee as TSESTree.Node]), - }); - - hasIssue.push(variable); - } else { - thisTypeUsageMap.set(variable, callExpression); - } - } -} - -function getVariable(node: estree.SimpleCallExpression, context: Rule.RuleContext) { - if (node.callee.type === 'Identifier') { - return getVariableFromName(context, node.callee.name); - } - return undefined; -} diff --git a/eslint-bridge/src/linting/eslint/rules/index-of-compare-to-positive-number.ts b/eslint-bridge/src/linting/eslint/rules/index-of-compare-to-positive-number.ts deleted file mode 100644 index 3ad8a6c729b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/index-of-compare-to-positive-number.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2692/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isArray, isRequiredParserServices, RequiredParserServices } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - considerIncludes: - "This check ignores index 0; consider using 'includes' method to make this check safe and explicit.", - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - return { - BinaryExpression(node: estree.Node) { - const expression = node as estree.BinaryExpression; - if ( - expression.operator === '>' && - isZero(expression.right) && - isArrayIndexOfCall(expression.left, services) - ) { - context.report({ node, messageId: 'considerIncludes' }); - } - }, - }; - }, -}; - -function isZero(node: estree.Expression): boolean { - return node.type === 'Literal' && node.value === 0; -} - -function isArrayIndexOfCall(node: estree.Expression, services: RequiredParserServices): boolean { - return ( - node.type === 'CallExpression' && - node.arguments.length === 1 && - node.callee.type === 'MemberExpression' && - node.callee.property.type === 'Identifier' && - node.callee.property.name === 'indexOf' && - isArray(node.callee.object, services) - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/index.ts b/eslint-bridge/src/linting/eslint/rules/index.ts deleted file mode 100644 index 3b6f413614d..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/index.ts +++ /dev/null @@ -1,476 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { Rule } from 'eslint'; - -import { rule as anchorPrecedence } from './anchor-precedence'; -import { rule as argumentType } from './argument-type'; -import { rule as argumentsOrder } from './arguments-order'; -import { rule as argumentsUsage } from './arguments-usage'; -import { rule as arrayCallBackWithoutReturn } from './array-callback-without-return'; -import { rule as arrayConstructor } from './array-constructor'; -import { rule as arrowFunctionConvention } from './arrow-function-convention'; -import { rule as assertionsInTests } from './assertions-in-tests'; -import { rule as awsApigatewayPublicApi } from './aws-apigateway-public-api'; -import { rule as awsEc2RdsDmsPublic } from './aws-ec2-rds-dms-public'; -import { rule as awsEc2UnencryptedEbsVolume } from './aws-ec2-unencrypted-ebs-volume'; -import { rule as awsEfsUnencrypted } from './aws-efs-unencrypted'; -import { rule as awsIamAllPrivileges } from './aws-iam-all-privileges'; -import { rule as awsIamAllResourcesAccessible } from './aws-iam-all-resources-accessible'; -import { rule as awsIamPrivilegeEscalation } from './aws-iam-privilege-escalation'; -import { rule as awsIamPublicAccess } from './aws-iam-public-access'; -import { rule as awsOpensearchserviceDomain } from './aws-opensearchservice-domain'; -import { rule as awsRdsUnencryptedDatabases } from './aws-rds-unencrypted-databases'; -import { rule as awsRestrictedIpAdminAccess } from './aws-restricted-ip-admin-access'; -import { rule as awsS3BucketGrantedAccess } from './aws-s3-bucket-granted-access'; -import { rule as awsS3BucketInsecureHttp } from './aws-s3-bucket-insecure-http'; -import { rule as awsS3BucketPublicAccess } from './aws-s3-bucket-public-access'; -import { rule as awsS3BucketServerEncryption } from './aws-s3-bucket-server-encryption'; -import { rule as awsS3BucketVersioning } from './aws-s3-bucket-versioning'; -import { rule as awsSagemakerUnencryptedNotebook } from './aws-sagemaker-unencrypted-notebook'; -import { rule as awsSnsUnencryptedTopics } from './aws-sns-unencrypted-topics'; -import { rule as awsSqsUnencryptedQueue } from './aws-sqs-unencrypted-queue'; -import { rule as bitwiseOperators } from './bitwise-operators'; -import { rule as boolParamDefault } from './bool-param-default'; -import { rule as callArgumentLine } from './call-argument-line'; -import { rule as certificateTransparency } from './certificate-transparency'; -import { rule as chaiDeterminateAssertion } from './chai-determinate-assertion'; -import { rule as className } from './class-name'; -import { rule as classPrototype } from './class-prototype'; -import { rule as codeEval } from './code-eval'; -import { rule as commaOrLogicalOrCase } from './comma-or-logical-or-case'; -import { rule as commentRegex } from './comment-regex'; -import { rule as conciseRegex } from './concise-regex'; -import { rule as conditionalIndentation } from './conditional-indentation'; -import { rule as confidentialInformationLogging } from './confidential-information-logging'; -import { rule as constructorForSideEffects } from './constructor-for-side-effects'; -import { rule as contentLength } from './content-length'; -import { rule as contentSecurityPolicy } from './content-security-policy'; -import { rule as cookieNoHttpOnly } from './cookie-no-httponly'; -import { rule as cookies } from './cookies'; -import { rule as cors } from './cors'; -import { rule as csrf } from './csrf'; -import { rule as cyclomaticComplexity } from './cyclomatic-complexity'; -import { rule as declarationsInGlobalScope } from './declarations-in-global-scope'; -import { rule as deprecation } from './deprecation'; -import { rule as destructuringAssignmentSyntax } from './destructuring-assignment-syntax'; -import { rule as differentTypesComparison } from './different-types-comparison'; -import { rule as disabledAutoEscaping } from './disabled-auto-escaping'; -import { rule as disabledResourceIntegrity } from './disabled-resource-integrity'; -import { rule as disabledTimeout } from './disabled-timeout'; -import { rule as dnsPrefetching } from './dns-prefetching'; -import { rule as duplicatesInCharacterClass } from './duplicates-in-character-class'; -import { rule as emptyStringRepetition } from './empty-string-repetition'; -import { rule as encryption } from './encryption'; -import { rule as encryptionSecureMode } from './encryption-secure-mode'; -import { rule as existingGroups } from './existing-groups'; -import { rule as expressionComplexity } from './expression-complexity'; -import { rule as fileHeader } from './file-header'; -import { rule as fileNameDifferFromClass } from './file-name-differ-from-class'; -import { rule as filePermissions } from './file-permissions'; -import { rule as fileUploads } from './file-uploads'; -import { rule as fixmeTag } from './fixme-tag'; -import { rule as forIn } from './for-in'; -import { rule as forLoopIncrementSign } from './for-loop-increment-sign'; -import { rule as frameAncestors } from './frame-ancestors'; -import { rule as functionInsideLoop } from './function-inside-loop'; -import { rule as functionName } from './function-name'; -import { rule as functionReturnType } from './function-return-type'; -import { rule as futureReservedWords } from './future-reserved-words'; -import { rule as generatorWithoutYield } from './generator-without-yield'; -import { rule as hashing } from './hashing'; -import { rule as hiddenFiles } from './hidden-files'; -import { rule as inOperatorTypeError } from './in-operator-type-error'; -import { rule as inconsistentFunctionCall } from './inconsistent-function-call'; -import { rule as indexOfCompareToPositiveNumber } from './index-of-compare-to-positive-number'; -import { rule as insecureCookie } from './insecure-cookie'; -import { rule as insecureJwtToken } from './insecure-jwt-token'; -import { rule as invertedAssertionArguments } from './inverted-assertion-arguments'; -import { rule as labelPosition } from './label-position'; -import { rule as linkWithTargetBlank } from './link-with-target-blank'; -import { rule as maxUnionSize } from './max-union-size'; -import { rule as misplacedLoopCounter } from './misplaced-loop-counter'; -import { rule as nestedControlFlow } from './nested-control-flow'; -import { rule as newOperatorMisuse } from './new-operator-misuse'; -import { rule as noAccessorFieldMismatch } from './no-accessor-field-mismatch'; -import { rule as noAlphabeticalSort } from './no-alphabetical-sort'; -import { rule as noAngularBypassSanitization } from './no-angular-bypass-sanitization'; -import { rule as noArrayDelete } from './no-array-delete'; -import { rule as noAssociativeArrays } from './no-associative-arrays'; -import { rule as noBuiltInOverride } from './no-built-in-override'; -import { rule as noCaseLabelInSwitch } from './no-case-label-in-switch'; -import { rule as noClearTextProtocols } from './no-clear-text-protocols'; -import { rule as noCodeAfterDone } from './no-code-after-done'; -import { rule as noCommentedCode } from './no-commented-code'; -import { rule as noDeadStore } from './no-dead-store'; -import { rule as noDeleteVar } from './no-delete-var'; -import { rule as noDuplicateInComposite } from './no-duplicate-in-composite'; -import { rule as noEmptyAfterReluctant } from './no-empty-after-reluctant'; -import { rule as noEmptyAlternatives } from './no-empty-alternatives'; -import { rule as noEmptyGroup } from './no-empty-group'; -import { rule as noEqualsInForTermination } from './no-equals-in-for-termination'; -import { rule as noExclusiveTests } from './no-exclusive-tests'; -import { rule as noForInIterable } from './no-for-in-iterable'; -import { rule as noFunctionDeclarationInBlock } from './no-function-declaration-in-block'; -import { rule as noGlobalThis } from './no-global-this'; -import { rule as noGlobalsShadowing } from './no-globals-shadowing'; -import { rule as noHardcodedCredentials } from './no-hardcoded-credentials'; -import { rule as noHardcodedIp } from './no-hardcoded-ip'; -import { rule as noHookSetterInBody } from './no-hook-setter-in-body'; -import { rule as noImplicitDependencies } from './no-implicit-dependencies'; -import { rule as noImplicitGlobal } from './no-implicit-global'; -import { rule as noInMisuse } from './no-in-misuse'; -import { rule as noIncompleteAssertions } from './no-incomplete-assertions'; -import { rule as noInconsistentReturns } from './no-inconsistent-returns'; -import { rule as noIncorrectStringConcat } from './no-incorrect-string-concat'; -import { rule as noInfiniteLoop } from './no-infinite-loop'; -import { rule as noIntrusivePermissions } from './no-intrusive-permissions'; -import { rule as noInvalidAwait } from './no-invalid-await'; -import { rule as noInvariantReturns } from './no-invariant-returns'; -import { rule as noIpForward } from './no-ip-forward'; -import { rule as noLabels } from './no-labels'; -import { rule as noMimeSniff } from './no-mime-sniff'; -import { rule as noMisleadingArrayReverse } from './no-misleading-array-reverse'; -import { rule as noMixedContent } from './no-mixed-content'; -import { rule as noNestedAssignment } from './no-nested-assignment'; -import { rule as noNestedConditional } from './no-nested-conditional'; -import { rule as noNestedIncDec } from './no-nested-incdec'; -import { rule as noNewSymbol } from './no-new-symbol'; -import { rule as noOsCommandFromPath } from './no-os-command-from-path'; -import { rule as noParameterReassignment } from './no-parameter-reassignment'; -import { rule as noPrimitiveWrappers } from './no-primitive-wrappers'; -import { rule as noRedundantAssignments } from './no-redundant-assignments'; -import { rule as noRedundantOptional } from './no-redundant-optional'; -import { rule as noRedundantParentheses } from './no-redundant-parentheses'; -import { rule as noReferenceError } from './no-reference-error'; -import { rule as noReferrerPolicy } from './no-referrer-policy'; -import { rule as noRequireOrDefine } from './no-require-or-define'; -import { rule as noReturnTypeAny } from './no-return-type-any'; -import { rule as noSameArgumentAssert } from './no-same-argument-assert'; -import { rule as noTab } from './no-tab'; -import { rule as noTryPromise } from './no-try-promise'; -import { rule as noUndefinedArgument } from './no-undefined-argument'; -import { rule as noUndefinedAssignment } from './no-undefined-assignment'; -import { rule as noUnenclosedMultilineBlock } from './no-unenclosed-multiline-block'; -import { rule as noUniqKey } from './no-uniq-key'; -import { rule as noUnsafeUnzip } from './no-unsafe-unzip'; -import { rule as noUnthrownError } from './no-unthrown-error'; -import { rule as noUnusedFunctionArgument } from './no-unused-function-argument'; -import { rule as noUselessIncrement } from './no-useless-increment'; -import { rule as noUselessIntersection } from './no-useless-intersection'; -import { rule as noUselessReactSetstate } from './no-useless-react-setstate'; -import { rule as noVariableUsageBeforeDeclaration } from './no-variable-usage-before-declaration'; -import { rule as noVueBypassSanitization } from './no-vue-bypass-sanitization'; -import { rule as noWeakCipher } from './no-weak-cipher'; -import { rule as noWeakKeys } from './no-weak-keys'; -import { rule as noWildcardImport } from './no-wildcard-import'; -import { rule as nonNumberInArithmeticExpression } from './non-number-in-arithmetic-expression'; -import { rule as nullDereference } from './null-dereference'; -import { rule as operationReturningNan } from './operation-returning-nan'; -import { rule as osCommand } from './os-command'; -import { rule as postMessage } from './post-message'; -import { rule as preferDefaultLast } from './prefer-default-last'; -import { rule as preferPromiseShorthand } from './prefer-promise-shorthand'; -import { rule as preferTypeGuard } from './prefer-type-guard'; -import { rule as processArgv } from './process-argv'; -import { rule as productionDebug } from './production-debug'; -import { rule as pseudoRandom } from './pseudo-random'; -import { rule as publiclyWrittableDirectories } from './publicly-writable-directories'; -import { rule as regexComplexity } from './regex-complexity'; -import { rule as regularExpr } from './regular-expr'; -import { rule as rulesOfHooks } from './rules-of-hooks'; -import { rule as sessionRegeneration } from './session-regeneration'; -import { rule as shorthandPropertyGrouping } from './shorthand-property-grouping'; -import { rule as singleCharInCharacterClasses } from './single-char-in-character-classes'; -import { rule as singleCharacterAlternative } from './single-character-alternation'; -import { rule as slowRegex } from './slow-regex'; -import { rule as sockets } from './sockets'; -import { rule as sonarBlockScopedVar } from './sonar-block-scoped-var'; -import { rule as sonarJsxNoLeakedRender } from './sonar-jsx-no-leaked-render'; -import { rule as sonarMaxLines } from './sonar-max-lines'; -import { rule as sonarMaxLinesPerFunction } from './sonar-max-lines-per-function'; -import { rule as sonarMaxParams } from './sonar-max-params'; -import { rule as sonarNoControlRegex } from './sonar-no-control-regex'; -import { rule as sonarNoDupeKeys } from './sonar-no-dupe-keys'; -import { rule as sonarNoFallthrough } from './sonar-no-fallthrough'; -import { rule as sonarNoInvalidRegexp } from './sonar-no-invalid-regexp'; -import { rule as sonarNoMisleadingCharacterClass } from './sonar-no-misleading-character-class'; -import { rule as sonarNoRegexSpaces } from './sonar-no-regex-spaces'; -import { rule as sonarNoUnusedClassComponentMethods } from './sonar-no-unused-class-component-methods'; -import { rule as sonarNoUnusedVars } from './sonar-no-unused-vars'; -import { rule as sqlQueries } from './sql-queries'; -import { rule as standardInput } from './standard-input'; -import { rule as statefulRegex } from './stateful-regex'; -import { rule as strictTransportSecurity } from './strict-transport-security'; -import { rule as stringsComparison } from './strings-comparison'; -import { rule as superInvocation } from './super-invocation'; -import { rule as switchWithoutDefault } from './switch-without-default'; -import { rule as testCheckException } from './test-check-exception'; -import { rule as todoTag } from './todo-tag'; -import { rule as tooManyBreakOrContinueInLoop } from './too-many-break-or-continue-in-loop'; -import { rule as unicodeAwareRegex } from './unicode-aware-regex'; -import { rule as unusedImport } from './unused-import'; -import { rule as unusedNamedGroups } from './unused-named-groups'; -import { rule as unverifiedCertificate } from './unverified-certificate'; -import { rule as unverifiedHostname } from './unverified-hostname'; -import { rule as updatedConstVar } from './updated-const-var'; -import { rule as updatedLoopCounter } from './updated-loop-counter'; -import { rule as useTypeAlias } from './use-type-alias'; -import { rule as uselessStringOperation } from './useless-string-operation'; -import { rule as valuesNotConvertibleToNumbers } from './values-not-convertible-to-numbers'; -import { rule as variableName } from './variable-name'; -import { rule as voidUse } from './void-use'; -import { rule as weakSsl } from './weak-ssl'; -import { rule as webSqlDatabase } from './web-sql-database'; -import { rule as xPoweredBy } from './x-powered-by'; -import { rule as xmlParserXXE } from './xml-parser-xxe'; -import { rule as xpath } from './xpath'; - -/** - * The set of internal ESLint-based rules - */ -const rules: { [key: string]: Rule.RuleModule } = {}; - -/** - * Maps ESLint rule keys declared in the JavaScript checks to rule implementations - */ -rules['anchor-precedence'] = anchorPrecedence; -rules['argument-type'] = argumentType; -rules['arguments-order'] = argumentsOrder; -rules['arguments-usage'] = argumentsUsage; -rules['array-callback-without-return'] = arrayCallBackWithoutReturn; -rules['array-constructor'] = arrayConstructor; -rules['arrow-function-convention'] = arrowFunctionConvention; -rules['assertions-in-tests'] = assertionsInTests; -rules['aws-apigateway-public-api'] = awsApigatewayPublicApi; -rules['aws-ec2-rds-dms-public'] = awsEc2RdsDmsPublic; -rules['aws-ec2-unencrypted-ebs-volume'] = awsEc2UnencryptedEbsVolume; -rules['aws-efs-unencrypted'] = awsEfsUnencrypted; -rules['aws-iam-all-privileges'] = awsIamAllPrivileges; -rules['aws-iam-all-resources-accessible'] = awsIamAllResourcesAccessible; -rules['aws-iam-privilege-escalation'] = awsIamPrivilegeEscalation; -rules['aws-iam-public-access'] = awsIamPublicAccess; -rules['aws-opensearchservice-domain'] = awsOpensearchserviceDomain; -rules['aws-rds-unencrypted-databases'] = awsRdsUnencryptedDatabases; -rules['aws-restricted-ip-admin-access'] = awsRestrictedIpAdminAccess; -rules['aws-s3-bucket-granted-access'] = awsS3BucketGrantedAccess; -rules['aws-s3-bucket-insecure-http'] = awsS3BucketInsecureHttp; -rules['aws-s3-bucket-public-access'] = awsS3BucketPublicAccess; -rules['aws-s3-bucket-server-encryption'] = awsS3BucketServerEncryption; -rules['aws-s3-bucket-versioning'] = awsS3BucketVersioning; -rules['aws-sagemaker-unencrypted-notebook'] = awsSagemakerUnencryptedNotebook; -rules['aws-sns-unencrypted-topics'] = awsSnsUnencryptedTopics; -rules['aws-sqs-unencrypted-queue'] = awsSqsUnencryptedQueue; -rules['bitwise-operators'] = bitwiseOperators; -rules['bool-param-default'] = boolParamDefault; -rules['call-argument-line'] = callArgumentLine; -rules['certificate-transparency'] = certificateTransparency; -rules['chai-determinate-assertion'] = chaiDeterminateAssertion; -rules['class-name'] = className; -rules['class-prototype'] = classPrototype; -rules['code-eval'] = codeEval; -rules['comma-or-logical-or-case'] = commaOrLogicalOrCase; -rules['comment-regex'] = commentRegex; -rules['concise-regex'] = conciseRegex; -rules['conditional-indentation'] = conditionalIndentation; -rules['confidential-information-logging'] = confidentialInformationLogging; -rules['constructor-for-side-effects'] = constructorForSideEffects; -rules['content-length'] = contentLength; -rules['content-security-policy'] = contentSecurityPolicy; -rules['cookie-no-httponly'] = cookieNoHttpOnly; -rules['cookies'] = cookies; -rules['cors'] = cors; -rules['csrf'] = csrf; -rules['cyclomatic-complexity'] = cyclomaticComplexity; -rules['declarations-in-global-scope'] = declarationsInGlobalScope; -rules['deprecation'] = deprecation; -rules['destructuring-assignment-syntax'] = destructuringAssignmentSyntax; -rules['different-types-comparison'] = differentTypesComparison; -rules['disabled-auto-escaping'] = disabledAutoEscaping; -rules['disabled-resource-integrity'] = disabledResourceIntegrity; -rules['disabled-timeout'] = disabledTimeout; -rules['dns-prefetching'] = dnsPrefetching; -rules['duplicates-in-character-class'] = duplicatesInCharacterClass; -rules['empty-string-repetition'] = emptyStringRepetition; -rules['encryption'] = encryption; -rules['encryption-secure-mode'] = encryptionSecureMode; -rules['existing-groups'] = existingGroups; -rules['expression-complexity'] = expressionComplexity; -rules['file-header'] = fileHeader; -rules['file-name-differ-from-class'] = fileNameDifferFromClass; -rules['file-permissions'] = filePermissions; -rules['file-uploads'] = fileUploads; -rules['fixme-tag'] = fixmeTag; -rules['for-in'] = forIn; -rules['for-loop-increment-sign'] = forLoopIncrementSign; -rules['frame-ancestors'] = frameAncestors; -rules['function-inside-loop'] = functionInsideLoop; -rules['function-name'] = functionName; -rules['function-return-type'] = functionReturnType; -rules['future-reserved-words'] = futureReservedWords; -rules['generator-without-yield'] = generatorWithoutYield; -rules['hashing'] = hashing; -rules['hidden-files'] = hiddenFiles; -rules['in-operator-type-error'] = inOperatorTypeError; -rules['inconsistent-function-call'] = inconsistentFunctionCall; -rules['index-of-compare-to-positive-number'] = indexOfCompareToPositiveNumber; -rules['insecure-cookie'] = insecureCookie; -rules['insecure-jwt-token'] = insecureJwtToken; -rules['inverted-assertion-arguments'] = invertedAssertionArguments; -rules['label-position'] = labelPosition; -rules['link-with-target-blank'] = linkWithTargetBlank; -rules['max-union-size'] = maxUnionSize; -rules['misplaced-loop-counter'] = misplacedLoopCounter; -rules['nested-control-flow'] = nestedControlFlow; -rules['new-operator-misuse'] = newOperatorMisuse; -rules['no-accessor-field-mismatch'] = noAccessorFieldMismatch; -rules['no-alphabetical-sort'] = noAlphabeticalSort; -rules['no-angular-bypass-sanitization'] = noAngularBypassSanitization; -rules['no-array-delete'] = noArrayDelete; -rules['no-associative-arrays'] = noAssociativeArrays; -rules['no-built-in-override'] = noBuiltInOverride; -rules['no-case-label-in-switch'] = noCaseLabelInSwitch; -rules['no-clear-text-protocols'] = noClearTextProtocols; -rules['no-code-after-done'] = noCodeAfterDone; -rules['no-commented-code'] = noCommentedCode; -rules['no-dead-store'] = noDeadStore; -rules['no-delete-var'] = noDeleteVar; -rules['no-duplicate-in-composite'] = noDuplicateInComposite; -rules['no-empty-after-reluctant'] = noEmptyAfterReluctant; -rules['no-empty-alternatives'] = noEmptyAlternatives; -rules['no-empty-group'] = noEmptyGroup; -rules['no-equals-in-for-termination'] = noEqualsInForTermination; -rules['no-exclusive-tests'] = noExclusiveTests; -rules['no-for-in-iterable'] = noForInIterable; -rules['no-function-declaration-in-block'] = noFunctionDeclarationInBlock; -rules['no-global-this'] = noGlobalThis; -rules['no-globals-shadowing'] = noGlobalsShadowing; -rules['no-hardcoded-credentials'] = noHardcodedCredentials; -rules['no-hardcoded-ip'] = noHardcodedIp; -rules['no-hook-setter-in-body'] = noHookSetterInBody; -rules['no-implicit-dependencies'] = noImplicitDependencies; -rules['no-implicit-global'] = noImplicitGlobal; -rules['no-in-misuse'] = noInMisuse; -rules['no-incomplete-assertions'] = noIncompleteAssertions; -rules['no-inconsistent-returns'] = noInconsistentReturns; -rules['no-incorrect-string-concat'] = noIncorrectStringConcat; -rules['no-infinite-loop'] = noInfiniteLoop; -rules['no-intrusive-permissions'] = noIntrusivePermissions; -rules['no-invalid-await'] = noInvalidAwait; -rules['no-invariant-returns'] = noInvariantReturns; -rules['no-ip-forward'] = noIpForward; -rules['no-labels'] = noLabels; -rules['no-mime-sniff'] = noMimeSniff; -rules['no-misleading-array-reverse'] = noMisleadingArrayReverse; -rules['no-mixed-content'] = noMixedContent; -rules['no-nested-assignment'] = noNestedAssignment; -rules['no-nested-conditional'] = noNestedConditional; -rules['no-nested-incdec'] = noNestedIncDec; -rules['no-new-symbol'] = noNewSymbol; -rules['no-os-command-from-path'] = noOsCommandFromPath; -rules['no-parameter-reassignment'] = noParameterReassignment; -rules['no-primitive-wrappers'] = noPrimitiveWrappers; -rules['no-redundant-assignments'] = noRedundantAssignments; -rules['no-redundant-optional'] = noRedundantOptional; -rules['no-redundant-parentheses'] = noRedundantParentheses; -rules['no-reference-error'] = noReferenceError; -rules['no-referrer-policy'] = noReferrerPolicy; -rules['no-require-or-define'] = noRequireOrDefine; -rules['no-return-type-any'] = noReturnTypeAny; -rules['no-same-argument-assert'] = noSameArgumentAssert; -rules['no-tab'] = noTab; -rules['no-try-promise'] = noTryPromise; -rules['no-undefined-argument'] = noUndefinedArgument; -rules['no-undefined-assignment'] = noUndefinedAssignment; -rules['no-unenclosed-multiline-block'] = noUnenclosedMultilineBlock; -rules['no-uniq-key'] = noUniqKey; -rules['no-unsafe-unzip'] = noUnsafeUnzip; -rules['no-unthrown-error'] = noUnthrownError; -rules['no-unused-function-argument'] = noUnusedFunctionArgument; -rules['no-useless-increment'] = noUselessIncrement; -rules['no-useless-intersection'] = noUselessIntersection; -rules['no-useless-react-setstate'] = noUselessReactSetstate; -rules['no-variable-usage-before-declaration'] = noVariableUsageBeforeDeclaration; -rules['no-vue-bypass-sanitization'] = noVueBypassSanitization; -rules['no-weak-cipher'] = noWeakCipher; -rules['no-weak-keys'] = noWeakKeys; -rules['no-wildcard-import'] = noWildcardImport; -rules['non-number-in-arithmetic-expression'] = nonNumberInArithmeticExpression; -rules['null-dereference'] = nullDereference; -rules['operation-returning-nan'] = operationReturningNan; -rules['os-command'] = osCommand; -rules['post-message'] = postMessage; -rules['prefer-default-last'] = preferDefaultLast; -rules['prefer-promise-shorthand'] = preferPromiseShorthand; -rules['prefer-type-guard'] = preferTypeGuard; -rules['process-argv'] = processArgv; -rules['production-debug'] = productionDebug; -rules['pseudo-random'] = pseudoRandom; -rules['publicly-writable-directories'] = publiclyWrittableDirectories; -rules['regex-complexity'] = regexComplexity; -rules['regular-expr'] = regularExpr; -rules['rules-of-hooks'] = rulesOfHooks; -rules['session-regeneration'] = sessionRegeneration; -rules['shorthand-property-grouping'] = shorthandPropertyGrouping; -rules['single-char-in-character-classes'] = singleCharInCharacterClasses; -rules['single-character-alternation'] = singleCharacterAlternative; -rules['slow-regex'] = slowRegex; -rules['sockets'] = sockets; -rules['sonar-block-scoped-var'] = sonarBlockScopedVar; -rules['sonar-jsx-no-leaked-render'] = sonarJsxNoLeakedRender; -rules['sonar-max-lines'] = sonarMaxLines; -rules['sonar-max-lines-per-function'] = sonarMaxLinesPerFunction; -rules['sonar-max-params'] = sonarMaxParams; -rules['sonar-no-control-regex'] = sonarNoControlRegex; -rules['sonar-no-dupe-keys'] = sonarNoDupeKeys; -rules['sonar-no-fallthrough'] = sonarNoFallthrough; -rules['sonar-no-invalid-regexp'] = sonarNoInvalidRegexp; -rules['sonar-no-misleading-character-class'] = sonarNoMisleadingCharacterClass; -rules['sonar-no-regex-spaces'] = sonarNoRegexSpaces; -rules['sonar-no-unused-class-component-methods'] = sonarNoUnusedClassComponentMethods; -rules['sonar-no-unused-vars'] = sonarNoUnusedVars; -rules['sql-queries'] = sqlQueries; -rules['standard-input'] = standardInput; -rules['stateful-regex'] = statefulRegex; -rules['strict-transport-security'] = strictTransportSecurity; -rules['strings-comparison'] = stringsComparison; -rules['super-invocation'] = superInvocation; -rules['switch-without-default'] = switchWithoutDefault; -rules['test-check-exception'] = testCheckException; -rules['todo-tag'] = todoTag; -rules['too-many-break-or-continue-in-loop'] = tooManyBreakOrContinueInLoop; -rules['unicode-aware-regex'] = unicodeAwareRegex; -rules['unused-import'] = unusedImport; -rules['unused-named-groups'] = unusedNamedGroups; -rules['unverified-certificate'] = unverifiedCertificate; -rules['unverified-hostname'] = unverifiedHostname; -rules['updated-const-var'] = updatedConstVar; -rules['updated-loop-counter'] = updatedLoopCounter; -rules['use-type-alias'] = useTypeAlias; -rules['useless-string-operation'] = uselessStringOperation; -rules['values-not-convertible-to-numbers'] = valuesNotConvertibleToNumbers; -rules['variable-name'] = variableName; -rules['void-use'] = voidUse; -rules['weak-ssl'] = weakSsl; -rules['web-sql-database'] = webSqlDatabase; -rules['x-powered-by'] = xPoweredBy; -rules['xml-parser-xxe'] = xmlParserXXE; -rules['xpath'] = xpath; - -export { rules }; diff --git a/eslint-bridge/src/linting/eslint/rules/insecure-cookie.ts b/eslint-bridge/src/linting/eslint/rules/insecure-cookie.ts deleted file mode 100644 index e34e26201b2..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/insecure-cookie.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2092/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { CookieFlagCheck } from './cookie-flag-check'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - return { - CallExpression: (node: estree.Node) => - new CookieFlagCheck(context, 'secure').checkCookiesFromCallExpression(node), - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/insecure-jwt-token.ts b/eslint-bridge/src/linting/eslint/rules/insecure-jwt-token.ts deleted file mode 100644 index afaf5b80d96..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/insecure-jwt-token.ts +++ /dev/null @@ -1,149 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5659/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - getPropertyWithValue, - getValueOfExpression, - getObjectExpressionProperty, - toEncodedMessage, - isNullLiteral, - getFullyQualifiedName, -} from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - const SIGN_MESSAGE = 'Use only strong cipher algorithms when signing this JWT.'; - const VERIFY_MESSAGE = - 'Use only strong cipher algorithms when verifying the signature of this JWT.'; - const SECONDARY_MESSAGE = `The "algorithms" option should be defined and should not contain 'none'.`; - - function checkCallToSign( - callExpression: estree.CallExpression, - thirdArgumentValue: estree.ObjectExpression, - secondaryLocations: estree.Node[], - ) { - const unsafeAlgorithmProperty = getPropertyWithValue( - context, - thirdArgumentValue, - 'algorithm', - 'none', - ); - if (unsafeAlgorithmProperty) { - const unsafeAlgorithmValue = getValueOfExpression( - context, - unsafeAlgorithmProperty.value, - 'Literal', - ); - if (unsafeAlgorithmValue && unsafeAlgorithmValue !== unsafeAlgorithmProperty.value) { - secondaryLocations.push(unsafeAlgorithmValue); - } - raiseIssueOn(callExpression.callee, SIGN_MESSAGE, secondaryLocations); - } - } - - function checkCallToVerify( - callExpression: estree.CallExpression, - publicKey: estree.Node, - thirdArgumentValue: estree.ObjectExpression, - secondaryLocations: estree.Node[], - ) { - const algorithmsProperty = getObjectExpressionProperty(thirdArgumentValue, 'algorithms'); - if (!algorithmsProperty) { - if (isNullLiteral(publicKey)) { - raiseIssueOn(callExpression.callee, VERIFY_MESSAGE, secondaryLocations); - } - return; - } - const algorithmsValue = getValueOfExpression( - context, - algorithmsProperty.value, - 'ArrayExpression', - ); - if (!algorithmsValue) { - return; - } - const algorithmsContainNone = algorithmsValue.elements.some(e => { - const value = getValueOfExpression(context, e, 'Literal'); - return value?.value === 'none'; - }); - if (algorithmsContainNone) { - if (algorithmsProperty.value !== algorithmsValue) { - secondaryLocations.push(algorithmsValue); - } - raiseIssueOn(callExpression.callee, VERIFY_MESSAGE, secondaryLocations); - } - } - - function raiseIssueOn(node: estree.Node, message: string, secondaryLocations: estree.Node[]) { - context.report({ - node, - message: toEncodedMessage( - message, - secondaryLocations, - Array(secondaryLocations.length).fill(SECONDARY_MESSAGE), - ), - }); - } - - return { - CallExpression: (node: estree.Node) => { - const callExpression: estree.CallExpression = node as estree.CallExpression; - const fqn = getFullyQualifiedName(context, callExpression); - const isCallToSign = fqn === 'jsonwebtoken.sign'; - const isCallToVerify = fqn === 'jsonwebtoken.verify'; - if (!isCallToSign && !isCallToVerify) { - return; - } - if (callExpression.arguments.length < 3) { - // algorithm(s) property is contained in third argument of "sign" and "verify" calls - return; - } - const thirdArgument = callExpression.arguments[2]; - const thirdArgumentValue = getValueOfExpression(context, thirdArgument, 'ObjectExpression'); - if (!thirdArgumentValue) { - return; - } - const secondaryLocations: estree.Node[] = [thirdArgumentValue]; - if (thirdArgumentValue !== thirdArgument) { - secondaryLocations.push(thirdArgument); - } - if (isCallToSign) { - checkCallToSign(callExpression, thirdArgumentValue, secondaryLocations); - } - const secondArgument = callExpression.arguments[1]; - if (isCallToVerify) { - checkCallToVerify(callExpression, secondArgument, thirdArgumentValue, secondaryLocations); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/inverted-assertion-arguments.ts b/eslint-bridge/src/linting/eslint/rules/inverted-assertion-arguments.ts deleted file mode 100644 index c8a393b5adc..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/inverted-assertion-arguments.ts +++ /dev/null @@ -1,153 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3415/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isIdentifier, isLiteral, isMethodCall, Mocha, toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -const ASSERT_FUNCTIONS = [ - 'equal', - 'notEqual', - 'strictEqual', - 'notStrictEqual', - 'deepEqual', - 'notDeepEqual', - 'closeTo', - 'approximately', -]; - -export const rule: Rule.RuleModule = { - meta: { - hasSuggestions: true, - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - const testCases: estree.Node[] = []; - return { - CallExpression(node: estree.Node) { - if (Mocha.isTestCase(node)) { - testCases.push(node); - return; - } - if (testCases.length > 0) { - checkInvertedArguments(node as estree.CallExpression, context); - } - }, - 'CallExpression:exit': (node: estree.Node) => { - if (Mocha.isTestCase(node)) { - testCases.pop(); - } - }, - }; - }, -}; - -function checkInvertedArguments(node: estree.CallExpression, context: Rule.RuleContext) { - const args = extractAssertionsArguments(node); - if (args) { - const [actual, expected, format] = args; - if (isLiteral(actual) && !isLiteral(expected)) { - const message = toEncodedMessage( - `Swap these 2 arguments so they are in the correct order: ${format}.`, - [actual], - ['Other argument to swap.'], - ); - context.report({ - node: expected, - message, - suggest: [ - { - desc: 'Swap arguments', - fix: fixer => [ - fixer.replaceText(actual, context.getSourceCode().getText(expected)), - fixer.replaceText(expected, context.getSourceCode().getText(actual)), - ], - }, - ], - }); - } - } -} - -function extractAssertionsArguments( - node: estree.CallExpression, -): [estree.Node, estree.Node, string] | null { - return extractAssertArguments(node) ?? extractExpectArguments(node) ?? extractFailArguments(node); -} - -function extractAssertArguments( - node: estree.CallExpression, -): [estree.Node, estree.Node, string] | null { - if (isMethodCall(node) && node.arguments.length > 1) { - const { - callee: { object, property }, - arguments: [actual, expected], - } = node; - if (isIdentifier(object, 'assert') && isIdentifier(property, ...ASSERT_FUNCTIONS)) { - return [actual, expected, `${object.name}.${property.name}(actual, expected)`]; - } - } - return null; -} - -function extractExpectArguments( - node: estree.CallExpression, -): [estree.Node, estree.Node, string] | null { - if (node.callee.type !== 'MemberExpression') { - return null; - } - let { object, property } = node.callee; - if (!isIdentifier(property, 'equal', 'eql', 'closeTo')) { - return null; - } - while (object.type === 'MemberExpression') { - object = object.object; - } - if (object.type === 'CallExpression' && isIdentifier(object.callee, 'expect')) { - return [ - object.arguments[0], - node.arguments[0], - `${object.callee.name}(actual).to.${property.name}(expected)`, - ]; - } - return null; -} - -function extractFailArguments( - node: estree.CallExpression, -): [estree.Node, estree.Node, string] | null { - if (isMethodCall(node) && node.arguments.length > 1) { - const { - callee: { object, property }, - arguments: [actual, expected], - } = node; - if (isIdentifier(object, 'assert', 'expect', 'should') && isIdentifier(property, 'fail')) { - return [actual, expected, `${object.name}.${property.name}(actual, expected)`]; - } - } - return null; -} diff --git a/eslint-bridge/src/linting/eslint/rules/label-position.ts b/eslint-bridge/src/linting/eslint/rules/label-position.ts deleted file mode 100644 index 8ba564a5da5..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/label-position.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1439/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeLabel: 'Remove this "{{label}}" label.', - }, - }, - create(context: Rule.RuleContext) { - return { - LabeledStatement: (node: estree.Node) => - checkLabeledStatement(node as estree.LabeledStatement, context), - }; - }, -}; - -function checkLabeledStatement(node: estree.LabeledStatement, context: Rule.RuleContext) { - if (!isLoopStatement(node.body) && !isSwitchStatement(node.body)) { - context.report({ - messageId: 'removeLabel', - data: { - label: node.label.name, - }, - node: node.label, - }); - } -} - -function isLoopStatement(node: estree.Node) { - return ( - node.type === 'WhileStatement' || - node.type === 'DoWhileStatement' || - node.type === 'ForStatement' || - node.type === 'ForOfStatement' || - node.type === 'ForInStatement' - ); -} - -function isSwitchStatement(node: estree.Node) { - return node.type === 'SwitchStatement'; -} diff --git a/eslint-bridge/src/linting/eslint/rules/link-with-target-blank.ts b/eslint-bridge/src/linting/eslint/rules/link-with-target-blank.ts deleted file mode 100644 index 85b2f51719a..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/link-with-target-blank.ts +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5148/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getValueOfExpression, isIdentifier, isMethodCall, isStringLiteral } from './helpers'; - -const REQUIRED_OPTION = 'noopener'; -const REQUIRED_OPTION_INDEX = 2; -const URL_INDEX = 0; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - missingNoopener: 'Make sure not using "noopener" is safe here.', - }, - }, - create(context: Rule.RuleContext) { - return { - CallExpression: (node: estree.CallExpression) => { - if (!isMethodCall(node)) { - return; - } - const { object, property } = node.callee; - - const isWindowOpen = - isIdentifier(property, 'open') && - (isIdentifier(object, 'window') || isThisWindow(object)); - - if (!isWindowOpen) { - return; - } - - const args = node.arguments; - const hasHttpUrl = URL_INDEX < args.length && isHttpUrl(context, args[URL_INDEX]); - if (!hasHttpUrl) { - return; - } - - if ( - args.length <= REQUIRED_OPTION_INDEX || - !hasRequiredOption(context, args[REQUIRED_OPTION_INDEX]) - ) { - context.report({ - messageId: 'missingNoopener', - node: property, - }); - } - }, - }; - }, -}; - -function isThisWindow(node: estree.Node) { - return ( - node.type === 'MemberExpression' && - node.object.type === 'ThisExpression' && - isIdentifier(node.property, 'window') - ); -} - -function hasRequiredOption(context: Rule.RuleContext, argument: estree.Node) { - const stringOrNothing = extractString(context, argument); - return stringOrNothing !== undefined && stringOrNothing.includes(REQUIRED_OPTION); -} - -function isHttpUrl(context: Rule.RuleContext, argument: estree.Node): boolean { - const stringOrNothing = extractString(context, argument); - return ( - stringOrNothing !== undefined && - (stringOrNothing.startsWith('http://') || stringOrNothing.startsWith('https://')) - ); -} - -function extractString(context: Rule.RuleContext, node: estree.Node): string | undefined { - const literalNodeOrNothing = getValueOfExpression(context, node, 'Literal'); - if (literalNodeOrNothing === undefined || !isStringLiteral(literalNodeOrNothing)) { - return undefined; - } else { - return literalNodeOrNothing.value; - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/max-union-size.ts b/eslint-bridge/src/linting/eslint/rules/max-union-size.ts deleted file mode 100644 index 7cd296e22c6..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/max-union-size.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4622/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - refactorUnion: 'Refactor this union type to have less than {{threshold}} elements.', - }, - }, - create(context: Rule.RuleContext) { - return { - TSUnionType: (node: estree.Node) => { - const union = node as unknown as TSESTree.TSUnionType; - const [threshold] = context.options; - if (union.types.length > threshold && !isFromTypeStatement(union)) { - context.report({ - messageId: 'refactorUnion', - data: { - threshold, - }, - node, - }); - } - }, - }; - }, -}; - -function isFromTypeStatement(node: TSESTree.TSUnionType): boolean { - return node.parent !== undefined && node.parent.type === 'TSTypeAliasDeclaration'; -} diff --git a/eslint-bridge/src/linting/eslint/rules/misplaced-loop-counter.ts b/eslint-bridge/src/linting/eslint/rules/misplaced-loop-counter.ts deleted file mode 100644 index 3f1b8b7af3e..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/misplaced-loop-counter.ts +++ /dev/null @@ -1,183 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1994/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { areEquivalent } from 'eslint-plugin-sonarjs/lib/utils/equivalence'; -import { getParent, RuleContext } from './helpers'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -class ForInfo { - updatedExpressions: estree.Node[] = []; - testedExpressions: estree.Node[] = []; - - constructor(readonly forLoop: estree.ForStatement) {} -} - -export const rule: Rule.RuleModule = { - meta: { - messages: { - misplacedCounter: `This loop's stop condition tests "{{test}}" but the incrementer updates "{{update}}".`, - }, - }, - create(context: Rule.RuleContext) { - const forLoopStack: ForInfo[] = []; - - function join(expressions: estree.Node[]) { - return expressions.map(expr => context.getSourceCode().getText(expr)).join(', '); - } - - function isInsideUpdate(node: estree.Node) { - return isInside(node, f => f.update); - } - - function isInsideTest(node: estree.Node) { - return isInside(node, f => f.test); - } - - function isInside( - node: estree.Node, - getChild: (loop: estree.ForStatement) => estree.Expression | null | undefined, - ) { - if (forLoopStack.length > 0) { - const currentLoop = peekFor(); - const parentChain = context.getAncestors(); - parentChain.push(node); - const forLoopChild = getChild(currentLoop.forLoop); - if (forLoopChild) { - return parentChain.some(parentChainNode => forLoopChild === parentChainNode); - } - } - return false; - } - - function peekFor() { - return forLoopStack[forLoopStack.length - 1]; - } - - return { - ForStatement: (node: estree.Node) => { - forLoopStack.push(new ForInfo(node as estree.ForStatement)); - }, - 'ForStatement:exit': () => { - const forInfo = forLoopStack.pop()!; - if (forInfo.updatedExpressions.length === 0 || !forInfo.forLoop.test) { - return; - } - const hasIntersection = forInfo.testedExpressions.some(testedExpr => - forInfo.updatedExpressions.some(updatedExpr => - areEquivalent( - updatedExpr as TSESTree.Node, - testedExpr as TSESTree.Node, - (context as unknown as RuleContext).getSourceCode(), - ), - ), - ); - - if (!hasIntersection) { - context.report({ - loc: context.getSourceCode().getFirstToken(forInfo.forLoop)!.loc, - messageId: 'misplacedCounter', - data: { - test: join(forInfo.testedExpressions), - update: join(forInfo.updatedExpressions), - }, - }); - } - }, - - 'ForStatement AssignmentExpression': (node: estree.Node) => { - if (isInsideUpdate(node)) { - const left = (node as estree.AssignmentExpression).left; - const assignedExpressions: estree.Node[] = []; - computeAssignedExpressions(left, assignedExpressions); - const { updatedExpressions } = peekFor(); - assignedExpressions.forEach(ass => updatedExpressions.push(ass)); - } - }, - - 'ForStatement UpdateExpression': (node: estree.Node) => { - if (isInsideUpdate(node)) { - peekFor().updatedExpressions.push((node as estree.UpdateExpression).argument); - } - }, - - 'ForStatement CallExpression': (node: estree.Node) => { - if (!isInsideUpdate(node)) { - return; - } - const callee = getCalleeObject(node as estree.CallExpression); - if (callee) { - peekFor().updatedExpressions.push(callee); - } - }, - - 'ForStatement Identifier': (node: estree.Node) => { - if (isInsideTest(node)) { - const parent = getParent(context)!; - if (parent.type !== 'MemberExpression' || parent.computed || parent.object === node) { - peekFor().testedExpressions.push(node); - } - } - }, - - 'ForStatement MemberExpression': (node: estree.Node) => { - if ( - isInsideTest(node) && - getParent(context)!.type !== 'MemberExpression' && - getParent(context)!.type !== 'CallExpression' - ) { - peekFor().testedExpressions.push(node); - } - }, - }; - }, -}; - -function getCalleeObject(node: estree.CallExpression) { - let callee = node.callee; - while (callee.type === 'MemberExpression') { - callee = callee.object; - } - if (callee.type === 'Identifier' && callee !== node.callee) { - return callee; - } - return null; -} - -function computeAssignedExpressions(node: estree.Node | null, assigned: Array) { - switch (node?.type) { - case 'ArrayPattern': - node.elements.forEach(element => computeAssignedExpressions(element, assigned)); - break; - case 'ObjectPattern': - node.properties.forEach(property => computeAssignedExpressions(property, assigned)); - break; - case 'Property': - computeAssignedExpressions(node.value, assigned); - break; - case 'AssignmentPattern': - computeAssignedExpressions(node.left, assigned); - break; - default: - assigned.push(node); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/nested-control-flow.ts b/eslint-bridge/src/linting/eslint/rules/nested-control-flow.ts deleted file mode 100644 index f88211b2dfe..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/nested-control-flow.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S134/javascript - -import { Rule, AST } from 'eslint'; -import * as estree from 'estree'; -import { toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { type: 'integer' }, - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - - create(context: Rule.RuleContext) { - const sourceCode = context.getSourceCode(); - const [threshold] = context.options; - const nodeStack: AST.Token[] = []; - function push(n: AST.Token) { - nodeStack.push(n); - } - function pop() { - return nodeStack.pop(); - } - function check(node: estree.Node) { - if (nodeStack.length === threshold) { - context.report({ - message: toEncodedMessage( - `Refactor this code to not nest more than ${threshold} if/for/while/switch/try statements.`, - nodeStack, - nodeStack.map(_n => '+1'), - ), - loc: sourceCode.getFirstToken(node)!.loc, - }); - } - } - function isElseIf(node: estree.Node) { - const parent = last(context.getAncestors()); - return ( - node.type === 'IfStatement' && parent.type === 'IfStatement' && node === parent.alternate - ); - } - const controlFlowNodes = [ - 'ForStatement', - 'ForInStatement', - 'ForOfStatement', - 'WhileStatement', - 'DoWhileStatement', - 'IfStatement', - 'TryStatement', - 'SwitchStatement', - ].join(','); - return { - [controlFlowNodes]: (node: estree.Node) => { - if (isElseIf(node)) { - pop(); - push(sourceCode.getFirstToken(node)!); - } else { - check(node); - push(sourceCode.getFirstToken(node)!); - } - }, - [`${controlFlowNodes}:exit`]: (node: estree.Node) => { - if (!isElseIf(node)) { - pop(); - } - }, - }; - }, -}; - -function last(arr: Array) { - return arr[arr.length - 1]; -} diff --git a/eslint-bridge/src/linting/eslint/rules/new-operator-misuse.ts b/eslint-bridge/src/linting/eslint/rules/new-operator-misuse.ts deleted file mode 100644 index 8a59b68ca6f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/new-operator-misuse.ts +++ /dev/null @@ -1,116 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2999/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import * as ts from 'typescript'; -import { - isRequiredParserServices, - getTypeFromTreeNode, - getSignatureFromCallee, - toEncodedMessage, -} from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { type: 'object' }, - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - const { considerJSDoc } = context.options[0]; - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - return { - 'NewExpression[callee.type!="ThisExpression"]': (node: estree.Node) => { - const { callee } = node as estree.NewExpression; - const type = getTypeFromTreeNode(callee, services); - const signature = getSignatureFromCallee(node, services); - if (!isInstantiable(type, signature, considerJSDoc) && !isAny(type)) { - const functionToken = context - .getSourceCode() - .getFirstToken(node, token => token.type === 'Keyword' && token.value === 'function'); - const newToken = context - .getSourceCode() - .getFirstToken(node, token => token.type === 'Keyword' && token.value === 'new')!; - const text = isFunction(type) ? 'this function' : context.getSourceCode().getText(callee); - const loc = callee.type === 'FunctionExpression' ? functionToken!.loc : callee.loc!; - context.report({ - message: toEncodedMessage(`Replace ${text} with a constructor function.`, [newToken]), - loc, - }); - } - }, - }; - }, -}; - -function isInstantiable( - type: ts.Type, - signature: ts.Signature | undefined, - considerJSDoc: boolean, -): boolean { - return ( - isClass(type) || - isModule(type) || - isConstructor(type, signature, considerJSDoc) || - (type.isUnionOrIntersection() && - type.types.some(tp => isInstantiable(tp, signature, considerJSDoc))) - ); -} - -function isClass(type: ts.Type) { - return ( - type.symbol && - ((type.symbol.flags & ts.SymbolFlags.Class) !== 0 || - (type.symbol.flags & ts.SymbolFlags.Type) !== 0) - ); -} - -function isModule(type: ts.Type) { - return type.symbol && (type.symbol.flags & ts.SymbolFlags.Module) !== 0; -} - -function isFunction(type: ts.Type) { - return type.symbol && (type.symbol.flags & ts.SymbolFlags.Function) !== 0; -} - -function isConstructor(type: ts.Type, signature: ts.Signature | undefined, considerJSDoc: boolean) { - return isFunction(type) && (!considerJSDoc || hasJSDocAnnotation(signature)); -} - -function hasJSDocAnnotation(signature: ts.Signature | undefined) { - return ( - signature !== undefined && - signature.getJsDocTags().some(tag => ['constructor', 'class'].includes(tag.name)) - ); -} - -function isAny(type: ts.Type) { - return type.flags === ts.TypeFlags.Any; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-accessor-field-mismatch.ts b/eslint-bridge/src/linting/eslint/rules/no-accessor-field-mismatch.ts deleted file mode 100644 index 9643e470700..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-accessor-field-mismatch.ts +++ /dev/null @@ -1,263 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4275/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -interface AccessorInfo { - type: 'getter' | 'setter'; - name: string; -} - -interface Field { - name: string; - node: TSESTree.Node; -} - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - - create(context: Rule.RuleContext) { - const currentFieldsStack = [new Map()]; - - function checkAccessor(accessor: TSESTree.Property | TSESTree.MethodDefinition) { - const accessorIsPublic = - accessor.type !== 'MethodDefinition' || accessor.accessibility === 'public'; - const accessorInfo = getAccessorInfo(accessor); - const statements = getFunctionBody(accessor.value); - if (!accessorInfo || !accessorIsPublic || !statements || statements.length > 1) { - return; - } - - const matchingFields = findMatchingFields( - currentFieldsStack[currentFieldsStack.length - 1], - accessorInfo.name, - ); - if ( - matchingFields.length > 0 && - (statements.length === 0 || - !isUsingAccessorFieldInBody(statements[0], accessorInfo, matchingFields)) - ) { - const fieldToRefer = matchingFields[0]; - const primaryMessage = - `Refactor this ${accessorInfo.type} ` + - `so that it actually refers to the property '${fieldToRefer.name}'.`; - const secondaryLocations = [fieldToRefer.node]; - const secondaryMessages = ['Property which should be referred.']; - - context.report({ - message: toEncodedMessage(primaryMessage, secondaryLocations, secondaryMessages), - loc: accessor.key.loc, - }); - } - } - - return { - Property: (node: estree.Node) => checkAccessor(node as TSESTree.Property), - MethodDefinition: (node: estree.Node) => checkAccessor(node as TSESTree.MethodDefinition), - - ClassBody: (node: estree.Node) => { - const classBody = node as TSESTree.ClassBody; - const fields = getFieldMap(classBody.body, classElement => - (classElement.type === 'PropertyDefinition' || - classElement.type === 'TSAbstractPropertyDefinition') && - !classElement.static - ? classElement.key - : null, - ); - const fieldsFromConstructor = fieldsDeclaredInConstructorParameters(classBody); - const allFields = new Map([...fields, ...fieldsFromConstructor]); - currentFieldsStack.push(allFields); - }, - ObjectExpression: (node: estree.Node) => { - const currentFields = getFieldMap((node as TSESTree.ObjectExpression).properties, prop => - isValidObjectField(prop) ? prop.key : null, - ); - currentFieldsStack.push(currentFields); - }, - ':matches(ClassBody, ObjectExpression):exit': () => { - currentFieldsStack.pop(); - }, - }; - }, -}; - -function getAccessorInfo( - accessor: TSESTree.Property | TSESTree.MethodDefinition, -): AccessorInfo | null { - let name = getName(accessor.key); - if (!name) { - return null; - } - - name = name.toLowerCase(); - if (accessor.kind === 'get') { - return { type: 'getter', name }; - } else if (accessor.kind === 'set') { - return { type: 'setter', name }; - } else { - return setterOrGetter(name, accessor.value); - } -} - -function getName(key: TSESTree.Node) { - if (key.type === 'Literal') { - return String(key.value); - } else if (key.type === 'Identifier') { - return key.name; - } - return null; -} - -function setterOrGetter(name: string, functionExpression: TSESTree.Node): AccessorInfo | null { - if (functionExpression.type !== 'FunctionExpression') { - return null; - } - - if (name.startsWith('set') && functionExpression.params.length === 1) { - return { type: 'setter', name: name.substring(3) }; - } - if (name.startsWith('get') && functionExpression.params.length === 0) { - return { type: 'getter', name: name.substring(3) }; - } - - return null; -} - -function getFieldMap( - elements: T[], - getPropertyName: (arg: T) => TSESTree.PropertyName | null, -) { - const fields: Map = new Map(); - for (const element of elements) { - const propertyNameNode = getPropertyName(element); - if (propertyNameNode) { - const name = getName(propertyNameNode); - if (name) { - fields.set(name.toLowerCase(), { - name, - node: element, - }); - } - } - } - return fields; -} - -function isValidObjectField(prop: TSESTree.Node): prop is TSESTree.Property { - return prop.type === 'Property' && !prop.method && prop.kind === 'init'; -} - -function fieldsDeclaredInConstructorParameters(containingClass: TSESTree.ClassBody) { - const constr = getConstructorOf(containingClass); - if (constr) { - const fieldsFromConstructor = new Map(); - for (const parameter of constr.params) { - if ( - parameter.type === 'TSParameterProperty' && - (parameter.accessibility || parameter.readonly) - ) { - const parameterName = getName(parameter.parameter); - if (parameterName) { - fieldsFromConstructor.set(parameterName, { - name: parameterName, - node: parameter, - }); - } - } - } - return fieldsFromConstructor; - } else { - return new Map(); - } -} - -function getConstructorOf( - containingClass: TSESTree.ClassBody, -): TSESTree.FunctionExpression | TSESTree.TSEmptyBodyFunctionExpression | undefined { - for (const classElement of containingClass.body) { - if (classElement.type === 'MethodDefinition' && getName(classElement.key) === 'constructor') { - return classElement.value; - } - } -} - -function findMatchingFields(currentFields: Map, name: string) { - const underscoredTargetName1 = `_${name}`; - const underscoredTargetName2 = `${name}_`; - const exactFieldName = currentFields.get(name); - const underscoreFieldName1 = currentFields.get(underscoredTargetName1); - const underscoreFieldName2 = currentFields.get(underscoredTargetName2); - return [exactFieldName, underscoreFieldName1, underscoreFieldName2].filter( - field => field, - ) as Field[]; -} - -function getFunctionBody(node: TSESTree.Node) { - if (node.type !== 'FunctionExpression' || !node.body) { - return null; - } - return node.body.body; -} - -function getPropertyName(expression: TSESTree.Expression | null) { - if ( - expression && - expression.type === 'MemberExpression' && - expression.object.type === 'ThisExpression' - ) { - return getName(expression.property); - } - return null; -} - -function getFieldUsedInsideSimpleBody(statement: TSESTree.Statement, accessorInfo: AccessorInfo) { - if (accessorInfo.type === 'setter') { - if ( - statement.type === 'ExpressionStatement' && - statement.expression.type === 'AssignmentExpression' - ) { - return getPropertyName(statement.expression.left); - } - } else if (statement.type === 'ReturnStatement') { - return getPropertyName(statement.argument); - } - return null; -} - -function isUsingAccessorFieldInBody( - statement: TSESTree.Statement, - accessorInfo: AccessorInfo, - matchingFields: Field[], -) { - const usedField = getFieldUsedInsideSimpleBody(statement, accessorInfo); - return !usedField || matchingFields.some(matchingField => usedField === matchingField.name); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-alphabetical-sort.ts b/eslint-bridge/src/linting/eslint/rules/no-alphabetical-sort.ts deleted file mode 100644 index f9c0230e531..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-alphabetical-sort.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2871/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import * as ts from 'typescript'; -import { isRequiredParserServices, sortLike, RequiredParserServices } from './helpers'; - -const compareFunctionPlaceholder = '(a, b) => (a - b)'; - -export const rule: Rule.RuleModule = { - meta: { - hasSuggestions: true, - messages: { - provideCompareFunction: - 'Provide a compare function to avoid sorting elements alphabetically.', - suggestCompareFunction: 'Add a comparator function to sort in ascending order', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - return { - CallExpression: (node: estree.Node) => { - const call = node as TSESTree.CallExpression; - const callee = call.callee; - if (call.arguments.length === 0 && callee.type === 'MemberExpression') { - const { object, property } = callee; - const text = context.getSourceCode().getText(property as estree.Node); - if (sortLike.includes(text)) { - const arrayElementType = arrayElementTypeOf(object, services); - if (arrayElementType && arrayElementType.kind === ts.SyntaxKind.NumberKeyword) { - const closingParenthesis = context - .getSourceCode() - .getLastToken(node, token => token.value === ')')!; - context.report({ - messageId: 'provideCompareFunction', - node: property as estree.Node, - suggest: [ - { - messageId: 'suggestCompareFunction', - fix: fixer => - fixer.insertTextBefore(closingParenthesis, compareFunctionPlaceholder), - }, - ], - }); - } - } - } - }, - }; - }, -}; - -function arrayElementTypeOf(node: TSESTree.Node, services: RequiredParserServices) { - const { typeToTypeNode, getTypeAtLocation } = services.program.getTypeChecker(); - const typeNode = typeToTypeNode( - getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node)), - undefined, - undefined, - ); - if (typeNode && ts.isArrayTypeNode(typeNode)) { - return typeNode.elementType; - } - return undefined; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-angular-bypass-sanitization.ts b/eslint-bridge/src/linting/eslint/rules/no-angular-bypass-sanitization.ts deleted file mode 100644 index ca26c2d461d..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-angular-bypass-sanitization.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6268/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isMemberWithProperty, isLiteral } from './helpers'; - -const bypassMethods = [ - 'bypassSecurityTrustHtml', - 'bypassSecurityTrustStyle', - 'bypassSecurityTrustScript', - 'bypassSecurityTrustUrl', - 'bypassSecurityTrustResourceUrl', -]; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - checkAngularBypass: 'Make sure disabling Angular built-in sanitization is safe here.', - }, - }, - create(context: Rule.RuleContext) { - return { - CallExpression: (node: estree.Node) => { - const { callee, arguments: args } = node as estree.CallExpression; - - if ( - isMemberWithProperty(callee, ...bypassMethods) && - args.length === 1 && - !isHardcodedLiteral(args[0]) - ) { - context.report({ - messageId: 'checkAngularBypass', - node: (callee as estree.MemberExpression).property, - }); - } - }, - }; - }, -}; - -function isHardcodedLiteral(node: estree.Node) { - if (node.type === 'TemplateLiteral') { - return node.expressions.length === 0; - } else { - return isLiteral(node); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-array-delete.ts b/eslint-bridge/src/linting/eslint/rules/no-array-delete.ts deleted file mode 100644 index 25c7dcfb388..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-array-delete.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2870/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getParent, isArray, isRequiredParserServices } from './helpers'; - -const ArrayDeleteExpression = - "UnaryExpression[operator='delete'] > MemberExpression[computed=true]"; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeDelete: 'Remove this use of "delete".', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (isRequiredParserServices(services)) { - return { - [ArrayDeleteExpression]: (node: estree.Node) => { - const member = node as estree.MemberExpression; - const object = member.object; - if (isArray(object, services)) { - raiseIssue(context); - } - }, - }; - } - return {}; - }, -}; - -function raiseIssue(context: Rule.RuleContext): void { - const deleteKeyword = context.getSourceCode().getFirstToken(getParent(context)!); - context.report({ - messageId: 'removeDelete', - loc: deleteKeyword!.loc, - }); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-associative-arrays.ts b/eslint-bridge/src/linting/eslint/rules/no-associative-arrays.ts deleted file mode 100644 index d468df19f5f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-associative-arrays.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3579/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isArray, isString, isRequiredParserServices } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - noAssociativeArray: - 'Make it an object if it must have named properties; otherwise, use a numeric index here.', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - - if (!isRequiredParserServices(services)) { - return {}; - } - - return { - 'AssignmentExpression[left.type="MemberExpression"]'(node: estree.Node) { - const { property, object } = (node as estree.AssignmentExpression) - .left as estree.MemberExpression; - if (isString(property, services) && isArray(object, services)) { - context.report({ - messageId: 'noAssociativeArray', - node, - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-built-in-override.ts b/eslint-bridge/src/linting/eslint/rules/no-built-in-override.ts deleted file mode 100644 index 0d61396c177..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-built-in-override.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2424/javascript - -import { globalsByLibraries } from './helpers'; -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeOverride: 'Remove this override of "{{overridden}}".', - }, - }, - create(context: Rule.RuleContext) { - const overriden: Set = new Set(); - - function isBuiltIn(variable: Scope.Variable) { - return globalsByLibraries.builtin.includes(variable.name); - } - - function checkVariable(variable: Scope.Variable) { - if (isBuiltIn(variable)) { - variable.defs.forEach(def => overriden.add(def.name)); - variable.references - .filter(ref => ref.isWrite()) - .forEach(ref => overriden.add(ref.identifier)); - } - } - - function checkScope(scope: Scope.Scope) { - scope.variables.forEach(checkVariable); - scope.childScopes.forEach(checkScope); - } - - function isTSEnumMemberId(node: estree.Identifier) { - const id = node as TSESTree.Identifier; - return id.parent?.type === 'TSEnumMember'; - } - - return { - Program: () => { - checkScope(context.getScope()); - }, - 'Program:exit': () => { - overriden.forEach(node => { - if (!isTSEnumMemberId(node)) { - context.report({ - messageId: 'removeOverride', - data: { - overridden: node.name, - }, - node, - }); - } - }); - overriden.clear(); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-case-label-in-switch.ts b/eslint-bridge/src/linting/eslint/rules/no-case-label-in-switch.ts deleted file mode 100644 index a8ab9d00a02..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-case-label-in-switch.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1219/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeLabel: 'Remove this misleading "{{label}}" label.', - }, - }, - create(context: Rule.RuleContext) { - const stack: number[] = [0]; - function enterCase() { - stack.push(stack.pop()! + 1); - } - function leaveCase() { - stack.push(stack.pop()! - 1); - } - function inCase() { - return stack[stack.length - 1] > 0; - } - return { - SwitchCase: () => { - enterCase(); - }, - LabeledStatement: (node: estree.Node) => { - if (inCase()) { - const label = (node as estree.LabeledStatement).label; - context.report({ - messageId: 'removeLabel', - data: { - label: label.name, - }, - node: label, - }); - } - }, - 'FunctionExpression, FunctionDeclaration': () => { - stack.push(0); - }, - 'SwitchCase:exit': () => { - leaveCase(); - }, - 'FunctionExpression, FunctionDeclaration :exit': () => { - stack.pop(); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-clear-text-protocols.aws.ts b/eslint-bridge/src/linting/eslint/rules/no-clear-text-protocols.aws.ts deleted file mode 100644 index 2efebe4299b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-clear-text-protocols.aws.ts +++ /dev/null @@ -1,229 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5332/javascript - -import { Rule } from 'eslint'; -import { AwsCdkCheckArguments, AwsCdkTemplate } from './helpers/aws/cdk'; -import * as estree from 'estree'; - -const sensitivePorts = [80, 8080, 8000, 8008]; - -export const rule: Rule.RuleModule = AwsCdkTemplate( - { - 'aws-cdk-lib.aws_elasticache.CfnReplicationGroup': AwsCdkCheckArguments( - 'replicationGroup', - true, - 'transitEncryptionEnabled', - { primitives: { invalid: [false] } }, - ), - 'aws-cdk-lib.aws_kinesis.Stream': AwsCdkCheckArguments( - 'streamEncryptionDisabled', - false, - 'encryption', - { fqns: { invalid: ['aws_cdk_lib.aws_kinesis.StreamEncryption.UNENCRYPTED'] } }, - ), - 'aws-cdk-lib.aws_kinesis.CfnStream': AwsCdkCheckArguments( - 'streamEncryptionDisabled', - true, - 'streamEncryption', - ), - 'aws-cdk-lib.aws_elasticloadbalancing.LoadBalancer': { - callExpression: AwsCdkCheckArguments( - 'noSSLTLS', - false, - 'externalProtocol', - { - fqns: { - invalid: [ - 'aws-cdk-lib.aws_elasticloadbalancing.LoadBalancingProtocol.TCP', - 'aws-cdk-lib.aws_elasticloadbalancing.LoadBalancingProtocol.HTTP', - ], - }, - }, - false, - 0, - ), - functionName: 'addListener', - newExpression: AwsCdkCheckArguments('noSSLTLS', false, ['listeners', 'externalProtocol'], { - fqns: { - invalid: [ - 'aws-cdk-lib.aws_elasticloadbalancing.LoadBalancingProtocol.TCP', - 'aws-cdk-lib.aws_elasticloadbalancing.LoadBalancingProtocol.HTTP', - ], - }, - }), - }, - 'aws-cdk-lib.aws_elasticloadbalancing.CfnLoadBalancer': AwsCdkCheckArguments( - 'noSSLTLS', - false, - ['listeners', 'protocol'], - { primitives: { invalid: ['tcp', 'http'], case_insensitive: true } }, - ), - 'aws-cdk-lib.aws_elasticloadbalancingv2.ApplicationLoadBalancer': { - callExpression: httpOrSensitivePort(1), - functionName: 'addListener', - }, - 'aws-cdk-lib.aws_elasticloadbalancingv2.ApplicationListener': httpOrSensitivePort(2), - 'aws-cdk-lib.aws_elasticloadbalancingv2.NetworkLoadBalancer': { - callExpression: (expr: estree.NewExpression, ctx: Rule.RuleContext) => { - const httpProtocol = AwsCdkCheckArguments( - 'noSSLTLS', - false, - 'protocol', - { - fqns: { - invalid: [ - 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.HTTP', - 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.TCP', - 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.UDP', - 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.TCP_UDP', - ], - }, - }, - true, - 1, - ); - const node = httpProtocol(expr, ctx); - if (node) { - ctx.report({ messageId: 'noSSLTLS', node }); - } else { - const missingProtocol = AwsCdkCheckArguments( - 'noSSLTLS', - true, - 'protocol', - undefined, - true, - 1, - ); - if (missingProtocol(expr, ctx)) { - const certificatesChecker = AwsCdkCheckArguments( - 'noSSLTLS', - true, - 'certificates', - undefined, - true, - 1, - ); - const portNode = certificatesChecker(expr, ctx); - if (portNode) { - ctx.report({ messageId: 'noSSLTLS', node: portNode }); - } - } - } - }, - functionName: 'addListener', - }, - 'aws-cdk-lib.aws_elasticloadbalancingv2.NetworkListener': ( - expr: estree.NewExpression, - ctx: Rule.RuleContext, - ) => { - const httpProtocol = AwsCdkCheckArguments( - 'noSSLTLS', - false, - 'protocol', - { - fqns: { - invalid: [ - 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.TCP', - 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.UDP', - 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.TCP_UDP', - ], - }, - }, - true, - ); - const node = httpProtocol(expr, ctx); - if (node) { - ctx.report({ messageId: 'noSSLTLS', node }); - } else { - const missingProtocol = AwsCdkCheckArguments('noSSLTLS', true, 'protocol', undefined, true); - if (missingProtocol(expr, ctx)) { - const certificatesChecker = AwsCdkCheckArguments( - 'noSSLTLS', - true, - 'certificates', - undefined, - true, - ); - const portNode = certificatesChecker(expr, ctx); - if (portNode) { - ctx.report({ messageId: 'noSSLTLS', node: portNode }); - } - } - } - }, - 'aws-cdk-lib.aws_elasticloadbalancingv2.CfnListener': AwsCdkCheckArguments( - 'noSSLTLS', - false, - 'protocol', - { primitives: { invalid: ['HTTP', 'TCP', 'UDP', 'TCP_UDP'], case_insensitive: true } }, - ), - }, - { - meta: { - messages: { - replicationGroup: 'Make sure that disabling transit encryption is safe here.', - noSSLTLS: - 'Make sure that using network protocols without an SSL/TLS underlay is safe here.', - streamEncryptionDisabled: 'Make sure that disabling stream encryption is safe here.', - }, - }, - }, -); - -function httpOrSensitivePort(position: number) { - return function (expr: estree.NewExpression, ctx: Rule.RuleContext) { - const httpProtocol = AwsCdkCheckArguments( - 'noSSLTLS', - false, - 'protocol', - { fqns: { invalid: ['aws-cdk-lib.aws_elasticloadbalancingv2.ApplicationProtocol.HTTP'] } }, - true, - position, - ); - const node = httpProtocol(expr, ctx); - if (node) { - ctx.report({ messageId: 'noSSLTLS', node }); - } else { - const missingProtocol = AwsCdkCheckArguments( - 'noSSLTLS', - true, - 'protocol', - undefined, - true, - position, - ); - if (missingProtocol(expr, ctx)) { - const portChecker = AwsCdkCheckArguments( - 'noSSLTLS', - false, - 'port', - { primitives: { invalid: sensitivePorts } }, - true, - position, - ); - const portNode = portChecker(expr, ctx); - if (portNode) { - ctx.report({ messageId: 'noSSLTLS', node: portNode }); - } - } - } - }; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-clear-text-protocols.lib.ts b/eslint-bridge/src/linting/eslint/rules/no-clear-text-protocols.lib.ts deleted file mode 100644 index d9fb3759a24..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-clear-text-protocols.lib.ts +++ /dev/null @@ -1,240 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5332/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { URL } from 'url'; -import { - getValueOfExpression, - getObjectExpressionProperty, - getParent, - getFullyQualifiedName, -} from './helpers'; -import { normalizeFQN } from './helpers/aws/cdk'; - -const INSECURE_PROTOCOLS = ['http://', 'ftp://', 'telnet://']; -const LOOPBACK_PATTERN = /localhost|127(?:\.[0-9]+){0,2}\.[0-9]+$|\/\/(?:0*\:)*?:?0*1$/; -const EXCEPTION_FULL_HOSTS = [ - 'www.w3.org', - 'xml.apache.org', - 'schemas.xmlsoap.org', - 'schemas.openxmlformats.org', - 'rdfs.org', - 'purl.org', - 'xmlns.com', - 'schemas.google.com', - 'a9.com', - 'ns.adobe.com', - 'ltsc.ieee.org', - 'docbook.org', - 'graphml.graphdrawing.org', - 'json-schema.org', -]; -const EXCEPTION_TOP_HOSTS = [/(.*\.)?example\.com$/, /(.*\.)?example\.org$/, /(.*\.)?test\.com$/]; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - insecureProtocol: 'Using {{protocol}} protocol is insecure. Use {{alternative}} instead.', - }, - }, - create(context: Rule.RuleContext) { - function checkNodemailer(callExpression: estree.CallExpression) { - const firstArg = callExpression.arguments.length > 0 ? callExpression.arguments[0] : null; - if (!firstArg) { - return; - } - - const firstArgValue = getValueOfExpression(context, firstArg, 'ObjectExpression'); - - const ses = getObjectExpressionProperty(firstArgValue, 'SES'); - if (ses && usesSesCommunication(ses)) { - return; - } - - const secure = getObjectExpressionProperty(firstArgValue, 'secure'); - if (secure && (secure.value.type !== 'Literal' || secure.value.raw !== 'false')) { - return; - } - - const requireTls = getObjectExpressionProperty(firstArgValue, 'requireTLS'); - if (requireTls && (requireTls.value.type !== 'Literal' || requireTls.value.raw !== 'false')) { - return; - } - - const port = getObjectExpressionProperty(firstArgValue, 'port'); - if (port && (port.value.type !== 'Literal' || port.value.raw === '465')) { - return; - } - - context.report({ node: callExpression.callee, ...getMessageAndData('http') }); - } - - function usesSesCommunication(sesProperty: estree.Property) { - const configuration = getValueOfExpression(context, sesProperty.value, 'ObjectExpression'); - if (!configuration) { - return false; - } - - const ses = getValueOfExpression( - context, - getObjectExpressionProperty(configuration, 'ses')?.value, - 'NewExpression', - ); - if (!ses || normalizeFQN(getFullyQualifiedName(context, ses)) !== '@aws_sdk.client_ses.SES') { - return false; - } - - const aws = getObjectExpressionProperty(configuration, 'aws'); - if ( - !aws || - normalizeFQN(getFullyQualifiedName(context, aws.value)) !== '@aws_sdk.client_ses' - ) { - return false; - } - - return true; - } - - function checkCallToFtp(callExpression: estree.CallExpression) { - if ( - callExpression.callee.type === 'MemberExpression' && - callExpression.callee.property.type === 'Identifier' && - callExpression.callee.property.name === 'connect' - ) { - const newExpression = getValueOfExpression( - context, - callExpression.callee.object, - 'NewExpression', - ); - if (!!newExpression && getFullyQualifiedName(context, newExpression.callee) === 'ftp') { - const firstArg = callExpression.arguments.length > 0 ? callExpression.arguments[0] : null; - if (!firstArg) { - return; - } - const firstArgValue = getValueOfExpression(context, firstArg, 'ObjectExpression'); - const secure = getObjectExpressionProperty(firstArgValue, 'secure'); - if (secure && secure.value.type === 'Literal' && secure.value.raw === 'false') { - context.report({ - node: callExpression.callee, - ...getMessageAndData('ftp'), - }); - } - } - } - } - - function checkCallToRequire(callExpression: estree.CallExpression) { - if (callExpression.callee.type === 'Identifier' && callExpression.callee.name === 'require') { - const firstArg = callExpression.arguments.length > 0 ? callExpression.arguments[0] : null; - if ( - firstArg && - firstArg.type === 'Literal' && - typeof firstArg.value === 'string' && - firstArg.value === 'telnet-client' - ) { - context.report({ - node: firstArg, - ...getMessageAndData('telnet'), - }); - } - } - } - - function isExceptionUrl(value: string) { - if (INSECURE_PROTOCOLS.includes(value)) { - const parent = getParent(context); - return !(parent?.type === 'BinaryExpression' && parent.operator === '+'); - } - return hasExceptionHost(value); - } - - function hasExceptionHost(value: string) { - let url; - - try { - url = new URL(value); - } catch (err) { - return false; - } - - const host = url.hostname; - return ( - host.length === 0 || - LOOPBACK_PATTERN.test(host) || - EXCEPTION_FULL_HOSTS.some(exception => exception === host) || - EXCEPTION_TOP_HOSTS.some(exception => exception.test(host)) - ); - } - - return { - Literal: (node: estree.Node) => { - const literal = node as estree.Literal; - if (typeof literal.value === 'string') { - const value = literal.value.trim().toLocaleLowerCase(); - const insecure = INSECURE_PROTOCOLS.find(protocol => value.startsWith(protocol)); - if (insecure && !isExceptionUrl(value)) { - const protocol = insecure.substring(0, insecure.indexOf(':')); - context.report({ - ...getMessageAndData(protocol), - node, - }); - } - } - }, - CallExpression: (node: estree.Node) => { - const callExpression = node as estree.CallExpression; - if (getFullyQualifiedName(context, callExpression) === 'nodemailer.createTransport') { - checkNodemailer(callExpression); - } - checkCallToFtp(callExpression); - checkCallToRequire(callExpression); - }, - ImportDeclaration: (node: estree.Node) => { - const importDeclaration = node as estree.ImportDeclaration; - if ( - typeof importDeclaration.source.value === 'string' && - importDeclaration.source.value === 'telnet-client' - ) { - context.report({ - node: importDeclaration.source, - ...getMessageAndData('telnet'), - }); - } - }, - }; - }, -}; - -function getMessageAndData(protocol: string) { - let alternative; - switch (protocol) { - case 'http': - alternative = 'https'; - break; - case 'ftp': - alternative = 'sftp, scp or ftps'; - break; - default: - alternative = 'ssh'; - } - return { messageId: 'insecureProtocol', data: { protocol, alternative } }; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-clear-text-protocols.ts b/eslint-bridge/src/linting/eslint/rules/no-clear-text-protocols.ts deleted file mode 100644 index 108549d8ea5..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-clear-text-protocols.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5332/javascript - -import { Rule } from 'eslint'; -import { mergeRules } from './decorators/helpers'; -import { rule as networkProtocolsRule } from './no-clear-text-protocols.lib'; -import { rule as awsRule } from './no-clear-text-protocols.aws'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { ...networkProtocolsRule.meta!.messages, ...awsRule.meta!.messages }, - }, - create(context: Rule.RuleContext) { - return mergeRules(networkProtocolsRule.create(context), awsRule.create(context)); - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-code-after-done.ts b/eslint-bridge/src/linting/eslint/rules/no-code-after-done.ts deleted file mode 100644 index 05653e68183..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-code-after-done.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6079/javascript - -import { Rule, Scope } from 'eslint'; -import { getVariableFromIdentifier, Mocha, toEncodedMessage } from './helpers'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - let currentDoneVariable: Scope.Variable | undefined; - let doneCall: estree.Node | undefined; - let doneSegment: Rule.CodePathSegment | undefined; - - let currentSegment: Rule.CodePathSegment | undefined; - let currentCase: Mocha.TestCase; - const segmentFirstStatement: Map = new Map(); - - function checkForTestCase(node: estree.Node) { - const testCase = Mocha.extractTestCase(node); - if (!testCase) { - return; - } - - currentCase = testCase; - currentDoneVariable = undefined; - if (testCase.callback.params.length === 0) { - return; - } - const [done] = testCase.callback.params; - if (done.type !== 'Identifier') { - return; - } - const callbackScope = context - .getScope() - .childScopes.find(scope => scope.block === testCase.callback); - if (!callbackScope) { - return; - } - currentDoneVariable = getVariableFromIdentifier(done, callbackScope); - } - - function checkForDoneCall(node: estree.CallExpression) { - const { callee } = node; - if ( - currentDoneVariable && - currentDoneVariable.references.some(ref => ref.identifier === callee) - ) { - doneCall = node; - doneSegment = currentSegment; - } - } - - function report(statementAfterDone: estree.Node) { - context.report({ - node: statementAfterDone, - message: toEncodedMessage(`Move this code before the call to "done".`, [ - doneCall as TSESTree.Node, - ]), - }); - - doneSegment = undefined; - doneCall = undefined; - currentDoneVariable = undefined; - } - - return { - CallExpression: (node: estree.Node) => { - checkForTestCase(node); - checkForDoneCall(node as estree.CallExpression); - }, - - ExpressionStatement: (node: estree.Node) => { - if (currentSegment && currentSegment === doneSegment) { - report(node); - } - - if (currentSegment && !segmentFirstStatement.has(currentSegment)) { - segmentFirstStatement.set(currentSegment, node); - } - }, - - onCodePathSegmentStart(segment: Rule.CodePathSegment) { - currentSegment = segment; - }, - - onCodePathEnd(_codePath: Rule.CodePath, node: estree.Node) { - currentSegment = undefined; - if (currentCase?.callback === node && doneSegment) { - // we report an issue if one of 'doneSegment.nextSegments' is not empty - const statementAfterDone = doneSegment.nextSegments - .map(segment => segmentFirstStatement.get(segment)) - .find(stmt => !!stmt); - if (statementAfterDone) { - report(statementAfterDone); - } - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-commented-code.ts b/eslint-bridge/src/linting/eslint/rules/no-commented-code.ts deleted file mode 100644 index 5989a7bafc0..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-commented-code.ts +++ /dev/null @@ -1,204 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S125/javascript - -import { Rule, SourceCode } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import * as babel from '@babel/eslint-parser'; -import { buildParserOptions } from 'parsing/jsts'; -import { CodeRecognizer, JavaScriptFootPrint } from '../linter/recognizers'; - -const EXCLUDED_STATEMENTS = ['BreakStatement', 'LabeledStatement', 'ContinueStatement']; - -const recognizer = new CodeRecognizer(0.9, new JavaScriptFootPrint()); - -interface GroupComment { - value: string; - nodes: TSESTree.Comment[]; -} - -export const rule: Rule.RuleModule = { - meta: { - messages: { - commentedCode: 'Remove this commented out code.', - commentedCodeFix: 'Remove this commented out code', - }, - hasSuggestions: true, - }, - create(context: Rule.RuleContext) { - function getGroupedComments(comments: TSESTree.Comment[]): GroupComment[] { - const groupedComments: GroupComment[] = []; - let currentGroup: TSESTree.Comment[] = []; - for (const comment of comments) { - if (comment.type === 'Block') { - groupedComments.push({ value: comment.value, nodes: [comment] }); - } else if ( - currentGroup.length === 0 || - areAdjacentLineComments(currentGroup[currentGroup.length - 1], comment) - ) { - currentGroup.push(comment); - } else { - groupedComments.push({ - value: currentGroup.map(lineComment => lineComment.value).join('\n'), - nodes: currentGroup, - }); - currentGroup = [comment]; - } - } - - if (currentGroup.length > 0) { - groupedComments.push({ - value: currentGroup.map(lineComment => lineComment.value).join('\n'), - nodes: currentGroup, - }); - } - - return groupedComments; - } - - function areAdjacentLineComments(previous: TSESTree.Comment, next: TSESTree.Comment) { - const nextCommentLine = next.loc.start.line; - if (previous.loc.start.line + 1 === nextCommentLine) { - const nextCodeToken = context.getSourceCode().getTokenAfter(previous); - return !nextCodeToken || nextCodeToken.loc.start.line > nextCommentLine; - } - return false; - } - - return { - 'Program:exit': () => { - const groupedComments = getGroupedComments( - context.getSourceCode().getAllComments() as TSESTree.Comment[], - ); - groupedComments.forEach(groupComment => { - const rawTextTrimmed = groupComment.value.trim(); - if (rawTextTrimmed !== '}' && containsCode(injectMissingBraces(rawTextTrimmed))) { - context.report({ - messageId: 'commentedCode', - loc: getCommentLocation(groupComment.nodes), - suggest: [ - { - messageId: 'commentedCodeFix', - fix(fixer) { - const start = groupComment.nodes[0].range[0]; - const end = groupComment.nodes[groupComment.nodes.length - 1].range[1]; - return fixer.removeRange([start, end]); - }, - }, - ], - }); - } - }); - }, - }; - }, -}; - -function isExpressionExclusion(statement: estree.Node, code: SourceCode) { - if (statement.type === 'ExpressionStatement') { - const expression = statement.expression; - if ( - expression.type === 'Identifier' || - expression.type === 'SequenceExpression' || - isUnaryPlusOrMinus(expression) || - isExcludedLiteral(expression) || - !code.getLastToken(statement, token => token.value === ';') - ) { - return true; - } - } - return false; -} - -function isExclusion(parsedBody: Array, code: SourceCode) { - if (parsedBody.length === 1) { - const singleStatement = parsedBody[0]; - return ( - EXCLUDED_STATEMENTS.includes(singleStatement.type) || - isReturnThrowExclusion(singleStatement) || - isExpressionExclusion(singleStatement, code) - ); - } - return false; -} - -function containsCode(value: string) { - if (!couldBeJsCode(value)) { - return false; - } - - try { - const options = buildParserOptions( - { filePath: 'some/filePath', tsConfigs: [], fileContent: '', fileType: 'MAIN' }, - true, - ); - const result = babel.parse(value, options); - const parseResult = new SourceCode(value, result); - return parseResult.ast.body.length > 0 && !isExclusion(parseResult.ast.body, parseResult); - } catch (exception) { - return false; - } - - function couldBeJsCode(input: string): boolean { - return recognizer.extractCodeLines(input.split('\n')).length > 0; - } -} - -function injectMissingBraces(value: string) { - const openCurlyBraceNum = (value.match(/{/g) || []).length; - const closeCurlyBraceNum = (value.match(/}/g) || []).length; - const missingBraces = openCurlyBraceNum - closeCurlyBraceNum; - if (missingBraces > 0) { - return value + Array(missingBraces).fill('}').join(''); - } else if (missingBraces < 0) { - return Array(-missingBraces).fill('{').join('') + value; - } else { - return value; - } -} - -function getCommentLocation(nodes: TSESTree.Comment[]) { - return { - start: nodes[0].loc.start, - end: nodes[nodes.length - 1].loc.end, - }; -} - -function isReturnThrowExclusion(statement: estree.Node) { - if (statement.type === 'ReturnStatement' || statement.type === 'ThrowStatement') { - return statement.argument == null || statement.argument.type === 'Identifier'; - } - return false; -} - -function isUnaryPlusOrMinus(expression: estree.Expression) { - return ( - expression.type === 'UnaryExpression' && - (expression.operator === '+' || expression.operator === '-') - ); -} - -function isExcludedLiteral(expression: estree.Expression) { - if (expression.type === 'Literal') { - return typeof expression.value === 'string' || typeof expression.value === 'number'; - } - return false; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-dead-store.ts b/eslint-bridge/src/linting/eslint/rules/no-dead-store.ts deleted file mode 100644 index 6186e2cf6ce..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-dead-store.ts +++ /dev/null @@ -1,449 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1854/javascript - -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { - isLiteral, - isObjectExpression, - isIdentifier, - isAssignmentExpression, -} from 'eslint-plugin-sonarjs/lib/utils/nodes'; -import CodePath = Rule.CodePath; -import Variable = Scope.Variable; -import CodePathSegment = Rule.CodePathSegment; -import { - isUnaryExpression, - isArrayExpression, - LiveVariables, - lva, - ReferenceLike, - isNullLiteral, -} from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeAssignment: 'Remove this useless assignment to variable "{{variable}}".', - }, - }, - create(context: Rule.RuleContext) { - const codePathStack: CodePathContext[] = []; - const liveVariablesMap = new Map(); - const readVariables = new Set(); - // map from Variable to CodePath ids where variable is used - const variableUsages = new Map>(); - const referencesUsedInDestructuring = new Set(); - const destructuringStack: DestructuringContext[] = []; - - return { - ':matches(AssignmentExpression, VariableDeclarator[init])': (node: estree.Node) => { - pushAssignmentContext(node as AssignmentLike); - }, - ':matches(AssignmentExpression, VariableDeclarator[init]):exit': () => { - popAssignmentContext(); - }, - Identifier: (node: estree.Node) => { - if (isEnumConstant()) { - return; - } - checkIdentifierUsage(node as estree.Identifier); - }, - JSXIdentifier: (node: unknown) => { - checkIdentifierUsage(node as TSESTree.JSXIdentifier); - }, - ObjectPattern: () => { - destructuringStack.push(new DestructuringContext()); - }, - 'ObjectPattern > Property > Identifier': (node: estree.Node) => { - const destructuring = peek(destructuringStack)!; - const { ref } = resolveReference(node as estree.Identifier); - if (ref) { - destructuring.references.push(ref); - } - }, - 'ObjectPattern > :matches(RestElement, ExperimentalRestProperty)': () => { - peek(destructuringStack).hasRest = true; - }, - 'ObjectPattern:exit': () => { - const destructuring = destructuringStack.pop(); - if (destructuring && destructuring.hasRest) { - destructuring.references.forEach(ref => referencesUsedInDestructuring.add(ref)); - } - }, - - 'Program:exit': () => { - lva(liveVariablesMap); - liveVariablesMap.forEach(lva => { - checkSegment(lva); - reportNeverReadVariables(lva); - }); - }, - - // CodePath events - onCodePathSegmentStart: (segment: CodePathSegment) => { - liveVariablesMap.set(segment.id, new LiveVariables(segment)); - }, - onCodePathStart: codePath => { - pushContext(new CodePathContext(codePath)); - }, - onCodePathEnd: () => { - popContext(); - }, - }; - - function pushAssignmentContext(node: AssignmentLike) { - peek(codePathStack).assignmentStack.push(new AssignmentContext(node)); - } - - function popAssignmentContext() { - const assignment = peek(codePathStack).assignmentStack.pop()!; - assignment.rhs.forEach(r => processReference(r)); - assignment.lhs.forEach(r => processReference(r)); - } - - function checkSegment(liveVariables: LiveVariables) { - const willBeRead = new Set(liveVariables.out); - const references = [...liveVariables.references].reverse(); - references.forEach(ref => { - const variable = ref.resolved; - if (!variable) { - return; - } - if (ref.isWrite()) { - if (!willBeRead.has(variable) && shouldReport(ref)) { - report(ref); - } - willBeRead.delete(variable); - } - if (ref.isRead()) { - willBeRead.add(variable); - } - }); - } - - function reportNeverReadVariables(lva: LiveVariables) { - lva.references.forEach(ref => { - if (shouldReportReference(ref) && !readVariables.has(ref.resolved!)) { - report(ref); - } - }); - } - - function shouldReport(ref: ReferenceLike) { - const variable = ref.resolved; - return ( - variable && - shouldReportReference(ref) && - !variableUsedOutsideOfCodePath(variable) && - readVariables.has(variable) - ); - } - - function shouldReportReference(ref: ReferenceLike) { - const variable = ref.resolved; - return ( - variable && - isLocalVar(variable) && - !isReferenceWithBasicValue(ref) && - !isDefaultParameter(ref) && - !referencesUsedInDestructuring.has(ref) && - !variable.name.startsWith('_') && - !isIncrementOrDecrement(ref) && - !isNullAssignment(ref) - ); - } - - function isIncrementOrDecrement(ref: ReferenceLike) { - const parent = (ref.identifier as TSESTree.Identifier).parent; - return parent && parent.type === 'UpdateExpression'; - } - - function isNullAssignment(ref: ReferenceLike) { - const parent = (ref.identifier as TSESTree.Identifier).parent; - return ( - parent && - parent.type === 'AssignmentExpression' && - isNullLiteral(parent.right as estree.Node) - ); - } - - function isEnumConstant() { - return (context.getAncestors() as TSESTree.Node[]).some(n => n.type === 'TSEnumDeclaration'); - } - - function isDefaultParameter(ref: ReferenceLike) { - if (ref.identifier.type !== 'Identifier') { - return false; - } - const parent = (ref.identifier as TSESTree.Identifier).parent; - return parent && parent.type === 'AssignmentPattern'; - } - - function isLocalVar(variable: Variable) { - // @ts-ignore - const scope = variable.scope; - const node = scope.block as TSESTree.Node; - return node.type !== 'Program' && node.type !== 'TSModuleDeclaration'; - } - - function variableUsedOutsideOfCodePath(variable: Scope.Variable) { - return variableUsages.get(variable)!.size > 1; - } - - function isReferenceWithBasicValue(ref: ReferenceLike) { - return ref.init && ref.writeExpr && isBasicValue(ref.writeExpr); - } - - function isBasicValue(node: estree.Node): boolean { - const node1 = node as TSESTree.Node; - if (isLiteral(node1)) { - return node1.value === '' || [0, 1, null, true, false].includes(node1.value as any); - } - if (isIdentifier(node1)) { - return node1.name === 'undefined'; - } - if (isUnaryExpression(node)) { - return isBasicValue(node.argument); - } - if (isObjectExpression(node1)) { - return node1.properties.length === 0; - } - if (isArrayExpression(node)) { - return node.elements.length === 0; - } - return false; - } - - function report(ref: ReferenceLike) { - context.report({ - messageId: 'removeAssignment', - data: { - variable: ref.identifier.name, - }, - loc: ref.identifier.loc!, - }); - } - - function checkIdentifierUsage(node: estree.Identifier | TSESTree.JSXIdentifier) { - const { ref, variable } = - node.type === 'Identifier' ? resolveReference(node) : resolveJSXReference(node); - if (ref) { - processReference(ref); - if (variable) { - updateReadVariables(ref); - } - } - if (variable) { - updateVariableUsages(variable); - } - } - - function resolveJSXReference(node: TSESTree.JSXIdentifier) { - if (isJSXAttributeName(node)) { - return {}; - } - const jsxReference = new JSXReference(node, context.getScope()); - return { ref: jsxReference, variable: jsxReference.resolved }; - } - - function isJSXAttributeName(node: TSESTree.JSXIdentifier) { - const parent = node.parent; - return parent && parent.type === 'JSXAttribute' && parent.name === node; - } - - function processReference(ref: ReferenceLike) { - const assignmentStack = peek(codePathStack).assignmentStack; - if (assignmentStack.length > 0) { - const assignment = peek(assignmentStack); - assignment.add(ref); - } else { - peek(codePathStack).codePath.currentSegments.forEach(segment => { - lvaForSegment(segment).add(ref); - }); - } - } - - function lvaForSegment(segment: CodePathSegment) { - let lva; - if (liveVariablesMap.has(segment.id)) { - lva = liveVariablesMap.get(segment.id)!; - } else { - lva = new LiveVariables(segment); - liveVariablesMap.set(segment.id, lva); - } - return lva; - } - - function updateReadVariables(reference: ReferenceLike) { - const variable = reference.resolved!; - if (reference.isRead()) { - readVariables.add(variable); - } - } - - function updateVariableUsages(variable: Scope.Variable) { - const codePathId = peek(codePathStack).codePath.id; - if (variableUsages.has(variable)) { - variableUsages.get(variable)!.add(codePathId); - } else { - variableUsages.set(variable, new Set([codePathId])); - } - } - - function popContext() { - codePathStack.pop(); - } - - function pushContext(codePathContext: CodePathContext) { - codePathStack.push(codePathContext); - } - - function resolveReference(node: estree.Identifier) { - return resolveReferenceRecursively(node, context.getScope()); - } - - function resolveReferenceRecursively( - node: estree.Identifier, - scope: Scope.Scope | null, - depth = 0, - ): { ref: ReferenceLike | null; variable: Scope.Variable | null } { - if (scope === null || depth > 2) { - return { ref: null, variable: null }; - } - const ref = scope.references.find(r => r.identifier === node); - if (ref) { - return { ref, variable: ref.resolved }; - } else { - // if it's not a reference, it can be just declaration without initializer - const variable = scope.variables.find(v => v.defs.find(def => def.name === node)); - if (variable) { - return { ref: null, variable }; - } - // we only need 1-level recursion, only for switch expression, which is likely a bug in eslint - return resolveReferenceRecursively(node, scope.upper, depth + 1); - } - } - }, -}; - -class CodePathContext { - codePath: CodePath; - segments = new Map(); - assignmentStack: AssignmentContext[] = []; - - constructor(codePath: CodePath) { - this.codePath = codePath; - } -} - -class DestructuringContext { - hasRest = false; - references: ReferenceLike[] = []; -} - -type AssignmentLike = TSESTree.AssignmentExpression | TSESTree.VariableDeclarator; - -class AssignmentContext { - node: AssignmentLike; - - constructor(node: AssignmentLike) { - this.node = node; - } - - lhs = new Set(); - rhs = new Set(); - - isRhs(node: TSESTree.Node) { - return isAssignmentExpression(this.node) ? this.node.right === node : this.node.init === node; - } - - isLhs(node: TSESTree.Node) { - return isAssignmentExpression(this.node) ? this.node.left === node : this.node.id === node; - } - - add(ref: ReferenceLike) { - let parent = ref.identifier as TSESTree.Node | undefined; - while (parent) { - if (this.isLhs(parent)) { - this.lhs.add(ref); - break; - } - if (this.isRhs(parent)) { - this.rhs.add(ref); - break; - } - parent = parent.parent; - } - if (parent === null) { - throw new Error('failed to find assignment lhs/rhs'); - } - } -} - -class JSXReference implements ReferenceLike { - from: Scope.Scope; - identifier: TSESTree.JSXIdentifier; - init = false; - resolved: Scope.Variable | null; - writeExpr: estree.Node | null = null; - - constructor(node: TSESTree.JSXIdentifier, scope: Scope.Scope) { - this.from = scope; - this.identifier = node; - this.resolved = findJSXVariableInScope(node, scope); - } - - isRead(): boolean { - return true; - } - - isReadOnly(): boolean { - return true; - } - - isReadWrite(): boolean { - return false; - } - - isWrite(): boolean { - return false; - } - - isWriteOnly(): boolean { - return false; - } -} - -function findJSXVariableInScope( - node: TSESTree.JSXIdentifier, - scope: Scope.Scope | null, -): Scope.Variable | null { - return ( - scope && - (scope.variables.find(v => v.name === node.name) || findJSXVariableInScope(node, scope.upper)) - ); -} - -function peek(arr: Array) { - return arr[arr.length - 1]; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-delete-var.ts b/eslint-bridge/src/linting/eslint/rules/no-delete-var.ts deleted file mode 100644 index afbd41d27ca..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-delete-var.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3001/javascript - -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeDelete: 'Remove this "delete" operator or pass an object property to it.', - }, - }, - create(context: Rule.RuleContext) { - return { - "UnaryExpression[operator='delete'][argument.type!='MemberExpression'][argument.type!='ChainExpression']": - (node: estree.Node) => { - const { argument } = node as estree.UnaryExpression; - if (!isGlobalProperty(argument, context.getScope().references)) { - context.report({ - messageId: 'removeDelete', - node, - }); - } - }, - }; - }, -}; - -function isGlobalProperty(expr: estree.Expression, references: Scope.Reference[]) { - return ( - expr.type === 'Identifier' && - references.filter(ref => ref.identifier.name === expr.name && ref.resolved).length === 0 - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-duplicate-in-composite.ts b/eslint-bridge/src/linting/eslint/rules/no-duplicate-in-composite.ts deleted file mode 100644 index 51a45979407..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-duplicate-in-composite.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4621/javascript - -import { Rule, AST } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - hasSuggestions: true, - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - - create(context: Rule.RuleContext) { - return { - 'TSUnionType, TSIntersectionType'(node: estree.Node) { - const sourceCode = context.getSourceCode(); - const compositeType = node as unknown as TSESTree.TSUnionType | TSESTree.TSIntersectionType; - const groupedTypes: Map> = new Map(); - - compositeType.types.forEach(typescriptType => { - const nodeValue = sourceCode.getText(typescriptType as unknown as estree.Node); - const nodesWithGivenType = groupedTypes.get(nodeValue); - const nodeType = typescriptType as TSESTree.Node; - if (!nodesWithGivenType) { - groupedTypes.set(nodeValue, [nodeType]); - } else { - nodesWithGivenType.push(nodeType); - } - }); - - groupedTypes.forEach(duplicates => { - if (duplicates.length > 1) { - const suggest = getSuggestions(compositeType, duplicates, context); - const primaryNode = duplicates.splice(1, 1)[0]; - const secondaryMessages = Array(duplicates.length); - secondaryMessages[0] = `Original`; - secondaryMessages.fill(`Another duplicate`, 1, duplicates.length); - - context.report({ - message: toEncodedMessage( - `Remove this duplicated type or replace with another one.`, - duplicates, - secondaryMessages, - ), - loc: primaryNode.loc, - suggest, - }); - } - }); - }, - }; - }, -}; - -function getSuggestions( - composite: TSESTree.TSUnionType | TSESTree.TSIntersectionType, - duplicates: TSESTree.Node[], - context: Rule.RuleContext, -): Rule.SuggestionReportDescriptor[] { - const ranges: [number, number][] = duplicates.slice(1).map(duplicate => { - const idx = composite.types.indexOf(duplicate as TSESTree.TypeNode); - return [ - getEnd(context, composite.types[idx - 1], composite), - getEnd(context, duplicate, composite), - ]; - }); - return [ - { - desc: 'Remove duplicate types', - fix: fixer => ranges.map(r => fixer.removeRange(r)), - }, - ]; -} - -function getEnd(context: Rule.RuleContext, node: TSESTree.Node, composite: TSESTree.Node) { - let end: estree.Node | AST.Token = node as unknown as estree.Node; - while (true) { - const nextToken: AST.Token | null = context.getSourceCode().getTokenAfter(end); - if (nextToken && nextToken.value === ')' && nextToken.range![1] <= composite.range![1]) { - end = nextToken; - } else { - break; - } - } - return end.range![1]; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-empty-after-reluctant.ts b/eslint-bridge/src/linting/eslint/rules/no-empty-after-reluctant.ts deleted file mode 100644 index 012eefb522d..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-empty-after-reluctant.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6019/javascript - -import { Rule } from 'eslint'; -import * as regexpp from 'regexpp'; -import { createRegExpRule, RegexRuleContext } from './helpers/regex'; - -export const rule: Rule.RuleModule = createRegExpRule(context => { - return { - onRegExpLiteralEnter: (node: regexpp.AST.RegExpLiteral) => { - node.pattern.alternatives.forEach(({ elements }) => checkElements(elements, context)); - }, - }; -}); - -function report(quantifier: regexpp.AST.Quantifier, context: RegexRuleContext) { - const ending = quantifier.min === 1 ? '' : 's'; - const message = `Fix this reluctant quantifier that will only ever match ${quantifier.min} repetition${ending}.`; - context.reportRegExpNode({ - message, - regexpNode: quantifier, - node: context.node, - }); -} - -function checkElements(elements: regexpp.AST.Element[], context: RegexRuleContext) { - if (elements.length === 0) { - return; - } - - const lastElement = elements[elements.length - 1]; - if (lastElement.type === 'Quantifier' && !lastElement.greedy) { - report(lastElement, context); - return; - } - - if (elements.length === 1) { - return; - } - - const lastButOneElement = elements[elements.length - 2]; - if (lastButOneElement.type === 'Quantifier' && !lastButOneElement.greedy) { - if (lastElement.type === 'Assertion' && lastElement.kind === 'end') { - context.reportRegExpNode({ - message: `Remove the '?' from this unnecessarily reluctant quantifier.`, - regexpNode: lastButOneElement, - node: context.node, - }); - } else if (lastElement.type === 'Quantifier' && lastElement.min === 0) { - report(lastButOneElement, context); - } - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-empty-alternatives.ts b/eslint-bridge/src/linting/eslint/rules/no-empty-alternatives.ts deleted file mode 100644 index 0d92fc43dfa..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-empty-alternatives.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6323/javascript - -import { Rule } from 'eslint'; -import { last } from './helpers'; -import { Alternation } from './helpers/regex'; -import * as regexpp from 'regexpp'; -import { createRegExpRule } from './helpers/regex'; - -export const rule: Rule.RuleModule = createRegExpRule(context => { - function checkAlternation(alternation: Alternation) { - const { alternatives: alts } = alternation; - if (alts.length <= 1) { - return; - } - for (let i = 0; i < alts.length; i++) { - let alt = alts[i]; - if (alt.elements.length === 0 && !isLastEmptyInGroup(alt)) { - context.reportRegExpNode({ - message: 'Remove this empty alternative.', - regexpNode: alt, - offset: i === alts.length - 1 ? [-1, 0] : [0, 1], // we want to raise the issue on the | - node: context.node, - }); - } - } - } - - return { - onPatternEnter: checkAlternation, - onGroupEnter: checkAlternation, - onCapturingGroupEnter: checkAlternation, - }; -}); - -function isLastEmptyInGroup(alt: regexpp.AST.Alternative) { - const group = alt.parent; - return ( - (group.type === 'Group' || group.type === 'CapturingGroup') && - last(group.alternatives) === alt && - group.parent.type !== 'Quantifier' - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-empty-group.ts b/eslint-bridge/src/linting/eslint/rules/no-empty-group.ts deleted file mode 100644 index 656c099adea..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-empty-group.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6331/javascript - -import { Rule } from 'eslint'; -import { AST } from 'regexpp'; -import { createRegExpRule } from './helpers/regex'; - -export const rule: Rule.RuleModule = createRegExpRule(context => { - function checkEmptyGroup(group: AST.Group | AST.CapturingGroup) { - const { alternatives } = group; - if (alternatives.every(alt => alt.elements.length === 0)) { - context.reportRegExpNode({ - message: 'Remove this empty group.', - node: context.node, - regexpNode: group, - }); - } - } - return { - onGroupEnter: checkEmptyGroup, - onCapturingGroupEnter: checkEmptyGroup, - }; -}); diff --git a/eslint-bridge/src/linting/eslint/rules/no-equals-in-for-termination.ts b/eslint-bridge/src/linting/eslint/rules/no-equals-in-for-termination.ts deleted file mode 100644 index 0b762cec4ae..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-equals-in-for-termination.ts +++ /dev/null @@ -1,221 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S888/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getVariableFromName } from './helpers'; - -const allEqualityOperators = ['!=', '==', '!==', '===']; -const notEqualOperators = ['!==', '!=']; -const plusMinusOperators = ['+=', '-=']; - -interface CompleteForStatement extends estree.BaseStatement { - type: 'ForStatement'; - init?: estree.VariableDeclaration | estree.Expression | null; - test: estree.Expression; - update: estree.Expression; - body: estree.Statement; -} - -export const rule: Rule.RuleModule = { - meta: { - messages: { - replaceOperator: - "Replace '{{operator}}' operator with one of '<=', '>=', '<', or '>' comparison operators.", - }, - }, - create(context: Rule.RuleContext) { - return { - ForStatement: (node: estree.Node) => { - const forStatement = node as estree.ForStatement; - if (!forStatement.test || !forStatement.update) { - return; - } - const completeForStatement = node as CompleteForStatement; - const condition = completeForStatement.test; - if ( - isEquality(condition) && - isUpdateIncDec(completeForStatement.update) && - !isException(completeForStatement, context) - ) { - context.report({ - messageId: 'replaceOperator', - data: { - operator: condition.operator, - }, - node: condition, - }); - } - }, - }; - }, -}; - -function isEquality(expression: estree.Expression): expression is estree.BinaryExpression { - return ( - expression.type === 'BinaryExpression' && allEqualityOperators.includes(expression.operator) - ); -} - -function isUpdateIncDec(expression: estree.Expression): boolean { - if (isIncDec(expression) || expression.type === 'UpdateExpression') { - return true; - } else if (expression.type === 'SequenceExpression') { - return expression.expressions.every(isUpdateIncDec); - } - return false; -} - -function isIncDec(expression: estree.Expression): expression is estree.AssignmentExpression { - return ( - expression.type === 'AssignmentExpression' && plusMinusOperators.includes(expression.operator) - ); -} - -function isException(forStatement: CompleteForStatement, context: Rule.RuleContext) { - return ( - isNontrivialConditionException(forStatement) || - isTrivialIteratorException(forStatement, context) - ); -} - -function isNontrivialConditionException(forStatement: CompleteForStatement) { - //If we reach this point, we know that test is an equality kind - const condition = forStatement.test as estree.BinaryExpression; - const counters: Array = []; - collectCounters(forStatement.update, counters); - return condition.left.type !== 'Identifier' || !counters.includes(condition.left.name); -} - -function collectCounters(expression: estree.Expression, counters: Array) { - let counter: estree.Node | null | undefined = undefined; - - if (isIncDec(expression)) { - counter = expression.left; - } else if (expression.type === 'UpdateExpression') { - counter = expression.argument; - } else if (expression.type === 'SequenceExpression') { - expression.expressions.forEach(e => collectCounters(e, counters)); - } - - if (counter && counter.type === 'Identifier') { - counters.push(counter.name); - } -} - -function isTrivialIteratorException(forStatement: CompleteForStatement, context: Rule.RuleContext) { - const init = forStatement.init; - const condition = forStatement.test; - - if (init && isNotEqual(condition)) { - const updatedByOne = checkForUpdateByOne(forStatement.update, forStatement.body, context); - if (updatedByOne !== 0) { - const beginValue = getValue(init); - const endValue = getValue(condition); - return ( - beginValue !== undefined && - endValue !== undefined && - updatedByOne === Math.sign(endValue - beginValue) - ); - } - } - - return false; -} - -function isNotEqual(node: estree.Node): node is estree.BinaryExpression { - return node.type === 'BinaryExpression' && notEqualOperators.includes(node.operator); -} - -function checkForUpdateByOne( - update: estree.Expression, - loopBody: estree.Node, - context: Rule.RuleContext, -) { - if (isUpdateByOne(update, loopBody, context)) { - if (update.operator === '++' || update.operator === '+=') { - return +1; - } - if (update.operator === '--' || update.operator === '-=') { - return -1; - } - } - return 0; -} - -function isUpdateByOne( - update: estree.Expression, - loopBody: estree.Node, - context: Rule.RuleContext, -): update is estree.UpdateExpression | estree.AssignmentExpression { - return ( - (update.type === 'UpdateExpression' && !isUsedInsideBody(update.argument, loopBody, context)) || - (isUpdateOnOneWithAssign(update) && !isUsedInsideBody(update.left, loopBody, context)) - ); -} - -function isUsedInsideBody(id: estree.Node, loopBody: estree.Node, context: Rule.RuleContext) { - if (id.type === 'Identifier') { - const variable = getVariableFromName(context, id.name); - const bodyRange = loopBody.range; - if (variable && bodyRange) { - return variable.references.some(ref => isInBody(ref.identifier, bodyRange)); - } - } - return false; -} - -function isInBody(id: estree.Identifier, bodyRange: [number, number]) { - return id && id.range && id.range[0] > bodyRange[0] && id.range[1] < bodyRange[1]; -} - -function getValue(node: estree.Node) { - if (isNotEqual(node)) { - return getInteger(node.right); - } else if (isOneVarDeclaration(node)) { - const variable = node.declarations[0]; - return getInteger(variable.init); - } else if (node.type === 'AssignmentExpression') { - return getInteger(node.right); - } - return undefined; -} - -function getInteger(node: estree.Node | undefined | null) { - if (node && node.type === 'Literal' && typeof node.value === 'number') { - return node.value; - } - return undefined; -} - -function isOneVarDeclaration(node: estree.Node): node is estree.VariableDeclaration { - return node.type === 'VariableDeclaration' && node.declarations.length === 1; -} - -function isUpdateOnOneWithAssign( - expression: estree.Expression, -): expression is estree.AssignmentExpression { - if (isIncDec(expression)) { - const right = expression.right; - return right.type === 'Literal' && right.value === 1; - } - return false; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-exclusive-tests.ts b/eslint-bridge/src/linting/eslint/rules/no-exclusive-tests.ts deleted file mode 100644 index eb326b1773e..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-exclusive-tests.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6426/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isMethodCall, isIdentifier } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - hasSuggestions: true, - messages: { - issue: 'Remove ".only()" from your test case.', - quickfix: 'Remove ."only()".', - }, - }, - create(context: Rule.RuleContext) { - return { - CallExpression: (node: estree.CallExpression) => { - if (isMethodCall(node)) { - const { property, object } = node.callee; - if (isIdentifier(property, 'only') && isIdentifier(object, 'describe', 'it', 'test')) { - context.report({ - messageId: 'issue', - node: property, - suggest: [ - { - fix: (fixer: Rule.RuleFixer) => { - const fixes = [fixer.remove(property)]; - const dotBeforeOnly = context.getSourceCode().getTokenBefore(property); - if (dotBeforeOnly != null) { - fixes.push(fixer.remove(dotBeforeOnly)); - } - return fixes; - }, - messageId: 'quickfix', - }, - ], - }); - } - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-for-in-iterable.ts b/eslint-bridge/src/linting/eslint/rules/no-for-in-iterable.ts deleted file mode 100644 index feb66d65d58..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-for-in-iterable.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4139/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import ts from 'typescript'; -import { getTypeFromTreeNode, isRequiredParserServices } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - useForOf: 'Use "for...of" to iterate over this "{{iterable}}".', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - return { - ForInStatement: (node: estree.Node) => { - const type = getTypeFromTreeNode((node as estree.ForInStatement).right, services); - if (isIterable(type)) { - const iterable = type.symbol ? type.symbol.name : 'String'; - context.report({ - messageId: 'useForOf', - data: { iterable }, - loc: context.getSourceCode().getFirstToken(node)!.loc, - }); - } - }, - }; - }, -}; - -function isIterable(type: ts.Type) { - return isCollection(type) || isString(type); -} - -function isCollection(type: ts.Type) { - return ( - type.symbol !== undefined && - [ - 'Array', - 'Int8Array', - 'Uint8Array', - 'Uint8ClampedArray', - 'Int16Array', - 'Uint16Array', - 'Int32Array', - 'Uint32Array', - 'Float32Array', - 'Float64Array', - 'BigInt64Array', - 'BigUint64Array', - 'Set', - 'Map', - ].includes(type.symbol.name) - ); -} - -function isString(type: ts.Type) { - return ( - (type.symbol !== undefined && type.symbol.name === 'String') || - (type.flags & ts.TypeFlags.StringLike) !== 0 - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-function-declaration-in-block.ts b/eslint-bridge/src/linting/eslint/rules/no-function-declaration-in-block.ts deleted file mode 100644 index d808b071bb9..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-function-declaration-in-block.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1530/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getMainFunctionTokenLocation } from 'eslint-plugin-sonarjs/lib/utils/locations'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { getParent, RuleContext } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - blockedFunction: 'Do not use function declarations within blocks.', - }, - }, - create(context: Rule.RuleContext) { - return { - ':not(FunctionDeclaration, FunctionExpression, ArrowFunctionExpression) > BlockStatement > FunctionDeclaration': - (node: estree.Node) => { - context.report({ - messageId: 'blockedFunction', - loc: getMainFunctionTokenLocation( - node as TSESTree.FunctionDeclaration, - getParent(context) as TSESTree.Node, - context as unknown as RuleContext, - ), - }); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-global-this.ts b/eslint-bridge/src/linting/eslint/rules/no-global-this.ts deleted file mode 100644 index 2a377c883fe..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-global-this.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2990/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -export const rule: Rule.RuleModule = { - meta: { - hasSuggestions: true, - messages: { - removeThis: `Remove the use of "this".`, - suggestRemoveThis: 'Remove "this"', - suggestUseWindow: 'Replace "this" with "window" object', - }, - }, - create(context: Rule.RuleContext) { - return { - 'MemberExpression[object.type="ThisExpression"]'(node: estree.Node) { - const memberExpression = node as estree.MemberExpression; - const scopeType = context.getScope().variableScope.type; - const isInsideClass = context - .getAncestors() - .some( - ancestor => ancestor.type === 'ClassDeclaration' || ancestor.type === 'ClassExpression', - ); - if ((scopeType === 'global' || scopeType === 'module') && !isInsideClass) { - const suggest: Rule.SuggestionReportDescriptor[] = []; - if (!memberExpression.computed) { - const propertyText = context.getSourceCode().getText(memberExpression.property); - suggest.push( - { - messageId: 'suggestRemoveThis', - fix: fixer => fixer.replaceText(node, propertyText), - }, - { - messageId: 'suggestUseWindow', - fix: fixer => fixer.replaceText(memberExpression.object, 'window'), - }, - ); - } - context.report({ - messageId: 'removeThis', - node: memberExpression.object, - suggest, - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-globals-shadowing.ts b/eslint-bridge/src/linting/eslint/rules/no-globals-shadowing.ts deleted file mode 100644 index 7b8f2d15de8..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-globals-shadowing.ts +++ /dev/null @@ -1,124 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2137/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -const illegalNames = ['eval', 'arguments', 'undefined', 'NaN', 'Infinity']; - -const getDeclarationIssue = (redeclareType: string) => (name: string) => ({ - messageId: 'forbidDeclaration', - data: { symbol: name, type: redeclareType }, -}); - -const getModificationIssue = (functionName: string) => ({ - messageId: 'removeModification', - data: { symbol: functionName }, -}); - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeModification: 'Remove the modification of "{{symbol}}".', - forbidDeclaration: 'Do not use "{{symbol}}" to declare a {{type}} - use another name.', - }, - }, - create(context: Rule.RuleContext) { - return { - 'FunctionDeclaration, FunctionExpression': function (node: estree.Node) { - const func = node as estree.FunctionDeclaration | estree.FunctionExpression; - reportBadUsageOnFunction(func, func.id, context); - }, - ArrowFunctionExpression: function (node: estree.Node) { - reportBadUsageOnFunction(node as estree.ArrowFunctionExpression, undefined, context); - }, - VariableDeclaration(node: estree.Node) { - (node as estree.VariableDeclaration).declarations.forEach(decl => { - reportBadUsage(decl.id, getDeclarationIssue('variable'), context); - }); - }, - UpdateExpression(node: estree.Node) { - reportBadUsage((node as estree.UpdateExpression).argument, getModificationIssue, context); - }, - AssignmentExpression(node: estree.Node) { - reportBadUsage((node as estree.AssignmentExpression).left, getModificationIssue, context); - }, - CatchClause(node: estree.Node) { - reportBadUsage( - (node as estree.CatchClause).param, - getDeclarationIssue('variable'), - context, - ); - }, - }; - }, -}; - -function reportBadUsageOnFunction( - func: estree.Function, - id: estree.Node | null | undefined, - context: Rule.RuleContext, -) { - reportBadUsage(id, getDeclarationIssue('function'), context); - func.params.forEach(p => { - reportBadUsage(p, getDeclarationIssue('parameter'), context); - }); -} - -function reportBadUsage( - node: estree.Node | null | undefined, - buildMessageAndData: (name: string) => { messageId: string; data: any }, - context: Rule.RuleContext, -) { - if (node) { - switch (node.type) { - case 'Identifier': { - if (illegalNames.includes(node.name)) { - context.report({ - node: node, - ...buildMessageAndData(node.name), - }); - } - break; - } - case 'RestElement': - reportBadUsage(node.argument, buildMessageAndData, context); - break; - case 'ObjectPattern': - node.properties.forEach(prop => { - if (prop.type === 'Property') { - reportBadUsage(prop.value, buildMessageAndData, context); - } else { - reportBadUsage(prop.argument, buildMessageAndData, context); - } - }); - break; - case 'ArrayPattern': - node.elements.forEach(elem => { - reportBadUsage(elem, buildMessageAndData, context); - }); - break; - case 'AssignmentPattern': - reportBadUsage(node.left, buildMessageAndData, context); - break; - } - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-hardcoded-credentials.ts b/eslint-bridge/src/linting/eslint/rules/no-hardcoded-credentials.ts deleted file mode 100644 index 35cde9816a7..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-hardcoded-credentials.ts +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2068/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isStringLiteral } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - reviewCredential: 'Review this potentially hardcoded credential.', - }, - }, - create(context: Rule.RuleContext) { - const variableNames = context.options; - const literalRegExp = variableNames.map(name => new RegExp(`${name}=.+`)); - return { - VariableDeclarator: (node: estree.Node) => { - const declaration = node as estree.VariableDeclarator; - checkAssignment(context, variableNames, declaration.id, declaration.init); - }, - AssignmentExpression: (node: estree.Node) => { - const assignment = node as estree.AssignmentExpression; - checkAssignment(context, variableNames, assignment.left, assignment.right); - }, - Property: (node: estree.Node) => { - const property = node as estree.Property; - checkAssignment(context, variableNames, property.key, property.value); - }, - Literal: (node: estree.Node) => { - const literal = node as estree.Literal; - checkLiteral(context, literalRegExp, literal); - }, - }; - }, -}; - -function checkAssignment( - context: Rule.RuleContext, - patterns: string[], - variable: estree.Node, - initializer?: estree.Node | null, -) { - if ( - initializer && - isStringLiteral(initializer) && - (initializer.value as string).length > 0 && - patterns.some(pattern => context.getSourceCode().getText(variable).includes(pattern)) - ) { - context.report({ - messageId: 'reviewCredential', - node: initializer, - }); - } -} - -function checkLiteral(context: Rule.RuleContext, patterns: RegExp[], literal: estree.Literal) { - if (isStringLiteral(literal) && patterns.some(pattern => pattern.test(literal.value as string))) { - context.report({ - messageId: 'reviewCredential', - node: literal, - }); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-hardcoded-ip.ts b/eslint-bridge/src/linting/eslint/rules/no-hardcoded-ip.ts deleted file mode 100644 index 6e2e4742fb9..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-hardcoded-ip.ts +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1313/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isIP } from 'net'; - -const netMaskRegex = /(^[^\/]+)\/\d{1,3}$/; -const acceptedIpAddresses = ['255.255.255.255', '::1', '::', '0:0:0:0:0:0:0:1', '0:0:0:0:0:0:0:0']; -const ipV4Octets = 4; -const ipV4MappedToV6Prefix = '::ffff:0:'; -const acceptedIpV6Starts = [ - // https://datatracker.ietf.org/doc/html/rfc3849 - '2001:db8:', -]; -const acceptedIpV4Starts = [ - '127.', - '0.', - // avoid FP for OID http://www.oid-info.com/introduction.htm - '2.5', - // https://datatracker.ietf.org/doc/html/rfc5737 - '192.0.2.', - '198.51.100.', - '203.0.113.', -]; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - checkIP: 'Make sure using a hardcoded IP address {{ip}} is safe here.', - }, - }, - create(context: Rule.RuleContext) { - function isException(ip: string) { - return ( - acceptedIpV6Starts.some(prefix => ip.startsWith(prefix)) || - acceptedIpV4Starts.some( - prefix => ip.startsWith(ipV4MappedToV6Prefix + prefix) || ip.startsWith(prefix), - ) || - acceptedIpAddresses.includes(ip) - ); - } - function isIPV4OctalOrHex(ip: string) { - const digits = ip.split('.'); - if (digits.length !== ipV4Octets) { - return false; - } - const decimalDigits = []; - for (const digit of digits) { - if (digit.match(/^0[0-7]*$/)) { - decimalDigits.push(parseInt(digit, 8)); - } else if (digit.match(/^0[xX][0-9a-fA-F]+$/)) { - decimalDigits.push(parseInt(digit, 16)); - } else { - return false; - } - } - const convertedIp = `${decimalDigits[0]}.${decimalDigits[1]}.${decimalDigits[2]}.${decimalDigits[3]}`; - return !isException(convertedIp) && isIP(convertedIp) !== 0; - } - return { - Literal(node: estree.Node) { - const { value } = node as estree.Literal; - if (typeof value !== 'string') { - return; - } - let ip = value; - const result = value.match(netMaskRegex); - if (result) { - ip = result[1]; - } - if ((!isException(ip) && isIP(ip) !== 0) || isIPV4OctalOrHex(ip)) { - context.report({ - node, - messageId: 'checkIP', - data: { - ip: value, - }, - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-hook-setter-in-body.ts b/eslint-bridge/src/linting/eslint/rules/no-hook-setter-in-body.ts deleted file mode 100644 index 7e8848b21a0..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-hook-setter-in-body.ts +++ /dev/null @@ -1,173 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6442/javascript - -import { Rule, Scope as ESLintScope } from 'eslint'; -import Variable = ESLintScope.Variable; -import Scope = ESLintScope.Scope; -import * as estree from 'estree'; -import { - findFirstMatchingLocalAncestor, - getFullyQualifiedName, - getVariableFromName, - isFunctionNode, - isIdentifier, -} from './helpers'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -type HookDeclarator = estree.VariableDeclarator & { - id: { - elements: estree.Identifier[]; - }; - init: estree.CallExpression; -}; - -type SetterCall = estree.CallExpression & { - callee: estree.Identifier; -}; - -const REACT_MODULE = 'react'; -const REACT_PATTERN = /^[^a-z]/; -const HOOK_FUNCTION = 'useState'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - noHookSetterInBody: - 'Remove this state setter call, perhaps move it to an event handler or JSX attribute', - }, - }, - create(context: Rule.RuleContext) { - function isHookCall(node: estree.CallExpression): boolean { - return ( - getFullyQualifiedName(context, node) === `${REACT_MODULE}.${HOOK_FUNCTION}` && - node.arguments.length === 1 - ); - } - - function getReactComponentScope(): Scope | null { - const scope = context.getScope(); - const isReact = isFunctionNode(scope.block) && matchesReactComponentName(scope.block, 1); - return isReact ? scope : null; - } - - function isInsideFunctionScope(scope: Scope | null): boolean { - function searchUpperFunctionScope(current: Scope | null): Scope | null { - if (current === null) { - return null; - } else if (current.type === 'function') { - return current; - } else { - return searchUpperFunctionScope(current.upper); - } - } - - return scope !== null && searchUpperFunctionScope(context.getScope()) === scope; - } - - function isInsideConditional(node: estree.Node): boolean { - return ( - findFirstMatchingLocalAncestor(node as TSESTree.Node, n => n.type === 'IfStatement') !== - undefined - ); - } - - let reactComponentScope: Scope | null; // Scope of the React component render function. - const setters: Variable[] = []; // Setter variables returned by the React useState() function. - - return { - ':function'() { - reactComponentScope ??= getReactComponentScope(); // Store the top-most React component scope. - }, - - ':function:exit'() { - if (context.getScope() === reactComponentScope) { - // Clean variables when leaving the React component scope. - reactComponentScope = null; - setters.length = 0; - } - }, - - // Selector matching declarations like: const [count, setCount] = useState(0); - ['VariableDeclarator[init.type="CallExpression"]' + - ':has(ArrayPattern[elements.length=2][elements.0.type="Identifier"][elements.1.type="Identifier"])']( - node: estree.VariableDeclarator, - ) { - if (!isInsideFunctionScope(reactComponentScope)) { - return; - } - - const hookDeclarator = node as HookDeclarator; - - if (isHookCall(hookDeclarator.init)) { - const variable = getVariableFromName(context, hookDeclarator.id.elements[1].name); - if (variable != null) { - setters.push(variable); - } - } - }, - - // Selector matching function calls like: setCount(1) - 'CallExpression[callee.type="Identifier"][arguments.length=1]'(node: estree.CallExpression) { - if ( - !isInsideFunctionScope(reactComponentScope) || - setters.length === 0 || - isInsideConditional(node) - ) { - return; - } - - const maybeSetterCall = node as SetterCall; - - const calleeVariable = getVariableFromName(context, maybeSetterCall.callee.name); - if (setters.some(variable => variable === calleeVariable)) { - context.report({ - messageId: 'noHookSetterInBody', - node: node.callee, - }); - } - }, - }; - }, -}; - -function hasParent(node: estree.Node): node is Rule.Node { - return (node as Rule.Node).parent != null; -} - -function matchesReactComponentName(node: estree.Node | null, max = 0): boolean { - if (node == null) { - return false; - } else if (isIdentifier(node)) { - return REACT_PATTERN.test(node.name); - } else if (node.type === 'FunctionDeclaration') { - return matchesReactComponentName(node.id); - } else if (node.type === 'VariableDeclarator') { - return matchesReactComponentName(node.id); - } else if (node.type === 'AssignmentExpression') { - return matchesReactComponentName(node.left); - } else if (node.type === 'MemberExpression') { - return matchesReactComponentName(node.property); - } else if (hasParent(node) && max > 0) { - return matchesReactComponentName(node.parent, max - 1); - } else { - return false; - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-implicit-dependencies.ts b/eslint-bridge/src/linting/eslint/rules/no-implicit-dependencies.ts deleted file mode 100644 index 5f6af30d87b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-implicit-dependencies.ts +++ /dev/null @@ -1,279 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4328/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import builtins from 'builtin-modules'; -import * as path from 'path'; -import * as fs from 'fs'; -import * as ts from 'typescript'; -import { RequiredParserServices } from './helpers'; -import { stripBOM } from 'helpers'; - -const DefinitelyTyped = '@types/'; - -/** - * Cache for each dirname the dependencies of the package.json in this directory, empty set when no package.json. - */ -const dirCache: Map> = new Map(); - -/** - * Cache for the available dependencies by dirname. - */ -const cache: Map> = new Map(); - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeOrAddDependency: 'Either remove this import or add it as a dependency.', - }, - }, - create(context: Rule.RuleContext) { - const whitelist = context.options; - const dependencies = getDependencies(context.getFilename()); - const aliasedPathsMappingPatterns = extractPathMappingPatterns(context.parserServices); - const baseUrl = getBaseUrl(context.parserServices); - if (aliasedPathsMappingPatterns === 'matchAll') { - // deactivates this rule altogether. - return {}; - } - return { - CallExpression: (node: estree.Node) => { - const call = node as estree.CallExpression; - if ( - call.callee.type === 'Identifier' && - call.callee.name === 'require' && - call.arguments.length === 1 - ) { - const [argument] = call.arguments; - if (argument.type === 'Literal') { - const requireToken = call.callee; - raiseOnImplicitImport( - argument, - requireToken.loc!, - dependencies, - whitelist, - aliasedPathsMappingPatterns, - baseUrl, - context, - ); - } - } - }, - ImportDeclaration: (node: estree.Node) => { - const module = (node as estree.ImportDeclaration).source; - const importToken = context.getSourceCode().getFirstToken(node); - raiseOnImplicitImport( - module, - importToken!.loc, - dependencies, - whitelist, - aliasedPathsMappingPatterns, - baseUrl, - context, - ); - }, - }; - }, -}; - -function raiseOnImplicitImport( - module: estree.Literal, - loc: estree.SourceLocation, - dependencies: Set, - whitelist: string[], - aliasedPathsMappingPatterns: PathMappingPattern[], - baseUrl: string | undefined, - context: Rule.RuleContext, -) { - const moduleName = module.value; - if (typeof moduleName !== 'string') { - return; - } - - if (ts.isExternalModuleNameRelative(moduleName)) { - return; - } - - if (aliasedPathsMappingPatterns.some(pattern => pattern.isApplicableTo(moduleName))) { - return; - } - - if (['node:', 'data:', 'file:'].some(prefix => moduleName.startsWith(prefix))) { - return; - } - - if (baseUrl) { - const underBaseUrlPath = path.join(baseUrl, moduleName); - const extensions = ['', '.ts', '.d.ts', '.tsx', '.js', '.jsx', '.vue', '.mjs']; - if (extensions.some(extension => fs.existsSync(underBaseUrlPath + extension))) { - return; - } - } - - const packageName = getPackageName(moduleName); - if ( - !whitelist.includes(packageName) && - !builtins.includes(packageName) && - !dependencies.has(packageName) - ) { - context.report({ - messageId: 'removeOrAddDependency', - loc, - }); - } -} - -function getPackageName(name: string) { - /* - - scoped `@namespace/foo/bar` -> package `@namespace/foo` - - scope `foo/bar` -> package `foo` - */ - const parts = name.split('/'); - if (!name.startsWith('@')) { - return parts[0]; - } else { - return `${parts[0]}/${parts[1]}`; - } -} - -function getDependencies(fileName: string) { - let dirname = path.dirname(fileName); - const cached = cache.get(dirname); - if (cached) { - return cached; - } - - const result = new Set(); - cache.set(dirname, result); - - while (true) { - const dirCached = dirCache.get(dirname); - if (dirCached) { - dirCached.forEach(d => result.add(d)); - } else { - const packageJsonPath = path.join(path.resolve(dirname), 'package.json'); - const dep = fs.existsSync(packageJsonPath) - ? getDependenciesFromPackageJson(packageJsonPath) - : new Set(); - dep.forEach(d => result.add(d)); - dirCache.set(dirname, dep); - } - - const upperDir = path.dirname(dirname); - if (upperDir === dirname) { - break; - } else { - dirname = upperDir; - } - } - - return result; -} - -function getDependenciesFromPackageJson(packageJsonPath: string) { - const result = new Set(); - try { - const content = JSON.parse(readFile(packageJsonPath)); - if (content.dependencies !== undefined) { - addDependencies(result, content.dependencies); - } - if (content.devDependencies !== undefined) { - addDependencies(result, content.devDependencies); - } - if (content.peerDependencies !== undefined) { - addDependencies(result, content.peerDependencies); - } - } catch {} - return result; -} - -function addDependencies(result: Set, dependencies: any) { - Object.keys(dependencies).forEach(name => - result.add(name.startsWith(DefinitelyTyped) ? name.substring(DefinitelyTyped.length) : name), - ); -} - -/** - * The matching pattern part of a path mapping specified - * in `paths` in `tsconfig.json`. - */ -interface PathMappingPattern { - isApplicableTo(name: string): boolean; -} - -class PathMappingNoAsteriskPattern implements PathMappingPattern { - constructor(private readonly value: string) {} - isApplicableTo(name: string): boolean { - return name === this.value; - } -} - -class PathMappingSingleAsteriskPattern implements PathMappingPattern { - constructor(private readonly prefix: string, private readonly suffix: string) {} - isApplicableTo(name: string): boolean { - return name.startsWith(this.prefix) && name.endsWith(this.suffix); - } -} - -const PATH_MAPPING_ASTERISK_PATTERN = /^([^*]*)\*([^*]*)$/; // matches any string with single asterisk '*' -const PATH_MAPPING_ASTERISK_PATTERN_PREFIX_IDX = 1; -const PATH_MAPPING_ASTERISK_PATTERN_SUFFIX_IDX = 2; -function extractPathMappingPatterns( - parserServices: RequiredParserServices, -): PathMappingPattern[] | 'matchAll' { - const compilerOptions = parserServices.program && parserServices.program.getCompilerOptions(); - const paths = (compilerOptions && compilerOptions.paths) || []; - const pathMappingPatterns: PathMappingPattern[] = []; - for (const p in paths) { - if (p === '*') { - return 'matchAll'; - } else { - const m = p.match(PATH_MAPPING_ASTERISK_PATTERN); - if (m) { - pathMappingPatterns.push( - new PathMappingSingleAsteriskPattern( - m[PATH_MAPPING_ASTERISK_PATTERN_PREFIX_IDX], - m[PATH_MAPPING_ASTERISK_PATTERN_SUFFIX_IDX], - ), - ); - } else if (!p.includes('*')) { - pathMappingPatterns.push(new PathMappingNoAsteriskPattern(p)); - } else { - // This case should not occur: `tsc` emits error if there is more than one asterisk - } - } - } - return pathMappingPatterns; -} - -function getBaseUrl(parserServices: RequiredParserServices): string | undefined { - if (parserServices.program && parserServices.program.getCompilerOptions()) { - return parserServices.program.getCompilerOptions().baseUrl; - } - - return undefined; -} - -function readFile(filePath: string) { - const fileContent = fs.readFileSync(filePath, { encoding: 'utf8' }); - return stripBOM(fileContent); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-implicit-global.ts b/eslint-bridge/src/linting/eslint/rules/no-implicit-global.ts deleted file mode 100644 index ba64230dfb5..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-implicit-global.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2703/javascript - -import { Rule } from 'eslint'; -import { flatMap, globalsByLibraries } from './helpers'; - -const excludedNames = new Set(flatMap(Object.values(globalsByLibraries), globals => globals)); - -export const rule: Rule.RuleModule = { - meta: { - messages: { - explicitModifier: - 'Add the "let", "const" or "var" keyword to this declaration of "{{variable}}" to make it explicit.', - }, - }, - create(context: Rule.RuleContext) { - return { - 'Program:exit'() { - const globalScope = context.getScope(); - const alreadyReported: Set = new Set(); - globalScope.through - .filter(ref => ref.isWrite()) - .forEach(ref => { - const name = ref.identifier.name; - if (!alreadyReported.has(name) && !excludedNames.has(name)) { - alreadyReported.add(name); - context.report({ - messageId: 'explicitModifier', - data: { - variable: name, - }, - node: ref.identifier, - }); - } - }); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-in-misuse.ts b/eslint-bridge/src/linting/eslint/rules/no-in-misuse.ts deleted file mode 100644 index af32d50fc68..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-in-misuse.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4619/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isArray, isNumber, isRequiredParserServices } from './helpers'; -import { isLiteral } from 'eslint-plugin-sonarjs/lib/utils/nodes'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -export const rule: Rule.RuleModule = { - meta: { - hasSuggestions: true, - messages: { - inMisuse: 'Use "indexOf" or "includes" (available from ES2016) instead.', - suggestIndexOf: 'Replace with "indexOf" method', - suggestIncludes: 'Replace with "includes" method', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - - function prototypeProperty(node: estree.Expression) { - const expr = node as TSESTree.Expression; - if (!isLiteral(expr) || typeof expr.value !== 'string') { - return false; - } - - return ['indexOf', 'lastIndexOf', 'forEach', 'map', 'filter', 'every', 'some'].includes( - expr.value, - ); - } - - if (isRequiredParserServices(services)) { - return { - "BinaryExpression[operator='in']": (node: estree.Node) => { - const { left, right } = node as estree.BinaryExpression; - if (isArray(right, services) && !prototypeProperty(left) && !isNumber(left, services)) { - const leftText = context.getSourceCode().getText(left); - const rightText = context.getSourceCode().getText(right); - context.report({ - messageId: 'inMisuse', - node, - suggest: [ - { - messageId: 'suggestIndexOf', - fix: fixer => fixer.replaceText(node, `${rightText}.indexOf(${leftText}) > -1`), - }, - { - messageId: 'suggestIncludes', - fix: fixer => fixer.replaceText(node, `${rightText}.includes(${leftText})`), - }, - ], - }); - } - }, - }; - } - return {}; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-incomplete-assertions.ts b/eslint-bridge/src/linting/eslint/rules/no-incomplete-assertions.ts deleted file mode 100644 index b195b0e9c1a..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-incomplete-assertions.ts +++ /dev/null @@ -1,171 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2970/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isIdentifier, isNumberLiteral } from './helpers'; - -const assertionFunctions = [ - 'a', - 'an', - 'include', - 'includes', - 'contain', - 'contains', - 'equal', - 'equals', - 'eq', - 'eql', - 'eqls', - 'above', - 'gt', - 'greaterThan', - 'least', - 'gte', - 'below', - 'lt', - 'lessThan', - 'most', - 'lte', - 'within', - 'instanceof', - 'instanceOf', - 'property', - 'ownPropertyDescriptor', - 'haveOwnPropertyDescriptor', - 'lengthOf', - 'length', - 'match', - 'matches', - 'string', - 'key', - 'keys', - 'throw', - 'throws', - 'Throw', - 'respondTo', - 'respondsTo', - 'satisfy', - 'satisfies', - 'closeTo', - 'approximately', - 'members', - 'oneOf', - 'change', - 'changes', - 'increase', - 'increases', - 'decrease', - 'decreases', - 'by', - 'fail', -]; - -const gettersOrModifiers = [ - 'to', - 'be', - 'been', - 'is', - 'that', - 'which', - 'and', - 'has', - 'have', - 'with', - 'at', - 'of', - 'same', - 'but', - 'does', - 'still', - - // Modifier functions - 'not', - 'deep', - 'nested', - 'own', - 'ordered', - 'any', - 'all', - 'itself', - - 'should', -]; - -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - return { - ExpressionStatement(node: estree.Node) { - const exprStatement = node as estree.ExpressionStatement; - if (exprStatement.expression.type === 'MemberExpression') { - const { property } = exprStatement.expression; - if (isTestAssertion(exprStatement.expression)) { - if (isIdentifier(property, ...assertionFunctions)) { - context.report({ - node: property, - message: `Call this '${property.name}' assertion.`, - }); - } - if (isIdentifier(property, ...gettersOrModifiers)) { - context.report({ - node: property, - message: `Complete this assertion; '${property.name}' doesn't assert anything by itself.`, - }); - } - } - } - if (isExpectCall(exprStatement.expression)) { - const { callee } = exprStatement.expression; - context.report({ - node: callee, - message: `Complete this assertion; '${callee.name}' doesn't assert anything by itself.`, - }); - } - }, - }; - }, -}; - -function isTestAssertion(node: estree.MemberExpression): boolean { - const { object, property } = node; - // Chai's BDD style where 'should' extends Object.prototype https://www.chaijs.com/guide/styles/ - if (isIdentifier(object) && isIdentifier(property, 'should')) { - return true; - } - if (isExpectCall(object) || isIdentifier(object, 'assert', 'expect', 'should')) { - return true; - } else if (object.type === 'MemberExpression') { - return isTestAssertion(object); - } else if (object.type === 'CallExpression' && object.callee.type === 'MemberExpression') { - return isTestAssertion(object.callee); - } - return false; -} - -function isExpectCall( - node: estree.Node, -): node is estree.CallExpression & { callee: estree.Identifier } { - return ( - node.type === 'CallExpression' && - isIdentifier(node.callee, 'expect') && - !isNumberLiteral(node.arguments[0]) - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-inconsistent-returns.ts b/eslint-bridge/src/linting/eslint/rules/no-inconsistent-returns.ts deleted file mode 100644 index 4e5670b2067..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-inconsistent-returns.ts +++ /dev/null @@ -1,181 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3801/javascript - -import { AST, Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { getMainFunctionTokenLocation } from 'eslint-plugin-sonarjs/lib/utils/locations'; -import { getParent, RuleContext, toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -interface FunctionContext { - codePath: Rule.CodePath; - containsReturnWithValue: boolean; - containsReturnWithoutValue: boolean; - containsImplicitReturn: boolean; - returnStatements: estree.ReturnStatement[]; -} - -interface FunctionLikeDeclaration { - type: string; - id?: estree.Node | null; - returnType?: TSESTree.TSTypeAnnotation; -} - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - - create(context: Rule.RuleContext) { - const sourceCode = context.getSourceCode(); - const functionContextStack: FunctionContext[] = []; - const checkOnFunctionExit = (node: estree.Node) => - checkFunctionLikeDeclaration( - node as FunctionLikeDeclaration, - functionContextStack[functionContextStack.length - 1], - ); - - function checkFunctionLikeDeclaration( - node: FunctionLikeDeclaration, - functionContext?: FunctionContext, - ) { - if ( - !functionContext || - (!!node.returnType && - declaredReturnTypeContainsVoidOrNeverTypes(node.returnType.typeAnnotation)) - ) { - return; - } - - checkFunctionForImplicitReturn(functionContext); - - if (hasInconsistentReturns(functionContext)) { - const [secondaryLocationsHolder, secondaryLocationMessages] = getSecondaryLocations( - functionContext, - node as estree.Node, - ); - const message = toEncodedMessage( - `Refactor this function to use "return" consistently.`, - secondaryLocationsHolder, - secondaryLocationMessages, - ); - - context.report({ - message, - loc: getMainFunctionTokenLocation( - node as TSESTree.FunctionLike, - getParent(context) as TSESTree.Node, - context as unknown as RuleContext, - ), - }); - } - } - - function checkFunctionForImplicitReturn(functionContext: FunctionContext) { - // As this method is called at the exit point of a function definition, the current - // segments are the ones leading to the exit point at the end of the function. If they - // are reachable, it means there is an implicit return. - functionContext.containsImplicitReturn = functionContext.codePath.currentSegments.some( - segment => segment.reachable, - ); - } - - function getSecondaryLocations( - functionContext: FunctionContext, - node: estree.Node, - ): [Array, Array] { - const secondaryLocationsHolder = functionContext.returnStatements.slice() as TSESTree.Node[]; - const secondaryLocationMessages: string[] = functionContext.returnStatements.map( - returnStatement => - returnStatement.argument ? 'Return with value' : 'Return without value', - ); - - if (functionContext.containsImplicitReturn) { - const closeCurlyBraceToken = sourceCode.getLastToken(node, token => token.value === '}'); - if (!!closeCurlyBraceToken) { - secondaryLocationsHolder.push(closeCurlyBraceToken as TSESTree.Node); - secondaryLocationMessages.push('Implicit return without value'); - } - } - - return [secondaryLocationsHolder, secondaryLocationMessages]; - } - - return { - onCodePathStart(codePath: Rule.CodePath) { - functionContextStack.push({ - codePath, - containsReturnWithValue: false, - containsReturnWithoutValue: false, - containsImplicitReturn: false, - returnStatements: [], - }); - }, - onCodePathEnd() { - functionContextStack.pop(); - }, - - ReturnStatement(node: estree.Node) { - const currentContext = functionContextStack[functionContextStack.length - 1]; - if (!!currentContext) { - const returnStatement = node as estree.ReturnStatement; - currentContext.containsReturnWithValue = - currentContext.containsReturnWithValue || !!returnStatement.argument; - currentContext.containsReturnWithoutValue = - currentContext.containsReturnWithoutValue || !returnStatement.argument; - currentContext.returnStatements.push(returnStatement); - } - }, - 'FunctionDeclaration:exit': checkOnFunctionExit, - 'FunctionExpression:exit': checkOnFunctionExit, - 'ArrowFunctionExpression:exit': checkOnFunctionExit, - }; - }, -}; - -function hasInconsistentReturns(functionContext: FunctionContext) { - return ( - functionContext.containsReturnWithValue && - (functionContext.containsReturnWithoutValue || functionContext.containsImplicitReturn) - ); -} - -function declaredReturnTypeContainsVoidOrNeverTypes(returnTypeNode: TSESTree.TypeNode): boolean { - return ( - isVoidType(returnTypeNode) || - (returnTypeNode.type === 'TSUnionType' && - returnTypeNode.types.some(declaredReturnTypeContainsVoidOrNeverTypes)) - ); -} - -function isVoidType(typeNode: TSESTree.TypeNode) { - return ( - typeNode.type === 'TSUndefinedKeyword' || - typeNode.type === 'TSVoidKeyword' || - typeNode.type === 'TSNeverKeyword' - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-incorrect-string-concat.ts b/eslint-bridge/src/linting/eslint/rules/no-incorrect-string-concat.ts deleted file mode 100644 index 5b42b36a611..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-incorrect-string-concat.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3402/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import * as tsTypes from 'typescript'; -import { - RequiredParserServices, - isRequiredParserServices, - getTypeFromTreeNode, - toEncodedMessage, - isStringLiteral, -} from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -const message = `Review this expression to be sure that the concatenation was intended.`; -const objectLikeTypes = new Set(['object', 'Object']); - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - const services: RequiredParserServices = context.parserServices; - - if (!isRequiredParserServices(services)) { - return {}; - } - - const checker = services.program.getTypeChecker(); - - function isStringPlusNonString(type1: tsTypes.Type, type2: tsTypes.Type) { - if (isLiteralType(type1) || isLiteralType(type2)) { - return false; - } - const isObjectLike = objectLikeTypes.has(checker.typeToString(type2)); - // @ts-ignore private API, see https://github.com/microsoft/TypeScript/issues/9879 - return isStringType(type1) && !isObjectLike && !checker.isTypeAssignableTo(type1, type2); - } - - function getOperatorLocation(left: estree.Node, right: estree.Node) { - return context - .getSourceCode() - .getTokensBetween(left, right) - .find(token => token.value === '+')!.loc; - } - - return { - 'BinaryExpression[operator="+"]'(node: estree.Node) { - const { left, right } = node as estree.BinaryExpression; - if ( - isStringLiteral(left) || - isStringLiteral(right) || - isConcatenation(left) || - isConcatenation(right) - ) { - return; - } - - const leftType = getTypeFromTreeNode(left, services); - const rightType = getTypeFromTreeNode(right, services); - if ( - isStringPlusNonString(leftType, rightType) || - isStringPlusNonString(rightType, leftType) - ) { - context.report({ - message: toEncodedMessage( - message, - [left, right], - [ - `left operand has type ${checker.typeToString(leftType)}.`, - `right operand has type ${checker.typeToString(rightType)}.`, - ], - ), - loc: getOperatorLocation(left, right), - }); - } - }, - }; - }, -}; - -function isStringType(typ: tsTypes.Type) { - return (typ.getFlags() & tsTypes.TypeFlags.StringLike) !== 0; -} - -function isLiteralType(type: tsTypes.Type): boolean { - if (type.isUnion()) { - return type.types.some(t => isLiteralType(t)); - } - return type.isStringLiteral(); -} - -function isConcatenation(node: estree.Node) { - return node.type === 'BinaryExpression' && node.operator === '+'; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-infinite-loop.ts b/eslint-bridge/src/linting/eslint/rules/no-infinite-loop.ts deleted file mode 100644 index e6f7bc3bed0..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-infinite-loop.ts +++ /dev/null @@ -1,162 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2189/javascript - -import { Rule, Scope } from 'eslint'; -import { eslintRules } from 'linting/eslint/rules/core'; -import * as estree from 'estree'; -import { childrenOf } from 'linting/eslint'; -import { interceptReport, mergeRules } from './decorators/helpers'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { isUndefined } from './helpers'; - -const noUnmodifiedLoopEslint = eslintRules['no-unmodified-loop-condition']; - -export const rule: Rule.RuleModule = { - meta: { - messages: { ...noUnmodifiedLoopEslint.meta!.messages }, - }, - create(context: Rule.RuleContext) { - /** - * Decorates ESLint `no-unmodified-loop-condition` to raise one issue per symbol. - */ - const alreadyRaisedSymbols: Set = new Set(); - const ruleDecoration: Rule.RuleModule = interceptReport( - noUnmodifiedLoopEslint, - function (context: Rule.RuleContext, descriptor: Rule.ReportDescriptor) { - const node = (descriptor as any).node as estree.Node; - - const symbol = context.getScope().references.find(v => v.identifier === node)?.resolved; - /** Ignoring symbols that have already been reported */ - if (isUndefined(node) || (symbol && alreadyRaisedSymbols.has(symbol))) { - return; - } - - /** Ignoring symbols called on or passed as arguments */ - for (const reference of symbol?.references || []) { - const id = reference.identifier as TSESTree.Node; - - if ( - id.parent?.type === 'CallExpression' && - id.parent.arguments.includes(id as TSESTree.CallExpressionArgument) - ) { - return; - } - - if ( - id.parent?.type === 'MemberExpression' && - id.parent.parent?.type === 'CallExpression' && - id.parent.object === id - ) { - return; - } - } - - if (symbol) { - alreadyRaisedSymbols.add(symbol); - } - - context.report(descriptor); - }, - ); - - /** - * Extends ESLint `no-unmodified-loop-condition` to consider more corner cases. - */ - const MESSAGE = "Correct this loop's end condition to not be invariant."; - const ruleExtension: Rule.RuleModule = { - create(context: Rule.RuleContext) { - return { - WhileStatement: checkWhileStatement, - DoWhileStatement: checkWhileStatement, - ForStatement: (node: estree.Node) => { - const { test, body } = node as estree.ForStatement; - if (!test || (test.type === 'Literal' && test.value === true)) { - const hasEndCondition = LoopVisitor.hasEndCondition(body, context); - if (!hasEndCondition) { - const firstToken = context.getSourceCode().getFirstToken(node); - context.report({ - loc: firstToken!.loc, - message: MESSAGE, - }); - } - } - }, - }; - - function checkWhileStatement(node: estree.Node) { - const whileStatement = node as estree.WhileStatement | estree.DoWhileStatement; - if (whileStatement.test.type === 'Literal' && whileStatement.test.value === true) { - const hasEndCondition = LoopVisitor.hasEndCondition(whileStatement.body, context); - if (!hasEndCondition) { - const firstToken = context.getSourceCode().getFirstToken(node); - context.report({ loc: firstToken!.loc, message: MESSAGE }); - } - } - } - }, - }; - - const decorationListeners: Rule.RuleListener = ruleDecoration.create(context); - const extensionListeners: Rule.RuleListener = ruleExtension.create(context); - - return mergeRules(decorationListeners, extensionListeners); - }, -}; - -class LoopVisitor { - hasEndCondition = false; - - static hasEndCondition(node: estree.Node, context: Rule.RuleContext) { - const visitor = new LoopVisitor(); - visitor.visit(node, context); - return visitor.hasEndCondition; - } - - private visit(root: estree.Node, context: Rule.RuleContext) { - const visitNode = (node: estree.Node, isNestedLoop = false) => { - switch (node.type) { - case 'WhileStatement': - case 'DoWhileStatement': - case 'ForStatement': - isNestedLoop = true; - break; - case 'FunctionExpression': - case 'FunctionDeclaration': - // Don't consider nested functions - return; - case 'BreakStatement': - if (!isNestedLoop || !!node.label) { - this.hasEndCondition = true; - } - break; - case 'YieldExpression': - case 'ReturnStatement': - case 'ThrowStatement': - this.hasEndCondition = true; - return; - } - childrenOf(node, context.getSourceCode().visitorKeys).forEach(child => - visitNode(child, isNestedLoop), - ); - }; - visitNode(root); - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-intrusive-permissions.ts b/eslint-bridge/src/linting/eslint/rules/no-intrusive-permissions.ts deleted file mode 100644 index 7fc9170297e..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-intrusive-permissions.ts +++ /dev/null @@ -1,198 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5604/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isIdentifier, isMemberExpression, getValueOfExpression } from './helpers'; - -const permissions = ['geolocation', 'camera', 'microphone', 'notifications', 'persistent-storage']; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - checkPermission: 'Make sure the use of the {{feature}} is necessary.', - }, - }, - create(context: Rule.RuleContext) { - return { - 'CallExpression[callee.type="MemberExpression"]'(node: estree.Node) { - const call = node as estree.CallExpression; - const callee = call.callee as estree.MemberExpression; - if ( - isNavigatorMemberExpression(callee, 'permissions', 'query') && - call.arguments.length > 0 - ) { - checkPermissions(context, call); - return; - } - if ( - context.options.includes('geolocation') && - isNavigatorMemberExpression(callee, 'geolocation', 'watchPosition', 'getCurrentPosition') - ) { - context.report({ - messageId: 'checkPermission', - data: { - feature: 'geolocation', - }, - node: callee, - }); - return; - } - if ( - isNavigatorMemberExpression(callee, 'mediaDevices', 'getUserMedia') && - call.arguments.length > 0 - ) { - const firstArg = getValueOfExpression(context, call.arguments[0], 'ObjectExpression'); - checkForCameraAndMicrophonePermissions(context, callee, firstArg); - return; - } - if ( - context.options.includes('notifications') && - isMemberExpression(callee, 'Notification', 'requestPermission') - ) { - context.report({ - messageId: 'checkPermission', - data: { - feature: 'notifications', - }, - node: callee, - }); - return; - } - if ( - context.options.includes('persistent-storage') && - isMemberExpression(callee.object, 'navigator', 'storage') - ) { - context.report({ - messageId: 'checkPermission', - data: { - feature: 'persistent-storage', - }, - node: callee, - }); - } - }, - NewExpression(node: estree.Node) { - const { callee } = node as estree.NewExpression; - if (context.options.includes('notifications') && isIdentifier(callee, 'Notification')) { - context.report({ - messageId: 'checkPermission', - data: { - feature: 'notifications', - }, - node: callee, - }); - } - }, - }; - }, -}; - -function checkForCameraAndMicrophonePermissions( - context: Rule.RuleContext, - callee: estree.MemberExpression, - firstArg: estree.ObjectExpression | undefined, -) { - if (!firstArg) { - return; - } - const shouldCheckAudio = context.options.includes('microphone'); - const shouldCheckVideo = context.options.includes('camera'); - if (!shouldCheckAudio && !shouldCheckVideo) { - return; - } - const perms = []; - for (const prop of firstArg.properties) { - if (prop.type === 'Property') { - const { value, key } = prop; - if (isIdentifier(key, 'audio') && shouldCheckAudio && isOtherThanFalse(context, value)) { - perms.push('microphone'); - } else if ( - isIdentifier(key, 'video') && - shouldCheckVideo && - isOtherThanFalse(context, value) - ) { - perms.push('camera'); - } - } - } - if (perms.length > 0) { - context.report({ - messageId: 'checkPermission', - data: { - feature: perms.join(' and '), - }, - node: callee, - }); - } -} - -function isOtherThanFalse(context: Rule.RuleContext, value: estree.Node) { - const exprValue = getValueOfExpression(context, value, 'Literal'); - if (exprValue && exprValue.value === false) { - return false; - } - return true; -} - -function checkPermissions(context: Rule.RuleContext, call: estree.CallExpression) { - const firstArg = getValueOfExpression(context, call.arguments[0], 'ObjectExpression'); - if (firstArg?.type === 'ObjectExpression') { - const nameProp = firstArg.properties.find(prop => hasNamePropertyWithPermission(prop, context)); - if (nameProp) { - const { value } = (nameProp as estree.Property).value as estree.Literal; - context.report({ - messageId: 'checkPermission', - data: { - feature: String(value), - }, - node: nameProp, - }); - } - } -} - -function isNavigatorMemberExpression( - { object, property }: estree.MemberExpression, - firstProperty: string, - ...secondProperty: string[] -) { - return ( - isMemberExpression(object, 'navigator', firstProperty) && - isIdentifier(property, ...secondProperty) - ); -} - -function hasNamePropertyWithPermission( - prop: estree.Property | estree.SpreadElement, - context: Rule.RuleContext, -) { - if (prop.type === 'Property' && isIdentifier(prop.key, 'name')) { - const value = getValueOfExpression(context, prop.value, 'Literal'); - return ( - value && - typeof value.value === 'string' && - permissions.includes(value.value) && - context.options.includes(value.value) - ); - } - return false; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-invalid-await.ts b/eslint-bridge/src/linting/eslint/rules/no-invalid-await.ts deleted file mode 100644 index 5700c323e0e..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-invalid-await.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4123/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import * as ts from 'typescript'; -import { isRequiredParserServices, getTypeFromTreeNode } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - refactorAwait: "Refactor this redundant 'await' on a non-promise.", - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (isRequiredParserServices(services)) { - return { - AwaitExpression: (node: estree.Node) => { - const awaitedType = getTypeFromTreeNode( - (node as estree.AwaitExpression).argument, - services, - ); - if (!hasThenMethod(awaitedType) && !isAny(awaitedType) && !isUnion(awaitedType)) { - context.report({ - messageId: 'refactorAwait', - node, - }); - } - }, - }; - } - return {}; - }, -}; - -function hasThenMethod(type: ts.Type) { - const thenProperty = type.getProperty('then'); - return thenProperty?.declarations?.some( - d => d.kind === ts.SyntaxKind.MethodSignature || d.kind === ts.SyntaxKind.MethodDeclaration, - ); -} - -function isAny(type: ts.Type) { - return Boolean(type.flags & ts.TypeFlags.Any); -} - -function isUnion(type: ts.Type) { - return Boolean(type.flags & ts.TypeFlags.Union); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-invariant-returns.ts b/eslint-bridge/src/linting/eslint/rules/no-invariant-returns.ts deleted file mode 100644 index d3cd13ae4b6..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-invariant-returns.ts +++ /dev/null @@ -1,222 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3516/javascript - -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { getMainFunctionTokenLocation } from 'eslint-plugin-sonarjs/lib/utils/locations'; -import { - findFirstMatchingAncestor, - FUNCTION_NODES, - getParent, - isElementWrite, - RuleContext, - toEncodedMessage, -} from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -interface FunctionContext { - codePath: Rule.CodePath; - containsReturnWithoutValue: boolean; - returnStatements: estree.ReturnStatement[]; -} - -interface SingleWriteVariable { - variable: Scope.Variable; - initExpression?: estree.Expression | null; -} - -type LiteralValue = number | RegExp | string | null | boolean | bigint; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - - create(context: Rule.RuleContext) { - const functionContextStack: FunctionContext[] = []; - - const checkOnFunctionExit = (node: estree.Node) => - checkInvariantReturnStatements(node, functionContextStack[functionContextStack.length - 1]); - - function checkInvariantReturnStatements(node: estree.Node, functionContext?: FunctionContext) { - if (!functionContext || hasDifferentReturnTypes(functionContext)) { - return; - } - - const returnedValues = functionContext.returnStatements.map( - returnStatement => returnStatement.argument as estree.Node, - ); - if (areAllSameValue(returnedValues, context.getScope())) { - const message = toEncodedMessage( - `Refactor this function to not always return the same value.`, - returnedValues as TSESTree.Node[], - returnedValues.map(_ => 'Returned value.'), - returnedValues.length, - ); - - context.report({ - message, - loc: getMainFunctionTokenLocation( - node as TSESTree.FunctionLike, - getParent(context) as TSESTree.Node, - context as unknown as RuleContext, - ), - }); - } - } - - return { - onCodePathStart(codePath: Rule.CodePath) { - functionContextStack.push({ - codePath, - containsReturnWithoutValue: false, - returnStatements: [], - }); - }, - onCodePathEnd() { - functionContextStack.pop(); - }, - ReturnStatement(node: estree.Node) { - const currentContext = functionContextStack[functionContextStack.length - 1]; - if (currentContext) { - const returnStatement = node as estree.ReturnStatement; - currentContext.containsReturnWithoutValue = - currentContext.containsReturnWithoutValue || !returnStatement.argument; - currentContext.returnStatements.push(returnStatement); - } - }, - 'FunctionDeclaration:exit': checkOnFunctionExit, - 'FunctionExpression:exit': checkOnFunctionExit, - 'ArrowFunctionExpression:exit': checkOnFunctionExit, - }; - }, -}; - -function hasDifferentReturnTypes(functionContext: FunctionContext) { - // As this method is called at the exit point of a function definition, the current - // segments are the ones leading to the exit point at the end of the function. If they - // are reachable, it means there is an implicit return. - const hasImplicitReturn = functionContext.codePath.currentSegments.some( - segment => segment.reachable, - ); - - return ( - hasImplicitReturn || - functionContext.containsReturnWithoutValue || - functionContext.returnStatements.length <= 1 || - functionContext.codePath.thrownSegments.length > 0 - ); -} - -function areAllSameValue(returnedValues: estree.Node[], scope: Scope.Scope) { - const firstReturnedValue = returnedValues[0]; - const firstValue = getLiteralValue(firstReturnedValue, scope); - if (firstValue !== undefined) { - return returnedValues - .slice(1) - .every(returnedValue => getLiteralValue(returnedValue, scope) === firstValue); - } else if (firstReturnedValue.type === 'Identifier') { - const singleWriteVariable = getSingleWriteDefinition(firstReturnedValue.name, scope); - if (singleWriteVariable) { - const readReferenceIdentifiers = singleWriteVariable.variable.references - .slice(1) - .map(ref => ref.identifier); - return returnedValues.every(returnedValue => - readReferenceIdentifiers.includes(returnedValue as estree.Identifier), - ); - } - } - return false; -} - -function getSingleWriteDefinition( - variableName: string, - scope: Scope.Scope, -): SingleWriteVariable | null { - const variable = scope.set.get(variableName); - if (variable) { - const references = variable.references.slice(1); - if (!references.some(ref => ref.isWrite() || isPossibleObjectUpdate(ref))) { - let initExpression = null; - if (variable.defs.length === 1 && variable.defs[0].type === 'Variable') { - initExpression = variable.defs[0].node.init; - } - return { variable, initExpression }; - } - } - return null; -} - -function isPossibleObjectUpdate(ref: Scope.Reference) { - const expressionStatement = findFirstMatchingAncestor( - ref.identifier as TSESTree.Node, - n => n.type === 'ExpressionStatement' || FUNCTION_NODES.includes(n.type), - ) as estree.Node | undefined; - - // To avoid FP, we consider method calls as write operations, since we do not know whether they will - // update the object state or not. - return ( - expressionStatement && - expressionStatement.type === 'ExpressionStatement' && - (isElementWrite(expressionStatement, ref) || - expressionStatement.expression.type === 'CallExpression') - ); -} - -function getLiteralValue(returnedValue: estree.Node, scope: Scope.Scope): LiteralValue | undefined { - if (returnedValue.type === 'Literal') { - return returnedValue.value; - } else if (returnedValue.type === 'UnaryExpression') { - const innerReturnedValue = getLiteralValue(returnedValue.argument, scope); - return innerReturnedValue !== undefined - ? evaluateUnaryLiteralExpression(returnedValue.operator, innerReturnedValue) - : undefined; - } else if (returnedValue.type === 'Identifier') { - const singleWriteVariable = getSingleWriteDefinition(returnedValue.name, scope); - if (singleWriteVariable && singleWriteVariable.initExpression) { - return getLiteralValue(singleWriteVariable.initExpression, scope); - } - } - return undefined; -} - -function evaluateUnaryLiteralExpression(operator: string, innerReturnedValue: LiteralValue) { - switch (operator) { - case '-': - return -Number(innerReturnedValue); - case '+': - return Number(innerReturnedValue); - case '~': - return ~Number(innerReturnedValue); - case '!': - return !Boolean(innerReturnedValue); - case 'typeof': - return typeof innerReturnedValue; - default: - return undefined; - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-ip-forward.ts b/eslint-bridge/src/linting/eslint/rules/no-ip-forward.ts deleted file mode 100644 index 7942d6aa069..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-ip-forward.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5759/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - getObjectExpressionProperty, - getValueOfExpression, - toEncodedMessage, - getFullyQualifiedName, -} from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - return { - CallExpression(node: estree.Node) { - const call = node as estree.CallExpression; - const { callee, arguments: args } = call; - if (isSensitiveFQN(context, call) && args.length > 0) { - const xfwdProp = getObjectExpressionProperty(args[0], 'xfwd'); - if (!xfwdProp) { - return; - } - const xfwdValue = getValueOfExpression(context, xfwdProp.value, 'Literal'); - if (xfwdValue?.value === true) { - context.report({ - node: callee, - message: toEncodedMessage('Make sure forwarding client IP address is safe here.', [ - xfwdProp, - ]), - }); - } - } - }, - }; - }, -}; - -function isSensitiveFQN(context: Rule.RuleContext, call: estree.CallExpression) { - const fqn = getFullyQualifiedName(context, call); - return ( - fqn && - ['http-proxy.createProxyServer', 'http-proxy-middleware.createProxyMiddleware'].includes(fqn) - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-labels.ts b/eslint-bridge/src/linting/eslint/rules/no-labels.ts deleted file mode 100644 index b573da938ae..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-labels.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1119/javascript - -import { Rule } from 'eslint'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeLabel: 'Refactor the code to remove this label and the need for it.', - }, - }, - create(context: Rule.RuleContext) { - return { - LabeledStatement(node) { - const sourceCode = context.getSourceCode(); - context.report({ - messageId: 'removeLabel', - loc: sourceCode.getFirstToken(node)!.loc, - }); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-mime-sniff.ts b/eslint-bridge/src/linting/eslint/rules/no-mime-sniff.ts deleted file mode 100644 index e2ba5ce254a..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-mime-sniff.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5734/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { Express, getFullyQualifiedName, getPropertyWithValue } from './helpers'; - -const HELMET = 'helmet'; -const NO_SNIFF = 'noSniff'; - -export const rule: Rule.RuleModule = Express.SensitiveMiddlewarePropertyRule( - findFalseNoSniffPropertyFromHelmet, - `Make sure allowing browsers to sniff MIME types is safe here.`, -); - -/** - * Looks for property `noSniff: false` in node looking - * somewhat similar to `helmet(?)`, and returns it. - */ -function findFalseNoSniffPropertyFromHelmet( - context: Rule.RuleContext, - node: estree.CallExpression, -): estree.Property[] { - let sensitive: estree.Property | undefined; - const { callee, arguments: args } = node; - if ( - getFullyQualifiedName(context, callee) === HELMET && - args.length === 1 && - args[0].type === 'ObjectExpression' - ) { - sensitive = getPropertyWithValue(context, args[0], NO_SNIFF, false); - } - return sensitive ? [sensitive] : []; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-misleading-array-reverse.ts b/eslint-bridge/src/linting/eslint/rules/no-misleading-array-reverse.ts deleted file mode 100644 index e52e95c209f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-misleading-array-reverse.ts +++ /dev/null @@ -1,153 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4043/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import * as ts from 'typescript'; -import { - isArray, - sortLike, - isRequiredParserServices, - RequiredParserServices, - getSymbolAtLocation, - localAncestorsChain, -} from './helpers'; - -const arrayMutatingMethods = ['reverse', "'reverse'", '"reverse"', ...sortLike]; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - moveMethod: 'Move this array "{{method}}" operation to a separate statement.', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - return { - CallExpression(node: estree.Node) { - const callee = (node as estree.CallExpression).callee; - if (callee.type === 'MemberExpression') { - const propertyText = context.getSourceCode().getText(callee.property); - if (isArrayMutatingCall(callee, services, propertyText)) { - const mutatedArray = callee.object; - - if ( - isIdentifierOrPropertyAccessExpression(mutatedArray, services) && - !isInSelfAssignment(mutatedArray, node) && - isForbiddenOperation(node) - ) { - context.report({ - messageId: 'moveMethod', - data: { - method: formatMethod(propertyText), - }, - node, - }); - } - } - } - }, - }; - }, -}; - -function formatMethod(mutatingMethod: string) { - if (mutatingMethod.startsWith('"') || mutatingMethod.startsWith("'")) { - return mutatingMethod.substr(1, mutatingMethod.length - 2); - } else { - return mutatingMethod; - } -} - -function isArrayMutatingCall( - memberExpression: estree.MemberExpression, - services: RequiredParserServices, - propertyText: string, -) { - return arrayMutatingMethods.includes(propertyText) && isArray(memberExpression.object, services); -} - -function isIdentifierOrPropertyAccessExpression( - node: estree.Node, - services: RequiredParserServices, -): boolean { - return ( - node.type === 'Identifier' || - (node.type === 'MemberExpression' && !isGetAccessor(node.property, services)) - ); -} - -function isGetAccessor(node: estree.Node, services: RequiredParserServices): boolean { - const symbol = getSymbolAtLocation(node, services); - const declarations = symbol && symbol.declarations; - return ( - declarations !== undefined && - declarations.length === 1 && - declarations[0].kind === ts.SyntaxKind.GetAccessor - ); -} - -function isInSelfAssignment(mutatedArray: estree.Node, node?: estree.Node): boolean { - const parent = (node as TSESTree.Node).parent; - return ( - // check assignment - parent !== undefined && - parent.type === 'AssignmentExpression' && - parent.operator === '=' && - parent.left.type === 'Identifier' && - mutatedArray.type === 'Identifier' && - parent.left.name === mutatedArray.name - ); -} - -function isForbiddenOperation(node: estree.Node) { - return !isStandaloneExpression(node) && !isReturnedExpression(node); -} - -function isStandaloneExpression(node: estree.Node) { - const ancestors = localAncestorsChain(node as TSESTree.Node); - const returnIdx = ancestors.findIndex(ancestor => ancestor.type === 'ExpressionStatement'); - return ( - returnIdx > -1 && - ancestors - .slice(0, returnIdx) - .every(ancestor => ['ChainExpression', 'LogicalExpression'].includes(ancestor.type)) - ); -} - -function isReturnedExpression(node: estree.Node) { - const ancestors = localAncestorsChain(node as TSESTree.Node); - const returnIdx = ancestors.findIndex(ancestor => ancestor.type === 'ReturnStatement'); - return ( - returnIdx > -1 && - ancestors - .slice(0, returnIdx) - .every(ancestor => - ['ArrayExpression', 'ObjectExpression', 'ConditionalExpression', 'SpreadElement'].includes( - ancestor.type, - ), - ) - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-mixed-content.ts b/eslint-bridge/src/linting/eslint/rules/no-mixed-content.ts deleted file mode 100644 index 3ac8e1455fc..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-mixed-content.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5730/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { Express, getObjectExpressionProperty, getFullyQualifiedName } from './helpers'; - -const HELMET = 'helmet'; -const HELMET_CSP = 'helmet-csp'; -const DIRECTIVES = 'directives'; -const CONTENT_SECURITY_POLICY = 'contentSecurityPolicy'; -const BLOCK_ALL_MIXED_CONTENT_CAMEL = 'blockAllMixedContent'; -const BLOCK_ALL_MIXED_CONTENT_HYPHEN = 'block-all-mixed-content'; - -export const rule: Rule.RuleModule = Express.SensitiveMiddlewarePropertyRule( - findDirectivesWithMissingMixedContentPropertyFromHelmet, - `Make sure allowing mixed-content is safe here.`, -); - -function findDirectivesWithMissingMixedContentPropertyFromHelmet( - context: Rule.RuleContext, - node: estree.CallExpression, -): estree.Property[] { - let sensitive: estree.Property | undefined; - const { arguments: args } = node; - if (args.length === 1) { - const [options] = args; - const maybeDirectives = getObjectExpressionProperty(options, DIRECTIVES); - if ( - maybeDirectives && - isMissingMixedContentProperty(maybeDirectives) && - isValidHelmetModuleCall(context, node) - ) { - sensitive = maybeDirectives; - } - } - return sensitive ? [sensitive] : []; -} - -function isValidHelmetModuleCall(context: Rule.RuleContext, callExpr: estree.CallExpression) { - const fqn = getFullyQualifiedName(context, callExpr); - return fqn === `${HELMET}.${CONTENT_SECURITY_POLICY}` || fqn === HELMET_CSP; -} - -function isMissingMixedContentProperty(directives: estree.Property): boolean { - return !( - Boolean(getObjectExpressionProperty(directives.value, BLOCK_ALL_MIXED_CONTENT_CAMEL)) || - Boolean(getObjectExpressionProperty(directives.value, BLOCK_ALL_MIXED_CONTENT_HYPHEN)) - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-nested-assignment.ts b/eslint-bridge/src/linting/eslint/rules/no-nested-assignment.ts deleted file mode 100644 index 5a0af695d0b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-nested-assignment.ts +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1121/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getParent } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - extractAssignment: 'Extract the assignment of "{{symbol}}" from this expression.', - }, - }, - create(context: Rule.RuleContext) { - function isAssignmentStatement(parent: estree.Node) { - return parent.type === 'ExpressionStatement'; - } - - function isEnclosingChain(parent: estree.Node) { - return parent.type === 'AssignmentExpression'; - } - - function isEnclosingRelation(parent: estree.Node) { - return ( - parent.type === 'BinaryExpression' && - ['==', '!=', '===', '!==', '<', '<=', '>', '>='].includes(parent.operator) - ); - } - - function isEnclosingSequence(parent: estree.Node) { - return parent.type === 'SequenceExpression'; - } - - function isEnclosingDeclarator(parent: estree.Node) { - return parent.type === 'VariableDeclarator'; - } - - function isLambdaBody(parent: estree.Node, expr: estree.AssignmentExpression) { - return parent.type === 'ArrowFunctionExpression' && parent.body === expr; - } - - function isConditionalAssignment(parent: estree.Node, expr: estree.AssignmentExpression) { - return parent.type === 'LogicalExpression' && parent.right === expr; - } - - function isWhileCondition(parent: estree.Node, expr: estree.AssignmentExpression) { - return ( - (parent.type === 'DoWhileStatement' || parent.type === 'WhileStatement') && - parent.test === expr - ); - } - - function isForInitOrUpdate(parent: estree.Node, expr: estree.AssignmentExpression) { - return parent.type === 'ForStatement' && (parent.init === expr || parent.update === expr); - } - - return { - AssignmentExpression: (node: estree.Node) => { - const assignment = node as estree.AssignmentExpression; - const parent = getParent(context); - if ( - parent && - !isAssignmentStatement(parent) && - !isEnclosingChain(parent) && - !isEnclosingRelation(parent) && - !isEnclosingSequence(parent) && - !isEnclosingDeclarator(parent) && - !isLambdaBody(parent, assignment) && - !isConditionalAssignment(parent, assignment) && - !isWhileCondition(parent, assignment) && - !isForInitOrUpdate(parent, assignment) - ) { - raiseIssue(assignment, context); - } - }, - }; - }, -}; - -function raiseIssue(node: estree.AssignmentExpression, context: Rule.RuleContext) { - const sourceCode = context.getSourceCode(); - const operator = sourceCode.getFirstTokenBetween( - node.left, - node.right, - token => token.value === node.operator, - ); - const text = sourceCode.getText(node.left); - context.report({ - messageId: 'extractAssignment', - data: { - symbol: text, - }, - loc: operator!.loc, - }); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-nested-conditional.ts b/eslint-bridge/src/linting/eslint/rules/no-nested-conditional.ts deleted file mode 100644 index 2ca93df650b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-nested-conditional.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3358/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - extractTernary: 'Extract this nested ternary operation into an independent statement.', - }, - }, - create(context: Rule.RuleContext) { - return { - 'ConditionalExpression ConditionalExpression': (node: estree.Node) => { - if (!isNestingBroken(context.getAncestors())) { - context.report({ - messageId: 'extractTernary', - node, - }); - } - }, - }; - }, -}; - -function isNestingBroken(ancestors: estree.Node[]) { - let parent = ancestors.pop()!; - while (parent.type !== 'ConditionalExpression') { - if (breaksNesting(parent)) { - return true; - } - parent = ancestors.pop()!; - } - return false; -} - -function breaksNesting(node: estree.Node) { - return [ - 'ArrayExpression', - 'ObjectExpression', - 'FunctionExpression', - 'ArrowFunctionExpression', - 'JSXExpressionContainer', - ].includes(node.type); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-nested-incdec.ts b/eslint-bridge/src/linting/eslint/rules/no-nested-incdec.ts deleted file mode 100644 index 0de9da06f50..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-nested-incdec.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S881/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - extractOperation: 'Extract this {{incrementType}} operation into a dedicated statement.', - }, - }, - create(context: Rule.RuleContext) { - function reportUpdateExpression(node: estree.UpdateExpression) { - context.report({ - messageId: 'extractOperation', - data: { - incrementType: node.operator === '++' ? 'increment' : 'decrement', - }, - node, - }); - } - - return { - UpdateExpression(node: estree.Node) { - if (!isIgnored(node, context.getAncestors())) { - reportUpdateExpression(node as estree.UpdateExpression); - } - }, - }; - }, -}; - -function isIgnored(node: estree.Node, ancestors: estree.Node[]): boolean { - const firstAncestor = ancestors.pop(); - - if (firstAncestor) { - switch (firstAncestor.type) { - case 'ExpressionStatement': - return true; - case 'ForStatement': - return firstAncestor.update === node; - case 'SequenceExpression': { - const secondAncestor = ancestors.pop(); - return ( - secondAncestor !== undefined && - secondAncestor.type === 'ForStatement' && - secondAncestor.update === firstAncestor - ); - } - } - } - return false; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-nested-template-literals.ts b/eslint-bridge/src/linting/eslint/rules/no-nested-template-literals.ts deleted file mode 100644 index c4c7a5aac77..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-nested-template-literals.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4624/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -const message = 'Refactor this code to not use nested template literals.'; - -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - return { - 'TemplateLiteral TemplateLiteral': function (node: estree.Node) { - context.report({ - message, - node, - }); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-new-symbol.ts b/eslint-bridge/src/linting/eslint/rules/no-new-symbol.ts deleted file mode 100644 index e80ace42d8f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-new-symbol.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3834/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getVariableFromName, toEncodedMessage } from './helpers'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -const SYMBOL = 'Symbol'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - function isSymbol(node: estree.Node) { - return node.type === 'Identifier' && node.name === SYMBOL; - } - function isShadowed(_node: estree.Node) { - const variable = getVariableFromName(context, SYMBOL); - return variable && variable.defs.length > 0; - } - return { - NewExpression: (node: estree.Node) => { - const { callee } = node as estree.NewExpression; - if (isSymbol(callee) && !isShadowed(callee)) { - const newToken = context - .getSourceCode() - .getFirstToken(node, token => token.value === 'new')!; - context.report({ - message: toEncodedMessage(`Remove this "new" operator.`, [callee as TSESTree.Node]), - loc: newToken.loc, - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-os-command-from-path.ts b/eslint-bridge/src/linting/eslint/rules/no-os-command-from-path.ts deleted file mode 100644 index ced71235426..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-os-command-from-path.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4036/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isStringLiteral, getValueOfExpression, getFullyQualifiedName } from './helpers'; - -const SENSITIVE_METHODS = ['exec', 'execSync', 'spawn', 'spawnSync', 'execFile', 'execFileSync']; -const REQUIRED_PATH_PREFIXES = ['./', '.\\', '../', '..\\', '/', '\\', 'C:\\']; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - issue: 'Make sure the "PATH" used to find this command includes only what you intend.', - }, - }, - create(context: Rule.RuleContext) { - return { - CallExpression: (node: estree.CallExpression) => { - const fqn = getFullyQualifiedName(context, node); - if (SENSITIVE_METHODS.some(method => fqn === `child_process.${method}`)) { - const sensitiveArg = findSensitiveArgument( - context, - node.arguments as estree.Expression[], - ); - if (sensitiveArg !== null) { - context.report({ - messageId: 'issue', - node: sensitiveArg, - }); - } - } - }, - }; - }, -}; - -function findSensitiveArgument(context: Rule.RuleContext, functionArgs: estree.Expression[]) { - if (functionArgs.length === 0) { - return null; - } - const pathArg = functionArgs[0]; // we know this for the SENSITIVE_METHODS - const literalInExpression: estree.Literal | undefined = getValueOfExpression( - context, - pathArg, - 'Literal', - ); - let stringLiteral: estree.Literal & { value: string }; - if (literalInExpression !== undefined && isStringLiteral(literalInExpression)) { - stringLiteral = literalInExpression; - } else { - return null; - } - const startsWithRequiredPrefix = REQUIRED_PATH_PREFIXES.some(prefix => - stringLiteral.value.startsWith(prefix), - ); - return startsWithRequiredPrefix ? null : pathArg; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-parameter-reassignment.ts b/eslint-bridge/src/linting/eslint/rules/no-parameter-reassignment.ts deleted file mode 100644 index 10c5609898f..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-parameter-reassignment.ts +++ /dev/null @@ -1,327 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1226/javascript - -import { AST, Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { getParent, resolveIdentifiers } from './helpers'; - -type ContextType = 'catch' | 'function' | 'foreach' | 'global'; - -interface ReassignmentContext { - type: ContextType; - variablesToCheckInCurrentScope: Set; - variablesToCheck: Set; - variablesRead: Set; - referencesByIdentifier: Map; - parentContext?: ReassignmentContext; -} - -export const rule: Rule.RuleModule = { - meta: { - messages: { - noReassignment: - 'Introduce a new variable or use its initial value before reassigning "{{reference}}".', - }, - }, - create(context: Rule.RuleContext) { - let variableUsageContext: ReassignmentContext = { - type: 'global', - variablesToCheckInCurrentScope: new Set(), - variablesToCheck: new Set(), - variablesRead: new Set(), - referencesByIdentifier: new Map(), - }; - - function checkIdentifierUsage( - identifier: estree.Identifier, - identifierContextType: ContextType, - ) { - if (variableUsageContext.type !== identifierContextType) { - return; - } - - const variableName = identifier.name; - const currentReference = getReference(variableUsageContext, identifier); - if ( - currentReference && - !currentReference.init && - !variableUsageContext.variablesRead.has(variableName) - ) { - if ( - variableUsageContext.variablesToCheck.has(variableName) && - currentReference.isWriteOnly() && - !isUsedInWriteExpression(variableName, currentReference.writeExpr) - ) { - // we do not raise issue when value is reassigned inside a top-level IfStatement, as it might be a shift or - // default value reassignment - if ( - isInsideIfStatement(context) || - context.getAncestors().some(node => node.type === 'SwitchCase') // issue-2398 - ) { - return; - } - raiseIssue(currentReference); - } - markAsRead(variableUsageContext, variableName); - } else if (variableName === 'arguments') { - markAllFunctionArgumentsAsRead(variableUsageContext); - } - } - - function isUsedInWriteExpression(variableName: string, writeExpr: estree.Node | null) { - return ( - writeExpr && - context - .getSourceCode() - .getFirstToken( - writeExpr, - token => token.value === variableName || token.value === 'arguments', - ) - ); - } - - function raiseIssue(reference: Scope.Reference) { - const locationHolder = getPreciseLocationHolder(reference); - context.report({ - messageId: 'noReassignment', - data: { - reference: reference.identifier.name, - }, - ...locationHolder, - }); - } - - function popContext() { - variableUsageContext = variableUsageContext.parentContext - ? variableUsageContext.parentContext - : variableUsageContext; - } - - return { - onCodePathStart(_codePath: Rule.CodePath, node: estree.Node) { - const currentScope = context.getScope(); - if (currentScope && currentScope.type === 'function') { - const { referencesByIdentifier, variablesToCheck, variablesToCheckInCurrentScope } = - computeNewContextInfo(variableUsageContext, context, node); - - const functionName = getFunctionName(node as estree.FunctionExpression); - if (functionName) { - variablesToCheck.delete(functionName); - } - - variableUsageContext = { - type: 'function', - parentContext: variableUsageContext, - variablesToCheck, - referencesByIdentifier, - variablesToCheckInCurrentScope, - variablesRead: computeSetDifference( - variableUsageContext.variablesRead, - variablesToCheckInCurrentScope, - ), - }; - } else { - variableUsageContext = { - type: 'global', - parentContext: variableUsageContext, - variablesToCheckInCurrentScope: new Set(), - variablesToCheck: new Set(), - variablesRead: new Set(), - referencesByIdentifier: new Map(), - }; - } - }, - - onCodePathSegmentLoop( - _fromSegment: Rule.CodePathSegment, - _toSegment: Rule.CodePathSegment, - node: estree.Node, - ) { - const parent = getParent(context); - if (!isForEachLoopStart(node, parent)) { - return; - } - const currentScope = context.getSourceCode().scopeManager.acquire(parent.body); - const { referencesByIdentifier, variablesToCheck, variablesToCheckInCurrentScope } = - computeNewContextInfo(variableUsageContext, context, parent.left); - - if (currentScope) { - for (const ref of currentScope.references) { - referencesByIdentifier.set(ref.identifier, ref); - } - } - - // In case of array or object pattern expression, the left hand side are not declared variables but simply identifiers - resolveIdentifiers(parent.left as TSESTree.Node, true) - .map(identifier => identifier.name) - .forEach(name => { - variablesToCheck.add(name); - variablesToCheckInCurrentScope.add(name); - }); - - variableUsageContext = { - type: 'foreach', - parentContext: variableUsageContext, - variablesToCheckInCurrentScope, - variablesToCheck, - variablesRead: computeSetDifference( - variableUsageContext.variablesRead, - variablesToCheckInCurrentScope, - ), - referencesByIdentifier, - }; - }, - - onCodePathSegmentStart(_segment: Rule.CodePathSegment, node: estree.Node) { - if (node.type !== 'CatchClause') { - return; - } - - const { referencesByIdentifier, variablesToCheck, variablesToCheckInCurrentScope } = - computeNewContextInfo(variableUsageContext, context, node); - - variableUsageContext = { - type: 'catch', - parentContext: variableUsageContext, - variablesToCheckInCurrentScope, - variablesToCheck, - variablesRead: computeSetDifference( - variableUsageContext.variablesRead, - variablesToCheckInCurrentScope, - ), - referencesByIdentifier, - }; - }, - - onCodePathEnd: popContext, - 'ForInStatement:exit': popContext, - 'ForOfStatement:exit': popContext, - 'CatchClause:exit': popContext, - '*:function > BlockStatement Identifier': (node: estree.Node) => - checkIdentifierUsage(node as estree.Identifier, 'function'), - 'ForInStatement > *:statement Identifier': (node: estree.Node) => - checkIdentifierUsage(node as estree.Identifier, 'foreach'), - 'ForOfStatement > *:statement Identifier': (node: estree.Node) => - checkIdentifierUsage(node as estree.Identifier, 'foreach'), - 'CatchClause > BlockStatement Identifier': (node: estree.Node) => - checkIdentifierUsage(node as estree.Identifier, 'catch'), - }; - }, -}; - -function isInsideIfStatement(context: Rule.RuleContext) { - const ancestors = context.getAncestors(); - for (let i = ancestors.length - 1; i >= 0; i--) { - if ( - ancestors[i].type === 'IfStatement' && - // We check if the consequent or the alternate are also ancestors - // Nodes in the test attribute should be raised - i < ancestors.length - 1 && - (ancestors[i + 1] === (ancestors[i] as estree.IfStatement).consequent || - ancestors[i + 1] === (ancestors[i] as estree.IfStatement).alternate) - ) { - return true; - } - } - return false; -} - -/** - * Computes the set difference (a \ b) - */ -function computeSetDifference(a: Set, b: Set) { - return new Set([...a].filter(str => !b.has(str))); -} - -function getFunctionName(node: estree.FunctionExpression) { - return !node.id ? null : node.id.name; -} - -function isForEachLoopStart( - node: estree.Node, - parent?: estree.Node, -): parent is estree.ForInStatement | estree.ForOfStatement { - return ( - node.type === 'BlockStatement' && - !!parent && - (parent.type === 'ForInStatement' || parent.type === 'ForOfStatement') - ); -} - -function computeNewContextInfo( - variableUsageContext: ReassignmentContext, - context: Rule.RuleContext, - node: estree.Node, -) { - const referencesByIdentifier = new Map(); - const variablesToCheck = new Set(variableUsageContext.variablesToCheck); - const variablesToCheckInCurrentScope = new Set(); - context.getDeclaredVariables(node).forEach(variable => { - variablesToCheck.add(variable.name); - variablesToCheckInCurrentScope.add(variable.name); - for (const currentRef of variable.references) { - referencesByIdentifier.set(currentRef.identifier, currentRef); - } - }); - return { referencesByIdentifier, variablesToCheck, variablesToCheckInCurrentScope }; -} - -function markAsRead(context: ReassignmentContext, variableName: string) { - context.variablesRead.add(variableName); - if (!context.variablesToCheckInCurrentScope.has(variableName) && context.parentContext) { - markAsRead(context.parentContext, variableName); - } -} - -function markAllFunctionArgumentsAsRead(variableUsageContext: ReassignmentContext) { - let functionContext: ReassignmentContext | undefined = variableUsageContext; - while (functionContext && functionContext.type !== 'function') { - functionContext = functionContext.parentContext; - } - - if (functionContext) { - for (const variableName of functionContext.variablesToCheckInCurrentScope) { - functionContext.variablesRead.add(variableName); - } - } -} - -function getPreciseLocationHolder( - reference: Scope.Reference, -): { node: estree.Node } | { loc: AST.SourceLocation } { - const identifierLoc = reference.identifier.loc; - if (identifierLoc && reference.writeExpr && reference.writeExpr.loc) { - return { loc: { start: identifierLoc.start, end: reference.writeExpr.loc.end } }; - } - return { node: reference.identifier }; -} - -function getReference( - variableUsageContext: ReassignmentContext, - identifier: estree.Identifier, -): Scope.Reference | undefined { - const identifierReference = variableUsageContext.referencesByIdentifier.get(identifier); - if (!identifierReference && variableUsageContext.parentContext) { - return getReference(variableUsageContext.parentContext, identifier); - } - return identifierReference; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-primitive-wrappers.ts b/eslint-bridge/src/linting/eslint/rules/no-primitive-wrappers.ts deleted file mode 100644 index 9300b3841f1..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-primitive-wrappers.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1533/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; - -const WRAPPER_TYPES = ['Boolean', 'Number', 'String']; - -export const rule: Rule.RuleModule = { - meta: { - hasSuggestions: true, - messages: { - removeConstructor: 'Remove this use of "{{constructor}}" constructor.', - replaceWrapper: - 'Replace this "{{wrapper}}" wrapper object with primitive type "{{primitive}}".', - suggestRemoveNew: 'Remove "new" operator', - suggestReplaceWrapper: 'Replace "{{wrapper}}" with "{{primitive}}"', - }, - }, - create(context: Rule.RuleContext) { - return { - NewExpression(node: estree.Node) { - const constructor = (node as estree.NewExpression).callee; - if (constructor.type === 'Identifier' && WRAPPER_TYPES.includes(constructor.name)) { - const newToken = context - .getSourceCode() - .getFirstToken(node, token => token.value === 'new')!; - const [begin, end] = newToken.range; - context.report({ - messageId: 'removeConstructor', - data: { - constructor: constructor.name, - }, - node, - suggest: [ - { - messageId: 'suggestRemoveNew', - fix: fixer => fixer.removeRange([begin, end + 1]), - }, - ], - }); - } - }, - TSTypeReference(node: estree.Node) { - const typeString = context.getSourceCode().getText(node); - if (WRAPPER_TYPES.includes(typeString)) { - const primitiveType = typeString.toLowerCase(); - context.report({ - messageId: 'replaceWrapper', - data: { - wrapper: typeString, - primitive: primitiveType, - }, - node, - suggest: [ - { - messageId: 'suggestReplaceWrapper', - data: { - wrapper: typeString, - primitive: primitiveType, - }, - fix: fixer => fixer.replaceText(node, primitiveType), - }, - ], - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-redundant-assignments.ts b/eslint-bridge/src/linting/eslint/rules/no-redundant-assignments.ts deleted file mode 100644 index 6c80af7b3f7..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-redundant-assignments.ts +++ /dev/null @@ -1,333 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4165/javascript - -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { isAssignmentExpression } from 'eslint-plugin-sonarjs/lib/utils/nodes'; -import CodePath = Rule.CodePath; -import Variable = Scope.Variable; -import Reference = Scope.Reference; -import CodePathSegment = Rule.CodePathSegment; -import { - getVariableFromIdentifier, - reachingDefinitions, - ReachingDefinitions, - resolveAssignedValues, - Values, -} from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - reviewAssignment: - 'Review this redundant assignment: "{{symbol}}" already holds the assigned value along all execution paths.', - }, - }, - create(context: Rule.RuleContext) { - const codePathStack: CodePathContext[] = []; - const reachingDefsMap = new Map(); - // map from Variable to CodePath ids where variable is used - const variableUsages = new Map>(); - - return { - ':matches(AssignmentExpression, VariableDeclarator[init])': (node: estree.Node) => { - pushAssignmentContext(node as AssignmentLike); - }, - ':matches(AssignmentExpression, VariableDeclarator[init]):exit': () => { - popAssignmentContext(); - }, - Identifier: (node: estree.Node) => { - if (isEnumConstant()) { - return; - } - checkIdentifierUsage(node as estree.Identifier); - }, - 'Program:exit': () => { - reachingDefinitions(reachingDefsMap); - reachingDefsMap.forEach(defs => { - checkSegment(defs); - }); - reachingDefsMap.clear(); - variableUsages.clear(); - while (codePathStack.length > 0) { - codePathStack.pop(); - } - }, - - // CodePath events - onCodePathSegmentStart: (segment: CodePathSegment) => { - reachingDefsMap.set(segment.id, new ReachingDefinitions(segment)); - }, - onCodePathStart: codePath => { - pushContext(new CodePathContext(codePath)); - }, - onCodePathEnd: () => { - popContext(); - }, - }; - - function popAssignmentContext() { - const assignment = peek(codePathStack).assignmentStack.pop()!; - assignment.rhs.forEach(r => processReference(r)); - assignment.lhs.forEach(r => processReference(r)); - } - - function pushAssignmentContext(node: AssignmentLike) { - peek(codePathStack).assignmentStack.push(new AssignmentContext(node)); - } - - function checkSegment(reachingDefs: ReachingDefinitions) { - const assignedValuesMap = new Map(reachingDefs.in); - reachingDefs.references.forEach(ref => { - const variable = ref.resolved; - if (!variable || !ref.isWrite() || !shouldReport(ref)) { - return; - } - const lhsValues = assignedValuesMap.get(variable); - const rhsValues = resolveAssignedValues( - variable, - ref.writeExpr, - assignedValuesMap, - ref.from, - ); - if (lhsValues?.type === 'AssignedValues' && lhsValues?.size === 1) { - const [lhsVal] = [...lhsValues]; - checkRedundantAssignement(ref, ref.writeExpr, lhsVal, rhsValues, variable.name); - } - assignedValuesMap.set(variable, rhsValues); - }); - } - - function checkRedundantAssignement( - { resolved: variable }: Scope.Reference, - node: estree.Node | null, - lhsVal: string | Variable, - rhsValues: Values, - name: string, - ) { - if (rhsValues.type === 'UnknownValue' || rhsValues.size !== 1) { - return; - } - const [rhsVal] = [...rhsValues]; - if (!isWrittenOnlyOnce(variable!) && lhsVal === rhsVal) { - context.report({ - node: node!, - messageId: 'reviewAssignment', - data: { - symbol: name, - }, - }); - } - } - - // to avoid raising on code like: - // while (cond) { let x = 42; } - function isWrittenOnlyOnce(variable: Scope.Variable) { - return variable.references.filter(ref => ref.isWrite()).length === 1; - } - - function shouldReport(ref: Reference) { - const variable = ref.resolved; - return variable && shouldReportReference(ref) && !variableUsedOutsideOfCodePath(variable); - } - - function shouldReportReference(ref: Reference) { - const variable = ref.resolved; - - return ( - variable && - !isDefaultParameter(ref) && - !variable.name.startsWith('_') && - !isCompoundAssignment(ref.writeExpr) && - !isSelfAssignement(ref) && - !variable.defs.some( - def => def.type === 'Parameter' || (def.type === 'Variable' && !def.node.init), - ) - ); - } - - function isEnumConstant() { - return (context.getAncestors() as TSESTree.Node[]).some(n => n.type === 'TSEnumDeclaration'); - } - - function variableUsedOutsideOfCodePath(variable: Scope.Variable) { - return variableUsages.get(variable)!.size > 1; - } - - function checkIdentifierUsage(node: estree.Identifier) { - const { ref, variable } = resolveReference(node); - if (ref) { - processReference(ref); - } - if (variable) { - updateVariableUsages(variable); - } - } - - function processReference(ref: Reference) { - const assignmentStack = peek(codePathStack).assignmentStack; - if (assignmentStack.length > 0) { - const assignment = peek(assignmentStack); - assignment.add(ref); - } else { - peek(codePathStack).codePath.currentSegments.forEach(segment => { - const reachingDefs = reachingDefsForSegment(segment); - reachingDefs.add(ref); - }); - } - } - - function reachingDefsForSegment(segment: CodePathSegment) { - let defs; - if (reachingDefsMap.has(segment.id)) { - defs = reachingDefsMap.get(segment.id)!; - } else { - defs = new ReachingDefinitions(segment); - reachingDefsMap.set(segment.id, defs); - } - return defs; - } - - function updateVariableUsages(variable: Scope.Variable) { - const codePathId = peek(codePathStack).codePath.id; - if (variableUsages.has(variable)) { - variableUsages.get(variable)!.add(codePathId); - } else { - variableUsages.set(variable, new Set([codePathId])); - } - } - - function pushContext(codePathContext: CodePathContext) { - codePathStack.push(codePathContext); - } - - function popContext() { - codePathStack.pop(); - } - - function resolveReferenceRecursively( - node: estree.Identifier, - scope: Scope.Scope | null, - ): { ref: Reference | null; variable: Scope.Variable | null } { - if (scope === null) { - return { ref: null, variable: null }; - } - const ref = scope.references.find(r => r.identifier === node); - if (ref) { - return { ref, variable: ref.resolved }; - } else { - // if it's not a reference, it can be just declaration without initializer - const variable = scope.variables.find(v => v.defs.find(def => def.name === node)); - if (variable) { - return { ref: null, variable }; - } - // in theory we only need 1-level recursion, only for switch expression, which is likely a bug in eslint - // generic recursion is used for safety & readability - return resolveReferenceRecursively(node, scope.upper); - } - } - - function resolveReference(node: estree.Identifier) { - return resolveReferenceRecursively(node, context.getScope()); - } - }, -}; - -class CodePathContext { - reachingDefinitionsMap = new Map(); - reachingDefinitionsStack: ReachingDefinitions[] = []; - codePath: CodePath; - segments = new Map(); - assignmentStack: AssignmentContext[] = []; - - constructor(codePath: CodePath) { - this.codePath = codePath; - } -} - -type AssignmentLike = TSESTree.AssignmentExpression | TSESTree.VariableDeclarator; - -class AssignmentContext { - node: AssignmentLike; - - constructor(node: AssignmentLike) { - this.node = node; - } - - lhs = new Set(); - rhs = new Set(); - - isRhs(node: TSESTree.Node) { - return isAssignmentExpression(this.node) ? this.node.right === node : this.node.init === node; - } - - isLhs(node: TSESTree.Node) { - return isAssignmentExpression(this.node) ? this.node.left === node : this.node.id === node; - } - - add(ref: Reference) { - let parent = ref.identifier as TSESTree.Node | undefined; - while (parent) { - if (this.isLhs(parent)) { - this.lhs.add(ref); - break; - } - if (this.isRhs(parent)) { - this.rhs.add(ref); - break; - } - parent = parent.parent; - } - if (parent === null) { - throw new Error('failed to find assignment lhs/rhs'); - } - } -} - -function peek(arr: Array) { - return arr[arr.length - 1]; -} - -function isSelfAssignement(ref: Reference) { - const lhs = ref.resolved; - if (ref.writeExpr?.type === 'Identifier') { - const rhs = getVariableFromIdentifier(ref.writeExpr, ref.from); - return lhs === rhs; - } - return false; -} - -function isCompoundAssignment(writeExpr: estree.Node | null) { - if (writeExpr && writeExpr.hasOwnProperty('parent')) { - const node = (writeExpr as TSESTree.Node).parent; - return node && node.type === 'AssignmentExpression' && node.operator !== '='; - } - return false; -} - -function isDefaultParameter(ref: Reference) { - if (ref.identifier.type !== 'Identifier') { - return false; - } - const parent = (ref.identifier as TSESTree.Identifier).parent; - return parent && parent.type === 'AssignmentPattern'; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-redundant-optional.ts b/eslint-bridge/src/linting/eslint/rules/no-redundant-optional.ts deleted file mode 100644 index 79fbc62e0a2..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-redundant-optional.ts +++ /dev/null @@ -1,145 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4782/javascript - -import { Rule, AST } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { isRequiredParserServices, toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - hasSuggestions: true, - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - - create(context: Rule.RuleContext) { - if (!isRequiredParserServices(context.parserServices)) { - return {}; - } - - function checkProperty(node: estree.Node) { - const tsNode = node as TSESTree.Node as - | TSESTree.PropertyDefinition - | TSESTree.TSPropertySignature; - const optionalToken = context - .getSourceCode() - .getFirstToken(node, token => token.value === '?'); - if (!tsNode.optional || !optionalToken) { - return; - } - - const typeNode = getUndefinedTypeAnnotation(tsNode.typeAnnotation); - if (typeNode) { - const suggest = getQuickFixSuggestions(context, optionalToken, typeNode); - const secondaryLocations = [typeNode]; - const message = toEncodedMessage( - "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", - secondaryLocations, - ); - context.report({ - message, - loc: optionalToken.loc, - suggest, - }); - } - } - - return { - 'PropertyDefinition, TSPropertySignature': (node: estree.Node) => checkProperty(node), - }; - }, -}; - -function getUndefinedTypeAnnotation(tsTypeAnnotation?: TSESTree.TSTypeAnnotation) { - if (tsTypeAnnotation) { - return getUndefinedTypeNode(tsTypeAnnotation.typeAnnotation); - } - return undefined; -} - -function getUndefinedTypeNode(typeNode: TSESTree.TypeNode): TSESTree.TypeNode | undefined { - if (typeNode.type === 'TSUndefinedKeyword') { - return typeNode; - } else if (typeNode.type === 'TSUnionType') { - return typeNode.types.map(getUndefinedTypeNode).find(tpe => tpe !== undefined); - } - return undefined; -} - -function getQuickFixSuggestions( - context: Rule.RuleContext, - optionalToken: AST.Token, - undefinedType: TSESTree.TypeNode, -): Rule.SuggestionReportDescriptor[] { - const suggestions: Rule.SuggestionReportDescriptor[] = [ - { - desc: 'Remove "?" operator', - fix: fixer => fixer.remove(optionalToken), - }, - ]; - if (undefinedType.parent?.type === 'TSUnionType') { - suggestions.push(getUndefinedRemovalSuggestion(context, undefinedType)); - } - return suggestions; -} - -function getUndefinedRemovalSuggestion( - context: Rule.RuleContext, - undefinedType: TSESTree.TypeNode, -): Rule.SuggestionReportDescriptor { - return { - desc: 'Remove "undefined" type annotation', - fix: fixer => { - const fixes: Rule.Fix[] = []; - const unionType = undefinedType.parent as TSESTree.TSUnionType; - if (unionType.types.length === 2) { - const unionTypeNode = unionType as any as estree.Node; - const otherType = - unionType.types[0] === undefinedType ? unionType.types[1] : unionType.types[0]; - const otherTypeText = context.getSourceCode().getText(otherType as any as estree.Node); - fixes.push(fixer.replaceText(unionTypeNode, otherTypeText)); - - const tokenBefore = context.getSourceCode().getTokenBefore(unionTypeNode); - const tokenAfter = context.getSourceCode().getTokenAfter(unionTypeNode); - if (tokenBefore?.value === '(' && tokenAfter?.value === ')') { - fixes.push(fixer.remove(tokenBefore)); - fixes.push(fixer.remove(tokenAfter)); - } - } else { - const index = unionType.types.indexOf(undefinedType); - if (index === 0) { - fixes.push(fixer.removeRange([undefinedType.range[0], unionType.types[1].range[0]])); - } else { - fixes.push( - fixer.removeRange([unionType.types[index - 1].range[1], undefinedType.range[1]]), - ); - } - } - return fixes; - }, - }; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-redundant-parentheses.ts b/eslint-bridge/src/linting/eslint/rules/no-redundant-parentheses.ts deleted file mode 100644 index d762866c0ab..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-redundant-parentheses.ts +++ /dev/null @@ -1,131 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1110/javascript - -import { AST, Rule, SourceCode } from 'eslint'; -import * as estree from 'estree'; -import { getParent, toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -interface ParenthesesPair { - openingParenthesis: AST.Token; - closingParenthesis: AST.Token; -} - -/** - * Parts of the grammar that are required to have parentheses. - */ -const parenthesized: { [key: string]: string } = { - DoWhileStatement: 'test', - IfStatement: 'test', - SwitchStatement: 'discriminant', - WhileStatement: 'test', - WithStatement: 'object', - ArrowFunctionExpression: 'body', - ImportExpression: 'source', -}; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - hasSuggestions: true, - }, - create(context: Rule.RuleContext) { - return { - '*': function (node: estree.Node) { - checkRedundantParentheses(context.getSourceCode(), node, context); - }, - }; - }, -}; - -function checkRedundantParentheses( - sourceCode: SourceCode, - node: estree.Node, - context: Rule.RuleContext, -) { - const parenthesesPairsAroundNode = getParenthesesPairsAround(sourceCode, node, node); - const parent = getParent(context); - - // Ignore parentheses pair from the parent node - if (!!parent && isInParentNodeParentheses(node, parent)) { - parenthesesPairsAroundNode.pop(); - } - // One pair of parentheses is allowed for readability purposes - parenthesesPairsAroundNode.shift(); - - parenthesesPairsAroundNode.forEach(parentheses => { - context.report({ - message: toEncodedMessage(`Remove these redundant parentheses.`, [ - parentheses.closingParenthesis, - ]), - loc: parentheses.openingParenthesis.loc, - suggest: [ - { - desc: 'Remove these redundant parentheses', - fix(fixer) { - return [ - fixer.remove(parentheses.openingParenthesis), - fixer.remove(parentheses.closingParenthesis), - ]; - }, - }, - ], - }); - }); -} - -function getParenthesesPairsAround( - sourceCode: SourceCode, - start: estree.Node | AST.Token, - end: estree.Node | AST.Token, -): ParenthesesPair[] { - const tokenBefore = sourceCode.getTokenBefore(start); - const tokenAfter = sourceCode.getTokenAfter(end); - - if (!!tokenBefore && !!tokenAfter && tokenBefore.value === '(' && tokenAfter.value === ')') { - return [ - { openingParenthesis: tokenBefore, closingParenthesis: tokenAfter }, - ...getParenthesesPairsAround(sourceCode, tokenBefore, tokenAfter), - ]; - } - - return []; -} - -function isInParentNodeParentheses(node: estree.Node, parent: estree.Node): boolean { - // Applying same logic as https://github.com/eslint/eslint/blob/main/lib/rules/no-sequences.js#L81 - // both rules (S1110 and S878) can contradict each other, so better use the same logic - const parentAttribute = parenthesized[parent.type as keyof typeof parenthesized]; - const nodeIsInConditionOfParent = - parentAttribute && - node === (parent[parentAttribute as keyof estree.Node] as unknown as estree.Node); - - const nodeIsArgumentOfCallExpression = - (parent.type === 'CallExpression' || parent.type === 'NewExpression') && - parent.arguments.includes(node as estree.Expression); - - return nodeIsInConditionOfParent || nodeIsArgumentOfCallExpression; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-reference-error.ts b/eslint-bridge/src/linting/eslint/rules/no-reference-error.ts deleted file mode 100644 index 52e65285c04..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-reference-error.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3827/javascript -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { findFirstMatchingAncestor, toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - const excludedNames = new Set(); - const undeclaredIdentifiersByName: Map = new Map(); - return { - 'Program:exit'() { - excludedNames.clear(); - undeclaredIdentifiersByName.clear(); - const globalScope = context.getScope(); - globalScope.through.forEach(ref => { - const identifier = ref.identifier; - if (excludedNames.has(identifier.name)) { - return; - } - if ( - ref.writeExpr || - hasTypeOfOperator(identifier as TSESTree.Node) || - isWithinWithStatement(identifier as TSESTree.Node) - ) { - excludedNames.add(identifier.name); - return; - } - const undeclaredIndentifiers = undeclaredIdentifiersByName.get(identifier.name); - if (!!undeclaredIndentifiers) { - undeclaredIndentifiers.push(identifier); - } else { - undeclaredIdentifiersByName.set(identifier.name, [identifier]); - } - }); - undeclaredIdentifiersByName.forEach((identifiers, name) => { - context.report({ - node: identifiers[0], - message: toEncodedMessage( - `\"${name}\" does not exist. Change its name or declare it so that its usage doesn't result in a \"ReferenceError\".`, - identifiers.slice(1), - ), - }); - }); - }, - }; - }, -}; - -function isWithinWithStatement(node: TSESTree.Node) { - return !!findFirstMatchingAncestor(node, ancestor => ancestor.type === 'WithStatement'); -} - -function hasTypeOfOperator(node: TSESTree.Node) { - const parent = node.parent; - return parent?.type === 'UnaryExpression' && parent.operator === 'typeof'; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-referrer-policy.ts b/eslint-bridge/src/linting/eslint/rules/no-referrer-policy.ts deleted file mode 100644 index 6845d589870..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-referrer-policy.ts +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5736/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { - Express, - getPropertyWithValue, - getObjectExpressionProperty, - getFullyQualifiedName, -} from './helpers'; - -const HELMET = 'helmet'; -const POLICY = 'policy'; -const REFERRER_POLICY = 'referrerPolicy'; -const UNSAFE_REFERRER_POLICY_VALUES = ['', 'unsafe-url', 'no-referrer-when-downgrade']; - -export const rule: Rule.RuleModule = Express.SensitiveMiddlewarePropertyRule( - findNoReferrerPolicyPropertyFromHelmet, - `Make sure disabling strict HTTP no-referrer policy is safe here.`, -); - -function findNoReferrerPolicyPropertyFromHelmet( - context: Rule.RuleContext, - node: estree.CallExpression, -): estree.Property[] { - let sensitive: estree.Property | undefined; - - const { callee, arguments: args } = node; - if (args.length === 1) { - const [options] = args; - - /* helmet({ referrerPolicy: false }) or helmet.referrerPolicy({ policy: }) */ - const fqn = getFullyQualifiedName(context, callee); - if (fqn === HELMET && options.type === 'ObjectExpression') { - sensitive = getPropertyWithValue(context, options, REFERRER_POLICY, false); - } else if (fqn === `${HELMET}.${REFERRER_POLICY}`) { - const maybePolicy = getObjectExpressionProperty(options, POLICY); - if (maybePolicy && !isSafePolicy(maybePolicy)) { - sensitive = maybePolicy; - } - } - } - - return sensitive ? [sensitive] : []; -} - -function isSafePolicy(policy: estree.Property): boolean { - const { value } = policy; - const values: Array = - value.type === 'ArrayExpression' ? value.elements : [value]; - const sensitiveValue = values.find( - v => - v?.type === 'Literal' && - typeof v.value === 'string' && - UNSAFE_REFERRER_POLICY_VALUES.includes(v.value), - ); - return !Boolean(sensitiveValue); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-require-or-define.ts b/eslint-bridge/src/linting/eslint/rules/no-require-or-define.ts deleted file mode 100644 index 2167327f4b0..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-require-or-define.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3533/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isRequiredParserServices, RequiredParserServices, isFunction, isString } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - standardImport: 'Use a standard "import" statement instead of "{{adhocImport}}".', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (!isRequiredParserServices(services)) { - return {}; - } - return { - 'CallExpression[callee.type="Identifier"]': (node: estree.Node) => { - if (context.getScope().type !== 'module' && context.getScope().type !== 'global') { - return; - } - const callExpression = node as estree.CallExpression; - const identifier = callExpression.callee as estree.Identifier; - if ( - isAmdImport(callExpression, identifier, services) || - isCommonJsImport(callExpression, identifier, services) - ) { - context.report({ - node: identifier, - messageId: 'standardImport', - data: { - adhocImport: identifier.name, - }, - }); - } - }, - }; - }, -}; - -function isCommonJsImport( - callExpression: estree.CallExpression, - identifier: estree.Identifier, - services: RequiredParserServices, -): boolean { - return ( - callExpression.arguments.length === 1 && - isString(callExpression.arguments[0], services) && - identifier.name === 'require' - ); -} - -function isAmdImport( - callExpression: estree.CallExpression, - identifier: estree.Identifier, - services: RequiredParserServices, -): boolean { - if (identifier.name !== 'require' && identifier.name !== 'define') { - return false; - } - if (callExpression.arguments.length !== 2 && callExpression.arguments.length !== 3) { - return false; - } - return isFunction(callExpression.arguments[callExpression.arguments.length - 1], services); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-return-type-any.ts b/eslint-bridge/src/linting/eslint/rules/no-return-type-any.ts deleted file mode 100644 index 62ab817eb6b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-return-type-any.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4324/javascript - -import { Rule } from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { isRequiredParserServices, RequiredParserServices } from './helpers'; -import * as estree from 'estree'; -import * as ts from 'typescript'; - -type ReturnedExpression = estree.Expression | undefined | null; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeOrChangeType: 'Remove this return type or change it to a more specific.', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - - if (isRequiredParserServices(services)) { - const returnedExpressions: ReturnedExpression[][] = []; - return { - ReturnStatement(node: estree.Node) { - if (returnedExpressions.length > 0) { - returnedExpressions[returnedExpressions.length - 1].push( - (node as estree.ReturnStatement).argument, - ); - } - }, - FunctionDeclaration: function () { - returnedExpressions.push([]); - }, - 'FunctionDeclaration:exit': function (node: estree.Node) { - const returnType = (node as TSESTree.FunctionDeclaration).returnType; - if ( - returnType && - returnType.typeAnnotation.type === 'TSAnyKeyword' && - returnedExpressions.length > 0 && - allReturnTypesEqual(returnedExpressions[returnedExpressions.length - 1], services) - ) { - context.report({ - messageId: 'removeOrChangeType', - loc: returnType.loc, - }); - } - returnedExpressions.pop(); - }, - }; - } - return {}; - }, -}; - -function allReturnTypesEqual( - returns: ReturnedExpression[], - services: RequiredParserServices, -): boolean { - const firstReturnType = getTypeFromTreeNode(returns.pop(), services); - if (!!firstReturnType && !!isPrimitiveType(firstReturnType)) { - return returns.every(nextReturn => { - const nextReturnType = getTypeFromTreeNode(nextReturn, services); - return !!nextReturnType && nextReturnType.flags === firstReturnType.flags; - }); - } - return false; -} - -function getTypeFromTreeNode(node: ReturnedExpression, services: RequiredParserServices) { - const checker = services.program.getTypeChecker(); - return checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node as TSESTree.Node)); -} - -function isPrimitiveType({ flags }: ts.Type) { - return ( - flags & ts.TypeFlags.BooleanLike || - flags & ts.TypeFlags.NumberLike || - flags & ts.TypeFlags.StringLike || - flags & ts.TypeFlags.EnumLike - ); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-same-argument-assert.ts b/eslint-bridge/src/linting/eslint/rules/no-same-argument-assert.ts deleted file mode 100644 index 5cc0655bef9..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-same-argument-assert.ts +++ /dev/null @@ -1,124 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5863/javascript - -import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; -import { Rule } from 'eslint'; -import { areEquivalent } from 'eslint-plugin-sonarjs/lib/utils/equivalence'; -import * as estree from 'estree'; -import { Chai, isIdentifier, isLiteral, toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - if (!Chai.isImported(context)) { - return {}; - } - return { - ExpressionStatement(node: estree.Node) { - const { expression } = node as estree.ExpressionStatement; - checkExpect(context, expression); - checkShould(context, expression); - checkAssert(context, expression); - }, - }; - }, -}; - -function checkAssert(context: Rule.RuleContext, expression: estree.Expression) { - if (expression.type === 'CallExpression') { - const { callee, arguments: args } = expression; - if (callee.type === 'MemberExpression' && isIdentifier(callee.object, 'assert')) { - findDuplicates(context, args); - } - } -} - -function checkExpect(context: Rule.RuleContext, expression: estree.Expression) { - let currentExpression: estree.Node = expression; - let args: estree.Node[] = []; - - while (true) { - if (currentExpression.type === 'CallExpression') { - args = [...currentExpression.arguments, ...args]; - currentExpression = currentExpression.callee; - } else if (currentExpression.type === 'MemberExpression') { - currentExpression = currentExpression.object; - } else if (isIdentifier(currentExpression, 'expect')) { - break; - } else { - return; - } - } - - findDuplicates(context, args); -} - -function checkShould(context: Rule.RuleContext, expression: estree.Expression) { - let currentExpression: estree.Node = expression; - let args: estree.Node[] = []; - let hasShould = false; - - while (true) { - if (currentExpression.type === 'CallExpression') { - args = [...currentExpression.arguments, ...args]; - currentExpression = currentExpression.callee; - } else if (currentExpression.type === 'MemberExpression') { - if (isIdentifier(currentExpression.property, 'should')) { - hasShould = true; - } - currentExpression = currentExpression.object; - } else if (isIdentifier(currentExpression, 'should')) { - break; - } else if (hasShould) { - args = [currentExpression, ...args]; - break; - } else { - return; - } - } - - findDuplicates(context, args); -} - -function findDuplicates(context: Rule.RuleContext, args: estree.Node[]) { - const castedContext = context.getSourceCode() as unknown as TSESLint.SourceCode; - for (let i = 0; i < args.length; i++) { - for (let j = i + 1; j < args.length; j++) { - const duplicates = areEquivalent( - args[i] as TSESTree.Node, - args[j] as TSESTree.Node, - castedContext, - ); - if (duplicates && !isLiteral(args[i])) { - const message = toEncodedMessage(`Replace this argument or its duplicate.`, [args[j]]); - context.report({ message, node: args[i] }); - } - } - } -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-tab.ts b/eslint-bridge/src/linting/eslint/rules/no-tab.ts deleted file mode 100644 index ef6486d26be..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-tab.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S105/javascript - -import { Rule } from 'eslint'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - replaceTab: 'Replace all tab characters in this file by sequences of white-spaces.', - }, - }, - create(context: Rule.RuleContext) { - return { - 'Program:exit': function () { - const firstTab = context - .getSourceCode() - .lines.map((content, line) => ({ content, line })) - .find(t => t.content.includes('\t')); - - if (firstTab !== undefined) { - context.report({ - messageId: 'replaceTab', - loc: { line: firstTab.line + 1, column: 0 }, - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-try-promise.ts b/eslint-bridge/src/linting/eslint/rules/no-try-promise.ts deleted file mode 100644 index fd5dcc3353b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-try-promise.ts +++ /dev/null @@ -1,202 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4822/javascript - -import { Rule, SourceCode } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { isRequiredParserServices, isThenable, toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -type CallLikeExpression = - | TSESTree.CallExpression - | TSESTree.NewExpression - | TSESTree.AwaitExpression; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (isRequiredParserServices(services)) { - return { - TryStatement: (node: estree.Node) => - visitTryStatement(node as TSESTree.TryStatement, context, services), - }; - } - return {}; - }, -}; - -function visitTryStatement( - tryStmt: TSESTree.TryStatement, - context: Rule.RuleContext, - services: any, -) { - if (tryStmt.handler) { - // without '.catch()' - const openPromises: TSESTree.Node[] = []; - // with '.catch()' - const capturedPromises: TSESTree.Node[] = []; - - let hasPotentiallyThrowingCalls = false; - CallLikeExpressionVisitor.getCallExpressions(tryStmt.block, context).forEach(callLikeExpr => { - if ( - callLikeExpr.type === 'AwaitExpression' || - !isThenable(callLikeExpr as estree.Node, services) - ) { - hasPotentiallyThrowingCalls = true; - return; - } - - if (isAwaitLike(callLikeExpr) || isThened(callLikeExpr) || isCatch(callLikeExpr)) { - return; - } - - (isCaught(callLikeExpr) ? capturedPromises : openPromises).push(callLikeExpr); - }); - - if (!hasPotentiallyThrowingCalls) { - checkForWrongCatch(tryStmt, openPromises, context); - checkForUselessCatch(tryStmt, openPromises, capturedPromises, context); - } - } -} - -class CallLikeExpressionVisitor { - private readonly callLikeExpressions: CallLikeExpression[] = []; - - static getCallExpressions(node: TSESTree.Node, context: Rule.RuleContext) { - const visitor = new CallLikeExpressionVisitor(); - visitor.visit(node, context); - return visitor.callLikeExpressions; - } - - private visit(root: TSESTree.Node, context: Rule.RuleContext) { - const visitNode = (node: TSESTree.Node) => { - switch (node.type) { - case 'AwaitExpression': - case 'CallExpression': - case 'NewExpression': - this.callLikeExpressions.push(node); - break; - case 'FunctionDeclaration': - case 'FunctionExpression': - case 'ArrowFunctionExpression': - return; - } - childrenOf(node, context.getSourceCode().visitorKeys).forEach(visitNode); - }; - visitNode(root); - } -} - -function checkForWrongCatch( - tryStmt: TSESTree.TryStatement, - openPromises: TSESTree.Node[], - context: Rule.RuleContext, -) { - if (openPromises.length > 0) { - const ending = openPromises.length > 1 ? 's' : ''; - const message = `Consider using 'await' for the promise${ending} inside this 'try' or replace it with 'Promise.prototype.catch(...)' usage${ending}.`; - const token = context.getSourceCode().getFirstToken(tryStmt as estree.Node); - context.report({ - message: toEncodedMessage(message, openPromises, Array(openPromises.length).fill('Promise')), - loc: token!.loc, - }); - } -} - -function checkForUselessCatch( - tryStmt: TSESTree.TryStatement, - openPromises: TSESTree.Node[], - capturedPromises: TSESTree.Node[], - context: Rule.RuleContext, -) { - if (openPromises.length === 0 && capturedPromises.length > 0) { - const ending = capturedPromises.length > 1 ? 's' : ''; - const message = `Consider removing this 'try' statement as promise${ending} rejection is already captured by '.catch()' method.`; - const token = context.getSourceCode().getFirstToken(tryStmt as estree.Node); - context.report({ - message: toEncodedMessage( - message, - capturedPromises, - Array(capturedPromises.length).fill('Caught promise'), - ), - loc: token!.loc, - }); - } -} - -function isAwaitLike(callExpr: CallLikeExpression) { - return ( - callExpr.parent && - (callExpr.parent.type === 'AwaitExpression' || callExpr.parent.type === 'YieldExpression') - ); -} - -function isThened(callExpr: CallLikeExpression) { - return ( - callExpr.parent && - callExpr.parent.type === 'MemberExpression' && - callExpr.parent.property.type === 'Identifier' && - callExpr.parent.property.name === 'then' - ); -} - -function isCaught(callExpr: CallLikeExpression) { - return ( - callExpr.parent && - callExpr.parent.type === 'MemberExpression' && - callExpr.parent.property.type === 'Identifier' && - callExpr.parent.property.name === 'catch' - ); -} - -function isCatch(callExpr: CallLikeExpression) { - return ( - callExpr.type === 'CallExpression' && - callExpr.callee.type === 'MemberExpression' && - callExpr.callee.property.type === 'Identifier' && - callExpr.callee.property.name === 'catch' - ); -} - -function childrenOf(node: TSESTree.Node, visitorKeys: SourceCode.VisitorKeys) { - const keys = visitorKeys[node.type]; - const children = []; - if (keys) { - for (const key of keys) { - const child = (node as any)[key]; - if (Array.isArray(child)) { - children.push(...child); - } else { - children.push(child); - } - } - } - return children.filter(Boolean); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-undefined-argument.ts b/eslint-bridge/src/linting/eslint/rules/no-undefined-argument.ts deleted file mode 100644 index 9c69c3aa312..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-undefined-argument.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4623/javascript - -import { Rule } from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { isRequiredParserServices, isUndefined, RequiredParserServices } from './helpers'; -import * as estree from 'estree'; -import * as ts from 'typescript'; - -export const rule: Rule.RuleModule = { - meta: { - hasSuggestions: true, - messages: { - removeUndefined: 'Remove this redundant "undefined".', - suggestRemoveUndefined: 'Remove this redundant argument', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (isRequiredParserServices(services)) { - return { - CallExpression: (node: estree.Node) => { - const call = node as estree.CallExpression; - const { arguments: args } = call; - if (args.length === 0) { - return; - } - - const lastArgument = args[args.length - 1]; - if (isUndefined(lastArgument) && isOptionalParameter(args.length - 1, call, services)) { - context.report({ - messageId: 'removeUndefined', - node: lastArgument, - suggest: [ - { - messageId: 'suggestRemoveUndefined', - fix: fixer => { - if (call.arguments.length === 1) { - const openingParen = context.getSourceCode().getTokenAfter(call.callee)!; - const closingParen = context.getSourceCode().getLastToken(node)!; - const [, begin] = openingParen.range; - const [end] = closingParen.range; - return fixer.removeRange([begin, end]); - } else { - const [, begin] = args[args.length - 2].range!; - const [, end] = lastArgument.range!; - return fixer.removeRange([begin, end]); - } - }, - }, - ], - }); - } - }, - }; - } - return {}; - }, -}; - -function isOptionalParameter( - paramIndex: number, - node: estree.CallExpression, - services: RequiredParserServices, -) { - const signature = services.program - .getTypeChecker() - .getResolvedSignature( - services.esTreeNodeToTSNodeMap.get(node as TSESTree.Node) as ts.CallLikeExpression, - ); - if (signature) { - const declaration = signature.declaration; - if (declaration && isFunctionLikeDeclaration(declaration)) { - const { parameters } = declaration; - const parameter = parameters[paramIndex]; - return parameter && (parameter.initializer || parameter.questionToken); - } - } - return false; -} - -function isFunctionLikeDeclaration( - declaration: ts.Declaration, -): declaration is ts.FunctionLikeDeclarationBase { - return [ - ts.SyntaxKind.FunctionDeclaration, - ts.SyntaxKind.FunctionExpression, - ts.SyntaxKind.ArrowFunction, - ts.SyntaxKind.MethodDeclaration, - ts.SyntaxKind.Constructor, - ts.SyntaxKind.GetAccessor, - ts.SyntaxKind.SetAccessor, - ].includes(declaration.kind); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-undefined-assignment.ts b/eslint-bridge/src/linting/eslint/rules/no-undefined-assignment.ts deleted file mode 100644 index e83f1b069d9..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-undefined-assignment.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2138/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isUndefined } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - useNull: 'Use null instead.', - }, - }, - create(context: Rule.RuleContext) { - function raiseOnUndefined(node: estree.Node) { - if (isUndefined(node)) { - context.report({ - messageId: 'useNull', - node, - }); - } - } - return { - VariableDeclarator: (node: estree.Node) => { - const { init } = node as estree.VariableDeclarator; - if (init) { - raiseOnUndefined(init); - } - }, - AssignmentExpression: (node: estree.Node) => { - const { right } = node as estree.AssignmentExpression; - raiseOnUndefined(right); - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-unenclosed-multiline-block.ts b/eslint-bridge/src/linting/eslint/rules/no-unenclosed-multiline-block.ts deleted file mode 100644 index 51862696b0d..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-unenclosed-multiline-block.ts +++ /dev/null @@ -1,220 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2681/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -const NestingStatementLike = [ - 'IfStatement', - 'ForStatement', - 'ForInStatement', - 'ForOfStatement', - 'WhileStatement', -]; - -type Statement = estree.Statement | estree.ModuleDeclaration; - -type NestingStatement = - | estree.IfStatement - | estree.ForStatement - | estree.ForInStatement - | estree.ForOfStatement - | estree.WhileStatement; - -export const rule: Rule.RuleModule = { - create(context: Rule.RuleContext) { - return { - Program: (node: estree.Node) => checkStatements((node as estree.Program).body, context), - BlockStatement: (node: estree.Node) => - checkStatements((node as estree.BlockStatement).body, context), - TSModuleBlock: (node: estree.Node) => - checkStatements((node as unknown as TSESTree.TSModuleBlock).body as Statement[], context), - }; - }, -}; - -function checkStatements(statements: Statement[], context: Rule.RuleContext) { - chain(statements) - .filter(chainedStatements => chainedStatements.areUnenclosed()) - .forEach(unenclosedConsecutives => { - if (unenclosedConsecutives.areAdjacent()) { - raiseAdjacenceIssue(unenclosedConsecutives, context); - } else if (unenclosedConsecutives.areBothIndented()) { - raiseBlockIssue( - unenclosedConsecutives, - countStatementsInTheSamePile(unenclosedConsecutives.prev, statements), - context, - ); - } else if (unenclosedConsecutives.areInlinedAndIndented()) { - raiseInlineAndIndentedIssue(unenclosedConsecutives, context); - } - }); -} - -function chain(statements: Statement[]): ChainedStatements[] { - return statements - .reduce((result, statement, i, array) => { - if (i < array.length - 1 && isNestingStatement(statement)) { - result.push({ prev: statement, next: array[i + 1] }); - } - return result; - }, new Array<{ prev: NestingStatement; next: Statement }>()) - .map(pair => { - return new ChainedStatements(pair.prev, extractLastBody(pair.prev), pair.next); - }); -} - -function extractLastBody(statement: NestingStatement) { - if (statement.type === 'IfStatement') { - if (statement.alternate) { - return statement.alternate; - } else { - return statement.consequent; - } - } else { - return statement.body; - } -} - -function countStatementsInTheSamePile(reference: Statement, statements: Statement[]) { - const startOfPile = position(reference).start; - let lastLineOfPile = startOfPile.line; - for (const statement of statements) { - const currentPosition = position(statement); - const currentLine = currentPosition.end.line; - const currentIndentation = currentPosition.start.column; - if (currentLine > startOfPile.line) { - if (currentIndentation === startOfPile.column) { - lastLineOfPile = currentPosition.end.line; - } else { - break; - } - } - } - return lastLineOfPile - startOfPile.line + 1; -} - -function raiseAdjacenceIssue(adjacentStatements: ChainedStatements, context: Rule.RuleContext) { - context.report({ - message: - `This statement will not be executed ${adjacentStatements.includedStatementQualifier()}; only the first statement will be. ` + - `The rest will execute ${adjacentStatements.excludedStatementsQualifier()}.`, - node: adjacentStatements.next, - }); -} - -function raiseBlockIssue( - piledStatements: ChainedStatements, - sizeOfPile: number, - context: Rule.RuleContext, -) { - context.report({ - message: - `This line will not be executed ${piledStatements.includedStatementQualifier()}; only the first line of this ${sizeOfPile}-line block will be. ` + - `The rest will execute ${piledStatements.excludedStatementsQualifier()}.`, - node: piledStatements.next, - }); -} - -function raiseInlineAndIndentedIssue( - chainedStatements: ChainedStatements, - context: Rule.RuleContext, -) { - context.report({ - message: - `This line will not be executed ${chainedStatements.includedStatementQualifier()}; only the first statement will be. ` + - `The rest will execute ${chainedStatements.excludedStatementsQualifier()}.`, - node: chainedStatements.next, - }); -} - -function isNestingStatement(node: estree.Node): node is NestingStatement { - return NestingStatementLike.includes(node.type); -} - -class ChainedStatements { - private readonly positions: Positions; - - constructor( - readonly topStatement: NestingStatement, - readonly prev: Statement, - readonly next: Statement, - ) { - const topPosition = position(topStatement); - const prevPosition = position(prev); - const nextPosition = position(next); - this.positions = { - prevTopStart: topPosition.start, - prevTopEnd: topPosition.end, - prevStart: prevPosition.start, - prevEnd: prevPosition.end, - nextStart: nextPosition.start, - nextEnd: nextPosition.end, - }; - } - - public areUnenclosed(): boolean { - return this.prev.type !== 'BlockStatement'; - } - - public areAdjacent(): boolean { - return this.positions.prevEnd.line === this.positions.nextStart.line; - } - - public areBothIndented(): boolean { - return ( - this.positions.prevStart.column === this.positions.nextStart.column && this.prevIsIndented() - ); - } - - public areInlinedAndIndented(): boolean { - return ( - this.positions.prevStart.line === this.positions.prevTopEnd.line && - this.positions.nextStart.column > this.positions.prevTopStart.column - ); - } - - public includedStatementQualifier(): string { - return this.topStatement.type === 'IfStatement' ? 'conditionally' : 'in a loop'; - } - - public excludedStatementsQualifier(): string { - return this.topStatement.type === 'IfStatement' ? 'unconditionally' : 'only once'; - } - - private prevIsIndented(): boolean { - return this.positions.prevStart.column > this.positions.prevTopStart.column; - } -} - -type Positions = { - prevTopStart: estree.Position; - prevTopEnd: estree.Position; - prevStart: estree.Position; - prevEnd: estree.Position; - nextStart: estree.Position; - nextEnd: estree.Position; -}; - -function position(node: estree.Node) { - return (node as TSESTree.Node).loc; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-uniq-key.ts b/eslint-bridge/src/linting/eslint/rules/no-uniq-key.ts deleted file mode 100644 index c988de196e6..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-uniq-key.ts +++ /dev/null @@ -1,158 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6486/javascript - -// inspired from `no-array-index` from `eslint-plugin-react`: -// https://github.com/jsx-eslint/eslint-plugin-react/blob/0a2f6b7e9df32215fcd4e3061ec69ea3f2eef793/lib/rules/no-array-index-key.js#L16 - -import { Rule } from 'eslint'; -import { isMemberExpression } from './helpers'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import * as estree from 'estree'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - noGeneratedKeys: 'Do not use generated values for keys of React list components.', - }, - }, - create(context: Rule.RuleContext) { - return { - "JSXAttribute[name.name='key']": (pNode: estree.Node) => { - // hack: it's not possible to type the argument node from TSESTree - const node = pNode as unknown as TSESTree.JSXAttribute; - - const value = node.value; - if (!value || value.type !== 'JSXExpressionContainer') { - // key='foo' or just simply 'key' - return; - } - - checkPropValue(context, value.expression); - }, - }; - }, -}; - -function checkPropValue(context: Rule.RuleContext, node: TSESTree.Node) { - if (isGeneratedExpression(node)) { - // key={bar} - context.report({ - messageId: 'noGeneratedKeys', - node: node as estree.Node, - }); - return; - } - - if (node.type === 'TemplateLiteral') { - // key={`foo-${bar}`} - node.expressions.filter(isGeneratedExpression).forEach(() => { - context.report({ - messageId: 'noGeneratedKeys', - node: node as estree.Node, - }); - }); - - return; - } - - if (node.type === 'BinaryExpression') { - // key={'foo' + bar} - const callExpressions = getCallExpressionsFromBinaryExpression( - node, - ) as TSESTree.CallExpression[]; - - callExpressions.filter(isGeneratedExpression).forEach(() => { - context.report({ - messageId: 'noGeneratedKeys', - node: node as estree.Node, - }); - }); - - return; - } - - if ( - node.type === 'CallExpression' && - node.callee && - node.callee.type === 'MemberExpression' && - node.callee.object && - isGeneratedExpression(node.callee.object) && - node.callee.property && - node.callee.property.type === 'Identifier' && - node.callee.property.name === 'toString' - ) { - // key={bar.toString()} - context.report({ - messageId: 'noGeneratedKeys', - node: node as estree.Node, - }); - return; - } - - if ( - node.type === 'CallExpression' && - node.callee && - node.callee.type === 'Identifier' && - node.callee.name === 'String' && - Array.isArray(node.arguments) && - node.arguments.length > 0 && - isGeneratedExpression(node.arguments[0]) - ) { - // key={String(bar)} - context.report({ - messageId: 'noGeneratedKeys', - node: node.arguments[0] as estree.Node, - }); - } -} - -function isGeneratedExpression(node: TSESTree.Node) { - return isMathRandom(node) || isDateNow(node); - - function isMathRandom(node: TSESTree.Node) { - return ( - node.type === 'CallExpression' && - isMemberExpression(node.callee as estree.Node, 'Math', 'random') - ); - } - - function isDateNow(node: TSESTree.Node) { - return ( - node.type === 'CallExpression' && - isMemberExpression(node.callee as estree.Node, 'Date', 'now') - ); - } -} - -function getCallExpressionsFromBinaryExpression(side: TSESTree.Node) { - if (side.type === 'CallExpression') { - return side; - } - - if (side.type === 'BinaryExpression') { - // recurse - const left: any = getCallExpressionsFromBinaryExpression(side.left); - const right: any = getCallExpressionsFromBinaryExpression(side.right); - return [].concat(left, right).filter(Boolean); - } - - return null; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-unsafe-unzip.ts b/eslint-bridge/src/linting/eslint/rules/no-unsafe-unzip.ts deleted file mode 100644 index 2cdaa66b997..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-unsafe-unzip.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S5042/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { isIdentifier, isLiteral, getValueOfExpression, getFullyQualifiedName } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - safeExpanding: 'Make sure that expanding this archive file is safe here.', - }, - }, - create(context: Rule.RuleContext) { - function canBeProperty(prop: estree.Property | estree.SpreadElement, name: string) { - return ( - prop.type === 'SpreadElement' || - isIdentifier(prop.key, name) || - (isLiteral(prop.key) && prop.key.value === name) - ); - } - - function isSensiteTarCall(call: estree.CallExpression, fqn: string | null) { - if (fqn === 'tar.x') { - const firstArg = call.arguments.length > 0 ? call.arguments[0] : null; - if (!firstArg) { - return false; - } - const firstArgValue = getValueOfExpression(context, firstArg, 'ObjectExpression'); - return ( - !!firstArgValue && !firstArgValue.properties.some(prop => canBeProperty(prop, 'filter')) - ); - } - return false; - } - - function isSensiteExtractZipCall(call: estree.CallExpression, fqn: string | null) { - if (fqn === 'extract-zip') { - const secondArg = call.arguments.length > 1 ? call.arguments[1] : null; - if (!secondArg) { - return false; - } - const secondArgValue = getValueOfExpression(context, secondArg, 'ObjectExpression'); - return ( - !!secondArgValue && - !secondArgValue.properties.some(prop => canBeProperty(prop, 'onEntry')) - ); - } - return false; - } - - return { - CallExpression(node: estree.Node) { - const call = node as estree.CallExpression; - const fqn = getFullyQualifiedName(context, call); - if ( - isSensiteTarCall(call, fqn) || - isSensiteExtractZipCall(call, fqn) || - fqn === 'jszip.loadAsync' || - fqn === 'yauzl.open' || - fqn === 'adm-zip.extractAllTo' - ) { - context.report({ - messageId: 'safeExpanding', - node: call.callee, - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-unthrown-error.ts b/eslint-bridge/src/linting/eslint/rules/no-unthrown-error.ts deleted file mode 100644 index a58ffff7bd2..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-unthrown-error.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S3984/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { getParent } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - hasSuggestions: true, - messages: { - throwOrRemoveError: 'Throw this error or remove this useless statement.', - suggestThrowError: 'Throw this error', - }, - }, - create(context: Rule.RuleContext) { - function looksLikeAnError(expression: estree.Expression | estree.Super): boolean { - const text = context.getSourceCode().getText(expression); - return text.endsWith('Error') || text.endsWith('Exception'); - } - - return { - 'ExpressionStatement > NewExpression': function (node: estree.Node) { - const expression = (node as estree.NewExpression).callee; - if (looksLikeAnError(expression)) { - context.report({ - messageId: 'throwOrRemoveError', - node, - suggest: [ - { - messageId: 'suggestThrowError', - fix: fixer => fixer.insertTextBefore(getParent(context)!, 'throw '), - }, - ], - }); - } - }, - }; - }, -}; diff --git a/eslint-bridge/src/linting/eslint/rules/no-unused-function-argument.ts b/eslint-bridge/src/linting/eslint/rules/no-unused-function-argument.ts deleted file mode 100644 index de07af8df88..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-unused-function-argument.ts +++ /dev/null @@ -1,192 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1172/javascript - -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; - -type FunctionLike = - | TSESTree.ArrowFunctionExpression - | TSESTree.FunctionDeclaration - | TSESTree.FunctionExpression; - -export const rule: Rule.RuleModule = { - meta: { - hasSuggestions: true, - messages: { - removeOrRenameParameter: - 'Remove the unused function parameter "{{param}}" or rename it to "_{{param}}" to make intention explicit.', - suggestRemoveParameter: 'Remove "{{param}}" (beware of call sites)', - suggestRenameParameter: 'Rename "{{param}}" to "_{{param}}"', - }, - }, - create(context: Rule.RuleContext) { - return { - 'FunctionDeclaration, FunctionExpression': function (node: estree.Node) { - reportUnusedArgument( - node, - (node as estree.FunctionDeclaration | estree.FunctionExpression).id, - context, - ); - }, - ArrowFunctionExpression: (node: estree.Node) => { - reportUnusedArgument(node, undefined, context); - }, - }; - }, -}; - -function reportUnusedArgument( - node: estree.Node, - functionId: estree.Identifier | undefined | null, - context: Rule.RuleContext, -) { - const parent = (node as TSESTree.Node).parent; - if (parent && parent.type === 'Property' && parent.kind === 'set') { - return; - } - - if ( - context - .getScope() - .variables.some( - v => v.name === 'arguments' && v.identifiers.length === 0 && v.references.length > 0, - ) - ) { - return; - } - - let parametersVariable = context.getDeclaredVariables(node); - - if (functionId) { - parametersVariable = parametersVariable.filter(v => v.name !== functionId.name); - } - - for (const param of parametersVariable) { - if ( - isUnusedVariable(param) && - !isIgnoredParameter(param) && - !isParameterProperty(param) && - !isThisParameter(param) - ) { - context.report({ - messageId: 'removeOrRenameParameter', - node: param.identifiers[0], - data: { - param: param.name, - }, - suggest: getSuggestions(param, context), - }); - } - } -} - -function getSuggestions(paramVariable: Scope.Variable, context: Rule.RuleContext) { - const paramIdentifier = paramVariable.identifiers[0]; - const suggestions: Rule.SuggestionReportDescriptor[] = [ - { - messageId: 'suggestRenameParameter', - data: { - param: paramVariable.name, - }, - fix: fixer => fixer.insertTextBefore(paramIdentifier, '_'), - }, - ]; - const func = paramVariable.defs[0].node as FunctionLike; - if ((paramIdentifier as TSESTree.Node).parent === func) { - suggestions.push(getParameterRemovalSuggestion(func, paramVariable, paramIdentifier, context)); - } - return suggestions; -} - -function getParameterRemovalSuggestion( - func: FunctionLike, - paramVariable: Scope.Variable, - paramIdentifier: estree.Identifier, - context: Rule.RuleContext, -): Rule.SuggestionReportDescriptor { - return { - messageId: 'suggestRemoveParameter', - data: { - param: paramVariable.name, - }, - fix: fixer => { - const paramIndex = func.params.indexOf(paramIdentifier as TSESTree.Parameter); - const param = func.params[paramIndex] as estree.Node; - if (func.params.length === 1) { - const openingParenthesis = context.getSourceCode().getTokenBefore(param); - const closingParenthesis = context - .getSourceCode() - .getTokenAfter(param, token => token.value === ')'); - let [start, end] = param.range!; - if (openingParenthesis && openingParenthesis.value === '(') { - start = openingParenthesis.range[0]; - end = closingParenthesis!.range[1]; - } - return fixer.replaceTextRange([start, end], '()'); - } else if (func.params.length - 1 === paramIndex) { - const commaAfter = context - .getSourceCode() - .getTokenAfter(param, token => token.value === ','); - const commaBefore = context - .getSourceCode() - .getTokenBefore(param, token => token.value === ',')!; - let start = commaBefore.range[1]; - let end = param.range![1]; - if (commaAfter) { - end = commaAfter.range[1]; - } else { - start = commaBefore.range[0]; - } - return fixer.removeRange([start, end]); - } else { - const [start] = func.params[paramIndex].range; - const [end] = func.params[paramIndex + 1].range; - return fixer.removeRange([start, end]); - } - }, - }; -} - -function isUnusedVariable(variable: Scope.Variable) { - const refs = variable.references; - //Parameter with default value has one reference, but should still be considered as unused. - return refs.length === 0 || (refs.length === 1 && refs[0].init); -} - -function isIgnoredParameter(variable: Scope.Variable) { - return variable.name.startsWith('_'); -} - -export function isParameterProperty(variable: Scope.Variable) { - return variable.defs.some(def => { - const parent = (def.name as TSESTree.Node).parent; - - return ( - parent?.type === 'TSParameterProperty' || - (parent?.type === 'AssignmentPattern' && parent.parent?.type === 'TSParameterProperty') - ); - }); -} - -function isThisParameter(variable: Scope.Variable) { - return variable.name === 'this'; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-useless-increment.ts b/eslint-bridge/src/linting/eslint/rules/no-useless-increment.ts deleted file mode 100644 index d5675584002..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-useless-increment.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S2123/javascript - -import { Rule, Scope } from 'eslint'; -import * as estree from 'estree'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeIncrement: 'Remove this {{updateOperator}}rement or correct the code not to waste it.', - }, - }, - create(context: Rule.RuleContext) { - function reportUpdateExpression(updateExpression: estree.UpdateExpression) { - const updateOperator = updateExpression.operator === '++' ? 'inc' : 'dec'; - context.report({ - messageId: 'removeIncrement', - data: { - updateOperator, - }, - node: updateExpression, - }); - } - - return { - 'ReturnStatement > UpdateExpression': function (node: estree.Node) { - const updateExpression = node as estree.UpdateExpression; - const argument = updateExpression.argument; - if ( - !updateExpression.prefix && - argument.type === 'Identifier' && - isLocalIdentifier(argument, context.getScope()) - ) { - reportUpdateExpression(updateExpression); - } - }, - AssignmentExpression(node: estree.Node) { - const assignment = node as estree.AssignmentExpression; - const rhs = assignment.right; - if (rhs.type === 'UpdateExpression' && !rhs.prefix) { - const lhs = assignment.left; - if ( - lhs.type === 'Identifier' && - rhs.argument.type === 'Identifier' && - rhs.argument.name === lhs.name - ) { - reportUpdateExpression(rhs); - } - } - }, - }; - }, -}; - -function isLocalIdentifier(id: estree.Identifier, scope: Scope.Scope) { - return scope.variables.some(v => v.identifiers.some(i => i.name === id.name)); -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-useless-intersection.ts b/eslint-bridge/src/linting/eslint/rules/no-useless-intersection.ts deleted file mode 100644 index 23530f79b2b..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-useless-intersection.ts +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S4335/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import * as ts from 'typescript'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { isRequiredParserServices } from './helpers'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - removeIntersection: 'Remove this type without members or change this type intersection.', - simplifyIntersection: 'Simplify this intersection as it always has type "{{type}}".', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - if (isRequiredParserServices(services)) { - return { - TSIntersectionType: (node: estree.Node) => { - const intersection = node as unknown as TSESTree.TSIntersectionType; - const anyOrNever = intersection.types.find(typeNode => - ['TSAnyKeyword', 'TSNeverKeyword'].includes(typeNode.type), - ); - if (anyOrNever) { - context.report({ - messageId: 'simplifyIntersection', - data: { - type: anyOrNever.type === 'TSAnyKeyword' ? 'any' : 'never', - }, - node, - }); - } else { - intersection.types.forEach(typeNode => { - const tp: ts.Type = services.program - .getTypeChecker() - .getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(typeNode)); - if (isTypeWithoutMembers(tp)) { - context.report({ - messageId: 'removeIntersection', - node: typeNode as unknown as estree.Node, - }); - } - }); - } - }, - }; - } - return {}; - }, -}; - -function isTypeWithoutMembers(tp: ts.Type): boolean { - return isNullLike(tp) || (isEmptyInterface(tp) && isStandaloneInterface(tp.symbol)); -} - -function isNullLike(tp: ts.Type): boolean { - return ( - Boolean(tp.flags & ts.TypeFlags.Null) || - Boolean(tp.flags & ts.TypeFlags.Undefined) || - Boolean(tp.flags & ts.TypeFlags.Void) - ); -} - -function isEmptyInterface(tp: ts.Type): boolean { - return ( - tp.getProperties().length === 0 && - (!(tp as ts.InterfaceTypeWithDeclaredMembers).declaredIndexInfos || - (tp as ts.InterfaceTypeWithDeclaredMembers).declaredIndexInfos.length === 0) - ); -} - -function isStandaloneInterface(typeSymbol: ts.Symbol) { - // there is no declarations for `{}` - // otherwise check that none of declarations has a heritage clause (`extends X` or `implements X`) - if (!typeSymbol) { - return false; - } - const { declarations } = typeSymbol; - return ( - !declarations || - declarations.every(declaration => { - return ( - isInterfaceDeclaration(declaration) && (declaration.heritageClauses || []).length === 0 - ); - }) - ); -} - -function isInterfaceDeclaration( - declaration: ts.Declaration, -): declaration is ts.InterfaceDeclaration { - return declaration.kind === ts.SyntaxKind.InterfaceDeclaration; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-useless-react-setstate.ts b/eslint-bridge/src/linting/eslint/rules/no-useless-react-setstate.ts deleted file mode 100644 index 243c88c3629..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-useless-react-setstate.ts +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6443/javascript - -import { Rule, Scope } from 'eslint'; -import { getFullyQualifiedName, getVariableFromName } from './helpers'; -import * as estree from 'estree'; - -type Reference = { - setter: Scope.Variable | undefined; - value: Scope.Variable | undefined; -}; - -const declarationSelector = [ - ':matches(', - [ - 'VariableDeclarator[init.callee.name="useState"]', - 'VariableDeclarator[init.callee.object.type="Identifier"][init.callee.property.name="useState"]', - ].join(','), - ')', - '[id.type="ArrayPattern"]', - '[id.elements.length=2]', - '[id.elements.0.type="Identifier"]', - '[id.elements.1.type="Identifier"]', -].join(''); - -const callSelector = [ - 'CallExpression[callee.type="Identifier"]', - '[arguments.length=1]', - '[arguments.0.type="Identifier"]', -].join(''); - -export const rule: Rule.RuleModule = { - meta: { - messages: { - uselessSetState: 'Change the argument of this setter to not use its matching state variable', - }, - }, - create(context: Rule.RuleContext) { - const referencesBySetterName: { [key: string]: Reference } = {}; - - return { - [declarationSelector](node: estree.VariableDeclarator) { - if (isReactCall(context, node.init as estree.CallExpression)) { - const { elements } = node.id as estree.ArrayPattern; - const setter = (elements[1] as estree.Identifier).name; - referencesBySetterName[setter] = { - setter: getVariableFromName(context, setter), - value: getVariableFromName(context, (elements[0] as estree.Identifier).name), - }; - } - }, - [callSelector](node: estree.CallExpression) { - const setter = getVariableFromName(context, (node.callee as estree.Identifier).name); - const value = getVariableFromName(context, (node.arguments[0] as estree.Identifier).name); - const key = setter?.name as string; - if ( - setter && - value && - referencesBySetterName.hasOwnProperty(key) && - referencesBySetterName[key].setter === setter && - referencesBySetterName[key].value === value - ) { - context.report({ - messageId: 'uselessSetState', - node, - }); - } - }, - }; - }, -}; - -function isReactCall(context: Rule.RuleContext, callExpr: estree.CallExpression): boolean { - const fqn = getFullyQualifiedName(context, callExpr); - if (fqn) { - const [module] = fqn.split('.'); - return module === 'react'; - } - return false; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-variable-usage-before-declaration.ts b/eslint-bridge/src/linting/eslint/rules/no-variable-usage-before-declaration.ts deleted file mode 100644 index 9c9ab8bc1f7..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-variable-usage-before-declaration.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S1526/javascript - -import { Rule } from 'eslint'; -import * as estree from 'estree'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { toEncodedMessage } from './helpers'; -import { SONAR_RUNTIME } from 'linting/eslint/linter/parameters'; - -export const rule: Rule.RuleModule = { - meta: { - schema: [ - { - // internal parameter for rules having secondary locations - enum: [SONAR_RUNTIME], - }, - ], - }, - - create(context: Rule.RuleContext) { - return { - "VariableDeclaration[kind='var']": (node: estree.Node) => { - const variables = context.getDeclaredVariables(node); - for (const variable of variables) { - const declaration = variable.identifiers[0]; - const misused = variable.references - .filter(reference => !reference.init && comesBefore(reference.identifier, declaration)) - .map(reference => reference.identifier); - if (misused.length > 0) { - context.report({ - message: toEncodedMessage( - `Move the declaration of \"${declaration.name}\" before this usage.`, - [declaration as TSESTree.Node], - ['Declaration'], - ), - node: misused[0], - }); - } - } - }, - }; - }, -}; - -function comesBefore(node: estree.Node, other: estree.Node) { - const nodeLine = line(node), - otherLine = line(other); - return nodeLine < otherLine || (nodeLine === otherLine && column(node) < column(other)); -} - -function line(node: estree.Node) { - return node.loc!.start.line; -} - -function column(node: estree.Node) { - return node.loc!.start.column; -} diff --git a/eslint-bridge/src/linting/eslint/rules/no-vue-bypass-sanitization.ts b/eslint-bridge/src/linting/eslint/rules/no-vue-bypass-sanitization.ts deleted file mode 100644 index 27dbfe12dcc..00000000000 --- a/eslint-bridge/src/linting/eslint/rules/no-vue-bypass-sanitization.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2023 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// https://sonarsource.github.io/rspec/#/rspec/S6299/javascript - -import * as estree from 'estree'; -import { Rule } from 'eslint'; -import { AST } from 'vue-eslint-parser'; - -export const rule: Rule.RuleModule = { - meta: { - messages: { - safeVueBypassing: 'Make sure bypassing Vue built-in sanitization is safe here.', - }, - }, - create(context: Rule.RuleContext) { - const services = context.parserServices; - - function attrsHref(calleeName: string) { - // select call expression with given name where second argument is object expression like { attrs: { href: 'bla' } } - return `CallExpression[callee.name='${calleeName}'] ObjectExpression.arguments:nth-child(2) > Property[key.name='attrs'] > ObjectExpression.value > Property[key.name='href']`; - } - - const ruleListener: Rule.RuleListener = { - ["JSXAttribute[name.name='domPropsInnerHTML']," + - "Property[key.name='domProps'] > ObjectExpression.value > Property[key.name='innerHTML']"]( - node: estree.Node, - ) { - context.report({ node, messageId: 'safeVueBypassing' }); - }, - [`${attrsHref('createElement')},${attrsHref('h')}`](node: estree.Node) { - context.report({ node, messageId: 'safeVueBypassing' }); - }, - }; - - // @ts-ignore - if (services.defineTemplateBodyVisitor) { - // analyze