├── .editorconfig ├── .eslintrc.json ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── codesee-arch-diagram.yml │ └── deploy.yml ├── .gitignore ├── .travis.yml ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── img ├── icon.png └── openProject.gif ├── jsconfig.json ├── package-lock.json ├── package.json ├── releases ├── git-project-manager-0.1.0.vsix ├── git-project-manager-0.1.1.vsix ├── git-project-manager-0.1.15.vsix ├── git-project-manager-0.1.16.vsix ├── git-project-manager-0.1.18.vsix ├── git-project-manager-0.1.2.vsix ├── git-project-manager-1.0.0.vsix └── git-project-manager-1.0.1.vsix ├── src ├── domain │ ├── ProjectQuickPick.ts │ ├── ProjectRepository.ts │ ├── RecentItem.ts │ ├── config.ts │ └── dirList.ts ├── extension.ts ├── gitProjectLocator.ts ├── gitProjectManager.ts ├── recentItems.ts └── test │ ├── runTest.ts │ └── suite │ ├── dirList.test.ts │ ├── extension.test.ts │ ├── gitProjectLocator.repoInfo.test.ts │ ├── gitProjectLocator.test.ts │ ├── gitProjectManager.test.ts │ ├── index.ts │ ├── noGit │ └── .gitkeep │ ├── noRepoProject │ └── .placeholder1 │ ├── projects │ └── .gitkeep │ ├── recentItems.test.ts │ ├── repo-info-test │ └── base-git │ │ ├── HEAD │ │ ├── config │ │ ├── description │ │ └── info │ │ └── exclude │ └── stateMock.ts ├── tsconfig.json ├── typings.json ├── typings └── walker.d.ts └── vsc-extension-quickstart.md /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | trim_trailing_whitespace = true 7 | 8 | # The indent size used in the `package.json` file cannot be changed 9 | # https://github.com/npm/npm/pull/3180#issuecomment-16336516 10 | [{.travis.yml,package.json}] 11 | indent_size = 2 -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/semi": "warn", 13 | "curly": "warn", 14 | "eqeqeq": "warn", 15 | "no-throw-literal": "warn", 16 | "semi": "off" 17 | } 18 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - VSCode flavor (Portable / Insiders / etc) 26 | - Version [2018.9] 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/workflows/codesee-arch-diagram.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | pull_request_target: 6 | types: [opened, synchronize, reopened] 7 | 8 | name: CodeSee Map 9 | 10 | jobs: 11 | test_map_action: 12 | runs-on: ubuntu-latest 13 | continue-on-error: true 14 | name: Run CodeSee Map Analysis 15 | steps: 16 | - name: checkout 17 | id: checkout 18 | uses: actions/checkout@v2 19 | with: 20 | repository: ${{ github.event.pull_request.head.repo.full_name }} 21 | ref: ${{ github.event.pull_request.head.ref }} 22 | fetch-depth: 0 23 | 24 | # codesee-detect-languages has an output with id languages. 25 | - name: Detect Languages 26 | id: detect-languages 27 | uses: Codesee-io/codesee-detect-languages-action@latest 28 | 29 | - name: Configure JDK 16 30 | uses: actions/setup-java@v2 31 | if: ${{ fromJSON(steps.detect-languages.outputs.languages).java }} 32 | with: 33 | java-version: '16' 34 | distribution: 'zulu' 35 | 36 | # CodeSee Maps Go support uses a static binary so there's no setup step required. 37 | 38 | - name: Configure Node.js 14 39 | uses: actions/setup-node@v2 40 | if: ${{ fromJSON(steps.detect-languages.outputs.languages).javascript }} 41 | with: 42 | node-version: '14' 43 | 44 | - name: Configure Python 3.x 45 | uses: actions/setup-python@v2 46 | if: ${{ fromJSON(steps.detect-languages.outputs.languages).python }} 47 | with: 48 | python-version: '3.x' 49 | architecture: 'x64' 50 | 51 | - name: Configure Ruby '3.x' 52 | uses: ruby/setup-ruby@v1 53 | if: ${{ fromJSON(steps.detect-languages.outputs.languages).ruby }} 54 | with: 55 | ruby-version: '3.0' 56 | 57 | # CodeSee Maps Rust support uses a static binary so there's no setup step required. 58 | 59 | - name: Generate Map 60 | id: generate-map 61 | uses: Codesee-io/codesee-map-action@latest 62 | with: 63 | step: map 64 | github_ref: ${{ github.ref }} 65 | languages: ${{ steps.detect-languages.outputs.languages }} 66 | 67 | - name: Upload Map 68 | id: upload-map 69 | uses: Codesee-io/codesee-map-action@latest 70 | with: 71 | step: mapUpload 72 | api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }} 73 | github_ref: ${{ github.ref }} 74 | 75 | - name: Insights 76 | id: insights 77 | uses: Codesee-io/codesee-map-action@latest 78 | with: 79 | step: insights 80 | api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }} 81 | github_ref: ${{ github.ref }} 82 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - "*" 5 | 6 | name: Deploy Extension 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: 12 15 | - run: npm ci 16 | - name: Publish to Open VSX Registry 17 | uses: HaaLeo/publish-vscode-extension@v0 18 | with: 19 | pat: ${{ secrets.OPEN_VSX_TOKEN }} 20 | - name: Publish to Visual Studio Marketplace 21 | uses: HaaLeo/publish-vscode-extension@v0 22 | with: 23 | pat: ${{ secrets.VS_MARKETPLACE_TOKEN }} 24 | registryUrl: https://marketplace.visualstudio.com 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode-test 2 | node_modules 3 | *.vsix 4 | npm-debug.log* 5 | *.log 6 | out 7 | .vscode-test/ 8 | *.vsix -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | 5 | sudo: false 6 | 7 | os: 8 | - osx 9 | - linux 10 | 11 | install: 12 | - | 13 | if [ $TRAVIS_OS_NAME == "linux" ]; then 14 | export DISPLAY=':99.0' 15 | /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & 16 | fi 17 | - npm install 18 | 19 | script: 20 | - npm run pretest 21 | - npm run test --silent 22 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/out/**/*.js" 17 | ], 18 | "preLaunchTask": "${defaultBuildTask}" 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceFolder}", 26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 27 | ], 28 | "outFiles": [ 29 | "${workspaceFolder}/out/test/**/*.js" 30 | ], 31 | "preLaunchTask": "${defaultBuildTask}" 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "**/.git": true, 5 | "dist": true, 6 | "node_modules": true, 7 | "out": true 8 | } 9 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "script": "compile", 7 | "group": { 8 | "kind": "build", 9 | "isDefault": true 10 | }, 11 | "problemMatcher": [], 12 | "label": "npm: compile", 13 | "detail": "./node_modules/typescript/bin/tsc -p ./" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | typings/** 3 | test/** 4 | .gitignore 5 | jsconfig.json 6 | vsc-extension-quickstart.md 7 | .vscode-test/** 8 | out/test/** 9 | src/** 10 | .gitignore 11 | vsc-extension-quickstart.md 12 | **/tsconfig.json 13 | **/.eslintrc.json 14 | **/*.map 15 | **/*.ts 16 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Next version 4 | 5 | 6 | ## 1.8.0 7 | 8 | - Fixed error that could happen when there are no `origin` remote - #63 9 | - Added publish to OpenVSX - #115 10 | - Updated dependencies 11 | 12 | ## 1.7.1 13 | 14 | - Workaround for #88 where there were erros loading projects from home dir on Ubuntu 15 | - Optimization to getProjectPath - PR #87 by [@KyrychukD](https://github.com/KyrychukD) 16 | 17 | ## 1.7.0 18 | 19 | - Issue #78 - Extension was pointing to the wrong config folder on VSCode-OSS - PR #79 by [@alyyasser](https://github.com/alyyasser) 20 | - Changed the shortcut to `gitProjectManager.openRecents` that overlaps with logout shortcut on MacOS - PR #82 by [@timlogemann](https://github.com/timlogemann) 21 | - Fixed the error that extension wasn't loading in some cases - PR #83 by [@Tedyst](https://github.com/Tedyst) 22 | - Isse #80 - Added option `displayProjectPath` that enables displaying project paths regardless of `checkRemoteOrigin value` - PR #84 by [@KyrychukD](https://github.com/KyrychukD) 23 | 24 | ## 1.6.0 25 | 26 | - Closed #71 - When configured to open in new window, if there isn't a folder in current workspace, open in the current window 27 | - Added the default value of max depth recursion to readme - PR #74 br @andys8 28 | - Improved screen shot presentation - PR #70 by @Tyriar 29 | - Fixed a typo in Readme - PR #69 from @a-sync 30 | 31 | ## 1.5.1 32 | 33 | - Fixed duplication when the same project is found in different base project paths - #68 by Tyriar 34 | 35 | ## 1.5.0 36 | 37 | - Added support to Mercurial and SVN projects (Issue #62) 38 | 39 | ## 1.4.0 40 | 41 | - Added compatibility with windows home path from PR #54 from [@DamonOehlman](https://github.com/DamonOehlman) 42 | - Fixed message related on issue #56 from [@DavidDeSloovere](https://github.com/DavidDeSloovere) 43 | 44 | ## 1.3.2 45 | 46 | - Fixed typo in message from PR #51 thanks to [@aaron7](https://github.com/aaron7) 47 | - Fixed #50 Use the Insiders config directory when running VS Code Insiders (reported by [@Tyriar](https://github.com/Tyriar)) 48 | 49 | ## 1.3.1 50 | 51 | - Fixed #50 where MaxDepthRecursion was not working (reported by [@Tyriar](https://github.com/Tyriar)) 52 | - Fixed #49 where the repository info was not shown (reported by [@Tyriar](https://github.com/Tyriar)) 53 | 54 | ## 1.3.0 55 | 56 | - Implemented a new configuration to stop looking deeper, after a project is found, ignoring MaxDepthRecursion (#47) 57 | - Refactored GitProjectLocator and GitProjectManager classes to receive configuration via injection, making test easier. 58 | 59 | ## 1.2.1 60 | 61 | - Fixed the info about the shortcut keys in mac (PR #45 thanks to @kaiwood) 62 | - Fixed #44 where **storeRepositoriesBetweenSessions** was not working to load from cache 63 | 64 | ## 1.2.0 65 | 66 | - Added support to subfolders (#34) 67 | - Lots of refactorings to improve stability and performance 68 | 69 | ## 1.1.0 70 | 71 | - Closes #39 Added a new command to open a project in a new window 72 | - Merged #38 from @zackschuster to fix a problem where the refresh info in status bar wasn't removed 73 | 74 | ## 1.0.1 75 | 76 | - Fixed #36, removing the promise callback from execute command, thanks to [@Tyriar](https://github.com/Tyriar) 77 | 78 | ## 1.0.0 79 | 80 | - Added new command "GPM - Open Recent Git Project" that lets you open your most recent projects even faster than before 81 | 82 | ## 0.1.18 83 | 84 | - [#32](https://github.com/felipecaputo/git-project-manager/issues/32) - Extension was not following symlinks 85 | 86 | ### 0.1.17 87 | 88 | - Hot fix for 0.1.16, that was with a publish error 89 | 90 | ### 0.1.16 91 | 92 | - [#31](https://github.com/felipecaputo/git-project-manager/issues/31) - Linux tilde alinas (~) was not considered an environment variable 93 | 94 | ### 0.1.15 95 | 96 | - Great contribuitions from [@Tyriar](https://github.com/Tyriar) with issues. Thanks a lot Daniel: 97 | - [#24](https://github.com/felipecaputo/git-project-manager/issues/24) - Restored promised QuickPick after version 0.1.14 removed it 98 | - [#21](https://github.com/felipecaputo/git-project-manager/issues/21) - Sorted project list 99 | - [#16](https://github.com/felipecaputo/git-project-manager/issues/16) - Fixed behavior that project list was keeping old repos removed from config 100 | - [#13](https://github.com/felipecaputo/git-project-manager/issues/13) - Parse environment variables in project folders config 101 | - [#11](https://github.com/felipecaputo/git-project-manager/issues/11) - Auto refresh project list after configuration changed 102 | 103 | - [#10](https://github.com/felipecaputo/git-project-manager/issues/10) - Auto refresh project list after configuration changed 104 | - [#12](https://github.com/felipecaputo/git-project-manager/issues/12) [#14](https://github.com/felipecaputo/git-project-manager/issues/14) - UX improvements 105 | 106 | ### 0.1.14 107 | 108 | - Temporary fix to #8 and #9, ShowQuickPick is not working when receive promises. As a side efect, quick pick will not be shown until 109 | all folders had been searched 110 | 111 | ### 0.1.13 112 | 113 | - Hotfix for 0.1.12, that was not considering **gitProjectManager.openInNewWindow** configuration 114 | 115 | ### 0.1.12 116 | 117 | - Now uses the new VSCode api to open folders, avoiding problems with path and configuration 118 | - Added configuration to define if the selected project will be opened in the same window or in a new window 119 | 120 | ### 0.1.11 121 | 122 | - Now it only shows the folder name instead of the complete path, and also, if *checkRemoteOrigin* is 123 | false, then it show the path as pick list description instead of remote origin 124 | - Changed the way we can configure codePath 125 | 126 | ### 0.1.10 127 | 128 | - Added new configuration "gitProjectManager.checkRemoteOrigin" that allows users to 129 | not check remote repository origin to improve performance 130 | 131 | ### 0.1.9 132 | 133 | - Fixed error in dependency management in VSCode 134 | 135 | ### 0.1.8 136 | 137 | - Improved error messages 138 | 139 | ### 0.1.7 140 | 141 | - Fixed problem with VSCode configuration that changed array config default value 142 | 143 | ### 0.1.6 144 | 145 | - Fixed issue #2 that wasn't working on **0.1.5** 146 | 147 | ### 0.1.5 148 | 149 | - Added two new configs to fix issue #2 and improve perfomance that are: 150 | - maxDepthRecursion 151 | - ignoredFolders 152 | 153 | ### 0.1.4 154 | 155 | - Partially fixed issue #1 (special thanks to @martinpengellyphillips) with PR #3 156 | that allow to configure the code application path 157 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at felipe.caputo (at) gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Felipe Caputo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Git Project Manager 2 | 3 | [![Build Status](https://travis-ci.org/felipecaputo/git-project-manager.svg?branch=master)](https://travis-ci.org/felipecaputo/git-project-manager) 4 | 5 | Git Project Manager (GPM) is a Microsoft VSCode extension that allows you to open a **new window targeting a git repository** directly from the VSCode window. 6 | 7 | ## Available commands 8 | 9 | Currently there are 3 available commands, all of them can be accessed via the VSCode [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) (`Ctrl+Shift+P` on Windows and 10 | `Cmd+Alt+P` on Mac) by typing **GPM**. 11 | 12 | ### GPM: Open Git Project *(Defaults to: `Ctrl+Alt+P`)* 13 | Shows a list of the available git repositories in all folders configured in **`"gitProjectManager.baseProjectsFolders"`**. 14 | The first time its opened, it searches all folders, after that it uses a cached repository info. 15 | 16 | ![open Git Project](/img/openProject.gif) 17 | 18 | ### GPM: Refresh Projects 19 | This command refreshes the cached repositories info for all configured folders. 20 | 21 | ### GPM: Refresh specific project folder 22 | This command allows you to select a specific folder and refresh its repositories, without 23 | refreshing all folders. 24 | 25 | ### GPM: Open Recent Git Project *(Defaults to `Ctrl+Shift+Q`)* 26 | This command opens a list of your most recent git projects, letting you swap even faster between them. 27 | 28 | The size of the list is configured in `"gitProjectManager.recentProjectsListSize"`. 29 | 30 | ## Available settings 31 | 32 | Before you can start using GPM, you need to configure the base folders that the extension will use to 33 | search for git repositories. Edit `settings.json` from the **File -> Preferences -> Settings** and add the 34 | following config: 35 | 36 | ```json 37 | { 38 | "gitProjectManager.baseProjectsFolders": [ 39 | "/home/user/nodeProjects", 40 | "/home/user/personal/pocs" 41 | ] 42 | } 43 | ``` 44 | 45 | Another available configuration is `"gitProjectManager.storeRepositoriesBetweenSessions"` that allows 46 | git repositories information to be stored between sessions to avoid the waiting time when you first load the repositories list. It's set to `false` by default. 47 | 48 | ```json 49 | { 50 | "gitProjectManager.storeRepositoriesBetweenSessions": true 51 | } 52 | ``` 53 | 54 | To improve performance there are 2 new and important configurations: 55 | 56 | 1. **ignoredFolders**: an array of folder names that will be ignored (*node_modules for example*) 57 | 58 | ```json 59 | { 60 | "gitProjectManager.ignoredFolders": ["node_modules"] 61 | } 62 | ``` 63 | 64 | 2. **maxDepthRecursion**: indicates the maximum recursion depth that will be searched starting in the configured folder (default: `2`) 65 | 66 | ```json 67 | { 68 | "gitProjectManager.maxDepthRecursion": 4 69 | } 70 | ``` 71 | 72 | In version 0.1.10 we also added the `"gitProjectManager.checkRemoteOrigin"` 73 | configuration that allows users to not check remote repository origin 74 | to improve performance: 75 | 76 | ```json 77 | { 78 | "gitProjectManager.checkRemoteOrigin": false 79 | } 80 | ``` 81 | 82 | Added in version 0.1.12, you can configure the behavior when opening a project if it will be opened in the same window 83 | or in a new window. (*this option is ignored if there aren't any opened folders in current window*)): 84 | 85 | ```json 86 | { 87 | "gitProjectManager.openInNewWindow": false 88 | } 89 | ``` 90 | 91 | ## Participate 92 | 93 | If you have any ideas, feel free to create issues and pull requests. 94 | -------------------------------------------------------------------------------- /img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipecaputo/git-project-manager/363eea2d4dae731dead5c50ce405d50bdab989ac/img/icon.png -------------------------------------------------------------------------------- /img/openProject.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipecaputo/git-project-manager/363eea2d4dae731dead5c50ce405d50bdab989ac/img/openProject.gif -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES6", 5 | "noLib": true 6 | }, 7 | "exclude": [ 8 | "node_modules" 9 | ] 10 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git-project-manager", 3 | "version": "1.8.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@eslint/eslintrc": { 8 | "version": "1.0.3", 9 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.3.tgz", 10 | "integrity": "sha512-DHI1wDPoKCBPoLZA3qDR91+3te/wDSc1YhKg3jR8NxKKRJq2hwHwcWv31cSwSYvIBrmbENoYMWcenW8uproQqg==", 11 | "dev": true, 12 | "requires": { 13 | "ajv": "^6.12.4", 14 | "debug": "^4.3.2", 15 | "espree": "^9.0.0", 16 | "globals": "^13.9.0", 17 | "ignore": "^4.0.6", 18 | "import-fresh": "^3.2.1", 19 | "js-yaml": "^3.13.1", 20 | "minimatch": "^3.0.4", 21 | "strip-json-comments": "^3.1.1" 22 | }, 23 | "dependencies": { 24 | "debug": { 25 | "version": "4.3.2", 26 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 27 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 28 | "dev": true, 29 | "requires": { 30 | "ms": "2.1.2" 31 | } 32 | }, 33 | "js-yaml": { 34 | "version": "3.14.1", 35 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", 36 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", 37 | "dev": true, 38 | "requires": { 39 | "argparse": "^1.0.7", 40 | "esprima": "^4.0.0" 41 | } 42 | }, 43 | "ms": { 44 | "version": "2.1.2", 45 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 46 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 47 | "dev": true 48 | } 49 | } 50 | }, 51 | "@humanwhocodes/config-array": { 52 | "version": "0.6.0", 53 | "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.6.0.tgz", 54 | "integrity": "sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==", 55 | "dev": true, 56 | "requires": { 57 | "@humanwhocodes/object-schema": "^1.2.0", 58 | "debug": "^4.1.1", 59 | "minimatch": "^3.0.4" 60 | }, 61 | "dependencies": { 62 | "debug": { 63 | "version": "4.3.2", 64 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 65 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 66 | "dev": true, 67 | "requires": { 68 | "ms": "2.1.2" 69 | } 70 | }, 71 | "ms": { 72 | "version": "2.1.2", 73 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 74 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 75 | "dev": true 76 | } 77 | } 78 | }, 79 | "@humanwhocodes/object-schema": { 80 | "version": "1.2.0", 81 | "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", 82 | "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", 83 | "dev": true 84 | }, 85 | "@nodelib/fs.scandir": { 86 | "version": "2.1.5", 87 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 88 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 89 | "dev": true, 90 | "requires": { 91 | "@nodelib/fs.stat": "2.0.5", 92 | "run-parallel": "^1.1.9" 93 | } 94 | }, 95 | "@nodelib/fs.stat": { 96 | "version": "2.0.5", 97 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 98 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 99 | "dev": true 100 | }, 101 | "@nodelib/fs.walk": { 102 | "version": "1.2.8", 103 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 104 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 105 | "dev": true, 106 | "requires": { 107 | "@nodelib/fs.scandir": "2.1.5", 108 | "fastq": "^1.6.0" 109 | } 110 | }, 111 | "@sinonjs/commons": { 112 | "version": "1.8.3", 113 | "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", 114 | "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", 115 | "dev": true, 116 | "requires": { 117 | "type-detect": "4.0.8" 118 | } 119 | }, 120 | "@sinonjs/fake-timers": { 121 | "version": "7.1.2", 122 | "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", 123 | "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", 124 | "dev": true, 125 | "requires": { 126 | "@sinonjs/commons": "^1.7.0" 127 | } 128 | }, 129 | "@sinonjs/samsam": { 130 | "version": "6.0.2", 131 | "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.0.2.tgz", 132 | "integrity": "sha512-jxPRPp9n93ci7b8hMfJOFDPRLFYadN6FSpeROFTR4UNF4i5b+EK6m4QXPO46BDhFgRy1JuS87zAnFOzCUwMJcQ==", 133 | "dev": true, 134 | "requires": { 135 | "@sinonjs/commons": "^1.6.0", 136 | "lodash.get": "^4.4.2", 137 | "type-detect": "^4.0.8" 138 | } 139 | }, 140 | "@sinonjs/text-encoding": { 141 | "version": "0.7.1", 142 | "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", 143 | "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", 144 | "dev": true 145 | }, 146 | "@tootallnate/once": { 147 | "version": "1.1.2", 148 | "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", 149 | "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", 150 | "dev": true 151 | }, 152 | "@types/chai": { 153 | "version": "4.2.22", 154 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.22.tgz", 155 | "integrity": "sha512-tFfcE+DSTzWAgifkjik9AySNqIyNoYwmR+uecPwwD/XRNfvOjmC/FjCxpiUGDkDVDphPfCUecSQVFw+lN3M3kQ==", 156 | "dev": true 157 | }, 158 | "@types/crypto-js": { 159 | "version": "4.0.2", 160 | "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.0.2.tgz", 161 | "integrity": "sha512-sCVniU+h3GcGqxOmng11BRvf9TfN9yIs8KKjB8C8d75W69cpTfZG80gau9yTx5SxF3gvHGbJhdESzzvnjtf3Og==", 162 | "dev": true 163 | }, 164 | "@types/glob": { 165 | "version": "7.2.0", 166 | "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", 167 | "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", 168 | "dev": true, 169 | "requires": { 170 | "@types/minimatch": "*", 171 | "@types/node": "*" 172 | } 173 | }, 174 | "@types/json-schema": { 175 | "version": "7.0.9", 176 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", 177 | "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", 178 | "dev": true 179 | }, 180 | "@types/minimatch": { 181 | "version": "3.0.5", 182 | "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", 183 | "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", 184 | "dev": true 185 | }, 186 | "@types/mocha": { 187 | "version": "9.0.0", 188 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz", 189 | "integrity": "sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==", 190 | "dev": true 191 | }, 192 | "@types/node": { 193 | "version": "16.11.6", 194 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz", 195 | "integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==", 196 | "dev": true 197 | }, 198 | "@types/rimraf": { 199 | "version": "3.0.2", 200 | "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz", 201 | "integrity": "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==", 202 | "dev": true, 203 | "requires": { 204 | "@types/glob": "*", 205 | "@types/node": "*" 206 | } 207 | }, 208 | "@types/sinon": { 209 | "version": "10.0.6", 210 | "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.6.tgz", 211 | "integrity": "sha512-6EF+wzMWvBNeGrfP3Nx60hhx+FfwSg1JJBLAAP/IdIUq0EYkqCYf70VT3PhuhPX9eLD+Dp+lNdpb/ZeHG8Yezg==", 212 | "dev": true, 213 | "requires": { 214 | "@sinonjs/fake-timers": "^7.1.0" 215 | } 216 | }, 217 | "@types/vscode": { 218 | "version": "1.61.0", 219 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.61.0.tgz", 220 | "integrity": "sha512-9k5Nwq45hkRwdfCFY+eKXeQQSbPoA114mF7U/4uJXRBJeGIO7MuJdhF1PnaDN+lllL9iKGQtd6FFXShBXMNaFg==", 221 | "dev": true 222 | }, 223 | "@typescript-eslint/eslint-plugin": { 224 | "version": "5.2.0", 225 | "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.2.0.tgz", 226 | "integrity": "sha512-qQwg7sqYkBF4CIQSyRQyqsYvP+g/J0To9ZPVNJpfxfekl5RmdvQnFFTVVwpRtaUDFNvjfe/34TgY/dpc3MgNTw==", 227 | "dev": true, 228 | "requires": { 229 | "@typescript-eslint/experimental-utils": "5.2.0", 230 | "@typescript-eslint/scope-manager": "5.2.0", 231 | "debug": "^4.3.2", 232 | "functional-red-black-tree": "^1.0.1", 233 | "ignore": "^5.1.8", 234 | "regexpp": "^3.2.0", 235 | "semver": "^7.3.5", 236 | "tsutils": "^3.21.0" 237 | }, 238 | "dependencies": { 239 | "ignore": { 240 | "version": "5.1.8", 241 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", 242 | "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", 243 | "dev": true 244 | } 245 | } 246 | }, 247 | "@typescript-eslint/experimental-utils": { 248 | "version": "5.2.0", 249 | "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.2.0.tgz", 250 | "integrity": "sha512-fWyT3Agf7n7HuZZRpvUYdFYbPk3iDCq6fgu3ulia4c7yxmPnwVBovdSOX7RL+k8u6hLbrXcdAehlWUVpGh6IEw==", 251 | "dev": true, 252 | "requires": { 253 | "@types/json-schema": "^7.0.9", 254 | "@typescript-eslint/scope-manager": "5.2.0", 255 | "@typescript-eslint/types": "5.2.0", 256 | "@typescript-eslint/typescript-estree": "5.2.0", 257 | "eslint-scope": "^5.1.1", 258 | "eslint-utils": "^3.0.0" 259 | } 260 | }, 261 | "@typescript-eslint/parser": { 262 | "version": "5.2.0", 263 | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.2.0.tgz", 264 | "integrity": "sha512-Uyy4TjJBlh3NuA8/4yIQptyJb95Qz5PX//6p8n7zG0QnN4o3NF9Je3JHbVU7fxf5ncSXTmnvMtd/LDQWDk0YqA==", 265 | "dev": true, 266 | "requires": { 267 | "@typescript-eslint/scope-manager": "5.2.0", 268 | "@typescript-eslint/types": "5.2.0", 269 | "@typescript-eslint/typescript-estree": "5.2.0", 270 | "debug": "^4.3.2" 271 | } 272 | }, 273 | "@typescript-eslint/scope-manager": { 274 | "version": "5.2.0", 275 | "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.2.0.tgz", 276 | "integrity": "sha512-RW+wowZqPzQw8MUFltfKYZfKXqA2qgyi6oi/31J1zfXJRpOn6tCaZtd9b5u9ubnDG2n/EMvQLeZrsLNPpaUiFQ==", 277 | "dev": true, 278 | "requires": { 279 | "@typescript-eslint/types": "5.2.0", 280 | "@typescript-eslint/visitor-keys": "5.2.0" 281 | } 282 | }, 283 | "@typescript-eslint/types": { 284 | "version": "5.2.0", 285 | "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.2.0.tgz", 286 | "integrity": "sha512-cTk6x08qqosps6sPyP2j7NxyFPlCNsJwSDasqPNjEQ8JMD5xxj2NHxcLin5AJQ8pAVwpQ8BMI3bTxR0zxmK9qQ==", 287 | "dev": true 288 | }, 289 | "@typescript-eslint/typescript-estree": { 290 | "version": "5.2.0", 291 | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.2.0.tgz", 292 | "integrity": "sha512-RsdXq2XmVgKbm9nLsE3mjNUM7BTr/K4DYR9WfFVMUuozHWtH5gMpiNZmtrMG8GR385EOSQ3kC9HiEMJWimxd/g==", 293 | "dev": true, 294 | "requires": { 295 | "@typescript-eslint/types": "5.2.0", 296 | "@typescript-eslint/visitor-keys": "5.2.0", 297 | "debug": "^4.3.2", 298 | "globby": "^11.0.4", 299 | "is-glob": "^4.0.3", 300 | "semver": "^7.3.5", 301 | "tsutils": "^3.21.0" 302 | } 303 | }, 304 | "@typescript-eslint/visitor-keys": { 305 | "version": "5.2.0", 306 | "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.2.0.tgz", 307 | "integrity": "sha512-Nk7HizaXWWCUBfLA/rPNKMzXzWS8Wg9qHMuGtT+v2/YpPij4nVXrVJc24N/r5WrrmqK31jCrZxeHqIgqRzs0Xg==", 308 | "dev": true, 309 | "requires": { 310 | "@typescript-eslint/types": "5.2.0", 311 | "eslint-visitor-keys": "^3.0.0" 312 | } 313 | }, 314 | "@ungap/promise-all-settled": { 315 | "version": "1.1.2", 316 | "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", 317 | "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", 318 | "dev": true 319 | }, 320 | "acorn": { 321 | "version": "8.5.0", 322 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", 323 | "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", 324 | "dev": true 325 | }, 326 | "acorn-jsx": { 327 | "version": "5.3.2", 328 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 329 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 330 | "dev": true 331 | }, 332 | "agent-base": { 333 | "version": "6.0.2", 334 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", 335 | "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", 336 | "dev": true, 337 | "requires": { 338 | "debug": "4" 339 | } 340 | }, 341 | "ajv": { 342 | "version": "6.12.6", 343 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 344 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 345 | "dev": true, 346 | "requires": { 347 | "fast-deep-equal": "^3.1.1", 348 | "fast-json-stable-stringify": "^2.0.0", 349 | "json-schema-traverse": "^0.4.1", 350 | "uri-js": "^4.2.2" 351 | } 352 | }, 353 | "ansi-colors": { 354 | "version": "4.1.1", 355 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 356 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 357 | "dev": true 358 | }, 359 | "ansi-regex": { 360 | "version": "5.0.1", 361 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 362 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 363 | "dev": true 364 | }, 365 | "ansi-styles": { 366 | "version": "4.3.0", 367 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 368 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 369 | "dev": true, 370 | "requires": { 371 | "color-convert": "^2.0.1" 372 | } 373 | }, 374 | "anymatch": { 375 | "version": "3.1.2", 376 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 377 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 378 | "dev": true, 379 | "requires": { 380 | "normalize-path": "^3.0.0", 381 | "picomatch": "^2.0.4" 382 | } 383 | }, 384 | "argparse": { 385 | "version": "1.0.10", 386 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 387 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 388 | "dev": true, 389 | "requires": { 390 | "sprintf-js": "~1.0.2" 391 | } 392 | }, 393 | "array-union": { 394 | "version": "2.1.0", 395 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", 396 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", 397 | "dev": true 398 | }, 399 | "assertion-error": { 400 | "version": "1.1.0", 401 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 402 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 403 | "dev": true 404 | }, 405 | "balanced-match": { 406 | "version": "1.0.0", 407 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 408 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 409 | "dev": true 410 | }, 411 | "big-integer": { 412 | "version": "1.6.50", 413 | "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.50.tgz", 414 | "integrity": "sha512-+O2uoQWFRo8ysZNo/rjtri2jIwjr3XfeAgRjAUADRqGG+ZITvyn8J1kvXLTaKVr3hhGXk+f23tKfdzmklVM9vQ==", 415 | "dev": true 416 | }, 417 | "binary": { 418 | "version": "0.3.0", 419 | "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", 420 | "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", 421 | "dev": true, 422 | "requires": { 423 | "buffers": "~0.1.1", 424 | "chainsaw": "~0.1.0" 425 | } 426 | }, 427 | "binary-extensions": { 428 | "version": "2.2.0", 429 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 430 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 431 | "dev": true 432 | }, 433 | "bluebird": { 434 | "version": "3.4.7", 435 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", 436 | "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", 437 | "dev": true 438 | }, 439 | "brace-expansion": { 440 | "version": "1.1.11", 441 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 442 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 443 | "dev": true, 444 | "requires": { 445 | "balanced-match": "^1.0.0", 446 | "concat-map": "0.0.1" 447 | } 448 | }, 449 | "braces": { 450 | "version": "3.0.2", 451 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 452 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 453 | "dev": true, 454 | "requires": { 455 | "fill-range": "^7.0.1" 456 | } 457 | }, 458 | "browser-stdout": { 459 | "version": "1.3.1", 460 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 461 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 462 | "dev": true 463 | }, 464 | "buffer-indexof-polyfill": { 465 | "version": "1.0.2", 466 | "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", 467 | "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", 468 | "dev": true 469 | }, 470 | "buffers": { 471 | "version": "0.1.1", 472 | "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", 473 | "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", 474 | "dev": true 475 | }, 476 | "callsites": { 477 | "version": "3.1.0", 478 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 479 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 480 | "dev": true 481 | }, 482 | "camelcase": { 483 | "version": "6.2.0", 484 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", 485 | "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", 486 | "dev": true 487 | }, 488 | "chai": { 489 | "version": "4.3.4", 490 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", 491 | "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", 492 | "dev": true, 493 | "requires": { 494 | "assertion-error": "^1.1.0", 495 | "check-error": "^1.0.2", 496 | "deep-eql": "^3.0.1", 497 | "get-func-name": "^2.0.0", 498 | "pathval": "^1.1.1", 499 | "type-detect": "^4.0.5" 500 | } 501 | }, 502 | "chainsaw": { 503 | "version": "0.1.0", 504 | "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", 505 | "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", 506 | "dev": true, 507 | "requires": { 508 | "traverse": ">=0.3.0 <0.4" 509 | } 510 | }, 511 | "chalk": { 512 | "version": "4.1.2", 513 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 514 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 515 | "dev": true, 516 | "requires": { 517 | "ansi-styles": "^4.1.0", 518 | "supports-color": "^7.1.0" 519 | } 520 | }, 521 | "check-error": { 522 | "version": "1.0.2", 523 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 524 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 525 | "dev": true 526 | }, 527 | "chokidar": { 528 | "version": "3.5.2", 529 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", 530 | "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", 531 | "dev": true, 532 | "requires": { 533 | "anymatch": "~3.1.2", 534 | "braces": "~3.0.2", 535 | "fsevents": "~2.3.2", 536 | "glob-parent": "~5.1.2", 537 | "is-binary-path": "~2.1.0", 538 | "is-glob": "~4.0.1", 539 | "normalize-path": "~3.0.0", 540 | "readdirp": "~3.6.0" 541 | }, 542 | "dependencies": { 543 | "glob-parent": { 544 | "version": "5.1.2", 545 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 546 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 547 | "dev": true, 548 | "requires": { 549 | "is-glob": "^4.0.1" 550 | } 551 | } 552 | } 553 | }, 554 | "cliui": { 555 | "version": "7.0.4", 556 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 557 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 558 | "dev": true, 559 | "requires": { 560 | "string-width": "^4.2.0", 561 | "strip-ansi": "^6.0.0", 562 | "wrap-ansi": "^7.0.0" 563 | } 564 | }, 565 | "color-convert": { 566 | "version": "2.0.1", 567 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 568 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 569 | "dev": true, 570 | "requires": { 571 | "color-name": "~1.1.4" 572 | } 573 | }, 574 | "color-name": { 575 | "version": "1.1.4", 576 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 577 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 578 | "dev": true 579 | }, 580 | "concat-map": { 581 | "version": "0.0.1", 582 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 583 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 584 | "dev": true 585 | }, 586 | "core-util-is": { 587 | "version": "1.0.3", 588 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 589 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", 590 | "dev": true 591 | }, 592 | "cross-spawn": { 593 | "version": "7.0.3", 594 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 595 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 596 | "dev": true, 597 | "requires": { 598 | "path-key": "^3.1.0", 599 | "shebang-command": "^2.0.0", 600 | "which": "^2.0.1" 601 | } 602 | }, 603 | "crypto-js": { 604 | "version": "4.1.1", 605 | "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", 606 | "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" 607 | }, 608 | "debug": { 609 | "version": "4.3.2", 610 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 611 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 612 | "dev": true, 613 | "requires": { 614 | "ms": "2.1.2" 615 | } 616 | }, 617 | "decamelize": { 618 | "version": "4.0.0", 619 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 620 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 621 | "dev": true 622 | }, 623 | "deep-eql": { 624 | "version": "3.0.1", 625 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 626 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 627 | "dev": true, 628 | "requires": { 629 | "type-detect": "^4.0.0" 630 | } 631 | }, 632 | "deep-is": { 633 | "version": "0.1.4", 634 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 635 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", 636 | "dev": true 637 | }, 638 | "diff": { 639 | "version": "5.0.0", 640 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 641 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 642 | "dev": true 643 | }, 644 | "dir-glob": { 645 | "version": "3.0.1", 646 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", 647 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", 648 | "dev": true, 649 | "requires": { 650 | "path-type": "^4.0.0" 651 | } 652 | }, 653 | "doctrine": { 654 | "version": "3.0.0", 655 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 656 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 657 | "dev": true, 658 | "requires": { 659 | "esutils": "^2.0.2" 660 | } 661 | }, 662 | "duplexer2": { 663 | "version": "0.1.4", 664 | "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", 665 | "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", 666 | "dev": true, 667 | "requires": { 668 | "readable-stream": "^2.0.2" 669 | } 670 | }, 671 | "emoji-regex": { 672 | "version": "8.0.0", 673 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 674 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 675 | "dev": true 676 | }, 677 | "enquirer": { 678 | "version": "2.3.6", 679 | "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", 680 | "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", 681 | "dev": true, 682 | "requires": { 683 | "ansi-colors": "^4.1.1" 684 | } 685 | }, 686 | "escalade": { 687 | "version": "3.1.1", 688 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 689 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 690 | "dev": true 691 | }, 692 | "escape-string-regexp": { 693 | "version": "4.0.0", 694 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 695 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 696 | "dev": true 697 | }, 698 | "eslint": { 699 | "version": "8.0.1", 700 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.0.1.tgz", 701 | "integrity": "sha512-LsgcwZgQ72vZ+SMp4K6pAnk2yFDWL7Ti4pJaRvsZ0Hsw2h8ZjUIW38a9AFn2cZXdBMlScMFYYgsSp4ttFI/0bA==", 702 | "dev": true, 703 | "requires": { 704 | "@eslint/eslintrc": "^1.0.3", 705 | "@humanwhocodes/config-array": "^0.6.0", 706 | "ajv": "^6.10.0", 707 | "chalk": "^4.0.0", 708 | "cross-spawn": "^7.0.2", 709 | "debug": "^4.3.2", 710 | "doctrine": "^3.0.0", 711 | "enquirer": "^2.3.5", 712 | "escape-string-regexp": "^4.0.0", 713 | "eslint-scope": "^6.0.0", 714 | "eslint-utils": "^3.0.0", 715 | "eslint-visitor-keys": "^3.0.0", 716 | "espree": "^9.0.0", 717 | "esquery": "^1.4.0", 718 | "esutils": "^2.0.2", 719 | "fast-deep-equal": "^3.1.3", 720 | "file-entry-cache": "^6.0.1", 721 | "functional-red-black-tree": "^1.0.1", 722 | "glob-parent": "^6.0.1", 723 | "globals": "^13.6.0", 724 | "ignore": "^4.0.6", 725 | "import-fresh": "^3.0.0", 726 | "imurmurhash": "^0.1.4", 727 | "is-glob": "^4.0.0", 728 | "js-yaml": "^4.1.0", 729 | "json-stable-stringify-without-jsonify": "^1.0.1", 730 | "levn": "^0.4.1", 731 | "lodash.merge": "^4.6.2", 732 | "minimatch": "^3.0.4", 733 | "natural-compare": "^1.4.0", 734 | "optionator": "^0.9.1", 735 | "progress": "^2.0.0", 736 | "regexpp": "^3.2.0", 737 | "semver": "^7.2.1", 738 | "strip-ansi": "^6.0.0", 739 | "strip-json-comments": "^3.1.0", 740 | "text-table": "^0.2.0", 741 | "v8-compile-cache": "^2.0.3" 742 | }, 743 | "dependencies": { 744 | "debug": { 745 | "version": "4.3.2", 746 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 747 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 748 | "dev": true, 749 | "requires": { 750 | "ms": "2.1.2" 751 | } 752 | }, 753 | "eslint-scope": { 754 | "version": "6.0.0", 755 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", 756 | "integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==", 757 | "dev": true, 758 | "requires": { 759 | "esrecurse": "^4.3.0", 760 | "estraverse": "^5.2.0" 761 | } 762 | }, 763 | "eslint-utils": { 764 | "version": "3.0.0", 765 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", 766 | "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", 767 | "dev": true, 768 | "requires": { 769 | "eslint-visitor-keys": "^2.0.0" 770 | }, 771 | "dependencies": { 772 | "eslint-visitor-keys": { 773 | "version": "2.1.0", 774 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", 775 | "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", 776 | "dev": true 777 | } 778 | } 779 | }, 780 | "eslint-visitor-keys": { 781 | "version": "3.0.0", 782 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz", 783 | "integrity": "sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q==", 784 | "dev": true 785 | }, 786 | "esrecurse": { 787 | "version": "4.3.0", 788 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 789 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 790 | "dev": true, 791 | "requires": { 792 | "estraverse": "^5.2.0" 793 | } 794 | }, 795 | "estraverse": { 796 | "version": "5.2.0", 797 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 798 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 799 | "dev": true 800 | }, 801 | "ms": { 802 | "version": "2.1.2", 803 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 804 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 805 | "dev": true 806 | }, 807 | "regexpp": { 808 | "version": "3.2.0", 809 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", 810 | "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", 811 | "dev": true 812 | } 813 | } 814 | }, 815 | "eslint-scope": { 816 | "version": "5.1.1", 817 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", 818 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", 819 | "dev": true, 820 | "requires": { 821 | "esrecurse": "^4.3.0", 822 | "estraverse": "^4.1.1" 823 | } 824 | }, 825 | "eslint-utils": { 826 | "version": "3.0.0", 827 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", 828 | "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", 829 | "dev": true, 830 | "requires": { 831 | "eslint-visitor-keys": "^2.0.0" 832 | }, 833 | "dependencies": { 834 | "eslint-visitor-keys": { 835 | "version": "2.1.0", 836 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", 837 | "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", 838 | "dev": true 839 | } 840 | } 841 | }, 842 | "eslint-visitor-keys": { 843 | "version": "3.0.0", 844 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz", 845 | "integrity": "sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q==", 846 | "dev": true 847 | }, 848 | "espree": { 849 | "version": "9.0.0", 850 | "resolved": "https://registry.npmjs.org/espree/-/espree-9.0.0.tgz", 851 | "integrity": "sha512-r5EQJcYZ2oaGbeR0jR0fFVijGOcwai07/690YRXLINuhmVeRY4UKSAsQPe/0BNuDgwP7Ophoc1PRsr2E3tkbdQ==", 852 | "dev": true, 853 | "requires": { 854 | "acorn": "^8.5.0", 855 | "acorn-jsx": "^5.3.1", 856 | "eslint-visitor-keys": "^3.0.0" 857 | }, 858 | "dependencies": { 859 | "eslint-visitor-keys": { 860 | "version": "3.0.0", 861 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz", 862 | "integrity": "sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q==", 863 | "dev": true 864 | } 865 | } 866 | }, 867 | "esprima": { 868 | "version": "4.0.1", 869 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 870 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 871 | "dev": true 872 | }, 873 | "esquery": { 874 | "version": "1.4.0", 875 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", 876 | "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", 877 | "dev": true, 878 | "requires": { 879 | "estraverse": "^5.1.0" 880 | }, 881 | "dependencies": { 882 | "estraverse": { 883 | "version": "5.2.0", 884 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 885 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 886 | "dev": true 887 | } 888 | } 889 | }, 890 | "esrecurse": { 891 | "version": "4.3.0", 892 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 893 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 894 | "dev": true, 895 | "requires": { 896 | "estraverse": "^5.2.0" 897 | }, 898 | "dependencies": { 899 | "estraverse": { 900 | "version": "5.3.0", 901 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 902 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 903 | "dev": true 904 | } 905 | } 906 | }, 907 | "estraverse": { 908 | "version": "4.3.0", 909 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", 910 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", 911 | "dev": true 912 | }, 913 | "esutils": { 914 | "version": "2.0.3", 915 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 916 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 917 | "dev": true 918 | }, 919 | "fast-deep-equal": { 920 | "version": "3.1.3", 921 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 922 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 923 | "dev": true 924 | }, 925 | "fast-glob": { 926 | "version": "3.2.7", 927 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", 928 | "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", 929 | "dev": true, 930 | "requires": { 931 | "@nodelib/fs.stat": "^2.0.2", 932 | "@nodelib/fs.walk": "^1.2.3", 933 | "glob-parent": "^5.1.2", 934 | "merge2": "^1.3.0", 935 | "micromatch": "^4.0.4" 936 | }, 937 | "dependencies": { 938 | "glob-parent": { 939 | "version": "5.1.2", 940 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 941 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 942 | "dev": true, 943 | "requires": { 944 | "is-glob": "^4.0.1" 945 | } 946 | } 947 | } 948 | }, 949 | "fast-json-stable-stringify": { 950 | "version": "2.1.0", 951 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 952 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 953 | "dev": true 954 | }, 955 | "fast-levenshtein": { 956 | "version": "2.0.6", 957 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 958 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 959 | "dev": true 960 | }, 961 | "fastq": { 962 | "version": "1.13.0", 963 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", 964 | "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", 965 | "dev": true, 966 | "requires": { 967 | "reusify": "^1.0.4" 968 | } 969 | }, 970 | "file-entry-cache": { 971 | "version": "6.0.1", 972 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", 973 | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", 974 | "dev": true, 975 | "requires": { 976 | "flat-cache": "^3.0.4" 977 | } 978 | }, 979 | "fill-range": { 980 | "version": "7.0.1", 981 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 982 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 983 | "dev": true, 984 | "requires": { 985 | "to-regex-range": "^5.0.1" 986 | } 987 | }, 988 | "find-up": { 989 | "version": "5.0.0", 990 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 991 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 992 | "dev": true, 993 | "requires": { 994 | "locate-path": "^6.0.0", 995 | "path-exists": "^4.0.0" 996 | } 997 | }, 998 | "flat": { 999 | "version": "5.0.2", 1000 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 1001 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 1002 | "dev": true 1003 | }, 1004 | "flat-cache": { 1005 | "version": "3.0.4", 1006 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", 1007 | "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", 1008 | "dev": true, 1009 | "requires": { 1010 | "flatted": "^3.1.0", 1011 | "rimraf": "^3.0.2" 1012 | } 1013 | }, 1014 | "flatted": { 1015 | "version": "3.2.2", 1016 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", 1017 | "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", 1018 | "dev": true 1019 | }, 1020 | "fs.realpath": { 1021 | "version": "1.0.0", 1022 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1023 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 1024 | "dev": true 1025 | }, 1026 | "fsevents": { 1027 | "version": "2.3.2", 1028 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1029 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1030 | "dev": true, 1031 | "optional": true 1032 | }, 1033 | "fstream": { 1034 | "version": "1.0.12", 1035 | "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", 1036 | "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", 1037 | "dev": true, 1038 | "requires": { 1039 | "graceful-fs": "^4.1.2", 1040 | "inherits": "~2.0.0", 1041 | "mkdirp": ">=0.5 0", 1042 | "rimraf": "2" 1043 | }, 1044 | "dependencies": { 1045 | "rimraf": { 1046 | "version": "2.7.1", 1047 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 1048 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 1049 | "dev": true, 1050 | "requires": { 1051 | "glob": "^7.1.3" 1052 | } 1053 | } 1054 | } 1055 | }, 1056 | "functional-red-black-tree": { 1057 | "version": "1.0.1", 1058 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 1059 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 1060 | "dev": true 1061 | }, 1062 | "get-caller-file": { 1063 | "version": "2.0.5", 1064 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 1065 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 1066 | "dev": true 1067 | }, 1068 | "get-func-name": { 1069 | "version": "2.0.0", 1070 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 1071 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 1072 | "dev": true 1073 | }, 1074 | "glob": { 1075 | "version": "7.1.6", 1076 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 1077 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 1078 | "dev": true, 1079 | "requires": { 1080 | "fs.realpath": "^1.0.0", 1081 | "inflight": "^1.0.4", 1082 | "inherits": "2", 1083 | "minimatch": "^3.0.4", 1084 | "once": "^1.3.0", 1085 | "path-is-absolute": "^1.0.0" 1086 | } 1087 | }, 1088 | "glob-parent": { 1089 | "version": "6.0.2", 1090 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 1091 | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 1092 | "dev": true, 1093 | "requires": { 1094 | "is-glob": "^4.0.3" 1095 | } 1096 | }, 1097 | "globals": { 1098 | "version": "13.11.0", 1099 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", 1100 | "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", 1101 | "dev": true, 1102 | "requires": { 1103 | "type-fest": "^0.20.2" 1104 | } 1105 | }, 1106 | "globby": { 1107 | "version": "11.0.4", 1108 | "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", 1109 | "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", 1110 | "dev": true, 1111 | "requires": { 1112 | "array-union": "^2.1.0", 1113 | "dir-glob": "^3.0.1", 1114 | "fast-glob": "^3.1.1", 1115 | "ignore": "^5.1.4", 1116 | "merge2": "^1.3.0", 1117 | "slash": "^3.0.0" 1118 | }, 1119 | "dependencies": { 1120 | "ignore": { 1121 | "version": "5.1.8", 1122 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", 1123 | "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", 1124 | "dev": true 1125 | } 1126 | } 1127 | }, 1128 | "graceful-fs": { 1129 | "version": "4.2.8", 1130 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", 1131 | "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", 1132 | "dev": true 1133 | }, 1134 | "growl": { 1135 | "version": "1.10.5", 1136 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 1137 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 1138 | "dev": true 1139 | }, 1140 | "has-flag": { 1141 | "version": "4.0.0", 1142 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1143 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1144 | "dev": true 1145 | }, 1146 | "he": { 1147 | "version": "1.2.0", 1148 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 1149 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 1150 | "dev": true 1151 | }, 1152 | "http-proxy-agent": { 1153 | "version": "4.0.1", 1154 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", 1155 | "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", 1156 | "dev": true, 1157 | "requires": { 1158 | "@tootallnate/once": "1", 1159 | "agent-base": "6", 1160 | "debug": "4" 1161 | } 1162 | }, 1163 | "https-proxy-agent": { 1164 | "version": "5.0.0", 1165 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", 1166 | "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", 1167 | "dev": true, 1168 | "requires": { 1169 | "agent-base": "6", 1170 | "debug": "4" 1171 | } 1172 | }, 1173 | "ignore": { 1174 | "version": "4.0.6", 1175 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 1176 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 1177 | "dev": true 1178 | }, 1179 | "import-fresh": { 1180 | "version": "3.3.0", 1181 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 1182 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 1183 | "dev": true, 1184 | "requires": { 1185 | "parent-module": "^1.0.0", 1186 | "resolve-from": "^4.0.0" 1187 | } 1188 | }, 1189 | "imurmurhash": { 1190 | "version": "0.1.4", 1191 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 1192 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 1193 | "dev": true 1194 | }, 1195 | "inflight": { 1196 | "version": "1.0.6", 1197 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1198 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1199 | "dev": true, 1200 | "requires": { 1201 | "once": "^1.3.0", 1202 | "wrappy": "1" 1203 | } 1204 | }, 1205 | "inherits": { 1206 | "version": "2.0.4", 1207 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1208 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1209 | "dev": true 1210 | }, 1211 | "is-binary-path": { 1212 | "version": "2.1.0", 1213 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1214 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1215 | "dev": true, 1216 | "requires": { 1217 | "binary-extensions": "^2.0.0" 1218 | } 1219 | }, 1220 | "is-extglob": { 1221 | "version": "2.1.1", 1222 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1223 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 1224 | "dev": true 1225 | }, 1226 | "is-fullwidth-code-point": { 1227 | "version": "3.0.0", 1228 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1229 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1230 | "dev": true 1231 | }, 1232 | "is-glob": { 1233 | "version": "4.0.3", 1234 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1235 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1236 | "dev": true, 1237 | "requires": { 1238 | "is-extglob": "^2.1.1" 1239 | } 1240 | }, 1241 | "is-number": { 1242 | "version": "7.0.0", 1243 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1244 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1245 | "dev": true 1246 | }, 1247 | "is-plain-obj": { 1248 | "version": "2.1.0", 1249 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 1250 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 1251 | "dev": true 1252 | }, 1253 | "is-unicode-supported": { 1254 | "version": "0.1.0", 1255 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 1256 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 1257 | "dev": true 1258 | }, 1259 | "isarray": { 1260 | "version": "0.0.1", 1261 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 1262 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 1263 | "dev": true 1264 | }, 1265 | "isexe": { 1266 | "version": "2.0.0", 1267 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1268 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1269 | "dev": true 1270 | }, 1271 | "js-yaml": { 1272 | "version": "4.1.0", 1273 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 1274 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 1275 | "dev": true, 1276 | "requires": { 1277 | "argparse": "^2.0.1" 1278 | }, 1279 | "dependencies": { 1280 | "argparse": { 1281 | "version": "2.0.1", 1282 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 1283 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 1284 | "dev": true 1285 | } 1286 | } 1287 | }, 1288 | "json-schema-traverse": { 1289 | "version": "0.4.1", 1290 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1291 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 1292 | "dev": true 1293 | }, 1294 | "json-stable-stringify-without-jsonify": { 1295 | "version": "1.0.1", 1296 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 1297 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 1298 | "dev": true 1299 | }, 1300 | "just-extend": { 1301 | "version": "4.2.1", 1302 | "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", 1303 | "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", 1304 | "dev": true 1305 | }, 1306 | "levn": { 1307 | "version": "0.4.1", 1308 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 1309 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 1310 | "dev": true, 1311 | "requires": { 1312 | "prelude-ls": "^1.2.1", 1313 | "type-check": "~0.4.0" 1314 | } 1315 | }, 1316 | "listenercount": { 1317 | "version": "1.0.1", 1318 | "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", 1319 | "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", 1320 | "dev": true 1321 | }, 1322 | "locate-path": { 1323 | "version": "6.0.0", 1324 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 1325 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 1326 | "dev": true, 1327 | "requires": { 1328 | "p-locate": "^5.0.0" 1329 | } 1330 | }, 1331 | "lodash.get": { 1332 | "version": "4.4.2", 1333 | "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", 1334 | "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", 1335 | "dev": true 1336 | }, 1337 | "lodash.merge": { 1338 | "version": "4.6.2", 1339 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 1340 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 1341 | "dev": true 1342 | }, 1343 | "log-symbols": { 1344 | "version": "4.1.0", 1345 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 1346 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 1347 | "dev": true, 1348 | "requires": { 1349 | "chalk": "^4.1.0", 1350 | "is-unicode-supported": "^0.1.0" 1351 | } 1352 | }, 1353 | "lru-cache": { 1354 | "version": "6.0.0", 1355 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 1356 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 1357 | "dev": true, 1358 | "requires": { 1359 | "yallist": "^4.0.0" 1360 | } 1361 | }, 1362 | "makeerror": { 1363 | "version": "1.0.11", 1364 | "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", 1365 | "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", 1366 | "requires": { 1367 | "tmpl": "1.0.x" 1368 | } 1369 | }, 1370 | "merge2": { 1371 | "version": "1.4.1", 1372 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 1373 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 1374 | "dev": true 1375 | }, 1376 | "micromatch": { 1377 | "version": "4.0.4", 1378 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", 1379 | "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", 1380 | "dev": true, 1381 | "requires": { 1382 | "braces": "^3.0.1", 1383 | "picomatch": "^2.2.3" 1384 | } 1385 | }, 1386 | "minimatch": { 1387 | "version": "3.0.4", 1388 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1389 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1390 | "dev": true, 1391 | "requires": { 1392 | "brace-expansion": "^1.1.7" 1393 | } 1394 | }, 1395 | "minimist": { 1396 | "version": "1.2.6", 1397 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 1398 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", 1399 | "dev": true 1400 | }, 1401 | "mkdirp": { 1402 | "version": "0.5.5", 1403 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 1404 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 1405 | "dev": true, 1406 | "requires": { 1407 | "minimist": "^1.2.5" 1408 | } 1409 | }, 1410 | "mocha": { 1411 | "version": "9.1.3", 1412 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", 1413 | "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", 1414 | "dev": true, 1415 | "requires": { 1416 | "@ungap/promise-all-settled": "1.1.2", 1417 | "ansi-colors": "4.1.1", 1418 | "browser-stdout": "1.3.1", 1419 | "chokidar": "3.5.2", 1420 | "debug": "4.3.2", 1421 | "diff": "5.0.0", 1422 | "escape-string-regexp": "4.0.0", 1423 | "find-up": "5.0.0", 1424 | "glob": "7.1.7", 1425 | "growl": "1.10.5", 1426 | "he": "1.2.0", 1427 | "js-yaml": "4.1.0", 1428 | "log-symbols": "4.1.0", 1429 | "minimatch": "3.0.4", 1430 | "ms": "2.1.3", 1431 | "nanoid": "3.1.25", 1432 | "serialize-javascript": "6.0.0", 1433 | "strip-json-comments": "3.1.1", 1434 | "supports-color": "8.1.1", 1435 | "which": "2.0.2", 1436 | "workerpool": "6.1.5", 1437 | "yargs": "16.2.0", 1438 | "yargs-parser": "20.2.4", 1439 | "yargs-unparser": "2.0.0" 1440 | }, 1441 | "dependencies": { 1442 | "debug": { 1443 | "version": "4.3.2", 1444 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 1445 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 1446 | "dev": true, 1447 | "requires": { 1448 | "ms": "2.1.2" 1449 | }, 1450 | "dependencies": { 1451 | "ms": { 1452 | "version": "2.1.2", 1453 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1454 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1455 | "dev": true 1456 | } 1457 | } 1458 | }, 1459 | "glob": { 1460 | "version": "7.1.7", 1461 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", 1462 | "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", 1463 | "dev": true, 1464 | "requires": { 1465 | "fs.realpath": "^1.0.0", 1466 | "inflight": "^1.0.4", 1467 | "inherits": "2", 1468 | "minimatch": "^3.0.4", 1469 | "once": "^1.3.0", 1470 | "path-is-absolute": "^1.0.0" 1471 | } 1472 | }, 1473 | "ms": { 1474 | "version": "2.1.3", 1475 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1476 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1477 | "dev": true 1478 | }, 1479 | "supports-color": { 1480 | "version": "8.1.1", 1481 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 1482 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 1483 | "dev": true, 1484 | "requires": { 1485 | "has-flag": "^4.0.0" 1486 | } 1487 | } 1488 | } 1489 | }, 1490 | "ms": { 1491 | "version": "2.1.2", 1492 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1493 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1494 | "dev": true 1495 | }, 1496 | "nanoid": { 1497 | "version": "3.1.25", 1498 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", 1499 | "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", 1500 | "dev": true 1501 | }, 1502 | "natural-compare": { 1503 | "version": "1.4.0", 1504 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 1505 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 1506 | "dev": true 1507 | }, 1508 | "nise": { 1509 | "version": "5.1.0", 1510 | "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.0.tgz", 1511 | "integrity": "sha512-W5WlHu+wvo3PaKLsJJkgPup2LrsXCcm7AWwyNZkUnn5rwPkuPBi3Iwk5SQtN0mv+K65k7nKKjwNQ30wg3wLAQQ==", 1512 | "dev": true, 1513 | "requires": { 1514 | "@sinonjs/commons": "^1.7.0", 1515 | "@sinonjs/fake-timers": "^7.0.4", 1516 | "@sinonjs/text-encoding": "^0.7.1", 1517 | "just-extend": "^4.0.2", 1518 | "path-to-regexp": "^1.7.0" 1519 | } 1520 | }, 1521 | "normalize-path": { 1522 | "version": "3.0.0", 1523 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1524 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1525 | "dev": true 1526 | }, 1527 | "once": { 1528 | "version": "1.4.0", 1529 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1530 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1531 | "dev": true, 1532 | "requires": { 1533 | "wrappy": "1" 1534 | } 1535 | }, 1536 | "optionator": { 1537 | "version": "0.9.1", 1538 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", 1539 | "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", 1540 | "dev": true, 1541 | "requires": { 1542 | "deep-is": "^0.1.3", 1543 | "fast-levenshtein": "^2.0.6", 1544 | "levn": "^0.4.1", 1545 | "prelude-ls": "^1.2.1", 1546 | "type-check": "^0.4.0", 1547 | "word-wrap": "^1.2.3" 1548 | } 1549 | }, 1550 | "p-limit": { 1551 | "version": "3.1.0", 1552 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 1553 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 1554 | "dev": true, 1555 | "requires": { 1556 | "yocto-queue": "^0.1.0" 1557 | } 1558 | }, 1559 | "p-locate": { 1560 | "version": "5.0.0", 1561 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 1562 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 1563 | "dev": true, 1564 | "requires": { 1565 | "p-limit": "^3.0.2" 1566 | } 1567 | }, 1568 | "parent-module": { 1569 | "version": "1.0.1", 1570 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 1571 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 1572 | "dev": true, 1573 | "requires": { 1574 | "callsites": "^3.0.0" 1575 | } 1576 | }, 1577 | "path-exists": { 1578 | "version": "4.0.0", 1579 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1580 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 1581 | "dev": true 1582 | }, 1583 | "path-is-absolute": { 1584 | "version": "1.0.1", 1585 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1586 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1587 | "dev": true 1588 | }, 1589 | "path-key": { 1590 | "version": "3.1.1", 1591 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 1592 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 1593 | "dev": true 1594 | }, 1595 | "path-to-regexp": { 1596 | "version": "1.8.0", 1597 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", 1598 | "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", 1599 | "dev": true, 1600 | "requires": { 1601 | "isarray": "0.0.1" 1602 | } 1603 | }, 1604 | "path-type": { 1605 | "version": "4.0.0", 1606 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 1607 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 1608 | "dev": true 1609 | }, 1610 | "pathval": { 1611 | "version": "1.1.1", 1612 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 1613 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 1614 | "dev": true 1615 | }, 1616 | "picomatch": { 1617 | "version": "2.3.0", 1618 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", 1619 | "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", 1620 | "dev": true 1621 | }, 1622 | "prelude-ls": { 1623 | "version": "1.2.1", 1624 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 1625 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 1626 | "dev": true 1627 | }, 1628 | "process-nextick-args": { 1629 | "version": "2.0.1", 1630 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 1631 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", 1632 | "dev": true 1633 | }, 1634 | "progress": { 1635 | "version": "2.0.3", 1636 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 1637 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 1638 | "dev": true 1639 | }, 1640 | "punycode": { 1641 | "version": "2.1.1", 1642 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 1643 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 1644 | "dev": true 1645 | }, 1646 | "queue-microtask": { 1647 | "version": "1.2.3", 1648 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1649 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1650 | "dev": true 1651 | }, 1652 | "randombytes": { 1653 | "version": "2.1.0", 1654 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 1655 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 1656 | "dev": true, 1657 | "requires": { 1658 | "safe-buffer": "^5.1.0" 1659 | } 1660 | }, 1661 | "readable-stream": { 1662 | "version": "2.3.7", 1663 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 1664 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 1665 | "dev": true, 1666 | "requires": { 1667 | "core-util-is": "~1.0.0", 1668 | "inherits": "~2.0.3", 1669 | "isarray": "~1.0.0", 1670 | "process-nextick-args": "~2.0.0", 1671 | "safe-buffer": "~5.1.1", 1672 | "string_decoder": "~1.1.1", 1673 | "util-deprecate": "~1.0.1" 1674 | }, 1675 | "dependencies": { 1676 | "isarray": { 1677 | "version": "1.0.0", 1678 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1679 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 1680 | "dev": true 1681 | }, 1682 | "safe-buffer": { 1683 | "version": "5.1.2", 1684 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1685 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1686 | "dev": true 1687 | } 1688 | } 1689 | }, 1690 | "readdirp": { 1691 | "version": "3.6.0", 1692 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1693 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1694 | "dev": true, 1695 | "requires": { 1696 | "picomatch": "^2.2.1" 1697 | } 1698 | }, 1699 | "regexpp": { 1700 | "version": "3.2.0", 1701 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", 1702 | "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", 1703 | "dev": true 1704 | }, 1705 | "require-directory": { 1706 | "version": "2.1.1", 1707 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1708 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 1709 | "dev": true 1710 | }, 1711 | "resolve-from": { 1712 | "version": "4.0.0", 1713 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 1714 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1715 | "dev": true 1716 | }, 1717 | "reusify": { 1718 | "version": "1.0.4", 1719 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1720 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1721 | "dev": true 1722 | }, 1723 | "rimraf": { 1724 | "version": "3.0.2", 1725 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 1726 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 1727 | "dev": true, 1728 | "requires": { 1729 | "glob": "^7.1.3" 1730 | } 1731 | }, 1732 | "run-parallel": { 1733 | "version": "1.2.0", 1734 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1735 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1736 | "dev": true, 1737 | "requires": { 1738 | "queue-microtask": "^1.2.2" 1739 | } 1740 | }, 1741 | "safe-buffer": { 1742 | "version": "5.2.1", 1743 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1744 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1745 | "dev": true 1746 | }, 1747 | "semver": { 1748 | "version": "7.3.5", 1749 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", 1750 | "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", 1751 | "dev": true, 1752 | "requires": { 1753 | "lru-cache": "^6.0.0" 1754 | } 1755 | }, 1756 | "serialize-javascript": { 1757 | "version": "6.0.0", 1758 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", 1759 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", 1760 | "dev": true, 1761 | "requires": { 1762 | "randombytes": "^2.1.0" 1763 | } 1764 | }, 1765 | "setimmediate": { 1766 | "version": "1.0.5", 1767 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", 1768 | "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", 1769 | "dev": true 1770 | }, 1771 | "shebang-command": { 1772 | "version": "2.0.0", 1773 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1774 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1775 | "dev": true, 1776 | "requires": { 1777 | "shebang-regex": "^3.0.0" 1778 | } 1779 | }, 1780 | "shebang-regex": { 1781 | "version": "3.0.0", 1782 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 1783 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 1784 | "dev": true 1785 | }, 1786 | "sinon": { 1787 | "version": "11.1.2", 1788 | "resolved": "https://registry.npmjs.org/sinon/-/sinon-11.1.2.tgz", 1789 | "integrity": "sha512-59237HChms4kg7/sXhiRcUzdSkKuydDeTiamT/jesUVHshBgL8XAmhgFo0GfK6RruMDM/iRSij1EybmMog9cJw==", 1790 | "dev": true, 1791 | "requires": { 1792 | "@sinonjs/commons": "^1.8.3", 1793 | "@sinonjs/fake-timers": "^7.1.2", 1794 | "@sinonjs/samsam": "^6.0.2", 1795 | "diff": "^5.0.0", 1796 | "nise": "^5.1.0", 1797 | "supports-color": "^7.2.0" 1798 | } 1799 | }, 1800 | "slash": { 1801 | "version": "3.0.0", 1802 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 1803 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", 1804 | "dev": true 1805 | }, 1806 | "sprintf-js": { 1807 | "version": "1.0.3", 1808 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1809 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1810 | "dev": true 1811 | }, 1812 | "string-width": { 1813 | "version": "4.2.3", 1814 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1815 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1816 | "dev": true, 1817 | "requires": { 1818 | "emoji-regex": "^8.0.0", 1819 | "is-fullwidth-code-point": "^3.0.0", 1820 | "strip-ansi": "^6.0.1" 1821 | } 1822 | }, 1823 | "string_decoder": { 1824 | "version": "1.1.1", 1825 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1826 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1827 | "dev": true, 1828 | "requires": { 1829 | "safe-buffer": "~5.1.0" 1830 | }, 1831 | "dependencies": { 1832 | "safe-buffer": { 1833 | "version": "5.1.2", 1834 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1835 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1836 | "dev": true 1837 | } 1838 | } 1839 | }, 1840 | "strip-ansi": { 1841 | "version": "6.0.1", 1842 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1843 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1844 | "dev": true, 1845 | "requires": { 1846 | "ansi-regex": "^5.0.1" 1847 | } 1848 | }, 1849 | "strip-json-comments": { 1850 | "version": "3.1.1", 1851 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1852 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1853 | "dev": true 1854 | }, 1855 | "supports-color": { 1856 | "version": "7.2.0", 1857 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1858 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1859 | "dev": true, 1860 | "requires": { 1861 | "has-flag": "^4.0.0" 1862 | } 1863 | }, 1864 | "text-table": { 1865 | "version": "0.2.0", 1866 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1867 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1868 | "dev": true 1869 | }, 1870 | "tmpl": { 1871 | "version": "1.0.5", 1872 | "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", 1873 | "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" 1874 | }, 1875 | "to-regex-range": { 1876 | "version": "5.0.1", 1877 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1878 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1879 | "dev": true, 1880 | "requires": { 1881 | "is-number": "^7.0.0" 1882 | } 1883 | }, 1884 | "traverse": { 1885 | "version": "0.3.9", 1886 | "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", 1887 | "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", 1888 | "dev": true 1889 | }, 1890 | "tslib": { 1891 | "version": "1.14.1", 1892 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 1893 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", 1894 | "dev": true 1895 | }, 1896 | "tsutils": { 1897 | "version": "3.21.0", 1898 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", 1899 | "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", 1900 | "dev": true, 1901 | "requires": { 1902 | "tslib": "^1.8.1" 1903 | } 1904 | }, 1905 | "type-check": { 1906 | "version": "0.4.0", 1907 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 1908 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 1909 | "dev": true, 1910 | "requires": { 1911 | "prelude-ls": "^1.2.1" 1912 | } 1913 | }, 1914 | "type-detect": { 1915 | "version": "4.0.8", 1916 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 1917 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 1918 | "dev": true 1919 | }, 1920 | "type-fest": { 1921 | "version": "0.20.2", 1922 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", 1923 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", 1924 | "dev": true 1925 | }, 1926 | "typescript": { 1927 | "version": "4.4.4", 1928 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", 1929 | "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", 1930 | "dev": true 1931 | }, 1932 | "unzipper": { 1933 | "version": "0.10.11", 1934 | "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", 1935 | "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", 1936 | "dev": true, 1937 | "requires": { 1938 | "big-integer": "^1.6.17", 1939 | "binary": "~0.3.0", 1940 | "bluebird": "~3.4.1", 1941 | "buffer-indexof-polyfill": "~1.0.0", 1942 | "duplexer2": "~0.1.4", 1943 | "fstream": "^1.0.12", 1944 | "graceful-fs": "^4.2.2", 1945 | "listenercount": "~1.0.1", 1946 | "readable-stream": "~2.3.6", 1947 | "setimmediate": "~1.0.4" 1948 | } 1949 | }, 1950 | "uri-js": { 1951 | "version": "4.4.1", 1952 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 1953 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 1954 | "dev": true, 1955 | "requires": { 1956 | "punycode": "^2.1.0" 1957 | } 1958 | }, 1959 | "util-deprecate": { 1960 | "version": "1.0.2", 1961 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1962 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 1963 | "dev": true 1964 | }, 1965 | "v8-compile-cache": { 1966 | "version": "2.3.0", 1967 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", 1968 | "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", 1969 | "dev": true 1970 | }, 1971 | "vscode-test": { 1972 | "version": "1.6.1", 1973 | "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz", 1974 | "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==", 1975 | "dev": true, 1976 | "requires": { 1977 | "http-proxy-agent": "^4.0.1", 1978 | "https-proxy-agent": "^5.0.0", 1979 | "rimraf": "^3.0.2", 1980 | "unzipper": "^0.10.11" 1981 | } 1982 | }, 1983 | "walker": { 1984 | "version": "1.0.7", 1985 | "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", 1986 | "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", 1987 | "requires": { 1988 | "makeerror": "1.0.x" 1989 | } 1990 | }, 1991 | "which": { 1992 | "version": "2.0.2", 1993 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1994 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1995 | "dev": true, 1996 | "requires": { 1997 | "isexe": "^2.0.0" 1998 | } 1999 | }, 2000 | "word-wrap": { 2001 | "version": "1.2.3", 2002 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", 2003 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 2004 | "dev": true 2005 | }, 2006 | "workerpool": { 2007 | "version": "6.1.5", 2008 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", 2009 | "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", 2010 | "dev": true 2011 | }, 2012 | "wrap-ansi": { 2013 | "version": "7.0.0", 2014 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 2015 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 2016 | "dev": true, 2017 | "requires": { 2018 | "ansi-styles": "^4.0.0", 2019 | "string-width": "^4.1.0", 2020 | "strip-ansi": "^6.0.0" 2021 | } 2022 | }, 2023 | "wrappy": { 2024 | "version": "1.0.2", 2025 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2026 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 2027 | "dev": true 2028 | }, 2029 | "y18n": { 2030 | "version": "5.0.8", 2031 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 2032 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 2033 | "dev": true 2034 | }, 2035 | "yallist": { 2036 | "version": "4.0.0", 2037 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 2038 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 2039 | "dev": true 2040 | }, 2041 | "yargs": { 2042 | "version": "16.2.0", 2043 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 2044 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 2045 | "dev": true, 2046 | "requires": { 2047 | "cliui": "^7.0.2", 2048 | "escalade": "^3.1.1", 2049 | "get-caller-file": "^2.0.5", 2050 | "require-directory": "^2.1.1", 2051 | "string-width": "^4.2.0", 2052 | "y18n": "^5.0.5", 2053 | "yargs-parser": "^20.2.2" 2054 | } 2055 | }, 2056 | "yargs-parser": { 2057 | "version": "20.2.4", 2058 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", 2059 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", 2060 | "dev": true 2061 | }, 2062 | "yargs-unparser": { 2063 | "version": "2.0.0", 2064 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 2065 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 2066 | "dev": true, 2067 | "requires": { 2068 | "camelcase": "^6.0.0", 2069 | "decamelize": "^4.0.0", 2070 | "flat": "^5.0.2", 2071 | "is-plain-obj": "^2.1.0" 2072 | } 2073 | }, 2074 | "yocto-queue": { 2075 | "version": "0.1.0", 2076 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 2077 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 2078 | "dev": true 2079 | } 2080 | } 2081 | } 2082 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git-project-manager", 3 | "displayName": "Git Project Manager", 4 | "description": "Allows you to change easily between git projects.", 5 | "icon": "img/icon.png", 6 | "version": "1.8.2", 7 | "publisher": "felipecaputo", 8 | "galleryBanner": { 9 | "color": "#202040", 10 | "theme": "dark" 11 | }, 12 | "license": "SEE LICENSE IN LICENSE.md", 13 | "bugs": { 14 | "url": "https://github.com/felipecaputo/git-project-manager/issues", 15 | "email": "felipe.caputo@gmail.com" 16 | }, 17 | "homepage": "https://github.com/felipecaputo/git-project-manager/blob/master/README.md", 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/felipecaputo/git-project-manager.git" 21 | }, 22 | "engines": { 23 | "vscode": "^1.61.0" 24 | }, 25 | "categories": [ 26 | "Other" 27 | ], 28 | "activationEvents": [ 29 | "onCommand:gitProjectManager.openProject", 30 | "onCommand:gitProjectManager.openProjectNewWindow", 31 | "onCommand:gitProjectManager.refreshProjects", 32 | "onCommand:gitProjectManager.refreshFolder", 33 | "onCommand:gitProjectManager.openRecents", 34 | "onCommand:gitProjectManager.openSubFolder", 35 | "onStartupFinished" 36 | ], 37 | "contributes": { 38 | "configuration": { 39 | "type": "object", 40 | "title": "Git Project Manager configuration", 41 | "properties": { 42 | "gitProjectManager.baseProjectsFolders": { 43 | "type": "array", 44 | "default": [], 45 | "description": "Specifies the base folders to search for git repositories" 46 | }, 47 | "gitProjectManager.storeRepositoriesBetweenSessions": { 48 | "type": "boolean", 49 | "default": false, 50 | "description": "Specifies whether saves repository folders' data between sessions" 51 | }, 52 | "gitProjectManager.ignoredFolders": { 53 | "type": "array", 54 | "default": [], 55 | "description": "Specifies folders to be ignored. (node_modules for example), improving search performance" 56 | }, 57 | "gitProjectManager.maxDepthRecursion": { 58 | "type": "integer", 59 | "default": 4, 60 | "description": "Indicate the maximum depth of folder recursion to search for projects. Any value below 1 means there is no limit" 61 | }, 62 | "gitProjectManager.checkRemoteOrigin": { 63 | "type": "boolean", 64 | "default": true, 65 | "description": "Indicates if extension will validate and get the remote origin of the git repository" 66 | }, 67 | "gitProjectManager.openInNewWindow": { 68 | "type": "boolean", 69 | "default": false, 70 | "description": "Define the behavior when opening a new project, if true a new VSCode will be opened with the selected project" 71 | }, 72 | "gitProjectManager.warnIfFolderNotFound": { 73 | "type": "boolean", 74 | "default": false, 75 | "description": "Define if extension should show a warn if a configured project folder is not found while searching for projects" 76 | }, 77 | "gitProjectManager.unversionedProjects": { 78 | "type": "array", 79 | "default": [], 80 | "description": "Allows to list projects that are not versioned in \"List Repositories\" command" 81 | }, 82 | "gitProjectManager.recentProjectsListSize": { 83 | "type": "integer", 84 | "default": 5, 85 | "description": "Number of recent projects to be kept to use with GPM - Open Recent" 86 | }, 87 | "gitProjectManager.searchInsideProjects": { 88 | "type": "boolean", 89 | "default": true, 90 | "description": "Define if extension should look for Git projects inside other Git projects." 91 | }, 92 | "gitProjectManager.supportsMercurial": { 93 | "type": "boolean", 94 | "default": false, 95 | "description": "Define if extension should look for Mercurial projects too." 96 | }, 97 | "gitProjectManager.supportsSVN": { 98 | "type": "boolean", 99 | "default": false, 100 | "description": "Define if extension should look for for SVN projects too." 101 | }, 102 | "gitProjectManager.displayProjectPath": { 103 | "type": "boolean", 104 | "default": false, 105 | "description": "Indicates if project path will be displayed in project picker." 106 | } 107 | } 108 | }, 109 | "commands": [ 110 | { 111 | "command": "gitProjectManager.openProject", 112 | "title": "Open Git Project", 113 | "category": "GPM" 114 | }, 115 | { 116 | "command": "gitProjectManager.openProjectNewWindow", 117 | "title": "Open Git Project in a New Window", 118 | "category": "GPM" 119 | }, 120 | { 121 | "command": "gitProjectManager.refreshProjects", 122 | "title": "Refresh Projects", 123 | "category": "GPM" 124 | }, 125 | { 126 | "command": "gitProjectManager.refreshFolder", 127 | "title": "Refresh specific projects folder", 128 | "category": "GPM" 129 | }, 130 | { 131 | "command": "gitProjectManager.openRecents", 132 | "title": "Open Recent Git Project", 133 | "category": "GPM" 134 | }, 135 | { 136 | "command": "gitProjectManager.openSubFolder", 137 | "title": "Open Git Project from SubFolder", 138 | "category": "GPM" 139 | } 140 | ], 141 | "keybindings": [ 142 | { 143 | "key": "ctrl+alt+p", 144 | "mac": "cmd+alt+p", 145 | "command": "gitProjectManager.openProject" 146 | }, 147 | { 148 | "key": "alt+shift+p", 149 | "mac": "alt+shift+p", 150 | "command": "gitProjectManager.openSubFolder" 151 | }, 152 | { 153 | "key": "ctrl+alt+n", 154 | "mac": "cmd+alt+n", 155 | "command": "gitProjectManager.openProjectNewWindow" 156 | }, 157 | { 158 | "key": "ctrl+shift+q", 159 | "mac": "cmd+alt+q", 160 | "command": "gitProjectManager.openRecents" 161 | } 162 | ] 163 | }, 164 | "main": "./out/extension.js", 165 | "devDependencies": { 166 | "@types/chai": "^4.2.22", 167 | "@types/crypto-js": "^4.0.2", 168 | "@types/glob": "^7.1.4", 169 | "@types/mocha": "^9.0.0", 170 | "@types/node": "^16.11.0", 171 | "@types/rimraf": "^3.0.2", 172 | "@types/sinon": "^10.0.4", 173 | "@types/vscode": "^1.61.0", 174 | "@typescript-eslint/eslint-plugin": "^5.0.0", 175 | "@typescript-eslint/parser": "^5.0.0", 176 | "chai": "^4.3.4", 177 | "eslint": "^8.0.1", 178 | "mocha": "^9.1.3", 179 | "rimraf": "^3.0.2", 180 | "sinon": "^11.1.2", 181 | "typescript": "^4.4.4", 182 | "vscode-test": "^1.6.1" 183 | }, 184 | "scripts": { 185 | "vscode:prepublish": "npm run compile", 186 | "postcompile": "mkdir -p out/test/suite/repo-info-test && cp -R src/test/suite/repo-info-test/* out/test/suite/repo-info-test", 187 | "compile": "./node_modules/typescript/bin/tsc -p ./", 188 | "lint": "eslint src --ext ts", 189 | "watch": "./node_modules/typescript/bin/tsc -watch -p ./", 190 | "pretest": "npm run compile", 191 | "test": "node ./out/test/runTest.js" 192 | }, 193 | "dependencies": { 194 | "crypto-js": "^4.1.1", 195 | "walker": "^1.0.7" 196 | } 197 | } -------------------------------------------------------------------------------- /releases/git-project-manager-0.1.0.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipecaputo/git-project-manager/363eea2d4dae731dead5c50ce405d50bdab989ac/releases/git-project-manager-0.1.0.vsix -------------------------------------------------------------------------------- /releases/git-project-manager-0.1.1.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipecaputo/git-project-manager/363eea2d4dae731dead5c50ce405d50bdab989ac/releases/git-project-manager-0.1.1.vsix -------------------------------------------------------------------------------- /releases/git-project-manager-0.1.15.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipecaputo/git-project-manager/363eea2d4dae731dead5c50ce405d50bdab989ac/releases/git-project-manager-0.1.15.vsix -------------------------------------------------------------------------------- /releases/git-project-manager-0.1.16.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipecaputo/git-project-manager/363eea2d4dae731dead5c50ce405d50bdab989ac/releases/git-project-manager-0.1.16.vsix -------------------------------------------------------------------------------- /releases/git-project-manager-0.1.18.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipecaputo/git-project-manager/363eea2d4dae731dead5c50ce405d50bdab989ac/releases/git-project-manager-0.1.18.vsix -------------------------------------------------------------------------------- /releases/git-project-manager-0.1.2.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipecaputo/git-project-manager/363eea2d4dae731dead5c50ce405d50bdab989ac/releases/git-project-manager-0.1.2.vsix -------------------------------------------------------------------------------- /releases/git-project-manager-1.0.0.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipecaputo/git-project-manager/363eea2d4dae731dead5c50ce405d50bdab989ac/releases/git-project-manager-1.0.0.vsix -------------------------------------------------------------------------------- /releases/git-project-manager-1.0.1.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipecaputo/git-project-manager/363eea2d4dae731dead5c50ce405d50bdab989ac/releases/git-project-manager-1.0.1.vsix -------------------------------------------------------------------------------- /src/domain/ProjectQuickPick.ts: -------------------------------------------------------------------------------- 1 | import { QuickPickItem } from 'vscode'; 2 | 3 | export default class ProjectQuickPick implements QuickPickItem { 4 | label: string = ''; 5 | description?: string | undefined; 6 | detail?: string | undefined; 7 | picked?: boolean | undefined; 8 | alwaysShow?: boolean | undefined; 9 | directory: string = ''; 10 | } -------------------------------------------------------------------------------- /src/domain/ProjectRepository.ts: -------------------------------------------------------------------------------- 1 | export default class ProjectRepository { 2 | name: string; 3 | directory: string; 4 | repository: string; 5 | constructor(name: string, dir: string, repo: string) { 6 | this.name = name; 7 | this.directory = dir; 8 | this.repository = repo; 9 | } 10 | } -------------------------------------------------------------------------------- /src/domain/RecentItem.ts: -------------------------------------------------------------------------------- 1 | export default class RecentItem { 2 | projectPath: string; 3 | repository: string; 4 | lastUsed: number; 5 | 6 | constructor(path: string, repo: string, lastUsed: number) { 7 | this.projectPath = path; 8 | this.repository = repo; 9 | this.lastUsed = lastUsed; 10 | } 11 | } -------------------------------------------------------------------------------- /src/domain/config.ts: -------------------------------------------------------------------------------- 1 | import { WorkspaceConfiguration } from 'vscode'; 2 | 3 | /** 4 | * @typedef Config 5 | * @type {Object} 6 | * @property {number} maxDepthRecursion Define how deep locator will search 7 | * @class Config 8 | */ 9 | export default class Config extends Object { 10 | maxDepthRecursion: number; 11 | ignoredFolders: string[]; 12 | baseProjectFolders: never[]; 13 | storeRepositoriesBetweenSessions: boolean; 14 | checkRemoteOrigin: boolean; 15 | openInNewWindow: boolean; 16 | warnIfFolderNotFound: boolean; 17 | unversionedProjects: never[]; 18 | recentProjectListSize: number; 19 | searchInsideProjects: boolean; 20 | supportsMercurial: boolean; 21 | supportsSVN: boolean; 22 | displayProjectPath: boolean; 23 | 24 | constructor(vscodeCfg?: WorkspaceConfiguration) { 25 | super(); 26 | this.maxDepthRecursion = 2; 27 | this.ignoredFolders = ['node_modules']; 28 | this.baseProjectFolders = []; 29 | this.storeRepositoriesBetweenSessions = false; 30 | this.checkRemoteOrigin = true; 31 | this.openInNewWindow = false; 32 | this.warnIfFolderNotFound = false; 33 | this.unversionedProjects = []; 34 | this.recentProjectListSize = 5; 35 | this.searchInsideProjects = true; 36 | this.supportsMercurial = false; 37 | this.supportsSVN = false; 38 | this.displayProjectPath = false; 39 | 40 | if (vscodeCfg) { 41 | this.loadConfigFromVsCode(vscodeCfg); 42 | } 43 | } 44 | 45 | loadConfigFromVsCode(vscodeConfig: WorkspaceConfiguration) { 46 | this.maxDepthRecursion = vscodeConfig.get('maxDepthRecursion', 2); 47 | this.ignoredFolders = vscodeConfig.get('ignoredFolders', []); 48 | this.baseProjectFolders = vscodeConfig.get('baseProjectsFolders', []); 49 | this.storeRepositoriesBetweenSessions = vscodeConfig.get('storeRepositoriesBetweenSessions', false); 50 | this.checkRemoteOrigin = vscodeConfig.get('checkRemoteOrigin', true); 51 | this.openInNewWindow = vscodeConfig.get('openInNewWindow') || false; 52 | this.warnIfFolderNotFound = vscodeConfig.get('warnIfFolderNotFound') || true; 53 | this.unversionedProjects = vscodeConfig.get('unversionedProjects', []); 54 | this.recentProjectListSize = vscodeConfig.get('recentProjectsListSize', 5); 55 | this.searchInsideProjects = vscodeConfig.get('searchInsideProjects', true); 56 | this.supportsMercurial = vscodeConfig.get('supportsMercurial', false); 57 | this.supportsSVN = vscodeConfig.get('supportsSVN', false); 58 | this.displayProjectPath = vscodeConfig.get('displayProjectPath', false); 59 | } 60 | } -------------------------------------------------------------------------------- /src/domain/dirList.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import ProjectRepository from './ProjectRepository'; 3 | 4 | export default class DirList { 5 | dirs: ProjectRepository[]; 6 | constructor() { 7 | this.dirs = []; 8 | } 9 | get dirList() { 10 | return this.dirs; 11 | } 12 | /** 13 | * Returns an array with all current directories 14 | * 15 | * @returns {[]string} An array that contains all directories 16 | * @readonly 17 | */ 18 | get directories() : string[] { 19 | return this.dirs.map(x => x.directory); 20 | } 21 | concat(aDirList: DirList) { 22 | aDirList.dirList.forEach(e => this.add(e.directory, e.repository)); 23 | } 24 | add(dirPath: string, repositoryName?: string) { 25 | const dirName = path.basename(dirPath); 26 | 27 | if (this.exists(dirPath)) { 28 | return; 29 | } 30 | 31 | this.dirs.push({ 32 | directory: dirPath, 33 | name: dirName, 34 | repository: repositoryName || 'not available' 35 | }); 36 | } 37 | exists(dirPath: string) { 38 | return this.dirs.find(e => e.directory === dirPath) !== undefined; 39 | } 40 | clear() { 41 | this.dirs = []; 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | // The module 'vscode' contains the VS Code extensibility API 2 | // Import the module and reference it with the alias vscode in your code below 3 | import * as vscode from 'vscode'; 4 | import ProjectManager from './gitProjectManager'; 5 | import Config from './domain/config'; 6 | const cfg = new Config(vscode.workspace.getConfiguration('gitProjectManager')); 7 | 8 | // this method is called when your extension is activated 9 | // your extension is activated the very first time the command is executed 10 | function activate(context: vscode.ExtensionContext) { 11 | const projectManager = new ProjectManager(cfg, context.globalState); 12 | 13 | let disposable = vscode.commands.registerCommand('gitProjectManager.openProject', function () { 14 | projectManager.showProjectList(false); 15 | }); 16 | 17 | let newWindowdisposable = vscode.commands.registerCommand('gitProjectManager.openProjectNewWindow', function () { 18 | projectManager.showProjectList(true); 19 | }); 20 | 21 | let subFoldersDisposable = vscode.commands.registerCommand('gitProjectManager.openSubFolder', function () { 22 | projectManager.showProjectsFromSubFolder(); 23 | }); 24 | 25 | let refreshDisposable = vscode.commands.registerCommand('gitProjectManager.refreshProjects', function () { 26 | projectManager.refreshList(); 27 | }); 28 | 29 | let specificRefreshDisposable = vscode.commands.registerCommand('gitProjectManager.refreshFolder', function () { 30 | projectManager.refreshSpecificFolder(); 31 | }); 32 | 33 | let openRecentDisposable = vscode.commands.registerCommand('gitProjectManager.openRecents', function () { 34 | projectManager.openRecentProjects(); 35 | }); 36 | 37 | context.subscriptions.push(disposable, refreshDisposable, specificRefreshDisposable, openRecentDisposable, subFoldersDisposable, newWindowdisposable); 38 | context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => { 39 | projectManager.config = new Config(vscode.workspace.getConfiguration('gitProjectManager')); 40 | projectManager.refreshList.bind(projectManager, true); 41 | })); 42 | } 43 | exports.activate = activate; 44 | 45 | // this method is called when your extension is deactivated 46 | function deactivate() { 47 | //clear things 48 | } 49 | exports.deactivate = deactivate; -------------------------------------------------------------------------------- /src/gitProjectLocator.ts: -------------------------------------------------------------------------------- 1 | import Config from "./domain/config"; 2 | 3 | // @ts-check 4 | import * as cp from 'child_process'; 5 | import * as vscode from 'vscode'; 6 | import * as walker from 'walker'; 7 | import * as path from 'path'; 8 | import { existsSync } from 'fs'; 9 | import DirList from './domain/dirList'; 10 | 11 | export default class ProjectLocator { 12 | dirList: DirList; 13 | config: Config; 14 | constructor(config: Config) { 15 | this.dirList = new DirList(); 16 | this.config = config || new Config(); 17 | } 18 | /** 19 | * Returns the depth of the directory path 20 | * 21 | * @param {String} s The path to be processed 22 | * @returns Number 23 | */ 24 | getPathDepth(s: string): number { 25 | return s.split(path.sep).length; 26 | } 27 | isMaxDeptReached(currentDepth: number, initialDepth: number) { 28 | return (this.config.maxDepthRecursion > 0) && ((currentDepth - initialDepth) > this.config.maxDepthRecursion); 29 | } 30 | isFolderIgnored(folder: string) { 31 | return this.config.ignoredFolders.indexOf(folder) !== -1; 32 | } 33 | /** 34 | * Returs true if the *directory* param refers to a folder that is nested to an already found project and 35 | * _gitProjectManager.searchInsideProjects_ is true 36 | * 37 | * @param {string} directory 38 | */ 39 | isNestedIgnoredFolder(directory: string) { 40 | return !this.config.searchInsideProjects && this.dirList.directories.some(dir => directory.includes(dir)); 41 | } 42 | checkFolderExists(folderPath: string) { 43 | const exists = existsSync(folderPath); 44 | if (!exists && this.config.warnIfFolderNotFound) { 45 | vscode.window.showWarningMessage(`Directory ${folderPath} does not exists.`); 46 | } 47 | 48 | return exists; 49 | } 50 | filterDir(dir: string, depth: number) { 51 | if (this.isFolderIgnored(path.basename(dir))) { return false; }; 52 | if (this.isMaxDeptReached(this.getPathDepth(dir), depth)) { return false; }; 53 | if (this.isNestedIgnoredFolder(dir)) { return false; }; 54 | 55 | return true; 56 | } 57 | walkDirectory(dir: string): Promise { 58 | var depth = this.getPathDepth(dir); 59 | 60 | return new Promise((resolve, reject) => { 61 | try { 62 | walker(dir) 63 | .filterDir((dir: string) => this.filterDir(dir, depth)) 64 | .on('dir', (absPath: string) => this.processDirectory(absPath)) 65 | .on('symlink', (absPath: string) => this.processDirectory(absPath)) 66 | .on('error', (e: string) => this.handleError(e)) 67 | .on('end', () => { 68 | resolve(this.dirList); 69 | }); 70 | } catch (error) { 71 | reject(error); 72 | } 73 | 74 | }); 75 | } 76 | async locateGitProjects(projectsDirList: string[]): Promise { 77 | 78 | /** @type {string[]} */ 79 | var promises: Promise[] = []; 80 | 81 | projectsDirList.forEach((projectBasePath) => { 82 | if (!this.checkFolderExists(projectBasePath)) { 83 | return; 84 | } 85 | 86 | promises.push(this.walkDirectory(projectBasePath)); 87 | }); 88 | 89 | await Promise.all(promises); 90 | 91 | return this.dirList; 92 | }; 93 | 94 | clearDirList() { 95 | this.dirList = new DirList(); 96 | }; 97 | 98 | extractRepoInfo(basePath: string): string | undefined { 99 | if (!this.config.checkRemoteOrigin) { 100 | return; 101 | } 102 | 103 | let originList = cp.execSync('git remote ', { cwd: basePath, encoding: 'utf8' }); 104 | 105 | let firstOrigin = originList?.split('\n').shift()?.trim(); 106 | if (firstOrigin === '') { 107 | return; 108 | } 109 | 110 | return cp.execSync(`git remote get-url ${firstOrigin}`, { cwd: basePath, encoding: 'utf8' }) 111 | ?.split('\n') 112 | .shift() 113 | ?.trim(); 114 | } 115 | processDirectory(absPath: string) { 116 | vscode.window.setStatusBarMessage(absPath, 600); 117 | if (existsSync(path.join(absPath, '.git', 'config'))) { 118 | this.dirList.add(absPath, this.extractRepoInfo(absPath)); 119 | } else if (this.config.supportsMercurial && existsSync(path.join(absPath, '.hg'))) { 120 | this.dirList.add(absPath, undefined); 121 | } else if (this.config.supportsSVN && existsSync(path.join(absPath, '.svn'))) { 122 | this.dirList.add(absPath, undefined); 123 | } 124 | } 125 | handleError(err: string) { 126 | console.log('Error walker:', err); 127 | } 128 | } -------------------------------------------------------------------------------- /src/gitProjectManager.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as path from 'path'; 3 | import { SHA256 } from 'crypto-js'; 4 | import Config from './domain/config'; 5 | import ProjectRepository from './domain/ProjectRepository'; 6 | 7 | import RecentItems from './recentItems'; 8 | import ProjectLocator from './gitProjectLocator'; 9 | import DirList from './domain/dirList'; 10 | import ProjectQuickPick from './domain/ProjectQuickPick'; 11 | 12 | const FOLDER = '\uD83D\uDCC2'; 13 | const GLOBE = '\uD83C\uDF10'; 14 | 15 | export default class GitProjectManager { 16 | config: Config; 17 | state: vscode.Memento; 18 | loadedRepoListFromFile: boolean; 19 | repoList: ProjectRepository[]; 20 | storedLists: Map; 21 | recentList: RecentItems; 22 | /** 23 | * Creates an instance of GitProjectManager. 24 | * 25 | * @param {object} config 26 | * @param {Memento} state 27 | */ 28 | constructor(config: Config, state: vscode.Memento) { 29 | this.config = config; 30 | this.state = state; 31 | this.loadedRepoListFromFile = false; 32 | this.repoList = []; 33 | this.storedLists = new Map(); 34 | this.recentList = new RecentItems(this.state, config.recentProjectListSize); 35 | 36 | this.updateRepoList = this.updateRepoList.bind(this); 37 | this.addRepoInRepoList = this.addRepoInRepoList.bind(this); 38 | } 39 | getQuickPickList(): ProjectQuickPick[] { 40 | this.repoList = this.repoList.sort((a, b) => { 41 | return a.name > b.name ? 1 : -1; 42 | }); 43 | 44 | 45 | // let homeDir = this.getHomePath().replace(new RegExp(`${path.sep}$`), '') + path.sep; 46 | return this.repoList.map(repo => { 47 | let description = ''; 48 | if (this.config.displayProjectPath || !this.config.checkRemoteOrigin) { 49 | let repoDir = repo.directory; 50 | // if (repoDir.startsWith(homeDir)) { 51 | // repoDir = '~/' + repoDir.substring(homeDir.length); 52 | // } 53 | description = `${FOLDER} ${repoDir}`; 54 | } 55 | if (this.config.checkRemoteOrigin) { 56 | description = `${GLOBE} ${repo.repository} ` + description; 57 | } 58 | var item = new ProjectQuickPick(); 59 | item.label = repo.name; 60 | item.description = description.trim(); 61 | item.directory = repo.directory; 62 | return item; 63 | }); 64 | } 65 | handleError(error: Error): Error { 66 | vscode.window.showErrorMessage(`Error in GPM Manager ${error}`); 67 | return error; 68 | } 69 | get storeDataBetweenSessions() { 70 | return this.config.storeRepositoriesBetweenSessions; 71 | } 72 | saveList() { 73 | if (!this.storeDataBetweenSessions) { 74 | return; 75 | } 76 | 77 | const lists = Array.from(this.storedLists.entries()).reduce( 78 | (storage, [hash, repos]) => ({ ...storage, [hash]: repos }), 79 | {}, 80 | ); 81 | this.state.update('lists', lists); 82 | } 83 | loadList() { 84 | if (!this.storeDataBetweenSessions) { 85 | return false; 86 | } 87 | 88 | const list = this.state.get('lists', false); 89 | if (!list) { 90 | return false; 91 | } 92 | 93 | this.storedLists = new Map(Array.from(Object.entries(list))); 94 | 95 | this.loadedRepoListFromFile = true; 96 | return true; 97 | } 98 | saveRepositoryInfo(directories: string[]) { 99 | this.storedLists.set(this.getDirectoriesHash(directories), this.repoList); 100 | this.saveList(); 101 | } 102 | 103 | loadRepositoryInfo() { 104 | if (this.loadedRepoListFromFile) { 105 | return false; 106 | } 107 | 108 | return this.loadList(); 109 | } 110 | 111 | addRepoInRepoList(repoInfo: ProjectRepository) { 112 | let map = this.repoList.map((info) => { 113 | return info.directory; 114 | }); 115 | if (map.indexOf(repoInfo.directory) === -1) { 116 | this.repoList.push(repoInfo); 117 | } 118 | } 119 | 120 | async getProjectsFolders(subFolder: string = ''): Promise { 121 | 122 | var isFolderConfigured = this.config.baseProjectFolders.length > 0; 123 | 124 | if (!isFolderConfigured) { 125 | throw new Error('You need to configure at least one folder in "gitProjectManager.baseProjectsFolders" before searching for projects.'); 126 | } 127 | 128 | var baseProjectsFolders: string[] = subFolder === '' ? vscode.workspace.getConfiguration('gitProjectManager').get('baseProjectsFolders') || [] : [subFolder]; 129 | var resolvedProjectsFolders = baseProjectsFolders.map(path => { 130 | return this.resolveEnvironmentVariables(process.platform, path); 131 | }); 132 | 133 | return resolvedProjectsFolders; 134 | } 135 | 136 | getHomePath() { 137 | return process.env.HOME || process.env.HOMEPATH; 138 | } 139 | 140 | resolveEnvironmentVariables(processPlatform: string, aPath: string) { 141 | var envVarMatcher = processPlatform === 'win32' ? /%([^%]+)%/g : /\$([^\/]+)/g; 142 | let resolvedPath = aPath.replace(envVarMatcher, (_, key) => process.env[key] || ''); 143 | 144 | const homePath = this.getHomePath() || ''; 145 | return resolvedPath.charAt(0) === '~' ? path.join(homePath, resolvedPath.substr(1)) : resolvedPath; 146 | }; 147 | /** 148 | * Show the list of found Git projects, and open the choosed project 149 | * 150 | * @param {Object} opts Aditional options, currently supporting only subfolders 151 | * @param {boolean} openInNewWindow If true, will open the selected project in a new windows, regardless of the OpenInNewWindow configuration 152 | * 153 | * @memberOf GitProjectManager 154 | */ 155 | async showProjectList(openInNewWindow: boolean, baseFolder?: string) { 156 | try { 157 | var options = { 158 | placeHolder: 'Select a folder to open: (it may take a few seconds to search the folders the first time)' 159 | }; 160 | 161 | var projectsPromise = this.getProjectsList(await this.getProjectsFolders(baseFolder)); 162 | 163 | var selected = await vscode.window.showQuickPick(projectsPromise, options); 164 | 165 | if (selected) { 166 | this.openProject(selected, openInNewWindow); 167 | } 168 | } catch (e) { 169 | vscode.window.showInformationMessage(`Error while showing Project list: ${e}`); 170 | } 171 | }; 172 | 173 | /** 174 | * Adds all projects added as unversioned in vsCode config 175 | * 176 | * @param {DirList} dirList 177 | */ 178 | addUnversionedProjects(dirList: DirList) { 179 | let unversioned = this.config.unversionedProjects; 180 | unversioned.forEach(proj => dirList.add(proj)); 181 | return dirList.dirs; 182 | } 183 | 184 | updateRepoList(dirList: ProjectRepository[], directories: string[]) { 185 | dirList.forEach(this.addRepoInRepoList); 186 | this.saveRepositoryInfo(directories); 187 | return dirList; 188 | } 189 | 190 | async getProjectsList(directories: string[]): Promise { 191 | 192 | this.repoList = this.storedLists.get(this.getDirectoriesHash(directories)); 193 | if (this.repoList) { 194 | return this.getQuickPickList(); 195 | } 196 | 197 | this.clearProjectList(); 198 | if (this.loadRepositoryInfo()) { 199 | this.repoList = this.storedLists.get(this.getDirectoriesHash(directories)); 200 | if (this.repoList) { 201 | return this.getQuickPickList(); 202 | } 203 | } 204 | 205 | const projectLocator = new ProjectLocator(this.config); 206 | await projectLocator.locateGitProjects(directories) 207 | .then(dirList => this.addUnversionedProjects(dirList)) 208 | .then(dirList => this.updateRepoList(dirList, directories)); 209 | 210 | return this.getQuickPickList(); 211 | 212 | }; 213 | 214 | openProject(pickedObj: ProjectQuickPick | string, openInNewWindow: boolean = false) { 215 | let projectPath = this.getProjectPath(pickedObj), 216 | uri = vscode.Uri.file(projectPath), 217 | newWindow = openInNewWindow || (this.config.openInNewWindow && !!vscode.workspace.workspaceFolders); 218 | 219 | this.recentList.addProject(projectPath, ''); 220 | vscode.commands.executeCommand('vscode.openFolder', uri, newWindow); 221 | } 222 | 223 | getProjectPath(pickedObj: ProjectQuickPick | string): string { 224 | if (pickedObj instanceof ProjectQuickPick) { 225 | return pickedObj.directory; 226 | } 227 | 228 | return pickedObj; 229 | } 230 | 231 | internalRefresh(folders: string[], suppressMessage: boolean) { 232 | this.storedLists = new Map(); 233 | this.getProjectsList(folders) 234 | .then(() => { 235 | if (!suppressMessage) { 236 | vscode.window.setStatusBarMessage('Git Project Manager - Project List Refreshed', 3000); 237 | } 238 | }) 239 | .catch((error) => { 240 | if (!suppressMessage) { 241 | this.handleError(error); 242 | } 243 | }); 244 | } 245 | 246 | clearProjectList() { 247 | this.repoList = []; 248 | } 249 | 250 | /** 251 | * Refreshs the current list of projects 252 | * @param {boolean} suppressMessage if true, no warning message will be shown. 253 | */ 254 | refreshList(suppressMessage: boolean = false) { 255 | this.clearProjectList(); 256 | this.getProjectsFolders() 257 | .then((folders) => { 258 | this.internalRefresh(folders, suppressMessage); 259 | }) 260 | .catch((error) => { 261 | if (!suppressMessage) { 262 | this.handleError(error); 263 | } 264 | }); 265 | }; 266 | 267 | refreshSpecificFolder() { 268 | var options = { 269 | placeHolder: 'Select a folder to open: (it may take a few seconds to search the folders the first time)' 270 | }; 271 | this.getProjectsFolders() 272 | .then((list) => { 273 | vscode.window.showQuickPick(list, options) 274 | .then((selection) => { 275 | if (!selection) { 276 | return; 277 | } 278 | this.internalRefresh([selection], false); 279 | }); 280 | }) 281 | .catch((error) => { 282 | console.log(error); 283 | }); 284 | 285 | }; 286 | 287 | openRecentProjects() { 288 | let self = this; 289 | if (this.recentList.list.length === 0) { 290 | vscode.window.showInformationMessage('It seems you haven\'t opened any projects using Git Project Manager extension yet!'); 291 | } 292 | 293 | vscode.window.showQuickPick(this.recentList.list.map(i => { 294 | return { 295 | label: path.basename(i.projectPath), 296 | description: i.projectPath 297 | }; 298 | })).then(selected => { 299 | if (selected) { 300 | self.openProject(selected.description); 301 | } 302 | }); 303 | } 304 | 305 | /** 306 | * Calculate a hash of directories list 307 | * 308 | * @param {String[]} directories 309 | * @returns {string} The hash of directories list 310 | * 311 | * @memberOf GitProjectManager 312 | */ 313 | getDirectoriesHash(directories: string[]) { 314 | return SHA256(directories.join('')).toString(); 315 | } 316 | 317 | showProjectsFromSubFolder() { 318 | vscode.window.showQuickPick(this.getProjectsFolders(), { 319 | canPickMany: false, 320 | placeHolder: 'Pick a folder to see the subfolder projects' 321 | }).then((folder: string | undefined) => { 322 | if (!folder) { 323 | return; 324 | } 325 | 326 | this.showProjectList(false, folder); 327 | }); 328 | } 329 | getChannelPath() { 330 | return vscode.env.appName.replace("Visual Studio ", ""); 331 | } 332 | 333 | } 334 | -------------------------------------------------------------------------------- /src/recentItems.ts: -------------------------------------------------------------------------------- 1 | import { Memento } from "vscode"; 2 | import RecentItem from './domain/RecentItem'; 3 | 4 | export default class RecentItems { 5 | state: Memento; 6 | listSize: number; 7 | list: Array; 8 | /** 9 | * Creates an instance of RecentItems. 10 | * 11 | * @param {Memento} state Global extension state. 12 | * @param {number} [listSize=5] Recent items list size. 13 | */ 14 | constructor(state: Memento, listSize: number = 5) { 15 | this.state = state; 16 | this.listSize = listSize; 17 | this.list = this.state.get('recent', []); 18 | } 19 | addProject(projectPath: string, gitRepo: string) { 20 | const idx = this.list.findIndex(p => p.projectPath === projectPath); 21 | if (idx >= 0) { 22 | this.list[idx].lastUsed = new Date().getTime(); 23 | } else { 24 | this.list.push(new RecentItem(projectPath, gitRepo, new Date().getTime())); 25 | }; 26 | 27 | this.sortList(); 28 | this.state.update('recent', this.list); 29 | } 30 | sortList() { 31 | this.list = this.list.sort((a, b) => b.lastUsed - a.lastUsed); 32 | if (this.list.length > this.listSize) { 33 | this.list = this.list.slice(0, this.listSize - 1); 34 | } 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from 'vscode-test'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /src/test/suite/dirList.test.ts: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | import DirList from '../../domain/dirList'; 4 | import { expect } from 'chai'; 5 | 6 | suite('dirList Tests', () => { 7 | test('should add directories to list', () => { 8 | let dirList = new DirList(); 9 | dirList.add('/home/user/path', 'path'); 10 | expect(dirList.dirList.length).to.be.equal(1); 11 | dirList.add('/home/user/path2', 'path2'); 12 | expect(dirList.dirList.length).to.be.equal(2); 13 | }); 14 | 15 | test('should not add duplicates', () => { 16 | let dirList = new DirList(); 17 | dirList.add('/home/user/path', 'path'); 18 | expect(dirList.dirList.length).to.be.equal(1); 19 | dirList.add('/home/user/path', 'path'); 20 | expect(dirList.dirList.length).to.be.equal(1); 21 | }); 22 | 23 | test('should validate existing repositories', () => { 24 | let dirList = new DirList(); 25 | dirList.add('/home/user/path', 'path'); 26 | expect(dirList.exists('/home/user/path')).to.be.true; 27 | }); 28 | 29 | test('shouldn\'t validate not existing repositories', () => { 30 | let dirList = new DirList(); 31 | dirList.add('/home/user/path', 'path'); 32 | expect(dirList.exists('/home/user/path2')).to.be.false; 33 | }) 34 | 35 | test('should concatenate two dirlist', () => { 36 | let dirList = new DirList(); 37 | dirList.add('/home/user/path', 'path'); 38 | dirList.add('/home/user/path2', 'path2'); 39 | 40 | let dirList2 = new DirList(); 41 | dirList2.add('/home/user/path2', 'path2'); 42 | dirList2.add('/home/user/path3', 'path3'); 43 | dirList2.add('/home/user/path4', 'path4'); 44 | 45 | dirList.concat(dirList2); 46 | 47 | expect(dirList.dirList.length).to.be.equal(4); 48 | 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.equal(-1, [1, 2, 3].indexOf(5)); 13 | assert.equal(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/test/suite/gitProjectLocator.repoInfo.test.ts: -------------------------------------------------------------------------------- 1 | import ProjectLocator from '../../gitProjectLocator'; 2 | import Config from '../../domain/config'; 3 | import { mkdirSync, chmodSync, writeFileSync } from 'fs'; 4 | import * as rimraf from 'rimraf'; 5 | import { join } from 'path'; 6 | import { expect } from 'chai'; 7 | import { execSync } from 'child_process'; 8 | 9 | suite('Get repository information', () => { 10 | 11 | let baseFolderName = join(__dirname, 'repo-info-test'); 12 | let gitConfigFilePath = join(baseFolderName, '.git/config'); 13 | 14 | setup(() => { 15 | execSync(`mkdir -p ${baseFolderName}/.git && cp -R ${baseFolderName}/base-git/* ${baseFolderName}/.git`); 16 | 17 | }) 18 | 19 | teardown(() => { 20 | rimraf.sync(join(baseFolderName, '.git')); 21 | }) 22 | 23 | test('should get information when we have a single remote upstream', () => { 24 | 25 | execSync('git remote add upstream git@github.com:felipecaputo/some-other-project.git', { cwd: baseFolderName }); 26 | 27 | const projectLocator = new ProjectLocator(new Config()); 28 | expect(projectLocator.extractRepoInfo(baseFolderName)).to.equals('git@github.com:felipecaputo/some-other-project.git'); 29 | 30 | }) 31 | 32 | test('should get information when we have a single remote origin', () => { 33 | 34 | execSync('git remote add origin git@github.com:felipecaputo/git-project-manager-123.git', { cwd: baseFolderName }); 35 | 36 | const projectLocator = new ProjectLocator(new Config()); 37 | expect(projectLocator.extractRepoInfo(baseFolderName)).to.equals('git@github.com:felipecaputo/git-project-manager-123.git'); 38 | 39 | }) 40 | 41 | test('should get information when we have more than one remote', () => { 42 | 43 | execSync('git remote add origin git@github.com:felipecaputo/git-project-manager-123.git', { cwd: baseFolderName }); 44 | execSync('git remote add upstream git@github.com:felipecaputo/some-other-project.git', { cwd: baseFolderName }); 45 | 46 | const projectLocator = new ProjectLocator(new Config()); 47 | expect(projectLocator.extractRepoInfo(baseFolderName)).to.equals('git@github.com:felipecaputo/git-project-manager-123.git'); 48 | 49 | }) 50 | 51 | test('should return empty on no remote', () => { 52 | const projectLocator = new ProjectLocator(new Config()); 53 | expect(projectLocator.extractRepoInfo(baseFolderName)).to.equals(undefined); 54 | 55 | }) 56 | }) -------------------------------------------------------------------------------- /src/test/suite/gitProjectLocator.test.ts: -------------------------------------------------------------------------------- 1 | /* global describe, it, before, after */ 2 | 3 | // 4 | // Note: This example test is leveraging the Mocha test framework. 5 | // Please refer to their documentation on https://mochajs.org/ for help. 6 | // 7 | 8 | 9 | // You can import and use all API from the 'vscode' module 10 | // as well as import your extension to test it 11 | // const vscode = require('vscode'); 12 | import ProjectLocator from '../../gitProjectLocator'; 13 | import * as path from 'path'; 14 | import * as fs from 'fs'; 15 | import { expect } from 'chai'; 16 | import * as rimraf from 'rimraf'; 17 | import Config from '../../domain/config'; 18 | 19 | const noGitFolder = path.join(__dirname, '/noGit'); 20 | const gitProjFolder = path.join(__dirname, '/projects'); 21 | const bothFolders = [noGitFolder, gitProjFolder]; 22 | const config = new Config(); 23 | 24 | const projectLocator = new ProjectLocator(config); 25 | 26 | // Defines a Mocha test suite to group tests of similar kind together 27 | 28 | suite("gitProjectLocator Tests", function () { 29 | 30 | suite("#Available functions", function () { 31 | // Defines a Mocha unit test 32 | test("Should export locateGitProjects function", function (done) { 33 | expect(typeof projectLocator.locateGitProjects).to.be.equals('function'); 34 | done(); 35 | }); 36 | }); 37 | 38 | suite("#Searching without repos", function () { 39 | test("Shouldn't find any repositories", function (done) { 40 | this.timeout(30000); 41 | projectLocator.locateGitProjects([noGitFolder]) 42 | .then(repoList => { 43 | expect(repoList.dirList.length).to.be.equal(0); 44 | done(); 45 | }); 46 | }); 47 | }); 48 | 49 | suite("#Searching repos", function () { 50 | 51 | const paths = [ 52 | path.join(gitProjFolder, 'project1/.git'), 53 | path.join(gitProjFolder, 'project2/.git'), 54 | path.join(gitProjFolder, 'project3/.hg'), 55 | path.join(gitProjFolder, 'project4/.hg'), 56 | path.join(gitProjFolder, 'project5/.svn'), 57 | path.join(gitProjFolder, 'project6/.svn'), 58 | path.join(gitProjFolder, 'project7/.svn') 59 | ]; 60 | 61 | suiteSetup(() => { 62 | paths.forEach(dir => { 63 | if (!fs.existsSync(path.resolve(dir, '..'))) { 64 | fs.mkdirSync(path.resolve(dir, '..'), { recursive: true }); 65 | } 66 | 67 | if (!fs.existsSync(dir)) { 68 | fs.mkdirSync(dir); 69 | } 70 | const configPath = path.join(dir, 'config'); 71 | if (!fs.existsSync(configPath)) { 72 | fs.writeFileSync(configPath, 'fake', { encoding: 'utf8' }); 73 | } 74 | }); 75 | }); 76 | 77 | suiteTeardown(() => { 78 | paths.forEach(dir => rimraf.sync(path.resolve(dir, '..'))); 79 | }); 80 | 81 | function checkFoundCount(locator: ProjectLocator, dirs: string[], count: number, done: Function) { 82 | locator.locateGitProjects(dirs) 83 | .then(repoList => { 84 | try { 85 | expect(repoList.dirList.length).to.be.equal(count); 86 | done(); 87 | } catch (e) { 88 | done(e); 89 | } 90 | }); 91 | } 92 | 93 | test("Should find 2 repositories", function (done) { 94 | this.timeout(20000); 95 | const newConfig = new Config(); 96 | newConfig.maxDepthRecursion = 5; 97 | const locator = new ProjectLocator(newConfig); 98 | checkFoundCount(locator, bothFolders, 2, done); 99 | }); 100 | 101 | test("Should find none", function (done) { 102 | this.timeout(20000); 103 | const newConfig = new Config(); 104 | newConfig.maxDepthRecursion = 1; 105 | 106 | const locator = new ProjectLocator(newConfig); 107 | 108 | locator.config = newConfig; 109 | checkFoundCount(locator, [path.resolve(path.join(__dirname, '.'))], 0, done); 110 | }); 111 | 112 | test("Should find 4 repositories", function (done) { 113 | this.timeout(20000); 114 | const newConfig = new Config(); 115 | newConfig.maxDepthRecursion = 5; 116 | newConfig.supportsMercurial = true; 117 | const locator = new ProjectLocator(newConfig); 118 | checkFoundCount(locator, bothFolders, 4, done); 119 | }); 120 | 121 | test("Should find 5 repositories", function (done) { 122 | this.timeout(20000); 123 | const newConfig = new Config(); 124 | newConfig.maxDepthRecursion = 5; 125 | newConfig.supportsSVN = true; 126 | const locator = new ProjectLocator(newConfig); 127 | checkFoundCount(locator, bothFolders, 5, done); 128 | }); 129 | 130 | test("Should find 7 repositories", function (done) { 131 | this.timeout(20000); 132 | const newConfig = new Config(); 133 | newConfig.maxDepthRecursion = 5; 134 | newConfig.supportsSVN = true; 135 | newConfig.supportsMercurial = true; 136 | const locator = new ProjectLocator(newConfig); 137 | checkFoundCount(locator, bothFolders, 7, done); 138 | }); 139 | 140 | }); 141 | 142 | suite('MaxDepthReached', () => { 143 | test('show return correct depth', () => { 144 | expect(projectLocator.isMaxDeptReached(10, 1)).to.be.true; 145 | }); 146 | }); 147 | 148 | 149 | }); 150 | -------------------------------------------------------------------------------- /src/test/suite/gitProjectManager.test.ts: -------------------------------------------------------------------------------- 1 | /* global describe, it, beforeEach, afterEach */ 2 | 3 | import { expect } from 'chai'; 4 | import { createSandbox, SinonSandbox } from 'sinon'; 5 | import * as vscode from 'vscode'; 6 | 7 | import ProjectManager from '../../gitProjectManager'; 8 | import Config from '../../domain/config'; 9 | import StateMock from './stateMock'; 10 | const projectManager = new ProjectManager(new Config(), new StateMock()); 11 | 12 | suite("gitProjectManager", function () { 13 | var sandbox: SinonSandbox; 14 | setup(function () { 15 | // create sandbox environment for mocking about 16 | sandbox = createSandbox(); 17 | }); 18 | 19 | teardown(function () { 20 | // restore the environment as it was before 21 | sandbox.restore(); 22 | }); 23 | 24 | suite("#Available functions", function () { 25 | test("Should export showProjectList function", function (done) { 26 | expect(typeof projectManager.showProjectList).to.be.equals("function"); 27 | done(); 28 | }); 29 | 30 | test("Should export openProject function", function (done) { 31 | expect(typeof projectManager.openProject).to.be.equals("function"); 32 | done(); 33 | }); 34 | 35 | test("Should export getProjectsList function", function (done) { 36 | expect(typeof projectManager.getProjectsList).to.be.equals("function"); 37 | done(); 38 | }); 39 | 40 | test("Should export refreshSpecificFolder function", function (done) { 41 | expect(typeof projectManager.refreshSpecificFolder).to.be.equals("function"); 42 | done(); 43 | }); 44 | 45 | test("Should export refreshList function", function (done) { 46 | expect(typeof projectManager.refreshList).to.be.equals("function"); 47 | done(); 48 | }); 49 | }); 50 | 51 | test('should call open project without new windows if vscode has no open folder', () => { 52 | sandbox.stub(vscode.workspace, 'workspaceFolders').callsFake(() => undefined); 53 | let mockCommand = sandbox.stub(vscode.commands, 'executeCommand'); 54 | projectManager.openProject('test', true); 55 | mockCommand.getCall(0).calledWith('vscode.openFolder', 'test', false); 56 | }); 57 | 58 | test('should call open project with new windows if vscode has an open folder', () => { 59 | sandbox.stub(vscode.workspace, 'workspaceFolders').callsFake(() => 'a');; 60 | let mockCommand = sandbox.stub(vscode.commands, 'executeCommand'); 61 | projectManager.openProject('test', true); 62 | mockCommand.getCall(0).calledWith('vscode.openFolder', 'test', true); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /src/test/suite/noGit/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipecaputo/git-project-manager/363eea2d4dae731dead5c50ce405d50bdab989ac/src/test/suite/noGit/.gitkeep -------------------------------------------------------------------------------- /src/test/suite/noRepoProject/.placeholder1: -------------------------------------------------------------------------------- 1 | #just placeholder -------------------------------------------------------------------------------- /src/test/suite/projects/.gitkeep: -------------------------------------------------------------------------------- 1 | #just placeholder -------------------------------------------------------------------------------- /src/test/suite/recentItems.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env node, mocha */ 2 | 3 | import RecentItems from '../../recentItems'; 4 | import { expect } from 'chai'; 5 | import { useFakeTimers } from 'sinon'; 6 | 7 | import StateMock from './stateMock'; 8 | 9 | function addProjectsToList(recentList: RecentItems, size: number) { 10 | switch (size) { 11 | case 6: 12 | recentList.addProject('f', 'g'); 13 | case 5: 14 | recentList.addProject('e', 'f'); 15 | case 4: 16 | recentList.addProject('d', 'e'); 17 | case 3: 18 | recentList.addProject('c', 'd'); 19 | case 2: 20 | recentList.addProject('b', 'c'); 21 | case 1: 22 | recentList.addProject('a', 'b'); 23 | } 24 | } 25 | 26 | suite('RecentItems', () => { 27 | let recentItems: RecentItems; 28 | 29 | setup(() => { 30 | recentItems = new RecentItems(new StateMock()); 31 | }); 32 | 33 | test('should start with an empty list', () => { 34 | expect(recentItems.list.length).to.be.equals(0); 35 | }); 36 | 37 | test('should add projects to list', () => { 38 | addProjectsToList(recentItems, 2); 39 | expect(recentItems.list.length).to.be.equals(2); 40 | }); 41 | 42 | test('should load projects on create', () => { 43 | addProjectsToList(recentItems, 2); 44 | const secondInstance = new RecentItems(recentItems.state); 45 | expect(secondInstance.list.length).to.be.equals(2); 46 | }); 47 | 48 | test('should not add the same project twice', () => { 49 | addProjectsToList(recentItems, 2); 50 | expect(recentItems.list.length).to.be.equals(2); 51 | recentItems.addProject('a', 'b'); 52 | expect(recentItems.list.length).to.be.equals(2); 53 | }); 54 | 55 | test('should be orderer by project added time', () => { 56 | let clock = useFakeTimers(); 57 | try { 58 | recentItems.addProject('first', '1'); 59 | 60 | clock.tick(1000); 61 | recentItems.addProject('second', '2'); 62 | 63 | clock.tick(1000); 64 | recentItems.addProject('third', '3'); 65 | expect(recentItems.list[0].projectPath).to.be.equals('third'); 66 | 67 | clock.tick(1000); 68 | recentItems.addProject('first', '1'); 69 | expect(recentItems.list[0].projectPath).to.be.equals('first'); 70 | } finally { 71 | clock.restore(); 72 | } 73 | 74 | 75 | }); 76 | 77 | test('should not add more projects than limit', () => { 78 | recentItems.listSize = 3; 79 | addProjectsToList(recentItems, 6); 80 | addProjectsToList(recentItems, 3); 81 | }); 82 | }); -------------------------------------------------------------------------------- /src/test/suite/repo-info-test/base-git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /src/test/suite/repo-info-test/base-git/config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = true 4 | bare = false 5 | logallrefupdates = true 6 | ignorecase = true 7 | precomposeunicode = true 8 | -------------------------------------------------------------------------------- /src/test/suite/repo-info-test/base-git/description: -------------------------------------------------------------------------------- 1 | Unnamed repository; edit this file 'description' to name the repository. 2 | -------------------------------------------------------------------------------- /src/test/suite/repo-info-test/base-git/info/exclude: -------------------------------------------------------------------------------- 1 | # git ls-files --others --exclude-from=.git/info/exclude 2 | # Lines that start with '#' are comments. 3 | # For a project mostly in C, the following would be a good set of 4 | # exclude patterns (uncomment them if you want to use them): 5 | # *.[oa] 6 | # *~ 7 | -------------------------------------------------------------------------------- /src/test/suite/stateMock.ts: -------------------------------------------------------------------------------- 1 | import { stringify } from "querystring"; 2 | 3 | export default class StateMock { 4 | data: Map; 5 | keys: () => readonly string[]; 6 | 7 | constructor() { 8 | this.data = new Map(); 9 | this.keys = () => [...this.data.keys()].map(k => '' + k); 10 | } 11 | get(key: string, defaultValue = undefined) { 12 | return this.data.get(key) || defaultValue; 13 | } 14 | async update(key: string, value: string) { 15 | this.data.set(key, value); 16 | } 17 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | ".vscode-test" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ambientDependencies": { 3 | "node": "registry:dt/node#4.0.0+20160412142033" 4 | }, 5 | "globalDevDependencies": { 6 | "chai": "registry:dt/chai#3.4.0+20160601211834", 7 | "mocha": "registry:dt/mocha#2.2.5+20161028141524", 8 | "sinon": "registry:dt/sinon#1.16.0+20160924120326" 9 | }, 10 | "globalDependencies": { 11 | "node": "registry:dt/node#6.0.0+20161110151007" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /typings/walker.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'walker'; -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your first VS Code Extension 2 | 3 | ## What's in the folder 4 | * This folder contains all of the files necessary for your extension 5 | * `package.json` - this is the manifest file in which you declare your extension and command. 6 | The sample plugin registers a command and defines its title and command name. With this information 7 | VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | * `extension.js` - this is the main file where you will provide the implementation of your command. 9 | The file exports one function, `activate`, which is called the very first time your extension is 10 | activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 11 | We pass the function containing the implementation of the command as the second parameter to 12 | `registerCommand`. 13 | 14 | ## Get up and running straight away 15 | * press `F5` to open a new window with your extension loaded 16 | * run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World` 17 | * set breakpoints in your code inside extension.ts to debug your extension 18 | * find output from your extension in the debug console 19 | 20 | ## Make changes 21 | * you can relaunch the extension from the debug toolbar after changing code in `extension.js` 22 | * you can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes 23 | 24 | ## Explore the API 25 | * you can open the full set of our API when you open the file `node_modules/vscode/vscode.d.ts` 26 | 27 | ## Run tests 28 | * open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Launch Tests` 29 | * press `F5` to run the tests in a new window with your extension loaded 30 | * see the output of the test result in the debug console 31 | * make changes to `test/extension.test.js` or create new test files inside the `test` folder 32 | * by convention, the test runner will only consider files matching the name pattern `**.test.js` 33 | * you can create folders inside the `test` folder to structure your tests any way you want --------------------------------------------------------------------------------