├── .eslintrc.json
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
└── tasks.json
├── .vscodeignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── resources
├── dark
│ ├── copy-to-folder.svg
│ ├── create.svg
│ ├── edit.svg
│ ├── folder.svg
│ ├── refresh.svg
│ ├── string.svg
│ ├── thumbnail.svg
│ ├── upload.svg
│ └── workshop-item-hidden.svg
├── light
│ ├── copy-to-folder.svg
│ ├── create.svg
│ ├── edit.svg
│ ├── folder.svg
│ ├── refresh.svg
│ ├── string.svg
│ ├── thumbnail.svg
│ ├── upload.svg
│ └── workshop-item-hidden.svg
├── menu-icon.svg
├── package-icon.png
├── readme
│ ├── configuration.png
│ ├── create-addon-1.png
│ ├── create-addon-2.png
│ ├── create-addon-3.png
│ └── features-copy-to-gmod.png
└── samples
│ ├── weapons
│ ├── weapon_sandbox_main_sample.lua
│ ├── weapon_sandbox_toolgun_sample.lua
│ ├── weapon_ttt_detective_sample.lua
│ ├── weapon_ttt_grenade_sample.lua
│ ├── weapon_ttt_primary_sample.lua
│ ├── weapon_ttt_secondary_sample.lua
│ └── weapon_ttt_traitor_sample.lua
│ └── workshop-thumbnail.jpg
├── src
├── Services
│ ├── GModAddonManager.ts
│ ├── GModWeaponManager.ts
│ ├── GModWorkshopManager.ts
│ └── LocalGModManager.ts
├── Views
│ ├── GModAddonInfoView.ts
│ ├── GModAddonWeaponsView.ts
│ └── GModWorkshopView.ts
├── Wizards
│ ├── AddonTagsWizard.ts
│ ├── AddonTypeWizard.ts
│ ├── CreateWeaponWizard.ts
│ ├── WorkshopThumbnailWizard.ts
│ └── WorkshopUploadWizard.ts
├── extension.ts
└── test
│ ├── runTest.ts
│ └── suite
│ ├── extension.test.ts
│ └── index.ts
├── tsconfig.json
└── vsc-extension-quickstart.md
/.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/naming-convention": "warn",
13 | "@typescript-eslint/semi": "warn",
14 | "curly": "warn",
15 | "eqeqeq": "warn",
16 | "no-throw-literal": "warn",
17 | "semi": "off"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | node_modules
3 | .vscode-test/
4 | *.vsix
5 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "dbaeumer.vscode-eslint"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/.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 | "runtimeExecutable": "${execPath}",
13 | "args": [
14 | "--extensionDevelopmentPath=${workspaceFolder}"
15 | ],
16 | "outFiles": [
17 | "${workspaceFolder}/out/**/*.js"
18 | ],
19 | "preLaunchTask": "${defaultBuildTask}"
20 | },
21 | {
22 | "name": "Extension Tests",
23 | "type": "extensionHost",
24 | "request": "launch",
25 | "runtimeExecutable": "${execPath}",
26 | "args": [
27 | "--extensionDevelopmentPath=${workspaceFolder}",
28 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
29 | ],
30 | "outFiles": [
31 | "${workspaceFolder}/out/test/**/*.js"
32 | ],
33 | "preLaunchTask": "${defaultBuildTask}"
34 | }
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "files.exclude": {
4 | "out": false // set this to true to hide the "out" folder with the compiled JS files
5 | },
6 | "search.exclude": {
7 | "out": true // set this to false to include "out" folder in search results
8 | },
9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts
10 | "typescript.tsc.autoDetect": "off"
11 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | // See https://go.microsoft.com/fwlink/?LinkId=733558
2 | // for the documentation about the tasks.json format
3 | {
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "type": "npm",
8 | "script": "watch",
9 | "problemMatcher": "$tsc-watch",
10 | "isBackground": true,
11 | "presentation": {
12 | "reveal": "never"
13 | },
14 | "group": {
15 | "kind": "build",
16 | "isDefault": true
17 | }
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | .vscode/**
2 | .vscode-test/**
3 | out/test/**
4 | src/**
5 | .gitignore
6 | vsc-extension-quickstart.md
7 | **/tsconfig.json
8 | **/.eslintrc.json
9 | **/*.map
10 | **/*.ts
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to the "gmod-sdk" extension will be documented in this file.
4 |
5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
6 |
7 | ## [Unreleased]
8 |
9 | - Initial release
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Michael Hawkins
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 | # GMod SDK for Visual Studio Code
2 |
3 | A VS Code extension to make GMod addon development easier.
4 |
5 | With this, you can quickly create and upload Garry's Mod addons to the workshop.
6 |
7 |
8 |
9 | It is recommended that you also install the [GLua language support extension](https://marketplace.visualstudio.com/items?itemName=aStonedPenguin.glua), for improved syntax highlighting and suggestions.
10 |
11 |
12 |
13 |
14 | # Create your first Workshop item
15 | 1. Open a folder in VS Code and click Create Addon
16 |
17 | 
18 |
19 | 2. Add your content to the addon.
20 | For example, create a weapon using the weapons interface.
21 |
22 | 
23 |
24 | 3. Upload your addon to the workshop (Steam must be running).
25 |
26 | 
27 |
28 |
29 |
30 |
31 | # Features
32 |
33 | ## Addon Development
34 | _Create and use an addon within minutes!_
35 |
36 | * Create an addon from an empty folder
37 | * Copy an addon project to your Garry's Mod folder (and use it in-game!)
38 | * Create a Garry's Mod weapon from different templates for TTT and Sandbox
39 |
40 |
41 |
42 | _Copy addons to your Garry's Mod folder and test them in-game_
43 | 
44 |
45 |
46 |
47 |
48 | ## Workshop Tools
49 | _Manage your workshop files at the click of a button!_
50 |
51 | * Upload an addon to your workshop- maps, weapons, gamemodes, etc.
52 | * Update an existing addon on the workshop
53 | * Change an addon's thumbnail
54 |
55 |
56 |
57 |
58 |
59 |
60 | # Configuration
61 | 1. Press `ctrl` + `,` or go to `File` -> `Preferences` -> `Settings`
62 | 2. Search for `gmod-sdk`
63 |
64 |
65 |
66 | ## Set your Garry's Mod folder location
67 |
68 | In order for this extension to work, it needs to know where your Garry's Mod folder is located.
69 | In the settings, you will need to set your
70 |
71 | * Addons folder location
72 | * gmpublish program location
73 | * gmad program location
74 |
75 | If you need help finding these things, there is a helpful guide [here](https://gist.github.com/BadgerCode/00600eab40556c6e8809590d263ea053).
76 |
77 | 
78 |
79 |
80 |
81 |
82 |
83 |
84 | # Contributing
85 | * Ideas/Problems - Please create an issue on Github or find an existing thread. We want to make Garry's Mod addon development easier for you!
86 | * Code
87 | * Clone this repository and open it in VS Code
88 | * Open a terminal and run `npm install`
89 | * To debug, press `F5`. This will open a new window with the extension running.
90 | * Use `ctrl+r` to reload the window
91 |
92 |
93 | # Resources
94 | * Icons
95 | * [Font Awesome](https://fontawesome.com/icons/list)
96 | * [Azure Functions Extension](https://github.com/microsoft/vscode-azurefunctions)
97 | * [VS Code Extension Examples](https://github.com/microsoft/vscode-extension-samples/)
98 | * [Garry's Mod Logo](https://icons8.com/icons/set/garrys-mod)
99 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gmod-sdk",
3 | "version": "0.1.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@babel/code-frame": {
8 | "version": "7.10.4",
9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
10 | "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
11 | "dev": true,
12 | "requires": {
13 | "@babel/highlight": "^7.10.4"
14 | }
15 | },
16 | "@babel/helper-validator-identifier": {
17 | "version": "7.10.4",
18 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
19 | "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
20 | "dev": true
21 | },
22 | "@babel/highlight": {
23 | "version": "7.10.4",
24 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
25 | "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
26 | "dev": true,
27 | "requires": {
28 | "@babel/helper-validator-identifier": "^7.10.4",
29 | "chalk": "^2.0.0",
30 | "js-tokens": "^4.0.0"
31 | },
32 | "dependencies": {
33 | "chalk": {
34 | "version": "2.4.2",
35 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
36 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
37 | "dev": true,
38 | "requires": {
39 | "ansi-styles": "^3.2.1",
40 | "escape-string-regexp": "^1.0.5",
41 | "supports-color": "^5.3.0"
42 | }
43 | }
44 | }
45 | },
46 | "@types/color-name": {
47 | "version": "1.1.1",
48 | "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
49 | "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
50 | "dev": true
51 | },
52 | "@types/eslint-visitor-keys": {
53 | "version": "1.0.0",
54 | "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
55 | "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==",
56 | "dev": true
57 | },
58 | "@types/fs-extra": {
59 | "version": "9.0.1",
60 | "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.1.tgz",
61 | "integrity": "sha512-B42Sxuaz09MhC3DDeW5kubRcQ5by4iuVQ0cRRWM2lggLzAa/KVom0Aft/208NgMvNQQZ86s5rVcqDdn/SH0/mg==",
62 | "dev": true,
63 | "requires": {
64 | "@types/node": "*"
65 | }
66 | },
67 | "@types/glob": {
68 | "version": "7.1.3",
69 | "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
70 | "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==",
71 | "dev": true,
72 | "requires": {
73 | "@types/minimatch": "*",
74 | "@types/node": "*"
75 | }
76 | },
77 | "@types/json-schema": {
78 | "version": "7.0.5",
79 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz",
80 | "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==",
81 | "dev": true
82 | },
83 | "@types/minimatch": {
84 | "version": "3.0.3",
85 | "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
86 | "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
87 | "dev": true
88 | },
89 | "@types/mocha": {
90 | "version": "8.0.2",
91 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.0.2.tgz",
92 | "integrity": "sha512-5cv8rmqT3KX9XtWDvSgGYfS4OwrKM2eei90GWLnTYz+AXRiBv5uYcKBjnkQ4katNvfYk3+o2bHGZUsDhdcoUyg==",
93 | "dev": true
94 | },
95 | "@types/node": {
96 | "version": "14.0.27",
97 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz",
98 | "integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==",
99 | "dev": true
100 | },
101 | "@types/vscode": {
102 | "version": "1.48.0",
103 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.48.0.tgz",
104 | "integrity": "sha512-sZJKzsJz1gSoFXcOJWw3fnKl2sseUgZmvB4AJZS+Fea+bC/jfGPVhmFL/FfQHld/TKtukVONsmoD3Pkyx9iadg==",
105 | "dev": true
106 | },
107 | "@typescript-eslint/eslint-plugin": {
108 | "version": "3.9.0",
109 | "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.9.0.tgz",
110 | "integrity": "sha512-UD6b4p0/hSe1xdTvRCENSx7iQ+KR6ourlZFfYuPC7FlXEzdHuLPrEmuxZ23b2zW96KJX9Z3w05GE/wNOiEzrVg==",
111 | "dev": true,
112 | "requires": {
113 | "@typescript-eslint/experimental-utils": "3.9.0",
114 | "debug": "^4.1.1",
115 | "functional-red-black-tree": "^1.0.1",
116 | "regexpp": "^3.0.0",
117 | "semver": "^7.3.2",
118 | "tsutils": "^3.17.1"
119 | }
120 | },
121 | "@typescript-eslint/experimental-utils": {
122 | "version": "3.9.0",
123 | "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.9.0.tgz",
124 | "integrity": "sha512-/vSHUDYizSOhrOJdjYxPNGfb4a3ibO8zd4nUKo/QBFOmxosT3cVUV7KIg8Dwi6TXlr667G7YPqFK9+VSZOorNA==",
125 | "dev": true,
126 | "requires": {
127 | "@types/json-schema": "^7.0.3",
128 | "@typescript-eslint/types": "3.9.0",
129 | "@typescript-eslint/typescript-estree": "3.9.0",
130 | "eslint-scope": "^5.0.0",
131 | "eslint-utils": "^2.0.0"
132 | }
133 | },
134 | "@typescript-eslint/parser": {
135 | "version": "3.9.0",
136 | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.9.0.tgz",
137 | "integrity": "sha512-rDHOKb6uW2jZkHQniUQVZkixQrfsZGUCNWWbKWep4A5hGhN5dLHMUCNAWnC4tXRlHedXkTDptIpxs6e4Pz8UfA==",
138 | "dev": true,
139 | "requires": {
140 | "@types/eslint-visitor-keys": "^1.0.0",
141 | "@typescript-eslint/experimental-utils": "3.9.0",
142 | "@typescript-eslint/types": "3.9.0",
143 | "@typescript-eslint/typescript-estree": "3.9.0",
144 | "eslint-visitor-keys": "^1.1.0"
145 | }
146 | },
147 | "@typescript-eslint/types": {
148 | "version": "3.9.0",
149 | "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.9.0.tgz",
150 | "integrity": "sha512-rb6LDr+dk9RVVXO/NJE8dT1pGlso3voNdEIN8ugm4CWM5w5GimbThCMiMl4da1t5u3YwPWEwOnKAULCZgBtBHg==",
151 | "dev": true
152 | },
153 | "@typescript-eslint/typescript-estree": {
154 | "version": "3.9.0",
155 | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.9.0.tgz",
156 | "integrity": "sha512-N+158NKgN4rOmWVfvKOMoMFV5n8XxAliaKkArm/sOypzQ0bUL8MSnOEBW3VFIeffb/K5ce/cAV0yYhR7U4ALAA==",
157 | "dev": true,
158 | "requires": {
159 | "@typescript-eslint/types": "3.9.0",
160 | "@typescript-eslint/visitor-keys": "3.9.0",
161 | "debug": "^4.1.1",
162 | "glob": "^7.1.6",
163 | "is-glob": "^4.0.1",
164 | "lodash": "^4.17.15",
165 | "semver": "^7.3.2",
166 | "tsutils": "^3.17.1"
167 | }
168 | },
169 | "@typescript-eslint/visitor-keys": {
170 | "version": "3.9.0",
171 | "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.9.0.tgz",
172 | "integrity": "sha512-O1qeoGqDbu0EZUC/MZ6F1WHTIzcBVhGqDj3LhTnj65WUA548RXVxUHbYhAW9bZWfb2rnX9QsbbP5nmeJ5Z4+ng==",
173 | "dev": true,
174 | "requires": {
175 | "eslint-visitor-keys": "^1.1.0"
176 | }
177 | },
178 | "acorn": {
179 | "version": "7.4.0",
180 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz",
181 | "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==",
182 | "dev": true
183 | },
184 | "acorn-jsx": {
185 | "version": "5.2.0",
186 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz",
187 | "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==",
188 | "dev": true
189 | },
190 | "agent-base": {
191 | "version": "4.3.0",
192 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
193 | "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
194 | "dev": true,
195 | "requires": {
196 | "es6-promisify": "^5.0.0"
197 | }
198 | },
199 | "ajv": {
200 | "version": "6.12.4",
201 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
202 | "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==",
203 | "dev": true,
204 | "requires": {
205 | "fast-deep-equal": "^3.1.1",
206 | "fast-json-stable-stringify": "^2.0.0",
207 | "json-schema-traverse": "^0.4.1",
208 | "uri-js": "^4.2.2"
209 | }
210 | },
211 | "ansi-colors": {
212 | "version": "4.1.1",
213 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
214 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
215 | "dev": true
216 | },
217 | "ansi-regex": {
218 | "version": "5.0.0",
219 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
220 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
221 | "dev": true
222 | },
223 | "ansi-styles": {
224 | "version": "3.2.1",
225 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
226 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
227 | "dev": true,
228 | "requires": {
229 | "color-convert": "^1.9.0"
230 | }
231 | },
232 | "anymatch": {
233 | "version": "3.1.1",
234 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
235 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
236 | "dev": true,
237 | "requires": {
238 | "normalize-path": "^3.0.0",
239 | "picomatch": "^2.0.4"
240 | }
241 | },
242 | "argparse": {
243 | "version": "1.0.10",
244 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
245 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
246 | "dev": true,
247 | "requires": {
248 | "sprintf-js": "~1.0.2"
249 | }
250 | },
251 | "array.prototype.map": {
252 | "version": "1.0.2",
253 | "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz",
254 | "integrity": "sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw==",
255 | "dev": true,
256 | "requires": {
257 | "define-properties": "^1.1.3",
258 | "es-abstract": "^1.17.0-next.1",
259 | "es-array-method-boxes-properly": "^1.0.0",
260 | "is-string": "^1.0.4"
261 | }
262 | },
263 | "astral-regex": {
264 | "version": "1.0.0",
265 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
266 | "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
267 | "dev": true
268 | },
269 | "at-least-node": {
270 | "version": "1.0.0",
271 | "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
272 | "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
273 | },
274 | "axios": {
275 | "version": "0.19.2",
276 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
277 | "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
278 | "requires": {
279 | "follow-redirects": "1.5.10"
280 | }
281 | },
282 | "balanced-match": {
283 | "version": "1.0.0",
284 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
285 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
286 | "dev": true
287 | },
288 | "binary-extensions": {
289 | "version": "2.1.0",
290 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
291 | "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
292 | "dev": true
293 | },
294 | "brace-expansion": {
295 | "version": "1.1.11",
296 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
297 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
298 | "dev": true,
299 | "requires": {
300 | "balanced-match": "^1.0.0",
301 | "concat-map": "0.0.1"
302 | }
303 | },
304 | "braces": {
305 | "version": "3.0.2",
306 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
307 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
308 | "dev": true,
309 | "requires": {
310 | "fill-range": "^7.0.1"
311 | }
312 | },
313 | "browser-stdout": {
314 | "version": "1.3.1",
315 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
316 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
317 | "dev": true
318 | },
319 | "callsites": {
320 | "version": "3.1.0",
321 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
322 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
323 | "dev": true
324 | },
325 | "camelcase": {
326 | "version": "5.3.1",
327 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
328 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
329 | "dev": true
330 | },
331 | "chalk": {
332 | "version": "4.1.0",
333 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
334 | "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
335 | "dev": true,
336 | "requires": {
337 | "ansi-styles": "^4.1.0",
338 | "supports-color": "^7.1.0"
339 | },
340 | "dependencies": {
341 | "ansi-styles": {
342 | "version": "4.2.1",
343 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
344 | "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
345 | "dev": true,
346 | "requires": {
347 | "@types/color-name": "^1.1.1",
348 | "color-convert": "^2.0.1"
349 | }
350 | },
351 | "color-convert": {
352 | "version": "2.0.1",
353 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
354 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
355 | "dev": true,
356 | "requires": {
357 | "color-name": "~1.1.4"
358 | }
359 | },
360 | "color-name": {
361 | "version": "1.1.4",
362 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
363 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
364 | "dev": true
365 | },
366 | "has-flag": {
367 | "version": "4.0.0",
368 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
369 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
370 | "dev": true
371 | },
372 | "supports-color": {
373 | "version": "7.1.0",
374 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
375 | "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
376 | "dev": true,
377 | "requires": {
378 | "has-flag": "^4.0.0"
379 | }
380 | }
381 | }
382 | },
383 | "chokidar": {
384 | "version": "3.3.1",
385 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz",
386 | "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==",
387 | "dev": true,
388 | "requires": {
389 | "anymatch": "~3.1.1",
390 | "braces": "~3.0.2",
391 | "fsevents": "~2.1.2",
392 | "glob-parent": "~5.1.0",
393 | "is-binary-path": "~2.1.0",
394 | "is-glob": "~4.0.1",
395 | "normalize-path": "~3.0.0",
396 | "readdirp": "~3.3.0"
397 | }
398 | },
399 | "cliui": {
400 | "version": "5.0.0",
401 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
402 | "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
403 | "dev": true,
404 | "requires": {
405 | "string-width": "^3.1.0",
406 | "strip-ansi": "^5.2.0",
407 | "wrap-ansi": "^5.1.0"
408 | },
409 | "dependencies": {
410 | "ansi-regex": {
411 | "version": "4.1.0",
412 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
413 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
414 | "dev": true
415 | },
416 | "strip-ansi": {
417 | "version": "5.2.0",
418 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
419 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
420 | "dev": true,
421 | "requires": {
422 | "ansi-regex": "^4.1.0"
423 | }
424 | }
425 | }
426 | },
427 | "color-convert": {
428 | "version": "1.9.3",
429 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
430 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
431 | "dev": true,
432 | "requires": {
433 | "color-name": "1.1.3"
434 | }
435 | },
436 | "color-name": {
437 | "version": "1.1.3",
438 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
439 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
440 | "dev": true
441 | },
442 | "concat-map": {
443 | "version": "0.0.1",
444 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
445 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
446 | "dev": true
447 | },
448 | "cross-spawn": {
449 | "version": "7.0.3",
450 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
451 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
452 | "dev": true,
453 | "requires": {
454 | "path-key": "^3.1.0",
455 | "shebang-command": "^2.0.0",
456 | "which": "^2.0.1"
457 | }
458 | },
459 | "debug": {
460 | "version": "4.1.1",
461 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
462 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
463 | "dev": true,
464 | "requires": {
465 | "ms": "^2.1.1"
466 | }
467 | },
468 | "decamelize": {
469 | "version": "1.2.0",
470 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
471 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
472 | "dev": true
473 | },
474 | "deep-is": {
475 | "version": "0.1.3",
476 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
477 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
478 | "dev": true
479 | },
480 | "define-properties": {
481 | "version": "1.1.3",
482 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
483 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
484 | "dev": true,
485 | "requires": {
486 | "object-keys": "^1.0.12"
487 | }
488 | },
489 | "diff": {
490 | "version": "4.0.2",
491 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
492 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
493 | "dev": true
494 | },
495 | "doctrine": {
496 | "version": "3.0.0",
497 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
498 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
499 | "dev": true,
500 | "requires": {
501 | "esutils": "^2.0.2"
502 | }
503 | },
504 | "emoji-regex": {
505 | "version": "7.0.3",
506 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
507 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
508 | "dev": true
509 | },
510 | "enquirer": {
511 | "version": "2.3.6",
512 | "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
513 | "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
514 | "dev": true,
515 | "requires": {
516 | "ansi-colors": "^4.1.1"
517 | }
518 | },
519 | "es-abstract": {
520 | "version": "1.17.6",
521 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
522 | "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
523 | "dev": true,
524 | "requires": {
525 | "es-to-primitive": "^1.2.1",
526 | "function-bind": "^1.1.1",
527 | "has": "^1.0.3",
528 | "has-symbols": "^1.0.1",
529 | "is-callable": "^1.2.0",
530 | "is-regex": "^1.1.0",
531 | "object-inspect": "^1.7.0",
532 | "object-keys": "^1.1.1",
533 | "object.assign": "^4.1.0",
534 | "string.prototype.trimend": "^1.0.1",
535 | "string.prototype.trimstart": "^1.0.1"
536 | }
537 | },
538 | "es-array-method-boxes-properly": {
539 | "version": "1.0.0",
540 | "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
541 | "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
542 | "dev": true
543 | },
544 | "es-get-iterator": {
545 | "version": "1.1.0",
546 | "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz",
547 | "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==",
548 | "dev": true,
549 | "requires": {
550 | "es-abstract": "^1.17.4",
551 | "has-symbols": "^1.0.1",
552 | "is-arguments": "^1.0.4",
553 | "is-map": "^2.0.1",
554 | "is-set": "^2.0.1",
555 | "is-string": "^1.0.5",
556 | "isarray": "^2.0.5"
557 | }
558 | },
559 | "es-to-primitive": {
560 | "version": "1.2.1",
561 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
562 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
563 | "dev": true,
564 | "requires": {
565 | "is-callable": "^1.1.4",
566 | "is-date-object": "^1.0.1",
567 | "is-symbol": "^1.0.2"
568 | }
569 | },
570 | "es6-promise": {
571 | "version": "4.2.8",
572 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
573 | "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
574 | "dev": true
575 | },
576 | "es6-promisify": {
577 | "version": "5.0.0",
578 | "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
579 | "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
580 | "dev": true,
581 | "requires": {
582 | "es6-promise": "^4.0.3"
583 | }
584 | },
585 | "escape-string-regexp": {
586 | "version": "1.0.5",
587 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
588 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
589 | "dev": true
590 | },
591 | "eslint": {
592 | "version": "7.7.0",
593 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.7.0.tgz",
594 | "integrity": "sha512-1KUxLzos0ZVsyL81PnRN335nDtQ8/vZUD6uMtWbF+5zDtjKcsklIi78XoE0MVL93QvWTu+E5y44VyyCsOMBrIg==",
595 | "dev": true,
596 | "requires": {
597 | "@babel/code-frame": "^7.0.0",
598 | "ajv": "^6.10.0",
599 | "chalk": "^4.0.0",
600 | "cross-spawn": "^7.0.2",
601 | "debug": "^4.0.1",
602 | "doctrine": "^3.0.0",
603 | "enquirer": "^2.3.5",
604 | "eslint-scope": "^5.1.0",
605 | "eslint-utils": "^2.1.0",
606 | "eslint-visitor-keys": "^1.3.0",
607 | "espree": "^7.2.0",
608 | "esquery": "^1.2.0",
609 | "esutils": "^2.0.2",
610 | "file-entry-cache": "^5.0.1",
611 | "functional-red-black-tree": "^1.0.1",
612 | "glob-parent": "^5.0.0",
613 | "globals": "^12.1.0",
614 | "ignore": "^4.0.6",
615 | "import-fresh": "^3.0.0",
616 | "imurmurhash": "^0.1.4",
617 | "is-glob": "^4.0.0",
618 | "js-yaml": "^3.13.1",
619 | "json-stable-stringify-without-jsonify": "^1.0.1",
620 | "levn": "^0.4.1",
621 | "lodash": "^4.17.19",
622 | "minimatch": "^3.0.4",
623 | "natural-compare": "^1.4.0",
624 | "optionator": "^0.9.1",
625 | "progress": "^2.0.0",
626 | "regexpp": "^3.1.0",
627 | "semver": "^7.2.1",
628 | "strip-ansi": "^6.0.0",
629 | "strip-json-comments": "^3.1.0",
630 | "table": "^5.2.3",
631 | "text-table": "^0.2.0",
632 | "v8-compile-cache": "^2.0.3"
633 | }
634 | },
635 | "eslint-scope": {
636 | "version": "5.1.0",
637 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz",
638 | "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==",
639 | "dev": true,
640 | "requires": {
641 | "esrecurse": "^4.1.0",
642 | "estraverse": "^4.1.1"
643 | }
644 | },
645 | "eslint-utils": {
646 | "version": "2.1.0",
647 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
648 | "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
649 | "dev": true,
650 | "requires": {
651 | "eslint-visitor-keys": "^1.1.0"
652 | }
653 | },
654 | "eslint-visitor-keys": {
655 | "version": "1.3.0",
656 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
657 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
658 | "dev": true
659 | },
660 | "espree": {
661 | "version": "7.2.0",
662 | "resolved": "https://registry.npmjs.org/espree/-/espree-7.2.0.tgz",
663 | "integrity": "sha512-H+cQ3+3JYRMEIOl87e7QdHX70ocly5iW4+dttuR8iYSPr/hXKFb+7dBsZ7+u1adC4VrnPlTkv0+OwuPnDop19g==",
664 | "dev": true,
665 | "requires": {
666 | "acorn": "^7.3.1",
667 | "acorn-jsx": "^5.2.0",
668 | "eslint-visitor-keys": "^1.3.0"
669 | }
670 | },
671 | "esprima": {
672 | "version": "4.0.1",
673 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
674 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
675 | "dev": true
676 | },
677 | "esquery": {
678 | "version": "1.3.1",
679 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
680 | "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
681 | "dev": true,
682 | "requires": {
683 | "estraverse": "^5.1.0"
684 | },
685 | "dependencies": {
686 | "estraverse": {
687 | "version": "5.2.0",
688 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
689 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
690 | "dev": true
691 | }
692 | }
693 | },
694 | "esrecurse": {
695 | "version": "4.2.1",
696 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
697 | "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
698 | "dev": true,
699 | "requires": {
700 | "estraverse": "^4.1.0"
701 | }
702 | },
703 | "estraverse": {
704 | "version": "4.3.0",
705 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
706 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
707 | "dev": true
708 | },
709 | "esutils": {
710 | "version": "2.0.3",
711 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
712 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
713 | "dev": true
714 | },
715 | "fast-deep-equal": {
716 | "version": "3.1.3",
717 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
718 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
719 | "dev": true
720 | },
721 | "fast-json-stable-stringify": {
722 | "version": "2.1.0",
723 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
724 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
725 | "dev": true
726 | },
727 | "fast-levenshtein": {
728 | "version": "2.0.6",
729 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
730 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
731 | "dev": true
732 | },
733 | "file-entry-cache": {
734 | "version": "5.0.1",
735 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
736 | "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
737 | "dev": true,
738 | "requires": {
739 | "flat-cache": "^2.0.1"
740 | }
741 | },
742 | "fill-range": {
743 | "version": "7.0.1",
744 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
745 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
746 | "dev": true,
747 | "requires": {
748 | "to-regex-range": "^5.0.1"
749 | }
750 | },
751 | "find-up": {
752 | "version": "4.1.0",
753 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
754 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
755 | "dev": true,
756 | "requires": {
757 | "locate-path": "^5.0.0",
758 | "path-exists": "^4.0.0"
759 | }
760 | },
761 | "flat": {
762 | "version": "4.1.0",
763 | "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz",
764 | "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==",
765 | "dev": true,
766 | "requires": {
767 | "is-buffer": "~2.0.3"
768 | }
769 | },
770 | "flat-cache": {
771 | "version": "2.0.1",
772 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
773 | "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
774 | "dev": true,
775 | "requires": {
776 | "flatted": "^2.0.0",
777 | "rimraf": "2.6.3",
778 | "write": "1.0.3"
779 | }
780 | },
781 | "flatted": {
782 | "version": "2.0.2",
783 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
784 | "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
785 | "dev": true
786 | },
787 | "follow-redirects": {
788 | "version": "1.5.10",
789 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
790 | "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
791 | "requires": {
792 | "debug": "=3.1.0"
793 | },
794 | "dependencies": {
795 | "debug": {
796 | "version": "3.1.0",
797 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
798 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
799 | "requires": {
800 | "ms": "2.0.0"
801 | }
802 | },
803 | "ms": {
804 | "version": "2.0.0",
805 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
806 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
807 | }
808 | }
809 | },
810 | "fs-extra": {
811 | "version": "9.0.1",
812 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
813 | "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
814 | "requires": {
815 | "at-least-node": "^1.0.0",
816 | "graceful-fs": "^4.2.0",
817 | "jsonfile": "^6.0.1",
818 | "universalify": "^1.0.0"
819 | }
820 | },
821 | "fs.realpath": {
822 | "version": "1.0.0",
823 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
824 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
825 | "dev": true
826 | },
827 | "fsevents": {
828 | "version": "2.1.3",
829 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
830 | "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
831 | "dev": true,
832 | "optional": true
833 | },
834 | "function-bind": {
835 | "version": "1.1.1",
836 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
837 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
838 | "dev": true
839 | },
840 | "functional-red-black-tree": {
841 | "version": "1.0.1",
842 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
843 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
844 | "dev": true
845 | },
846 | "get-caller-file": {
847 | "version": "2.0.5",
848 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
849 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
850 | "dev": true
851 | },
852 | "glob": {
853 | "version": "7.1.6",
854 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
855 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
856 | "dev": true,
857 | "requires": {
858 | "fs.realpath": "^1.0.0",
859 | "inflight": "^1.0.4",
860 | "inherits": "2",
861 | "minimatch": "^3.0.4",
862 | "once": "^1.3.0",
863 | "path-is-absolute": "^1.0.0"
864 | }
865 | },
866 | "glob-parent": {
867 | "version": "5.1.1",
868 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
869 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
870 | "dev": true,
871 | "requires": {
872 | "is-glob": "^4.0.1"
873 | }
874 | },
875 | "globals": {
876 | "version": "12.4.0",
877 | "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
878 | "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
879 | "dev": true,
880 | "requires": {
881 | "type-fest": "^0.8.1"
882 | }
883 | },
884 | "graceful-fs": {
885 | "version": "4.2.4",
886 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
887 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
888 | },
889 | "growl": {
890 | "version": "1.10.5",
891 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
892 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
893 | "dev": true
894 | },
895 | "has": {
896 | "version": "1.0.3",
897 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
898 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
899 | "dev": true,
900 | "requires": {
901 | "function-bind": "^1.1.1"
902 | }
903 | },
904 | "has-flag": {
905 | "version": "3.0.0",
906 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
907 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
908 | "dev": true
909 | },
910 | "has-symbols": {
911 | "version": "1.0.1",
912 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
913 | "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
914 | "dev": true
915 | },
916 | "he": {
917 | "version": "1.2.0",
918 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
919 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
920 | "dev": true
921 | },
922 | "http-proxy-agent": {
923 | "version": "2.1.0",
924 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
925 | "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
926 | "dev": true,
927 | "requires": {
928 | "agent-base": "4",
929 | "debug": "3.1.0"
930 | },
931 | "dependencies": {
932 | "debug": {
933 | "version": "3.1.0",
934 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
935 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
936 | "dev": true,
937 | "requires": {
938 | "ms": "2.0.0"
939 | }
940 | },
941 | "ms": {
942 | "version": "2.0.0",
943 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
944 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
945 | "dev": true
946 | }
947 | }
948 | },
949 | "https-proxy-agent": {
950 | "version": "2.2.4",
951 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
952 | "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
953 | "dev": true,
954 | "requires": {
955 | "agent-base": "^4.3.0",
956 | "debug": "^3.1.0"
957 | },
958 | "dependencies": {
959 | "debug": {
960 | "version": "3.2.6",
961 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
962 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
963 | "dev": true,
964 | "requires": {
965 | "ms": "^2.1.1"
966 | }
967 | }
968 | }
969 | },
970 | "ignore": {
971 | "version": "4.0.6",
972 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
973 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
974 | "dev": true
975 | },
976 | "import-fresh": {
977 | "version": "3.2.1",
978 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
979 | "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
980 | "dev": true,
981 | "requires": {
982 | "parent-module": "^1.0.0",
983 | "resolve-from": "^4.0.0"
984 | }
985 | },
986 | "imurmurhash": {
987 | "version": "0.1.4",
988 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
989 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
990 | "dev": true
991 | },
992 | "inflight": {
993 | "version": "1.0.6",
994 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
995 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
996 | "dev": true,
997 | "requires": {
998 | "once": "^1.3.0",
999 | "wrappy": "1"
1000 | }
1001 | },
1002 | "inherits": {
1003 | "version": "2.0.4",
1004 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1005 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
1006 | "dev": true
1007 | },
1008 | "is-arguments": {
1009 | "version": "1.0.4",
1010 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
1011 | "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
1012 | "dev": true
1013 | },
1014 | "is-binary-path": {
1015 | "version": "2.1.0",
1016 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
1017 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
1018 | "dev": true,
1019 | "requires": {
1020 | "binary-extensions": "^2.0.0"
1021 | }
1022 | },
1023 | "is-buffer": {
1024 | "version": "2.0.4",
1025 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
1026 | "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==",
1027 | "dev": true
1028 | },
1029 | "is-callable": {
1030 | "version": "1.2.0",
1031 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz",
1032 | "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==",
1033 | "dev": true
1034 | },
1035 | "is-date-object": {
1036 | "version": "1.0.2",
1037 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
1038 | "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
1039 | "dev": true
1040 | },
1041 | "is-extglob": {
1042 | "version": "2.1.1",
1043 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
1044 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
1045 | "dev": true
1046 | },
1047 | "is-fullwidth-code-point": {
1048 | "version": "2.0.0",
1049 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
1050 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
1051 | "dev": true
1052 | },
1053 | "is-glob": {
1054 | "version": "4.0.1",
1055 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
1056 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
1057 | "dev": true,
1058 | "requires": {
1059 | "is-extglob": "^2.1.1"
1060 | }
1061 | },
1062 | "is-map": {
1063 | "version": "2.0.1",
1064 | "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz",
1065 | "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==",
1066 | "dev": true
1067 | },
1068 | "is-number": {
1069 | "version": "7.0.0",
1070 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
1071 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
1072 | "dev": true
1073 | },
1074 | "is-plain-obj": {
1075 | "version": "1.1.0",
1076 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
1077 | "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
1078 | "dev": true
1079 | },
1080 | "is-regex": {
1081 | "version": "1.1.1",
1082 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
1083 | "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
1084 | "dev": true,
1085 | "requires": {
1086 | "has-symbols": "^1.0.1"
1087 | }
1088 | },
1089 | "is-set": {
1090 | "version": "2.0.1",
1091 | "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz",
1092 | "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==",
1093 | "dev": true
1094 | },
1095 | "is-string": {
1096 | "version": "1.0.5",
1097 | "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
1098 | "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==",
1099 | "dev": true
1100 | },
1101 | "is-symbol": {
1102 | "version": "1.0.3",
1103 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
1104 | "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
1105 | "dev": true,
1106 | "requires": {
1107 | "has-symbols": "^1.0.1"
1108 | }
1109 | },
1110 | "isarray": {
1111 | "version": "2.0.5",
1112 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
1113 | "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
1114 | "dev": true
1115 | },
1116 | "isexe": {
1117 | "version": "2.0.0",
1118 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1119 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
1120 | "dev": true
1121 | },
1122 | "iterate-iterator": {
1123 | "version": "1.0.1",
1124 | "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz",
1125 | "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==",
1126 | "dev": true
1127 | },
1128 | "iterate-value": {
1129 | "version": "1.0.2",
1130 | "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz",
1131 | "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==",
1132 | "dev": true,
1133 | "requires": {
1134 | "es-get-iterator": "^1.0.2",
1135 | "iterate-iterator": "^1.0.1"
1136 | }
1137 | },
1138 | "js-tokens": {
1139 | "version": "4.0.0",
1140 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
1141 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
1142 | "dev": true
1143 | },
1144 | "js-yaml": {
1145 | "version": "3.14.0",
1146 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
1147 | "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
1148 | "dev": true,
1149 | "requires": {
1150 | "argparse": "^1.0.7",
1151 | "esprima": "^4.0.0"
1152 | }
1153 | },
1154 | "json-schema-traverse": {
1155 | "version": "0.4.1",
1156 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
1157 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
1158 | "dev": true
1159 | },
1160 | "json-stable-stringify-without-jsonify": {
1161 | "version": "1.0.1",
1162 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
1163 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
1164 | "dev": true
1165 | },
1166 | "jsonfile": {
1167 | "version": "6.0.1",
1168 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
1169 | "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==",
1170 | "requires": {
1171 | "graceful-fs": "^4.1.6",
1172 | "universalify": "^1.0.0"
1173 | }
1174 | },
1175 | "levn": {
1176 | "version": "0.4.1",
1177 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
1178 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
1179 | "dev": true,
1180 | "requires": {
1181 | "prelude-ls": "^1.2.1",
1182 | "type-check": "~0.4.0"
1183 | }
1184 | },
1185 | "locate-path": {
1186 | "version": "5.0.0",
1187 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
1188 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
1189 | "dev": true,
1190 | "requires": {
1191 | "p-locate": "^4.1.0"
1192 | }
1193 | },
1194 | "lodash": {
1195 | "version": "4.17.20",
1196 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
1197 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
1198 | "dev": true
1199 | },
1200 | "log-symbols": {
1201 | "version": "3.0.0",
1202 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
1203 | "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
1204 | "dev": true,
1205 | "requires": {
1206 | "chalk": "^2.4.2"
1207 | },
1208 | "dependencies": {
1209 | "chalk": {
1210 | "version": "2.4.2",
1211 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
1212 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
1213 | "dev": true,
1214 | "requires": {
1215 | "ansi-styles": "^3.2.1",
1216 | "escape-string-regexp": "^1.0.5",
1217 | "supports-color": "^5.3.0"
1218 | }
1219 | }
1220 | }
1221 | },
1222 | "minimatch": {
1223 | "version": "3.0.4",
1224 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
1225 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
1226 | "dev": true,
1227 | "requires": {
1228 | "brace-expansion": "^1.1.7"
1229 | }
1230 | },
1231 | "minimist": {
1232 | "version": "1.2.5",
1233 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
1234 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
1235 | "dev": true
1236 | },
1237 | "mkdirp": {
1238 | "version": "0.5.5",
1239 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
1240 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
1241 | "dev": true,
1242 | "requires": {
1243 | "minimist": "^1.2.5"
1244 | }
1245 | },
1246 | "mocha": {
1247 | "version": "8.1.1",
1248 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.1.1.tgz",
1249 | "integrity": "sha512-p7FuGlYH8t7gaiodlFreseLxEmxTgvyG9RgPHODFPySNhwUehu8NIb0vdSt3WFckSneswZ0Un5typYcWElk7HQ==",
1250 | "dev": true,
1251 | "requires": {
1252 | "ansi-colors": "4.1.1",
1253 | "browser-stdout": "1.3.1",
1254 | "chokidar": "3.3.1",
1255 | "debug": "3.2.6",
1256 | "diff": "4.0.2",
1257 | "escape-string-regexp": "1.0.5",
1258 | "find-up": "4.1.0",
1259 | "glob": "7.1.6",
1260 | "growl": "1.10.5",
1261 | "he": "1.2.0",
1262 | "js-yaml": "3.13.1",
1263 | "log-symbols": "3.0.0",
1264 | "minimatch": "3.0.4",
1265 | "ms": "2.1.2",
1266 | "object.assign": "4.1.0",
1267 | "promise.allsettled": "1.0.2",
1268 | "serialize-javascript": "4.0.0",
1269 | "strip-json-comments": "3.0.1",
1270 | "supports-color": "7.1.0",
1271 | "which": "2.0.2",
1272 | "wide-align": "1.1.3",
1273 | "workerpool": "6.0.0",
1274 | "yargs": "13.3.2",
1275 | "yargs-parser": "13.1.2",
1276 | "yargs-unparser": "1.6.1"
1277 | },
1278 | "dependencies": {
1279 | "debug": {
1280 | "version": "3.2.6",
1281 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
1282 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
1283 | "dev": true,
1284 | "requires": {
1285 | "ms": "^2.1.1"
1286 | }
1287 | },
1288 | "has-flag": {
1289 | "version": "4.0.0",
1290 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
1291 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
1292 | "dev": true
1293 | },
1294 | "js-yaml": {
1295 | "version": "3.13.1",
1296 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
1297 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
1298 | "dev": true,
1299 | "requires": {
1300 | "argparse": "^1.0.7",
1301 | "esprima": "^4.0.0"
1302 | }
1303 | },
1304 | "strip-json-comments": {
1305 | "version": "3.0.1",
1306 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz",
1307 | "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==",
1308 | "dev": true
1309 | },
1310 | "supports-color": {
1311 | "version": "7.1.0",
1312 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
1313 | "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
1314 | "dev": true,
1315 | "requires": {
1316 | "has-flag": "^4.0.0"
1317 | }
1318 | }
1319 | }
1320 | },
1321 | "ms": {
1322 | "version": "2.1.2",
1323 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1324 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
1325 | "dev": true
1326 | },
1327 | "natural-compare": {
1328 | "version": "1.4.0",
1329 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
1330 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
1331 | "dev": true
1332 | },
1333 | "normalize-path": {
1334 | "version": "3.0.0",
1335 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
1336 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
1337 | "dev": true
1338 | },
1339 | "object-inspect": {
1340 | "version": "1.8.0",
1341 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
1342 | "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
1343 | "dev": true
1344 | },
1345 | "object-keys": {
1346 | "version": "1.1.1",
1347 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
1348 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
1349 | "dev": true
1350 | },
1351 | "object.assign": {
1352 | "version": "4.1.0",
1353 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
1354 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
1355 | "dev": true,
1356 | "requires": {
1357 | "define-properties": "^1.1.2",
1358 | "function-bind": "^1.1.1",
1359 | "has-symbols": "^1.0.0",
1360 | "object-keys": "^1.0.11"
1361 | }
1362 | },
1363 | "once": {
1364 | "version": "1.4.0",
1365 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1366 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
1367 | "dev": true,
1368 | "requires": {
1369 | "wrappy": "1"
1370 | }
1371 | },
1372 | "optionator": {
1373 | "version": "0.9.1",
1374 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
1375 | "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
1376 | "dev": true,
1377 | "requires": {
1378 | "deep-is": "^0.1.3",
1379 | "fast-levenshtein": "^2.0.6",
1380 | "levn": "^0.4.1",
1381 | "prelude-ls": "^1.2.1",
1382 | "type-check": "^0.4.0",
1383 | "word-wrap": "^1.2.3"
1384 | }
1385 | },
1386 | "p-limit": {
1387 | "version": "2.3.0",
1388 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
1389 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
1390 | "dev": true,
1391 | "requires": {
1392 | "p-try": "^2.0.0"
1393 | }
1394 | },
1395 | "p-locate": {
1396 | "version": "4.1.0",
1397 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
1398 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
1399 | "dev": true,
1400 | "requires": {
1401 | "p-limit": "^2.2.0"
1402 | }
1403 | },
1404 | "p-try": {
1405 | "version": "2.2.0",
1406 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
1407 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
1408 | "dev": true
1409 | },
1410 | "parent-module": {
1411 | "version": "1.0.1",
1412 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
1413 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
1414 | "dev": true,
1415 | "requires": {
1416 | "callsites": "^3.0.0"
1417 | }
1418 | },
1419 | "path-exists": {
1420 | "version": "4.0.0",
1421 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
1422 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
1423 | "dev": true
1424 | },
1425 | "path-is-absolute": {
1426 | "version": "1.0.1",
1427 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
1428 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
1429 | "dev": true
1430 | },
1431 | "path-key": {
1432 | "version": "3.1.1",
1433 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
1434 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
1435 | "dev": true
1436 | },
1437 | "picomatch": {
1438 | "version": "2.2.2",
1439 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
1440 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
1441 | "dev": true
1442 | },
1443 | "prelude-ls": {
1444 | "version": "1.2.1",
1445 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
1446 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
1447 | "dev": true
1448 | },
1449 | "progress": {
1450 | "version": "2.0.3",
1451 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
1452 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
1453 | "dev": true
1454 | },
1455 | "promise.allsettled": {
1456 | "version": "1.0.2",
1457 | "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz",
1458 | "integrity": "sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg==",
1459 | "dev": true,
1460 | "requires": {
1461 | "array.prototype.map": "^1.0.1",
1462 | "define-properties": "^1.1.3",
1463 | "es-abstract": "^1.17.0-next.1",
1464 | "function-bind": "^1.1.1",
1465 | "iterate-value": "^1.0.0"
1466 | }
1467 | },
1468 | "punycode": {
1469 | "version": "2.1.1",
1470 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
1471 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
1472 | "dev": true
1473 | },
1474 | "randombytes": {
1475 | "version": "2.1.0",
1476 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
1477 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
1478 | "dev": true,
1479 | "requires": {
1480 | "safe-buffer": "^5.1.0"
1481 | }
1482 | },
1483 | "readdirp": {
1484 | "version": "3.3.0",
1485 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz",
1486 | "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==",
1487 | "dev": true,
1488 | "requires": {
1489 | "picomatch": "^2.0.7"
1490 | }
1491 | },
1492 | "regexpp": {
1493 | "version": "3.1.0",
1494 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
1495 | "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
1496 | "dev": true
1497 | },
1498 | "require-directory": {
1499 | "version": "2.1.1",
1500 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
1501 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
1502 | "dev": true
1503 | },
1504 | "require-main-filename": {
1505 | "version": "2.0.0",
1506 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
1507 | "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
1508 | "dev": true
1509 | },
1510 | "resolve-from": {
1511 | "version": "4.0.0",
1512 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
1513 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
1514 | "dev": true
1515 | },
1516 | "rimraf": {
1517 | "version": "2.6.3",
1518 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
1519 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
1520 | "dev": true,
1521 | "requires": {
1522 | "glob": "^7.1.3"
1523 | }
1524 | },
1525 | "safe-buffer": {
1526 | "version": "5.2.1",
1527 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1528 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1529 | "dev": true
1530 | },
1531 | "semver": {
1532 | "version": "7.3.2",
1533 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
1534 | "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
1535 | "dev": true
1536 | },
1537 | "serialize-javascript": {
1538 | "version": "4.0.0",
1539 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
1540 | "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
1541 | "dev": true,
1542 | "requires": {
1543 | "randombytes": "^2.1.0"
1544 | }
1545 | },
1546 | "set-blocking": {
1547 | "version": "2.0.0",
1548 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
1549 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
1550 | "dev": true
1551 | },
1552 | "shebang-command": {
1553 | "version": "2.0.0",
1554 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
1555 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
1556 | "dev": true,
1557 | "requires": {
1558 | "shebang-regex": "^3.0.0"
1559 | }
1560 | },
1561 | "shebang-regex": {
1562 | "version": "3.0.0",
1563 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
1564 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
1565 | "dev": true
1566 | },
1567 | "slice-ansi": {
1568 | "version": "2.1.0",
1569 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
1570 | "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
1571 | "dev": true,
1572 | "requires": {
1573 | "ansi-styles": "^3.2.0",
1574 | "astral-regex": "^1.0.0",
1575 | "is-fullwidth-code-point": "^2.0.0"
1576 | }
1577 | },
1578 | "sprintf-js": {
1579 | "version": "1.0.3",
1580 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
1581 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
1582 | "dev": true
1583 | },
1584 | "string-width": {
1585 | "version": "3.1.0",
1586 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
1587 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
1588 | "dev": true,
1589 | "requires": {
1590 | "emoji-regex": "^7.0.1",
1591 | "is-fullwidth-code-point": "^2.0.0",
1592 | "strip-ansi": "^5.1.0"
1593 | },
1594 | "dependencies": {
1595 | "ansi-regex": {
1596 | "version": "4.1.0",
1597 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
1598 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
1599 | "dev": true
1600 | },
1601 | "strip-ansi": {
1602 | "version": "5.2.0",
1603 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
1604 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
1605 | "dev": true,
1606 | "requires": {
1607 | "ansi-regex": "^4.1.0"
1608 | }
1609 | }
1610 | }
1611 | },
1612 | "string.prototype.trimend": {
1613 | "version": "1.0.1",
1614 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz",
1615 | "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==",
1616 | "dev": true,
1617 | "requires": {
1618 | "define-properties": "^1.1.3",
1619 | "es-abstract": "^1.17.5"
1620 | }
1621 | },
1622 | "string.prototype.trimstart": {
1623 | "version": "1.0.1",
1624 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
1625 | "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==",
1626 | "dev": true,
1627 | "requires": {
1628 | "define-properties": "^1.1.3",
1629 | "es-abstract": "^1.17.5"
1630 | }
1631 | },
1632 | "strip-ansi": {
1633 | "version": "6.0.0",
1634 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
1635 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
1636 | "dev": true,
1637 | "requires": {
1638 | "ansi-regex": "^5.0.0"
1639 | }
1640 | },
1641 | "strip-json-comments": {
1642 | "version": "3.1.1",
1643 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
1644 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
1645 | "dev": true
1646 | },
1647 | "supports-color": {
1648 | "version": "5.5.0",
1649 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1650 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1651 | "dev": true,
1652 | "requires": {
1653 | "has-flag": "^3.0.0"
1654 | }
1655 | },
1656 | "table": {
1657 | "version": "5.4.6",
1658 | "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
1659 | "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
1660 | "dev": true,
1661 | "requires": {
1662 | "ajv": "^6.10.2",
1663 | "lodash": "^4.17.14",
1664 | "slice-ansi": "^2.1.0",
1665 | "string-width": "^3.0.0"
1666 | }
1667 | },
1668 | "text-table": {
1669 | "version": "0.2.0",
1670 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
1671 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
1672 | "dev": true
1673 | },
1674 | "to-regex-range": {
1675 | "version": "5.0.1",
1676 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1677 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1678 | "dev": true,
1679 | "requires": {
1680 | "is-number": "^7.0.0"
1681 | }
1682 | },
1683 | "tslib": {
1684 | "version": "1.13.0",
1685 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
1686 | "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==",
1687 | "dev": true
1688 | },
1689 | "tsutils": {
1690 | "version": "3.17.1",
1691 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz",
1692 | "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==",
1693 | "dev": true,
1694 | "requires": {
1695 | "tslib": "^1.8.1"
1696 | }
1697 | },
1698 | "type-check": {
1699 | "version": "0.4.0",
1700 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
1701 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
1702 | "dev": true,
1703 | "requires": {
1704 | "prelude-ls": "^1.2.1"
1705 | }
1706 | },
1707 | "type-fest": {
1708 | "version": "0.8.1",
1709 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
1710 | "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
1711 | "dev": true
1712 | },
1713 | "typescript": {
1714 | "version": "3.9.7",
1715 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
1716 | "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
1717 | "dev": true
1718 | },
1719 | "universalify": {
1720 | "version": "1.0.0",
1721 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
1722 | "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="
1723 | },
1724 | "uri-js": {
1725 | "version": "4.2.2",
1726 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
1727 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
1728 | "dev": true,
1729 | "requires": {
1730 | "punycode": "^2.1.0"
1731 | }
1732 | },
1733 | "v8-compile-cache": {
1734 | "version": "2.1.1",
1735 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
1736 | "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==",
1737 | "dev": true
1738 | },
1739 | "vscode-test": {
1740 | "version": "1.4.0",
1741 | "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.4.0.tgz",
1742 | "integrity": "sha512-Jt7HNGvSE0+++Tvtq5wc4hiXLIr2OjDShz/gbAfM/mahQpy4rKBnmOK33D+MR67ATWviQhl+vpmU3p/qwSH/Pg==",
1743 | "dev": true,
1744 | "requires": {
1745 | "http-proxy-agent": "^2.1.0",
1746 | "https-proxy-agent": "^2.2.4",
1747 | "rimraf": "^2.6.3"
1748 | }
1749 | },
1750 | "which": {
1751 | "version": "2.0.2",
1752 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
1753 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
1754 | "dev": true,
1755 | "requires": {
1756 | "isexe": "^2.0.0"
1757 | }
1758 | },
1759 | "which-module": {
1760 | "version": "2.0.0",
1761 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
1762 | "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
1763 | "dev": true
1764 | },
1765 | "wide-align": {
1766 | "version": "1.1.3",
1767 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
1768 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
1769 | "dev": true,
1770 | "requires": {
1771 | "string-width": "^1.0.2 || 2"
1772 | },
1773 | "dependencies": {
1774 | "ansi-regex": {
1775 | "version": "3.0.0",
1776 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
1777 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
1778 | "dev": true
1779 | },
1780 | "string-width": {
1781 | "version": "2.1.1",
1782 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
1783 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
1784 | "dev": true,
1785 | "requires": {
1786 | "is-fullwidth-code-point": "^2.0.0",
1787 | "strip-ansi": "^4.0.0"
1788 | }
1789 | },
1790 | "strip-ansi": {
1791 | "version": "4.0.0",
1792 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
1793 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
1794 | "dev": true,
1795 | "requires": {
1796 | "ansi-regex": "^3.0.0"
1797 | }
1798 | }
1799 | }
1800 | },
1801 | "word-wrap": {
1802 | "version": "1.2.3",
1803 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
1804 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
1805 | "dev": true
1806 | },
1807 | "workerpool": {
1808 | "version": "6.0.0",
1809 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.0.tgz",
1810 | "integrity": "sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA==",
1811 | "dev": true
1812 | },
1813 | "wrap-ansi": {
1814 | "version": "5.1.0",
1815 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
1816 | "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
1817 | "dev": true,
1818 | "requires": {
1819 | "ansi-styles": "^3.2.0",
1820 | "string-width": "^3.0.0",
1821 | "strip-ansi": "^5.0.0"
1822 | },
1823 | "dependencies": {
1824 | "ansi-regex": {
1825 | "version": "4.1.0",
1826 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
1827 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
1828 | "dev": true
1829 | },
1830 | "strip-ansi": {
1831 | "version": "5.2.0",
1832 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
1833 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
1834 | "dev": true,
1835 | "requires": {
1836 | "ansi-regex": "^4.1.0"
1837 | }
1838 | }
1839 | }
1840 | },
1841 | "wrappy": {
1842 | "version": "1.0.2",
1843 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1844 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
1845 | "dev": true
1846 | },
1847 | "write": {
1848 | "version": "1.0.3",
1849 | "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
1850 | "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
1851 | "dev": true,
1852 | "requires": {
1853 | "mkdirp": "^0.5.1"
1854 | }
1855 | },
1856 | "y18n": {
1857 | "version": "4.0.0",
1858 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
1859 | "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
1860 | "dev": true
1861 | },
1862 | "yargs": {
1863 | "version": "13.3.2",
1864 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
1865 | "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
1866 | "dev": true,
1867 | "requires": {
1868 | "cliui": "^5.0.0",
1869 | "find-up": "^3.0.0",
1870 | "get-caller-file": "^2.0.1",
1871 | "require-directory": "^2.1.1",
1872 | "require-main-filename": "^2.0.0",
1873 | "set-blocking": "^2.0.0",
1874 | "string-width": "^3.0.0",
1875 | "which-module": "^2.0.0",
1876 | "y18n": "^4.0.0",
1877 | "yargs-parser": "^13.1.2"
1878 | },
1879 | "dependencies": {
1880 | "find-up": {
1881 | "version": "3.0.0",
1882 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
1883 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
1884 | "dev": true,
1885 | "requires": {
1886 | "locate-path": "^3.0.0"
1887 | }
1888 | },
1889 | "locate-path": {
1890 | "version": "3.0.0",
1891 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
1892 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
1893 | "dev": true,
1894 | "requires": {
1895 | "p-locate": "^3.0.0",
1896 | "path-exists": "^3.0.0"
1897 | }
1898 | },
1899 | "p-locate": {
1900 | "version": "3.0.0",
1901 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
1902 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
1903 | "dev": true,
1904 | "requires": {
1905 | "p-limit": "^2.0.0"
1906 | }
1907 | },
1908 | "path-exists": {
1909 | "version": "3.0.0",
1910 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
1911 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
1912 | "dev": true
1913 | }
1914 | }
1915 | },
1916 | "yargs-parser": {
1917 | "version": "13.1.2",
1918 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
1919 | "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
1920 | "dev": true,
1921 | "requires": {
1922 | "camelcase": "^5.0.0",
1923 | "decamelize": "^1.2.0"
1924 | }
1925 | },
1926 | "yargs-unparser": {
1927 | "version": "1.6.1",
1928 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.1.tgz",
1929 | "integrity": "sha512-qZV14lK9MWsGCmcr7u5oXGH0dbGqZAIxTDrWXZDo5zUr6b6iUmelNKO6x6R1dQT24AH3LgRxJpr8meWy2unolA==",
1930 | "dev": true,
1931 | "requires": {
1932 | "camelcase": "^5.3.1",
1933 | "decamelize": "^1.2.0",
1934 | "flat": "^4.1.0",
1935 | "is-plain-obj": "^1.1.0",
1936 | "yargs": "^14.2.3"
1937 | },
1938 | "dependencies": {
1939 | "find-up": {
1940 | "version": "3.0.0",
1941 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
1942 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
1943 | "dev": true,
1944 | "requires": {
1945 | "locate-path": "^3.0.0"
1946 | }
1947 | },
1948 | "locate-path": {
1949 | "version": "3.0.0",
1950 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
1951 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
1952 | "dev": true,
1953 | "requires": {
1954 | "p-locate": "^3.0.0",
1955 | "path-exists": "^3.0.0"
1956 | }
1957 | },
1958 | "p-locate": {
1959 | "version": "3.0.0",
1960 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
1961 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
1962 | "dev": true,
1963 | "requires": {
1964 | "p-limit": "^2.0.0"
1965 | }
1966 | },
1967 | "path-exists": {
1968 | "version": "3.0.0",
1969 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
1970 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
1971 | "dev": true
1972 | },
1973 | "yargs": {
1974 | "version": "14.2.3",
1975 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz",
1976 | "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==",
1977 | "dev": true,
1978 | "requires": {
1979 | "cliui": "^5.0.0",
1980 | "decamelize": "^1.2.0",
1981 | "find-up": "^3.0.0",
1982 | "get-caller-file": "^2.0.1",
1983 | "require-directory": "^2.1.1",
1984 | "require-main-filename": "^2.0.0",
1985 | "set-blocking": "^2.0.0",
1986 | "string-width": "^3.0.0",
1987 | "which-module": "^2.0.0",
1988 | "y18n": "^4.0.0",
1989 | "yargs-parser": "^15.0.1"
1990 | }
1991 | },
1992 | "yargs-parser": {
1993 | "version": "15.0.1",
1994 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz",
1995 | "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==",
1996 | "dev": true,
1997 | "requires": {
1998 | "camelcase": "^5.0.0",
1999 | "decamelize": "^1.2.0"
2000 | }
2001 | }
2002 | }
2003 | }
2004 | }
2005 | }
2006 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gmod-sdk",
3 | "displayName": "GMod SDK",
4 | "description": "Tools for Garry's Mod addon development",
5 | "version": "0.2.1",
6 | "publisher": "BadgerCode",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/BadgerCode/GMod-SDK-VSCode"
10 | },
11 | "galleryBanner": {
12 | "color": "#3a3d41",
13 | "theme": "dark"
14 | },
15 | "homepage": "https://github.com/BadgerCode/GMod-SDK-VSCode/blob/master/README.md",
16 | "qna": "https://github.com/BadgerCode/GMod-SDK-VSCode/issues",
17 | "license": "SEE LICENSE IN LICENSE",
18 | "icon": "resources/package-icon.png",
19 | "engines": {
20 | "vscode": "^1.48.0"
21 | },
22 | "categories": [
23 | "Extension Packs",
24 | "Other"
25 | ],
26 | "keywords": [
27 | "gmod",
28 | "glua"
29 | ],
30 | "main": "./out/extension.js",
31 | "activationEvents": [
32 | "onCommand:gmodSDK.createAddon",
33 | "onCommand:gmodSDK.createWeapon",
34 | "onCommand:gmodSDK.uploadAddon",
35 | "onCommand:gmodSDK.updateAddonThumbnail",
36 | "onCommand:gmodSDK.copyToLocalGarrysmod",
37 | "onView:gmodAddonInfo",
38 | "onView:gmodAddonWeapons",
39 | "onView:gmodWorkshop"
40 | ],
41 | "contributes": {
42 | "configuration": {
43 | "title": "GMod SDK",
44 | "properties": {
45 | "gmod-sdk.gmadExecutablePath": {
46 | "type": "string",
47 | "markdownDescription": "The path to the **gmad** program, found in your Garry's Mod bin folder.\n\nFor example: `C:\\Program Files (x86)\\Steam\\steamapps\\common\\garrysmod\\bin\\gmad.exe`\n\n[Help](https://gist.github.com/BadgerCode/00600eab40556c6e8809590d263ea053)",
48 | "default": "C:\\Program Files (x86)\\Steam\\steamapps\\common\\garrysmod\\bin\\gmad.exe"
49 | },
50 | "gmod-sdk.gmpublishExecutablePath": {
51 | "type": "string",
52 | "markdownDescription": "The path to the **gmpublish** program, found in your Garry's Mod bin folder.\n\nFor example: `C:\\Program Files (x86)\\Steam\\steamapps\\common\\garrysmod\\bin\\gmpublish.exe`\n\n[Help](https://gist.github.com/BadgerCode/00600eab40556c6e8809590d263ea053)",
53 | "default": "C:\\Program Files (x86)\\Steam\\steamapps\\common\\garrysmod\\bin\\gmpublish.exe"
54 | },
55 | "gmod-sdk.garrysmodAddonsPath": {
56 | "type": "string",
57 | "markdownDescription": "The path to the **addons** folder, found in your Garry's Mod folder.\n\nFor example: `C:\\Program Files (x86)\\Steam\\steamapps\\common\\garrysmod\\garrysmod\\addons`\n\n[Help](https://gist.github.com/BadgerCode/00600eab40556c6e8809590d263ea053)",
58 | "default": "C:\\Program Files (x86)\\Steam\\steamapps\\common\\garrysmod\\garrysmod\\addons"
59 | },
60 | "gmod-sdk.steamID": {
61 | "type": "string",
62 | "markdownDescription": "Your long (steamID64) Steam ID. Used to load your workshop items.\n\n[Help](https://steamid.io/)\n\nE.g. 70561198021123456",
63 | "default": ""
64 | }
65 | }
66 | },
67 | "commands": [
68 | {
69 | "command": "gmodSDK.createAddon",
70 | "title": "Create Garry's Mod Addon"
71 | },
72 | {
73 | "command": "gmodSDK.createWeapon",
74 | "title": "Create Weapon",
75 | "icon": {
76 | "light": "resources/light/create.svg",
77 | "dark": "resources/dark/create.svg"
78 | }
79 | },
80 | {
81 | "command": "gmodSDK.uploadAddon",
82 | "title": "Upload addon to workshop",
83 | "icon": {
84 | "light": "resources/light/upload.svg",
85 | "dark": "resources/dark/upload.svg"
86 | }
87 | },
88 | {
89 | "command": "gmodSDK.updateAddonThumbnail",
90 | "title": "Set the thumbnail for a workshop addon",
91 | "icon": {
92 | "light": "resources/light/thumbnail.svg",
93 | "dark": "resources/dark/thumbnail.svg"
94 | }
95 | },
96 | {
97 | "command": "gmodSDK.copyToLocalGarrysmod",
98 | "title": "Copy the addon to your Garry's Mod folder.",
99 | "icon": {
100 | "light": "resources/light/copy-to-folder.svg",
101 | "dark": "resources/dark/copy-to-folder.svg"
102 | }
103 | },
104 | {
105 | "command": "gmodAddonInfo.setTitle",
106 | "title": "Edit addon title",
107 | "icon": {
108 | "light": "resources/light/edit.svg",
109 | "dark": "resources/dark/edit.svg"
110 | }
111 | },
112 | {
113 | "command": "gmodAddonInfo.setDescription",
114 | "title": "Edit addon description",
115 | "icon": {
116 | "light": "resources/light/edit.svg",
117 | "dark": "resources/dark/edit.svg"
118 | }
119 | },
120 | {
121 | "command": "gmodAddonInfo.setType",
122 | "title": "Set addon type",
123 | "icon": {
124 | "light": "resources/light/edit.svg",
125 | "dark": "resources/dark/edit.svg"
126 | }
127 | },
128 | {
129 | "command": "gmodAddonInfo.setTags",
130 | "title": "Set addon tags",
131 | "icon": {
132 | "light": "resources/light/edit.svg",
133 | "dark": "resources/dark/edit.svg"
134 | }
135 | },
136 | {
137 | "command": "gmodAddonInfo.refresh",
138 | "title": "Refresh",
139 | "icon": {
140 | "light": "resources/light/refresh.svg",
141 | "dark": "resources/dark/refresh.svg"
142 | }
143 | },
144 | {
145 | "command": "gmodWeapon.edit",
146 | "title": "Edit",
147 | "icon": {
148 | "light": "resources/light/edit.svg",
149 | "dark": "resources/dark/edit.svg"
150 | }
151 | },
152 | {
153 | "command": "gmodWorkshop.selectSteamID",
154 | "title": "Select Steam ID"
155 | }
156 | ],
157 | "menus": {
158 | "commandPalette": [
159 | {
160 | "command": "gmodAddonInfo.setTitle",
161 | "when": "false"
162 | },
163 | {
164 | "command": "gmodAddonInfo.setDescription",
165 | "when": "false"
166 | },
167 | {
168 | "command": "gmodAddonInfo.setType",
169 | "when": "false"
170 | },
171 | {
172 | "command": "gmodAddonInfo.setTags",
173 | "when": "false"
174 | },
175 | {
176 | "command": "gmodAddonInfo.refresh",
177 | "when": "false"
178 | },
179 | {
180 | "command": "gmodWeapon.edit",
181 | "when": "false"
182 | },
183 | {
184 | "command": "gmodWorkshop.selectSteamID",
185 | "when": "false"
186 | }
187 | ],
188 | "view/title": [
189 | {
190 | "command": "gmodAddonInfo.refresh",
191 | "when": "view == gmodAddonInfo || view == gmodAddonWeapons || view == gmodWorkshop",
192 | "group": "navigation"
193 | },
194 | {
195 | "command": "gmodSDK.copyToLocalGarrysmod",
196 | "when": "view == gmodAddonInfo",
197 | "group": "navigation"
198 | },
199 | {
200 | "command": "gmodSDK.createWeapon",
201 | "when": "view == gmodAddonWeapons",
202 | "group": "navigation"
203 | },
204 | {
205 | "command": "gmodSDK.uploadAddon",
206 | "when": "view == gmodWorkshop",
207 | "group": "navigation"
208 | },
209 | {
210 | "command": "gmodSDK.updateAddonThumbnail",
211 | "when": "view == gmodWorkshop",
212 | "group": "navigation"
213 | }
214 | ],
215 | "view/item/context": [
216 | {
217 | "command": "gmodAddonInfo.setTitle",
218 | "when": "view == gmodAddonInfo && viewItem == title",
219 | "group": "inline"
220 | },
221 | {
222 | "command": "gmodAddonInfo.setDescription",
223 | "when": "view == gmodAddonInfo && viewItem == description",
224 | "group": "inline"
225 | },
226 | {
227 | "command": "gmodAddonInfo.setType",
228 | "when": "view == gmodAddonInfo && viewItem == type",
229 | "group": "inline"
230 | },
231 | {
232 | "command": "gmodAddonInfo.setTags",
233 | "when": "view == gmodAddonInfo && viewItem == tags",
234 | "group": "inline"
235 | },
236 | {
237 | "command": "gmodWeapon.edit",
238 | "when": "view == gmodAddonWeapons && viewItem =~ /^weapons\\..*/",
239 | "group": "inline"
240 | },
241 | {
242 | "command": "gmodSDK.uploadAddon",
243 | "when": "view == gmodWorkshop && viewItem =~ /^item-.*/",
244 | "group": "inline"
245 | },
246 | {
247 | "command": "gmodSDK.updateAddonThumbnail",
248 | "when": "view == gmodWorkshop && viewItem =~ /^item-.*/",
249 | "group": "inline"
250 | }
251 | ]
252 | },
253 | "views": {
254 | "gmod-sdk": [
255 | {
256 | "id": "gmodAddonInfo",
257 | "name": "Addon Overview",
258 | "icon": "./resources/menu-icon.svg",
259 | "contextualTitle": "Addon Information"
260 | },
261 | {
262 | "id": "gmodAddonWeapons",
263 | "name": "Weapons",
264 | "icon": "./resources/menu-icon.svg",
265 | "contextualTitle": "Addon Weapons"
266 | },
267 | {
268 | "id": "gmodWorkshop",
269 | "name": "Workshop",
270 | "icon": "./resources/menu-icon.svg",
271 | "contextualTitle": "Garry's Mod Workshop"
272 | }
273 | ]
274 | },
275 | "viewsWelcome": [
276 | {
277 | "view": "gmodAddonInfo",
278 | "contents": "You are not in a Garry's Mod addon folder.\n(Could not find addon.json)\n[Create addon](command:gmodSDK.createAddon)"
279 | },
280 | {
281 | "view": "gmodWorkshop",
282 | "contents": "Please select your Steam account to view your workshop items.\n\nHow to get your Steam ID - [https://steamid.io/](https://steamid.io/)\n\n[Select Account](command:gmodWorkshop.selectSteamID)"
283 | }
284 | ],
285 | "viewsContainers": {
286 | "activitybar": [
287 | {
288 | "id": "gmod-sdk",
289 | "title": "Garry's Mod",
290 | "icon": "./resources/menu-icon.svg"
291 | }
292 | ]
293 | }
294 | },
295 | "scripts": {
296 | "vscode:prepublish": "npm run compile",
297 | "compile": "tsc -p ./",
298 | "lint": "eslint src --ext ts",
299 | "watch": "tsc -watch -p ./",
300 | "pretest": "npm run compile && npm run lint",
301 | "test": "node ./out/test/runTest.js"
302 | },
303 | "devDependencies": {
304 | "@types/fs-extra": "^9.0.1",
305 | "@types/glob": "^7.1.3",
306 | "@types/mocha": "^8.0.0",
307 | "@types/node": "^14.0.27",
308 | "@types/vscode": "^1.48.0",
309 | "@typescript-eslint/eslint-plugin": "^3.8.0",
310 | "@typescript-eslint/parser": "^3.8.0",
311 | "eslint": "^7.6.0",
312 | "mocha": "^8.0.1",
313 | "typescript": "^3.8.3",
314 | "vscode-test": "^1.4.0"
315 | },
316 | "dependencies": {
317 | "axios": "^0.19.2",
318 | "fs-extra": "^9.0.1",
319 | "glob": "^7.1.6"
320 | }
321 | }
--------------------------------------------------------------------------------
/resources/dark/copy-to-folder.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/create.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/edit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/folder.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/refresh.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/string.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/thumbnail.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/upload.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/dark/workshop-item-hidden.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/copy-to-folder.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/create.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/edit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/folder.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/refresh.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/string.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/thumbnail.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/upload.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/light/workshop-item-hidden.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/menu-icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/package-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BadgerCode/GMod-SDK-VSCode/69a7d2f4d481324b9632485137ac7c7c2a7d011d/resources/package-icon.png
--------------------------------------------------------------------------------
/resources/readme/configuration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BadgerCode/GMod-SDK-VSCode/69a7d2f4d481324b9632485137ac7c7c2a7d011d/resources/readme/configuration.png
--------------------------------------------------------------------------------
/resources/readme/create-addon-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BadgerCode/GMod-SDK-VSCode/69a7d2f4d481324b9632485137ac7c7c2a7d011d/resources/readme/create-addon-1.png
--------------------------------------------------------------------------------
/resources/readme/create-addon-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BadgerCode/GMod-SDK-VSCode/69a7d2f4d481324b9632485137ac7c7c2a7d011d/resources/readme/create-addon-2.png
--------------------------------------------------------------------------------
/resources/readme/create-addon-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BadgerCode/GMod-SDK-VSCode/69a7d2f4d481324b9632485137ac7c7c2a7d011d/resources/readme/create-addon-3.png
--------------------------------------------------------------------------------
/resources/readme/features-copy-to-gmod.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BadgerCode/GMod-SDK-VSCode/69a7d2f4d481324b9632485137ac7c7c2a7d011d/resources/readme/features-copy-to-gmod.png
--------------------------------------------------------------------------------
/resources/samples/weapons/weapon_sandbox_main_sample.lua:
--------------------------------------------------------------------------------
1 | AddCSLuaFile()
2 |
3 | SWEP.Base = "weapon_base"
4 | SWEP.PrintName = "AK47-Sample"
5 | SWEP.Category = "Other"
6 | SWEP.Author = "Your name here"
7 | SWEP.Instructions = [[Enter a description to let players know
8 | how to use your weapon]]
9 |
10 | SWEP.HoldType = "ar2"
11 | SWEP.Slot = 1
12 | SWEP.SlotPos = 0
13 | SWEP.Weight = 5
14 | SWEP.AutoSwitchTo = true
15 | SWEP.AutoSwitchFrom = false
16 |
17 | SWEP.Spawnable = true
18 | SWEP.AdminSpawnable = true
19 |
20 | SWEP.ViewModelFlip = true
21 | SWEP.UseHands = false
22 | SWEP.DrawCrosshair = true
23 |
24 | SWEP.Primary.Delay = 0.08
25 | SWEP.Primary.Recoil = 1.9
26 | SWEP.Primary.Automatic = true
27 | SWEP.Primary.Damage = 20
28 | SWEP.Primary.Cone = 0.025
29 | SWEP.Primary.Ammo = "smg1"
30 | SWEP.Primary.ClipSize = 45
31 | SWEP.Primary.ClipMax = 90
32 | SWEP.Primary.DefaultClip = 45
33 | SWEP.Primary.Sound = Sound("Weapon_AK47.Single")
34 |
35 | SWEP.Secondary.Delay = 1
36 |
37 | SWEP.AmmoEnt = "item_ammo_smg1_ttt"
38 |
39 | SWEP.ViewModelFOV = 72
40 | SWEP.ViewModel = "models/weapons/v_rif_ak47.mdl"
41 | SWEP.WorldModel = "models/weapons/w_rif_ak47.mdl"
42 |
43 |
44 | function SWEP:PrimaryAttack()
45 | -- Checks if we have enough ammo to shoot
46 | if (self:CanPrimaryAttack() == false) then return end
47 |
48 | -- weapon_base: SWEP:ShootBullet(damage, numberOfBullets, aimcone, ammoType, force, tracer)
49 | -- Shoots a bullet, handles player/weapon animations & applies recoil
50 | self:ShootBullet(
51 | self.Primary.Damage,
52 | 1,
53 | self.Primary.Cone,
54 | self.Primary.Ammo
55 | )
56 |
57 | self:TakePrimaryAmmo(1)
58 |
59 | self:EmitSound(self.Primary.Sound)
60 |
61 | self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
62 | end
63 |
64 |
65 | function SWEP:SecondaryAttack()
66 | if(!self:CanSecondaryAttack()) then return end
67 |
68 | if SERVER then
69 | self:GetOwner():ChatPrint("Right click!")
70 | end
71 |
72 | -- Delay when the gun can next be fired (secondary attack)
73 | self:SetNextSecondaryFire(CurTime() + self.Secondary.Delay)
74 | end
75 |
--------------------------------------------------------------------------------
/resources/samples/weapons/weapon_sandbox_toolgun_sample.lua:
--------------------------------------------------------------------------------
1 |
2 | -- IMPORTANT
3 | -- =========
4 | -- Set this to your file name without the ".lua" on the end
5 | -- Sandbox tools use the filename for storing information and translations
6 | local FileName = "$WEAPON_NAME$"
7 |
8 |
9 | TOOL.Category = "My Category"
10 | TOOL.Name = "#tool." .. FileName .. ".name"
11 |
12 | if CLIENT then
13 | language.Add("tool." .. FileName .. ".name", "My example tool")
14 | language.Add("tool." .. FileName .. ".desc", "This is an example tool")
15 | language.Add("tool." .. FileName .. ".0", "Click to get started")
16 | end
17 |
18 |
19 | TOOL.ClientConVar["secretmessage"] = "0"
20 |
21 |
22 |
23 | function TOOL:LeftClick(trace)
24 | if SERVER then
25 | self:GetOwner():ChatPrint("Left click!")
26 |
27 | local showSecretMessage = self:GetClientNumber("secretmessage") == 1
28 |
29 | if showSecretMessage then
30 | self:GetOwner():ChatPrint("Here is the secret message!")
31 | end
32 | end
33 | end
34 |
35 | function TOOL:RightClick(trace)
36 | if SERVER then
37 | self:GetOwner():ChatPrint("Right click!")
38 | end
39 | end
40 |
41 | function TOOL:Reload(trace)
42 | if SERVER then
43 | self:GetOwner():ChatPrint("Reload!")
44 | end
45 | end
46 |
47 |
48 | -- This function/hook is called every frame on client and every tick on the server
49 | function TOOL:Think()
50 | end
51 |
52 |
53 | -- This controls the part of the UI which shows options for this tool
54 | function TOOL.BuildCPanel(panel)
55 | panel:AddControl("Header", {
56 | Text = "#tool." .. FileName .. ".name",
57 | Description = "#tool." .. FileName .. ".desc"
58 | })
59 |
60 | panel:AddControl("Checkbox", {
61 | Label = "Enable secret message for left click",
62 | Command = FileName .. "_secretmessage"
63 | })
64 | end
65 |
--------------------------------------------------------------------------------
/resources/samples/weapons/weapon_ttt_detective_sample.lua:
--------------------------------------------------------------------------------
1 | AddCSLuaFile()
2 |
3 | SWEP.HoldType = "ar2"
4 |
5 | if CLIENT then
6 | SWEP.PrintName = "AK47"
7 | SWEP.Slot = 6
8 |
9 | SWEP.ViewModelFOV = 72
10 | SWEP.ViewModelFlip = true
11 |
12 | -- Traitor equipment menu settings
13 | SWEP.EquipMenuData = {
14 | type = "item_weapon",
15 | desc = "Example custom weapon."
16 | };
17 |
18 | SWEP.Icon = "vgui/ttt/icon_nades"
19 | end
20 |
21 | SWEP.Base = "weapon_tttbase"
22 |
23 | SWEP.Primary.Delay = 0.08
24 | SWEP.Primary.Recoil = 1.9
25 | SWEP.Primary.Automatic = true
26 | SWEP.Primary.Damage = 20
27 | SWEP.Primary.Cone = 0.025
28 | SWEP.Primary.Ammo = "smg1"
29 | SWEP.Primary.ClipSize = 45
30 | SWEP.Primary.ClipMax = 90
31 | SWEP.Primary.DefaultClip = 45
32 | SWEP.Primary.Sound = Sound( "Weapon_AK47.Single" )
33 |
34 | SWEP.AmmoEnt = "item_ammo_smg1_ttt"
35 |
36 | SWEP.UseHands = true
37 | SWEP.ViewModel = "models/weapons/v_rif_ak47.mdl"
38 | SWEP.WorldModel = "models/weapons/w_rif_ak47.mdl"
39 |
40 | SWEP.NoSights = false
41 | SWEP.IronSightsPos = Vector( 6.05, -5, 2.4 )
42 | SWEP.IronSightsAng = Vector( 2.2, -0.1, 0 )
43 |
44 |
45 | -- Detective equipment settings
46 |
47 | SWEP.Kind = WEAPON_EQUIP1
48 | SWEP.AutoSpawnable = false
49 | SWEP.CanBuy = { ROLE_DETECTIVE }
50 | SWEP.LimitedStock = false
51 | SWEP.AllowDrop = true
52 | SWEP.IsSilent = false
53 |
54 |
55 |
56 | function SWEP:PrimaryAttack()
57 | -- Checks if we have enough ammo to shoot
58 | if not self:CanPrimaryAttack() then return end
59 |
60 | -- weapon_tttbase: SWEP:ShootBullet(damage, recoil, numberOfBullets, cone)
61 | -- Shoots a bullet, handles player/weapon animations & applies recoil
62 | self:ShootBullet(
63 | self.Primary.Damage,
64 | self.Primary.Recoil,
65 | self.Primary.NumShots,
66 | self:GetPrimaryCone()
67 | )
68 |
69 | self:TakePrimaryAmmo(self.Primary.NumShots)
70 |
71 | self:EmitSound(self.Primary.Sound)
72 |
73 | self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
74 | end
75 |
76 |
77 | function SWEP:SecondaryAttack()
78 | if self.NoSights or (not self.IronSightsPos) then return end
79 |
80 | self:SetIronsights(not self:GetIronsights())
81 |
82 | self:SetNextSecondaryFire(CurTime() + 0.3)
83 | end
84 |
--------------------------------------------------------------------------------
/resources/samples/weapons/weapon_ttt_grenade_sample.lua:
--------------------------------------------------------------------------------
1 | AddCSLuaFile()
2 |
3 | SWEP.HoldType = "grenade"
4 |
5 | if CLIENT then
6 | SWEP.PrintName = "Sample Grenade"
7 | SWEP.Slot = 3
8 |
9 | SWEP.ViewModelFlip = false
10 | SWEP.ViewModelFOV = 54
11 |
12 | SWEP.Icon = "vgui/ttt/icon_nades"
13 | end
14 |
15 | SWEP.Base = "weapon_tttbasegrenade"
16 |
17 | SWEP.Kind = WEAPON_NADE
18 |
19 | SWEP.UseHands = true
20 | SWEP.ViewModel = "models/weapons/cstrike/c_eq_smokegrenade.mdl"
21 | SWEP.WorldModel = "models/weapons/w_eq_smokegrenade.mdl"
22 |
23 | SWEP.Weight = 5
24 | SWEP.AutoSpawnable = true
25 | SWEP.Spawnable = true
26 |
27 |
28 | function SWEP:GetGrenadeName()
29 | return "ttt_smokegrenade_proj"
30 | end
31 |
--------------------------------------------------------------------------------
/resources/samples/weapons/weapon_ttt_primary_sample.lua:
--------------------------------------------------------------------------------
1 | AddCSLuaFile()
2 |
3 | SWEP.HoldType = "crossbow"
4 |
5 | if CLIENT then
6 | SWEP.PrintName = "S.A.M.P.L.E."
7 | SWEP.Slot = 2
8 |
9 | SWEP.ViewModelFlip = false
10 | SWEP.ViewModelFOV = 54
11 |
12 | SWEP.Icon = "vgui/ttt/icon_m249"
13 | end
14 |
15 | SWEP.Base = "weapon_tttbase"
16 |
17 | SWEP.Spawnable = true
18 | SWEP.AutoSpawnable = true
19 |
20 | SWEP.Kind = WEAPON_HEAVY
21 |
22 | SWEP.Primary.Damage = 7
23 | SWEP.Primary.Delay = 0.06
24 | SWEP.Primary.Cone = 0.09
25 | SWEP.Primary.ClipSize = 150
26 | SWEP.Primary.ClipMax = 150
27 | SWEP.Primary.DefaultClip = 150
28 | SWEP.Primary.Automatic = true
29 | SWEP.Primary.Ammo = "AirboatGun"
30 | SWEP.Primary.Recoil = 1.9
31 | SWEP.Primary.Sound = Sound("Weapon_m249.Single")
32 |
33 | SWEP.UseHands = true
34 | SWEP.ViewModel = "models/weapons/cstrike/c_mach_m249para.mdl"
35 | SWEP.WorldModel = "models/weapons/w_mach_m249para.mdl"
36 |
37 | SWEP.HeadshotMultiplier = 2.2
38 |
39 | SWEP.IronSightsPos = Vector(-5.96, -5.119, 2.349)
40 | SWEP.IronSightsAng = Vector(0, 0, 0)
41 |
42 |
43 | function SWEP:PrimaryAttack()
44 | -- Checks if we have enough ammo to shoot
45 | if not self:CanPrimaryAttack() then return end
46 |
47 | -- weapon_tttbase: SWEP:ShootBullet(damage, recoil, numberOfBullets, cone)
48 | -- Shoots a bullet, handles player/weapon animations & applies recoil
49 | self:ShootBullet(
50 | self.Primary.Damage,
51 | self.Primary.Recoil,
52 | self.Primary.NumShots,
53 | self:GetPrimaryCone()
54 | )
55 |
56 | self:TakePrimaryAmmo(self.Primary.NumShots)
57 |
58 | self:EmitSound(self.Primary.Sound)
59 |
60 | self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
61 | end
62 |
63 |
64 | function SWEP:SecondaryAttack()
65 | if self.NoSights or (not self.IronSightsPos) then return end
66 |
67 | self:SetIronsights(not self:GetIronsights())
68 |
69 | self:SetNextSecondaryFire(CurTime() + 0.3)
70 | end
71 |
--------------------------------------------------------------------------------
/resources/samples/weapons/weapon_ttt_secondary_sample.lua:
--------------------------------------------------------------------------------
1 | AddCSLuaFile()
2 |
3 | SWEP.HoldType = "pistol"
4 |
5 | if CLIENT then
6 | SWEP.PrintName = "Sample Pistol"
7 | SWEP.Slot = 1
8 |
9 | SWEP.ViewModelFlip = false
10 | SWEP.ViewModelFOV = 54
11 |
12 | SWEP.Icon = "vgui/ttt/icon_pistol"
13 | end
14 |
15 | SWEP.Base = "weapon_tttbase"
16 |
17 | SWEP.Kind = WEAPON_PISTOL
18 |
19 | SWEP.Primary.Recoil = 1.5
20 | SWEP.Primary.Damage = 25
21 | SWEP.Primary.Delay = 0.38
22 | SWEP.Primary.Cone = 0.02
23 | SWEP.Primary.ClipSize = 20
24 | SWEP.Primary.Automatic = true
25 | SWEP.Primary.DefaultClip = 20
26 | SWEP.Primary.ClipMax = 60
27 | SWEP.Primary.Ammo = "Pistol"
28 | SWEP.Primary.Sound = Sound( "Weapon_FiveSeven.Single" )
29 |
30 | SWEP.AutoSpawnable = true
31 | SWEP.AmmoEnt = "item_ammo_pistol_ttt"
32 |
33 | SWEP.UseHands = true
34 | SWEP.ViewModel = "models/weapons/cstrike/c_pist_fiveseven.mdl"
35 | SWEP.WorldModel = "models/weapons/w_pist_fiveseven.mdl"
36 |
37 | SWEP.IronSightsPos = Vector(-5.95, -4, 2.799)
38 | SWEP.IronSightsAng = Vector(0, 0, 0)
39 |
40 |
41 | function SWEP:PrimaryAttack()
42 | -- Checks if we have enough ammo to shoot
43 | if not self:CanPrimaryAttack() then return end
44 |
45 | -- weapon_tttbase: SWEP:ShootBullet(damage, recoil, numberOfBullets, cone)
46 | -- Shoots a bullet, handles player/weapon animations & applies recoil
47 | self:ShootBullet(
48 | self.Primary.Damage,
49 | self.Primary.Recoil,
50 | self.Primary.NumShots,
51 | self:GetPrimaryCone()
52 | )
53 |
54 | self:TakePrimaryAmmo(self.Primary.NumShots)
55 |
56 | self:EmitSound(self.Primary.Sound)
57 |
58 | self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
59 | end
60 |
61 |
62 | function SWEP:SecondaryAttack()
63 | if self.NoSights or (not self.IronSightsPos) then return end
64 |
65 | self:SetIronsights(not self:GetIronsights())
66 |
67 | self:SetNextSecondaryFire(CurTime() + 0.3)
68 | end
69 |
--------------------------------------------------------------------------------
/resources/samples/weapons/weapon_ttt_traitor_sample.lua:
--------------------------------------------------------------------------------
1 | AddCSLuaFile()
2 |
3 | SWEP.HoldType = "ar2"
4 |
5 | if CLIENT then
6 | SWEP.PrintName = "AK47"
7 | SWEP.Slot = 6
8 |
9 | SWEP.ViewModelFOV = 72
10 | SWEP.ViewModelFlip = true
11 |
12 | -- Traitor equipment menu settings
13 | SWEP.EquipMenuData = {
14 | type = "item_weapon",
15 | desc = "Example custom weapon."
16 | };
17 |
18 | SWEP.Icon = "vgui/ttt/icon_nades"
19 | end
20 |
21 | SWEP.Base = "weapon_tttbase"
22 |
23 | SWEP.Primary.Delay = 0.08
24 | SWEP.Primary.Recoil = 1.9
25 | SWEP.Primary.Automatic = true
26 | SWEP.Primary.Damage = 20
27 | SWEP.Primary.Cone = 0.025
28 | SWEP.Primary.Ammo = "smg1"
29 | SWEP.Primary.ClipSize = 45
30 | SWEP.Primary.ClipMax = 90
31 | SWEP.Primary.DefaultClip = 45
32 | SWEP.Primary.Sound = Sound( "Weapon_AK47.Single" )
33 |
34 | SWEP.AmmoEnt = "item_ammo_smg1_ttt"
35 |
36 | SWEP.UseHands = true
37 | SWEP.ViewModel = "models/weapons/v_rif_ak47.mdl"
38 | SWEP.WorldModel = "models/weapons/w_rif_ak47.mdl"
39 |
40 | SWEP.NoSights = false
41 | SWEP.IronSightsPos = Vector( 6.05, -5, 2.4 )
42 | SWEP.IronSightsAng = Vector( 2.2, -0.1, 0 )
43 |
44 |
45 | -- Traitor equipment settings
46 |
47 | SWEP.Kind = WEAPON_EQUIP1
48 | SWEP.AutoSpawnable = false
49 | SWEP.CanBuy = { ROLE_TRAITOR }
50 | SWEP.LimitedStock = false
51 | SWEP.AllowDrop = true
52 | SWEP.IsSilent = false
53 |
54 |
55 | function SWEP:PrimaryAttack()
56 | -- Checks if we have enough ammo to shoot
57 | if not self:CanPrimaryAttack() then return end
58 |
59 | -- weapon_tttbase: SWEP:ShootBullet(damage, recoil, numberOfBullets, cone)
60 | -- Shoots a bullet, handles player/weapon animations & applies recoil
61 | self:ShootBullet(
62 | self.Primary.Damage,
63 | self.Primary.Recoil,
64 | self.Primary.NumShots,
65 | self:GetPrimaryCone()
66 | )
67 |
68 | self:TakePrimaryAmmo(self.Primary.NumShots)
69 |
70 | self:EmitSound(self.Primary.Sound)
71 |
72 | self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
73 | end
74 |
75 |
76 | function SWEP:SecondaryAttack()
77 | if self.NoSights or (not self.IronSightsPos) then return end
78 |
79 | self:SetIronsights(not self:GetIronsights())
80 |
81 | self:SetNextSecondaryFire(CurTime() + 0.3)
82 | end
83 |
--------------------------------------------------------------------------------
/resources/samples/workshop-thumbnail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BadgerCode/GMod-SDK-VSCode/69a7d2f4d481324b9632485137ac7c7c2a7d011d/resources/samples/workshop-thumbnail.jpg
--------------------------------------------------------------------------------
/src/Services/GModAddonManager.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as fs from 'fs';
3 | import * as path from 'path';
4 |
5 |
6 | export class GModAddonManager {
7 | constructor(private workspaceRoot: string | undefined) { }
8 |
9 | getAddonInfo(): GModAddonInfo | undefined {
10 | if (!this.workspaceRoot) {
11 | return undefined;
12 | }
13 |
14 | const addonJSONPath = path.join(this.workspaceRoot, 'addon.json');
15 | if (this.pathExists(addonJSONPath) == false) {
16 | return undefined;
17 | }
18 |
19 | var addonInfo = JSON.parse(fs.readFileSync(addonJSONPath, 'utf8'));
20 | return addonInfo;
21 | }
22 |
23 | create(): void {
24 | if (!this.workspaceRoot) {
25 | vscode.window.showErrorMessage('Please open a folder before creating an addon.');
26 | return;
27 | }
28 |
29 | const addonJSONPath = path.join(this.workspaceRoot, 'addon.json');
30 | if (this.pathExists(addonJSONPath)) {
31 | vscode.window.showErrorMessage('GMod addon already exists!');
32 | return;
33 | }
34 |
35 | var addonInfo = new GModAddonInfo("My GMod Addon");
36 |
37 | this.save(addonInfo);
38 | vscode.window.showInformationMessage('Created addon.json');
39 | }
40 |
41 | save(addonInfo: GModAddonInfo) {
42 | if (!this.workspaceRoot)
43 | return;
44 |
45 | const addonJSONPath = path.join(this.workspaceRoot, 'addon.json');
46 | fs.writeFileSync(addonJSONPath, JSON.stringify(addonInfo, null, 4));
47 | }
48 |
49 | private pathExists(p: string): boolean {
50 | try {
51 | fs.accessSync(p);
52 | } catch (err) {
53 | return false;
54 | }
55 | return true;
56 | }
57 | }
58 |
59 |
60 | export class GModAddonInfo {
61 | /**
62 | * Name of addon. Can be changed after publishing to the Steam Workshop.
63 | */
64 | title: string;
65 |
66 | /**
67 | * A short description of the addon. Can be changed after publishing to the Steam Workshop.
68 | */
69 | description: string;
70 |
71 | /**
72 | * Type of addon. Used for filtering addons on the Steam Workshop.
73 | */
74 | type: AddonType;
75 |
76 | /**
77 | * Up to two tags. Used for filtering addons on the Steam Workshop.
78 | */
79 | tags: AddonTag[];
80 |
81 | /**
82 | * A list of relative-paths to files that should not be included when publishing the addon.
83 | */
84 | ignore: string[];
85 |
86 | constructor(title: string) {
87 | this.title = title;
88 | this.description = "";
89 | this.type = AddonType.ServerContent;
90 | this.tags = [AddonTag.Fun];
91 | this.ignore = [".git/*", "README.md"];
92 | }
93 | }
94 |
95 | export enum AddonType {
96 | ServerContent = "servercontent",
97 | Gamemode = "gamemode",
98 | Map = "map",
99 | Weapon = "weapon",
100 | Vehicle = "vehicle",
101 | NPC = "npc",
102 | Tool = "tool",
103 | Effects = "effects",
104 | Model = "model"
105 | }
106 |
107 | export enum AddonTag {
108 | Fun = "fun",
109 | Roleplay = "roleplay",
110 | Scenic = "scenic",
111 | Movie = "movie",
112 | Realism = "realism",
113 | Cartoon = "cartoon",
114 | Water = "water",
115 | Comic = "comic",
116 | Build = "build"
117 | }
118 |
--------------------------------------------------------------------------------
/src/Services/GModWeaponManager.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from "vscode";
2 | import * as fs from "fs";
3 | import * as path from "path";
4 | import { glob } from "glob";
5 |
6 | export class GModWeaponManager {
7 | constructor(private workspaceRoot: string | undefined, private samplesRoot: string) { }
8 |
9 | getWeapons(): GModWeaponOverview {
10 | var weaponsOverview = new GModWeaponOverview();
11 |
12 | if (!this.workspaceRoot) return weaponsOverview;
13 |
14 |
15 | const weaponsPath = path.join(this.workspaceRoot, "lua/weapons");
16 | if (this.pathExists(weaponsPath)) {
17 | weaponsOverview.addWeapons(this.findWeapons(weaponsPath)
18 | .map(fullPath => new GModWeapon(path.basename(fullPath, ".lua"), `lua/weapons`, fullPath))
19 | );
20 | }
21 |
22 | const sandboxToolsPath = path.join(this.workspaceRoot, "lua/weapons/gmod_tool/stools");
23 | if (this.pathExists(sandboxToolsPath)) {
24 | weaponsOverview.addSandboxTools(this.findWeapons(sandboxToolsPath)
25 | .map(fullPath => new GModWeapon(path.basename(fullPath, ".lua"), `lua/weapons/gmod_tool/stools`, fullPath))
26 | );
27 | }
28 |
29 | const gamemodesPath = path.join(this.workspaceRoot, "gamemodes");
30 | if (this.pathExists(gamemodesPath)) {
31 | var gamemodes = fs.readdirSync(gamemodesPath, { withFileTypes: true })
32 | .filter((fileEntity) => fileEntity.isDirectory())
33 | .map((directory) => directory.name);
34 |
35 | for (let i = 0; i < gamemodes.length; i++) {
36 | const gamemode = gamemodes[i];
37 | var gamemodeWeaponsPath = path.join(gamemodesPath, gamemode, "entities/weapons/");
38 |
39 | if (this.pathExists(gamemodeWeaponsPath)) {
40 | weaponsOverview.addWeapons(this.findWeapons(gamemodeWeaponsPath)
41 | .map(fullPath => new GModWeapon(path.basename(fullPath, ".lua"), `gamemodes/${gamemode}/entities/weapons`, fullPath))
42 | );
43 | }
44 |
45 | const gamemodeSandboxToolsPath = path.join(gamemodesPath, gamemode, "entities/weapons/gmod_tool/stools");
46 | if (this.pathExists(gamemodeSandboxToolsPath)) {
47 | weaponsOverview.addSandboxTools(this.findWeapons(gamemodeSandboxToolsPath)
48 | .map(fullPath => new GModWeapon(path.basename(fullPath, ".lua"), `gamemodes/${gamemode}/entities/weapons/gmod_tool/stools`, fullPath))
49 | );
50 | }
51 | }
52 | }
53 |
54 | weaponsOverview.sort();
55 |
56 | return weaponsOverview;
57 | }
58 |
59 | private findWeapons(directoryPath: string): string[] {
60 | var directoryItems = fs.readdirSync(directoryPath, { withFileTypes: true });
61 | var weaponPaths: string[] = [];
62 |
63 | for (let i = 0; i < directoryItems.length; i++) {
64 | const dirItem = directoryItems[i];
65 | var fullPath = path.join(directoryPath, dirItem.name);
66 |
67 | if (dirItem.isFile()) {
68 | if (dirItem.name.endsWith(".lua")) {
69 | weaponPaths.push(fullPath);
70 | }
71 | }
72 | else if (dirItem.isDirectory()) {
73 | var weaponLuaFiles = glob.sync(path.join(fullPath, "@(shared|init|cl_init).lua"));
74 | if (weaponLuaFiles.length != 0)
75 | weaponPaths.push(fullPath);
76 | }
77 | }
78 |
79 | return weaponPaths;
80 | }
81 |
82 | editWeapon(weaponPath: string): void {
83 | // TODO: If path is a folder, open folder
84 | if (this.pathExists(weaponPath) == false)
85 | return;
86 |
87 | if (fs.lstatSync(weaponPath).isDirectory()) {
88 | this.openDirectory(weaponPath);
89 | }
90 | else {
91 | this.openFile(weaponPath);
92 | }
93 | }
94 |
95 | createWeaponFromTemplate(weaponName: string, weaponTemplate: any): void {
96 | if (!this.workspaceRoot) {
97 | return;
98 | }
99 |
100 | const weaponsPath = path.join(this.workspaceRoot, weaponTemplate.DestinationPath);
101 | if (this.pathExists(weaponsPath) == false) {
102 | fs.mkdirSync(weaponsPath, { recursive: true });
103 | }
104 |
105 | var newWeaponName = `${weaponTemplate.WeaponNamePrefix}${weaponName}`;
106 | var newWeaponPath = path.join(weaponsPath, `${newWeaponName}.lua`);
107 | var uniqueNumber = 1;
108 | while (this.pathExists(newWeaponPath)) {
109 | newWeaponName = `${weaponTemplate.WeaponNamePrefix}${weaponName}${uniqueNumber++}`;
110 | newWeaponPath = path.join(weaponsPath, `${newWeaponName}.lua`);
111 | }
112 |
113 | var sampleWeaponTemplatePath = path.join(this.samplesRoot, "weapons", weaponTemplate.Filename);
114 | if (this.pathExists(sampleWeaponTemplatePath) == false) {
115 | vscode.window.showErrorMessage(`Unable to find template '${weaponTemplate.Filename}'`);
116 | return;
117 | }
118 |
119 | var sampleWeaponLua = fs
120 | .readFileSync(sampleWeaponTemplatePath, "utf8")
121 | .replace(/\$WEAPON_NAME\$/g, newWeaponName);
122 |
123 | fs.writeFileSync(newWeaponPath, sampleWeaponLua);
124 |
125 | this.openFile(newWeaponPath);
126 | }
127 |
128 | private pathExists(p: string): boolean {
129 | try {
130 | fs.accessSync(p);
131 | } catch (err) {
132 | return false;
133 | }
134 | return true;
135 | }
136 |
137 | private openFile(filePath: string): void {
138 | vscode.workspace.openTextDocument(vscode.Uri.file(filePath)).then(
139 | (document: vscode.TextDocument) => {
140 | vscode.window.showTextDocument(document, vscode.ViewColumn.Active, false).then((e) => { });
141 | },
142 | (error: any) => {
143 | console.error(error);
144 | debugger;
145 | }
146 | );
147 | }
148 |
149 | private openDirectory(directoryPath: string): void {
150 | var weaponLuaFiles = glob.sync(path.join(directoryPath, "@(shared|init|cl_init).lua"));
151 | if (weaponLuaFiles.length == 0)
152 | return;
153 |
154 | vscode.workspace.openTextDocument(vscode.Uri.file(weaponLuaFiles[0])).then(
155 | (document: vscode.TextDocument) => {
156 | vscode.window.showTextDocument(document, vscode.ViewColumn.Active, false).then((e) => { });
157 | },
158 | (error: any) => {
159 | console.error(error);
160 | debugger;
161 | }
162 | );
163 | }
164 | }
165 |
166 | export class GModWeaponOverview {
167 | public weapons: GModWeapon[];
168 | public sandboxTools: GModWeapon[];
169 |
170 | constructor() {
171 | this.weapons = [];
172 | this.sandboxTools = [];
173 | }
174 |
175 | addWeapons(weapons: GModWeapon[]): void {
176 | this.weapons = this.weapons.concat(weapons);
177 | }
178 |
179 | addSandboxTools(tools: GModWeapon[]): void {
180 | this.sandboxTools = this.sandboxTools.concat(tools);
181 | }
182 |
183 | sort(): void {
184 | this.weapons.sort(this.sortFunc);
185 | this.sandboxTools.sort(this.sortFunc);
186 | }
187 |
188 | private sortFunc(a: GModWeapon, b: GModWeapon): number {
189 | if (a.name < b.name) {
190 | return -1;
191 | }
192 |
193 | if (a.name > b.name) {
194 | return 1;
195 | }
196 |
197 | if (a.relativePath < b.relativePath) {
198 | return -1;
199 | }
200 |
201 | if (a.relativePath > b.relativePath) {
202 | return 1;
203 | }
204 |
205 | return 0;
206 | }
207 | }
208 |
209 | export class GModWeapon {
210 | name: string;
211 | pathToFile: string;
212 | relativePath: string;
213 |
214 | constructor(name: string, relativePath: string, pathToFile: string) {
215 | this.name = name;
216 | this.relativePath = relativePath;
217 | this.pathToFile = pathToFile;
218 | }
219 | }
220 |
221 | export class GModWeaponTemplates {
222 | private static readonly WeaponSamples: any = {
223 | TTT: {
224 | Label: "TTT",
225 | Weapons: {
226 | Primary: {
227 | Filename: "weapon_ttt_primary_sample.lua",
228 | WeaponNamePrefix: "weapon_ttt_",
229 | DestinationPath: "lua/weapons/"
230 | },
231 | Secondary: {
232 | Filename: "weapon_ttt_secondary_sample.lua",
233 | WeaponNamePrefix: "weapon_ttt_",
234 | DestinationPath: "lua/weapons/"
235 | },
236 | Grenade: {
237 | Filename: "weapon_ttt_grenade_sample.lua",
238 | WeaponNamePrefix: "weapon_ttt_",
239 | DestinationPath: "lua/weapons/"
240 | },
241 | Traitor: {
242 | Filename: "weapon_ttt_traitor_sample.lua",
243 | WeaponNamePrefix: "weapon_ttt_",
244 | DestinationPath: "lua/weapons/"
245 | },
246 | Detective: {
247 | Filename: "weapon_ttt_detective_sample.lua",
248 | WeaponNamePrefix: "weapon_ttt_",
249 | DestinationPath: "lua/weapons/"
250 | }
251 | }
252 | },
253 | Sandbox: {
254 | Label: "Sandbox",
255 | Weapons: {
256 | Main: {
257 | Filename: "weapon_sandbox_main_sample.lua",
258 | WeaponNamePrefix: "weapon_",
259 | DestinationPath: "lua/weapons/"
260 | },
261 | ToolGun: {
262 | Filename: "weapon_sandbox_toolgun_sample.lua",
263 | WeaponNamePrefix: "",
264 | DestinationPath: "lua/weapons/gmod_tool/stools/"
265 | }
266 | }
267 | }
268 | };
269 |
270 | public static GetGamemodes(): string[] {
271 | return Object.keys(GModWeaponTemplates.WeaponSamples);
272 | }
273 |
274 | public static GetTemplateNames(gamemode: string): string[] {
275 | return Object.keys(GModWeaponTemplates.WeaponSamples[gamemode].Weapons);
276 | }
277 |
278 | public static GetTemplate(gamemode: string, template: string): any {
279 | return GModWeaponTemplates.WeaponSamples[gamemode].Weapons[template];
280 | }
281 | }
282 |
--------------------------------------------------------------------------------
/src/Services/GModWorkshopManager.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as fs from 'fs';
3 | import * as path from 'path';
4 | import axios from 'axios';
5 |
6 | export class GModWorkshopManager {
7 | private static DEBUGMODE: boolean = false;
8 |
9 | private get gmadExecutablePath(): string {
10 | var path = vscode.workspace.getConfiguration('gmod-sdk')
11 | .get("gmadExecutablePath");
12 |
13 | if (path == undefined || !this.pathExists(path)) {
14 | var errorMessage = `Unable to find gmad program. To fix this, Open Settings, search for gmod-sdk.gmadExecutablePath and follow the instructions.`;
15 | vscode.commands.executeCommand("workbench.action.openSettings2")
16 | .then(() => { vscode.window.showErrorMessage(errorMessage) });
17 | throw errorMessage;
18 | }
19 |
20 | return path;
21 | }
22 |
23 | private get gmpublishExecutablePath(): string {
24 | var path = vscode.workspace.getConfiguration('gmod-sdk')
25 | .get("gmpublishExecutablePath");
26 |
27 | if (path == undefined || !this.pathExists(path)) {
28 | var errorMessage = `Unable to find gmad program. To fix this, Open Settings, search for gmod-sdk.gmpublishExecutablePath and follow the instructions.`;
29 | vscode.commands.executeCommand("workbench.action.openSettings2")
30 | .then(() => { vscode.window.showErrorMessage(errorMessage) });
31 | throw errorMessage;
32 | }
33 |
34 | return path;
35 | }
36 |
37 | constructor(private workspacePath: string | undefined, private samplesRoot: string) { }
38 |
39 | getAddonsForUser(steamID64: string): Thenable {
40 | return new Promise((resolver, rejector) => {
41 | axios.get(`https://steamuserinfoapi.azurewebsites.net/api/profiles/${steamID64}/workshopitems/4000?pageNumber=1`)
42 | .then(response => {
43 | resolver(response.data.workshopItems);
44 | // Loading multiple pages of items takes too long
45 | // This is something to fix in the future
46 | })
47 | .catch(error => {
48 | console.log(error);
49 | rejector();
50 | });
51 | });
52 | }
53 |
54 | validateConfigForAddonUpload(): void {
55 | var gmadPath = this.gmadExecutablePath;
56 | }
57 |
58 | validateConfigForThumbnailUpload(): void {
59 | var gmpublishPath = this.gmpublishExecutablePath;
60 | }
61 |
62 | upload(): void {
63 | if (this.workspacePath == undefined)
64 | return;
65 |
66 | var gmaPath = path.join(this.workspacePath!, "workshop-file.gma");
67 | var thumbnailPath = path.join(this.samplesRoot, "workshop-thumbnail.jpg");
68 |
69 | if (GModWorkshopManager.DEBUGMODE) {
70 | console.log("Pretending to upload GMA");
71 | console.log(`GMA: ${gmaPath}`);
72 | console.log(`Thumbnail: ${thumbnailPath}`);
73 | return;
74 | }
75 |
76 | var gmadPath = this.gmadExecutablePath;
77 | var gmpublishPath = this.gmpublishExecutablePath;
78 |
79 | // TODO: Re-use terminal if exists/cleanup terminal on exit
80 | var terminal = vscode.window.createTerminal("GMod Publish");
81 | terminal.show();
82 |
83 | terminal.sendText(`& "${gmadPath}" create -folder "${this.workspacePath}" -out "${gmaPath}" -warninvalid`);
84 |
85 | terminal.sendText(`& "${gmpublishPath}" create -addon "${gmaPath}" -icon "${thumbnailPath}"`);
86 |
87 | // TODO: Wait for terminal to finish processing commands and delete the .gma file
88 | }
89 |
90 | updateAddon(fileID: string): void {
91 | if (this.workspacePath == undefined)
92 | return;
93 |
94 | var gmaPath = path.join(this.workspacePath!, "workshop-file.gma");
95 |
96 | if (GModWorkshopManager.DEBUGMODE) {
97 | console.log(`Pretending to upload GMA to existing addon ${fileID}`);
98 | console.log(`GMA: ${gmaPath}`);
99 | return;
100 | }
101 |
102 | var gmadPath = this.gmadExecutablePath;
103 | var gmpublishPath = this.gmpublishExecutablePath;
104 |
105 | var terminal = vscode.window.createTerminal("GMod Publish");
106 | terminal.show();
107 |
108 | terminal.sendText(`& "${gmadPath}" create -folder "${this.workspacePath}" -out "${gmaPath}" -warninvalid`);
109 |
110 | terminal.sendText(`& "${gmpublishPath}" update -id ${fileID} -addon "${gmaPath}"`);
111 |
112 | // TODO: Wait for terminal to finish processing commands and delete the .gma file
113 | }
114 |
115 | updateAddonThumbnail(fileID: string, thumbnailPath: string): void {
116 | if (GModWorkshopManager.DEBUGMODE) {
117 | console.log(`Pretending to update existing addon ${fileID} thumbnail`);
118 | console.log(`Thumbnail: ${thumbnailPath}`);
119 | return;
120 | }
121 |
122 | var gmpublishPath = this.gmpublishExecutablePath;
123 |
124 | var terminal = vscode.window.createTerminal("GMod Publish");
125 | terminal.show();
126 |
127 | terminal.sendText(`& "${gmpublishPath}" update -id ${fileID} -icon "${thumbnailPath}"`);
128 |
129 | // TODO: Wait for terminal to finish processing commands and delete the .gma file
130 | }
131 |
132 | private pathExists(p: string): boolean {
133 | try {
134 | fs.accessSync(p);
135 | } catch (err) {
136 | return false;
137 | }
138 | return true;
139 | }
140 | }
141 |
142 | export enum WorkshopItemVisibility {
143 | Public = 0,
144 | FriendsOnly = 1,
145 | Hidden = 2,
146 | Unlisted = 3
147 | }
148 |
--------------------------------------------------------------------------------
/src/Services/LocalGModManager.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as fs from 'fs-extra';
3 | import * as path from 'path';
4 |
5 |
6 | export class LocalGModManager {
7 | constructor(private workspaceRoot: string | undefined) { }
8 |
9 | syncWorkspaceWithAddon(destinationAddonFolderName: string): void {
10 | if (!this.workspaceRoot) {
11 | return;
12 | }
13 |
14 | var addonsFolderPath = vscode.workspace.getConfiguration('gmod-sdk')
15 | .get("garrysmodAddonsPath");
16 |
17 | if (addonsFolderPath == undefined || !this.pathExists(addonsFolderPath)) {
18 | var errorMessage = `Unable to find addons folder. To fix this, Open Settings, search for gmod-sdk.garrysmodAddonsPath and follow the instructions.`;
19 | vscode.commands.executeCommand("workbench.action.openSettings2")
20 | .then(() => { vscode.window.showErrorMessage(errorMessage) });
21 |
22 | return;
23 | }
24 |
25 | var destinationPath = path.join(addonsFolderPath, destinationAddonFolderName);
26 | try {
27 | if (this.pathExists(destinationPath) == true)
28 | fs.removeSync(destinationPath); // TODO: Warn user
29 |
30 | fs.copySync(this.workspaceRoot, destinationPath, { recursive: true });
31 |
32 | vscode.window.showInformationMessage(`The addon has been copied to your Garry's Mod folder. ${destinationPath}`)
33 | }
34 | catch (err) {
35 | vscode.window.showErrorMessage(`Error copying addon to the Garry's Mod folder: ${destinationPath} ${err}`);
36 | }
37 | }
38 |
39 | private pathExists(p: string): boolean {
40 | try {
41 | fs.accessSync(p);
42 | } catch (err) {
43 | return false;
44 | }
45 | return true;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Views/GModAddonInfoView.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as path from 'path';
3 | import { GModAddonManager, GModAddonInfo, AddonTag, AddonType } from '../Services/GModAddonManager';
4 |
5 | export class GModAddonInfoView implements vscode.TreeDataProvider {
6 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter();
7 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event;
8 |
9 | private addonInfo: GModAddonInfo | undefined;
10 |
11 | constructor(private addonManager: GModAddonManager) {
12 | this.addonInfo = this.addonManager.getAddonInfo();
13 | }
14 |
15 | getTreeItem(element: GModMenuItem): vscode.TreeItem {
16 | return element;
17 | }
18 |
19 | getChildren(element?: GModMenuItem): Thenable {
20 | if (this.addonInfo == undefined)
21 | return Promise.resolve([]);
22 |
23 | if (!element) {
24 | var typeDescription = this.isAddonTypeValid(this.addonInfo.type) ? this.addonInfo.type : "❌ INVALID TYPE";
25 | var tagsDescription = this.areTagsValid(this.addonInfo.tags)
26 | ? (this.addonInfo.tags.length <= 2 ? this.addonInfo.tags.join(", ") : "❌ TOO MANY TAGS")
27 | : "❌ INVALID TAGS";
28 |
29 | return Promise.resolve([
30 | new GModMenuItem("title", "Title", this.addonInfo.title),
31 | new GModMenuItem("description", "Description", this.addonInfo.description),
32 | new GModMenuItem("type", "Type", typeDescription),
33 | new GModMenuItem("tags", "Tags", tagsDescription),
34 | new GModMenuItem("ignoredFiles", "Ignored files", "", undefined, vscode.TreeItemCollapsibleState.Collapsed)
35 | ]);
36 | }
37 | else if (element.id == "ignoredFiles") {
38 | return Promise.resolve(
39 | this.addonInfo.ignore.map((filePath, index) => new GModMenuItem(`ignoredFiles.${index}`, filePath, ""))
40 | );
41 | }
42 | else {
43 | return Promise.resolve([]);
44 | }
45 | }
46 |
47 | refresh(): void {
48 | this.addonInfo = this.addonManager.getAddonInfo();
49 | this._onDidChangeTreeData.fire(undefined);
50 | }
51 |
52 | private isAddonTypeValid(type: AddonType): boolean {
53 | return Object.values(AddonType).includes(type);
54 | }
55 |
56 | private areTagsValid(tags: AddonTag[]): boolean {
57 | for (let i = 0; i < tags.length; i++) {
58 | const tag = tags[i];
59 | if (Object.values(AddonTag).includes(tag) == false)
60 | return false;
61 | }
62 | return true;
63 | }
64 | }
65 |
66 | export class GModMenuItem extends vscode.TreeItem {
67 | constructor(
68 | public readonly id: string,
69 | public readonly label: string,
70 | private value: string,
71 | iconName: string | undefined = undefined,
72 | public readonly collapsibleState: vscode.TreeItemCollapsibleState = vscode.TreeItemCollapsibleState.None
73 | ) {
74 | super(label, collapsibleState)
75 |
76 | if (iconName) {
77 | this.iconPath = {
78 | light: path.join(__filename, '..', '..', 'resources', 'light', iconName),
79 | dark: path.join(__filename, '..', '..', 'resources', 'dark', iconName)
80 | };
81 | }
82 |
83 | this.contextValue = id;
84 |
85 | this.tooltip = this.value;
86 | this.description = this.value;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/Views/GModAddonWeaponsView.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from "vscode";
2 | import * as path from "path";
3 | import { GModWeaponManager, GModWeapon, GModWeaponOverview } from "../Services/GModWeaponManager";
4 |
5 | export class GModAddonWeaponsView implements vscode.TreeDataProvider {
6 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter();
7 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event;
8 |
9 | private weaponOverview: GModWeaponOverview;
10 |
11 | constructor(private workspaceRoot: string | undefined, private weaponManager: GModWeaponManager) {
12 | this.weaponOverview = this.weaponManager.getWeapons();
13 | }
14 |
15 |
16 | getTreeItem(element: GModWeaponMenuItem): vscode.TreeItem {
17 | return element;
18 | }
19 |
20 | getChildren(element?: GModWeaponMenuItem): Thenable {
21 | if (this.workspaceRoot == undefined) return Promise.resolve([]);
22 |
23 | if (element == undefined) {
24 | var treeItems = [];
25 |
26 | if (this.weaponOverview.sandboxTools.length != 0)
27 | treeItems.push(GModWeaponMenuItem.CreateSubMenu('category.stools', "Sandbox Tools"));
28 |
29 | var weapons = this.weaponOverview.weapons.map((weapon, index) => GModWeaponMenuItem.CreateWeaponItem(weapon));
30 | return Promise.resolve(treeItems.concat(weapons));
31 | }
32 | else if (element.id == 'category.stools') {
33 | return Promise.resolve(this.weaponOverview.sandboxTools.map((tool, index) => GModWeaponMenuItem.CreateWeaponItem(tool)));
34 | }
35 | else {
36 | return Promise.resolve([]);
37 | }
38 | }
39 |
40 | refresh(): void {
41 | this.weaponOverview = this.weaponManager.getWeapons();
42 | this._onDidChangeTreeData.fire(undefined);
43 | }
44 | }
45 |
46 | export class GModWeaponMenuItem extends vscode.TreeItem {
47 | static CreateWeaponItem(weapon: GModWeapon): GModWeaponMenuItem {
48 | var menuItem = new GModWeaponMenuItem(`weapons.${weapon.relativePath}.${weapon.name}`, weapon.name, weapon.relativePath);
49 | menuItem.weapon = weapon;
50 | return menuItem;
51 | }
52 |
53 | static CreateSubMenu(id: string, label: string): GModWeaponMenuItem {
54 | return new GModWeaponMenuItem(id, label, undefined, "folder.svg", vscode.TreeItemCollapsibleState.Expanded);
55 | }
56 |
57 | weapon: GModWeapon | undefined;
58 | relativePath: string | undefined;
59 |
60 | constructor(
61 | public readonly id: string,
62 | label: string,
63 | relativePath: string | undefined = undefined,
64 | iconName: string | undefined = undefined,
65 | collapsedState: vscode.TreeItemCollapsibleState = vscode.TreeItemCollapsibleState.None
66 | ) {
67 | super(label, collapsedState);
68 |
69 | this.relativePath = relativePath;
70 | this.contextValue = id;
71 |
72 | if (iconName) {
73 | this.iconPath = {
74 | light: path.join(__filename, "..", "..", "resources", "light", iconName),
75 | dark: path.join(__filename, "..", "..", "resources", "dark", iconName)
76 | };
77 | }
78 |
79 | this.tooltip = this.weapon?.pathToFile;
80 | this.description = this.relativePath;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/Views/GModWorkshopView.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as path from 'path';
3 | import { GModWorkshopManager, WorkshopItemVisibility } from '../Services/GModWorkshopManager';
4 |
5 | export class GModWorkshopView implements vscode.TreeDataProvider {
6 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter();
7 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event;
8 |
9 | private workshopItems: any[] = [];
10 | private steamID: string | undefined = undefined;
11 | private isLoading: boolean = false;
12 |
13 | constructor(private workshopManager: GModWorkshopManager) {
14 | this.refresh();
15 | }
16 |
17 | getTreeItem(element: GModWorkshopMenuItem): vscode.TreeItem {
18 | return element;
19 | }
20 |
21 | getChildren(element?: GModWorkshopMenuItem): Thenable {
22 | if (this.steamID == undefined) {
23 | return Promise.resolve([]);
24 | }
25 |
26 | if (this.isLoading) {
27 | return Promise.resolve([
28 | new GModWorkshopMenuItem("loading", "Loading...")
29 | ]);
30 | }
31 |
32 | if (this.workshopItems.length == 0) {
33 | return Promise.resolve([
34 | new GModWorkshopMenuItem("no-items", "You don't have any workshop items")
35 | ]);
36 | }
37 |
38 | return Promise.resolve(this.workshopItems
39 | .map(item => {
40 | var icon = this.getIconForItemVisibility(item["visibility"] as WorkshopItemVisibility);
41 | var menuItem = new GModWorkshopMenuItem(`item-${item["publishedfileid"]}`, item["title"], item["publishedfileid"], icon);
42 | menuItem.workshopFileId = item["publishedfileid"];
43 |
44 | return menuItem;
45 | })
46 | );
47 | }
48 |
49 | refresh(): void {
50 | this.steamID = this.getSteamID();
51 |
52 | if (this.steamID == undefined) {
53 | this.workshopItems = [];
54 | this._onDidChangeTreeData.fire(undefined);
55 | return;
56 | }
57 |
58 | this.isLoading = true;
59 | this.workshopManager.getAddonsForUser(this.steamID)
60 | .then(response => {
61 | this.isLoading = false;
62 | this.workshopItems = response;
63 | this._onDidChangeTreeData.fire(undefined);
64 | });
65 | }
66 |
67 | private getSteamID(): string | undefined {
68 | var config = vscode.workspace.getConfiguration('gmod-sdk').get("steamID");
69 |
70 | if (config == undefined || config.length == 0)
71 | return undefined;
72 |
73 | return config
74 | }
75 |
76 | private getIconForItemVisibility(visibility: WorkshopItemVisibility): string | undefined {
77 | switch (visibility) {
78 | case WorkshopItemVisibility.FriendsOnly:
79 | case WorkshopItemVisibility.Hidden:
80 | case WorkshopItemVisibility.Unlisted:
81 | return "workshop-item-hidden.svg";
82 | case WorkshopItemVisibility.Public:
83 | default:
84 | return undefined;
85 | }
86 | }
87 | }
88 |
89 | export class GModWorkshopMenuItem extends vscode.TreeItem {
90 | workshopFileId: string | undefined;
91 |
92 | constructor(id: string,
93 | label: string,
94 | description: string | undefined = undefined,
95 | iconName: string | undefined = undefined,
96 | collapsedState: vscode.TreeItemCollapsibleState = vscode.TreeItemCollapsibleState.None
97 | ) {
98 | super(label, collapsedState)
99 |
100 | this.contextValue = id;
101 |
102 | if (iconName) {
103 | this.iconPath = {
104 | light: path.join(__filename, '..', '..', 'resources', 'light', iconName),
105 | dark: path.join(__filename, '..', '..', 'resources', 'dark', iconName)
106 | };
107 | }
108 |
109 | this.tooltip = label;
110 | this.description = description;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/Wizards/AddonTagsWizard.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import { GModAddonManager, AddonTag } from '../Services/GModAddonManager';
3 |
4 | export class AddonTagsWizard {
5 |
6 | constructor(private addonManager: GModAddonManager) { }
7 |
8 | show(): Thenable {
9 | return new Promise((resolver, rejector) => {
10 | var types = Object.keys(AddonTag);
11 |
12 | vscode.window
13 | .showQuickPick(types, { placeHolder: "Select the first tag" })
14 | .then(tag1 => {
15 | if (tag1 == undefined) {
16 | return;
17 | }
18 |
19 | var firstTag = AddonTag[tag1 as keyof typeof AddonTag];
20 |
21 | types.splice(types.indexOf(tag1), 1);
22 | types.unshift("None");
23 |
24 | vscode.window
25 | .showQuickPick(types, { placeHolder: "Select the second tag" })
26 | .then(tag2 => {
27 | if (tag2 == undefined) {
28 | return;
29 | }
30 |
31 | var tags = [firstTag];
32 |
33 | if (tag2 != "None") {
34 | var secondTag = AddonTag[tag2 as keyof typeof AddonTag];
35 | tags.push(secondTag);
36 | }
37 |
38 | var addonInfo = this.addonManager.getAddonInfo();
39 | if (addonInfo == undefined) {
40 | vscode.window.showErrorMessage("addon.json is missing.")
41 | return;
42 | }
43 |
44 | addonInfo.tags = tags;
45 | this.addonManager.save(addonInfo);
46 | resolver();
47 | });
48 | });
49 | });
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Wizards/AddonTypeWizard.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import { GModAddonManager, AddonType } from '../Services/GModAddonManager';
3 |
4 | export class AddonTypeWizard {
5 |
6 | constructor(private addonManager: GModAddonManager) { }
7 |
8 | show(): Thenable {
9 | return new Promise((resolver, rejector) => {
10 | var types = Object.keys(AddonType);
11 |
12 | vscode.window
13 | .showQuickPick(types, { placeHolder: "Select what type of addon you are making" })
14 | .then(type => {
15 | if (type == undefined) {
16 | return;
17 | }
18 |
19 | var addonInfo = this.addonManager.getAddonInfo();
20 | if (addonInfo == undefined) {
21 | vscode.window.showErrorMessage("addon.json is missing.")
22 | return;
23 | }
24 |
25 | addonInfo.type = AddonType[type as keyof typeof AddonType];
26 | this.addonManager.save(addonInfo);
27 | resolver();
28 | });
29 | });
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Wizards/CreateWeaponWizard.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import { GModWeaponManager, GModWeaponTemplates } from '../Services/GModWeaponManager';
3 |
4 | export class CreateWeaponWizard {
5 |
6 | constructor(private weaponManager: GModWeaponManager) { }
7 |
8 | show(): Thenable {
9 | return new Promise((resolver, rejector) => {
10 | vscode.window
11 | .showQuickPick(GModWeaponTemplates.GetGamemodes(), { placeHolder: "What gamemode is the weapon for?" })
12 | .then(gamemode => {
13 | if (gamemode == undefined) {
14 | return;
15 | }
16 |
17 | vscode.window
18 | .showQuickPick(GModWeaponTemplates.GetTemplateNames(gamemode), { placeHolder: "Which type of weapon?" })
19 | .then(weaponType => {
20 | if (weaponType == undefined) {
21 | return;
22 | }
23 |
24 | vscode.window.showInputBox({ prompt: "Enter a weapon name. e.g. cool_weapon", validateInput: this.weaponNameValidator })
25 | .then(weaponName => {
26 | if (weaponName == undefined) {
27 | return;
28 | }
29 |
30 | var weaponTemplate = GModWeaponTemplates.GetTemplate(gamemode, weaponType);
31 | this.weaponManager.createWeaponFromTemplate(weaponName, weaponTemplate);
32 | resolver();
33 | });
34 | });
35 | });
36 | });
37 | }
38 |
39 | private static readonly WeaponNameRegex: RegExp = /^[A-Za-z0-9_-]+$/;
40 | private weaponNameValidator(input: string): string {
41 | return CreateWeaponWizard.WeaponNameRegex.test(input) ? "" : "Please only use letters, numbers and underscores.";
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Wizards/WorkshopThumbnailWizard.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as fs from 'fs';
3 | import { GModWorkshopManager } from '../Services/GModWorkshopManager';
4 |
5 | export class WorkshopThumbnailWizard {
6 |
7 | constructor(private workshopManager: GModWorkshopManager) { }
8 |
9 | show(targetWorkshopFileID: string | undefined): void {
10 | this.workshopManager.validateConfigForThumbnailUpload();
11 |
12 | this.showThumbnailSelector()
13 | .then(thumbnailPath => {
14 | if (targetWorkshopFileID != undefined) {
15 | this.updateThumbnail(targetWorkshopFileID, thumbnailPath);
16 | return;
17 | }
18 |
19 | vscode.window.showInputBox({ prompt: "Enter the workshop file ID. This can be found at the end of the URL. E.g. https://steamcommunity.com/sharedfiles/filedetails/?id=2086515808 has a file ID of 2086515808" })
20 | .then(fileID => {
21 | if (fileID == undefined) {
22 | vscode.window.showInformationMessage(`You cancelled the thumbnail upload`);
23 | return;
24 | }
25 |
26 | this.updateThumbnail(fileID, thumbnailPath);
27 | });
28 | });
29 | }
30 |
31 | private showThumbnailSelector(): Thenable {
32 | return new Promise((resolver, rejector) => {
33 | vscode.window.showOpenDialog({
34 | canSelectFolders: false,
35 | canSelectMany: false,
36 | openLabel: "Select thumbnail",
37 | filters: {
38 | 'Images': ['jpg']
39 | }
40 | }).then(uri => {
41 | if (uri == undefined) {
42 | return;
43 | }
44 |
45 | var thumbnailPath = uri[0].fsPath;
46 | if (this.pathExists(thumbnailPath) == false) {
47 | vscode.window.showErrorMessage(`Unable to find thumbnail- ${thumbnailPath}`);
48 | return;
49 | }
50 |
51 | resolver(thumbnailPath);
52 | });
53 | });
54 | }
55 |
56 | private updateThumbnail(targetFileID: string, thumbnailPath: string) {
57 | if (isNaN(Number(targetFileID))) {
58 | vscode.window.showErrorMessage(`"${targetFileID}" is not a valid workshop File ID. E.g. https://steamcommunity.com/sharedfiles/filedetails/?id=2086515808 has a file ID of 2086515808`);
59 | return;
60 | }
61 |
62 | vscode.window.showInputBox({ prompt: `This will UPDATE the thumbnail for addon ${targetFileID}. Type YES to continue`, placeHolder: "YES" })
63 | .then(confirmation => {
64 | if (confirmation == undefined || confirmation.toLowerCase().trim() != "yes") {
65 | vscode.window.showInformationMessage(`You cancelled the workshop upload`);
66 | return;
67 | }
68 |
69 | this.workshopManager.updateAddonThumbnail(targetFileID, thumbnailPath);
70 | });
71 | }
72 |
73 | private pathExists(p: string): boolean {
74 | try {
75 | fs.accessSync(p);
76 | } catch (err) {
77 | return false;
78 | }
79 | return true;
80 | }
81 | }
--------------------------------------------------------------------------------
/src/Wizards/WorkshopUploadWizard.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import { GModWorkshopManager } from '../Services/GModWorkshopManager';
3 |
4 | export class WorkshopUploadWizard {
5 |
6 | constructor(private workshopManager: GModWorkshopManager) { }
7 |
8 | show(targetWorkshopFileID: string | undefined): void {
9 | this.workshopManager.validateConfigForAddonUpload();
10 |
11 | if (targetWorkshopFileID != undefined) {
12 | this.updateExistingItem(targetWorkshopFileID);
13 | return;
14 | }
15 |
16 | vscode.window
17 | .showQuickPick(["New Addon", "Existing Addon"], { placeHolder: "Upload a new addon or update an existing addon?" })
18 | .then(response => {
19 | if (response == undefined)
20 | return;
21 |
22 | var shouldUploadNewAddon = response == "New Addon";
23 | if (shouldUploadNewAddon) {
24 | vscode.window.showInputBox({ prompt: "This will upload a NEW addon to the workshop. Type YES to continue", placeHolder: "YES" })
25 | .then(confirmation => {
26 | if (confirmation == undefined || confirmation.toLowerCase().trim() != "yes") {
27 | vscode.window.showInformationMessage(`You cancelled the workshop upload`);
28 | return;
29 | }
30 | this.workshopManager.upload();
31 | });
32 | }
33 | else {
34 | vscode.window.showInputBox({ prompt: "Enter the workshop file ID. This can be found at the end of the URL. E.g. https://steamcommunity.com/sharedfiles/filedetails/?id=2086515808 has a file ID of 2086515808" })
35 | .then(fileID => {
36 | if (fileID == undefined) {
37 | vscode.window.showInformationMessage(`You cancelled the workshop upload`);
38 | return;
39 | }
40 |
41 | this.updateExistingItem(fileID);
42 | });
43 | }
44 | });
45 | }
46 |
47 | private updateExistingItem(fileID: string): void {
48 | var trimmedFileID = fileID.trim();
49 | if (isNaN(Number(trimmedFileID))) {
50 | vscode.window.showInformationMessage(`"${trimmedFileID}" is not a valid workshop File ID. E.g. https://steamcommunity.com/sharedfiles/filedetails/?id=2086515808 has a file ID of 2086515808`);
51 | return;
52 | }
53 |
54 | vscode.window.showInputBox({ prompt: `This will UPDATE the addon ${trimmedFileID}. Type YES to continue`, placeHolder: "YES" })
55 | .then(confirmation => {
56 | if (confirmation == undefined || confirmation.toLowerCase().trim() != "yes") {
57 | vscode.window.showInformationMessage(`You cancelled the workshop upload`);
58 | return;
59 | }
60 |
61 | this.workshopManager.updateAddon(trimmedFileID);
62 | });
63 | }
64 | }
--------------------------------------------------------------------------------
/src/extension.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as path from 'path';
3 | import { WorkshopUploadWizard } from './Wizards/WorkshopUploadWizard';
4 | import { WorkshopThumbnailWizard } from './Wizards/WorkshopThumbnailWizard';
5 | import { CreateWeaponWizard } from './Wizards/CreateWeaponWizard';
6 | import { GModAddonManager } from './Services/GModAddonManager';
7 | import { GModWeaponManager } from './Services/GModWeaponManager';
8 | import { GModWorkshopManager } from './Services/GModWorkshopManager';
9 | import { LocalGModManager } from './Services/LocalGModManager';
10 | import { GModAddonInfoView } from './Views/GModAddonInfoView';
11 | import { GModAddonWeaponsView, GModWeaponMenuItem } from './Views/GModAddonWeaponsView';
12 | import { GModWorkshopView, GModWorkshopMenuItem } from './Views/GModWorkshopView';
13 | import { AddonTypeWizard } from './Wizards/AddonTypeWizard';
14 | import { AddonTagsWizard } from './Wizards/AddonTagsWizard';
15 |
16 |
17 | export function activate(context: vscode.ExtensionContext) {
18 | console.log('Loading extension "gmod-sdk"');
19 |
20 | // DEPENDENCIES
21 | var addonManager = new GModAddonManager(vscode.workspace.rootPath);
22 | var weaponManager = new GModWeaponManager(vscode.workspace.rootPath, context.asAbsolutePath('resources/samples'));
23 | var workshopManager = new GModWorkshopManager(vscode.workspace.rootPath, context.asAbsolutePath('resources/samples'));
24 | var localGModManager = new LocalGModManager(vscode.workspace.rootPath);
25 |
26 |
27 |
28 | // SIDE BAR
29 | const gmodAddonInfoView = new GModAddonInfoView(addonManager);
30 | vscode.window.registerTreeDataProvider('gmodAddonInfo', gmodAddonInfoView);
31 |
32 | const gmodAddonWeaponView = new GModAddonWeaponsView(vscode.workspace.rootPath, weaponManager);
33 | vscode.window.registerTreeDataProvider('gmodAddonWeapons', gmodAddonWeaponView);
34 |
35 | const gmodWorkshopView = new GModWorkshopView(workshopManager);
36 | vscode.window.registerTreeDataProvider('gmodWorkshop', gmodWorkshopView);
37 |
38 |
39 | // COMMANDS
40 | let createAddonCommand = vscode.commands.registerCommand('gmodSDK.createAddon', () => {
41 | addonManager.create();
42 | gmodAddonInfoView.refresh();
43 | });
44 | context.subscriptions.push(createAddonCommand);
45 |
46 |
47 | let copyToGModFolderCommand = vscode.commands.registerCommand('gmodSDK.copyToLocalGarrysmod', () => {
48 | if (vscode.workspace.rootPath == undefined) {
49 | vscode.window.showInformationMessage("Please open a folder.")
50 | return;
51 | }
52 |
53 | localGModManager.syncWorkspaceWithAddon(path.basename(vscode.workspace.rootPath));
54 | });
55 | context.subscriptions.push(copyToGModFolderCommand);
56 |
57 |
58 | let createWeaponCommand = vscode.commands.registerCommand('gmodSDK.createWeapon', () => {
59 | if (vscode.workspace.rootPath == undefined) {
60 | vscode.window.showInformationMessage("Please open a folder.")
61 | return;
62 | }
63 |
64 | new CreateWeaponWizard(weaponManager)
65 | .show()
66 | .then(() => {
67 | gmodAddonWeaponView.refresh();
68 | });
69 | });
70 | context.subscriptions.push(createWeaponCommand);
71 |
72 |
73 | let uploadWorkshopCommand = vscode.commands.registerCommand('gmodSDK.uploadAddon', (targetWorkshopItem: GModWorkshopMenuItem | undefined) => {
74 | if (addonManager.getAddonInfo() == undefined) {
75 | vscode.window.showInformationMessage("addon.json missing. Please create an addon first.")
76 | return;
77 | }
78 |
79 | var targetWorkshopItemID = undefined;
80 | if (targetWorkshopItem != undefined && targetWorkshopItem.workshopFileId != undefined) {
81 | targetWorkshopItemID = targetWorkshopItem.workshopFileId;
82 | }
83 |
84 | new WorkshopUploadWizard(workshopManager).show(targetWorkshopItemID);
85 | });
86 | context.subscriptions.push(uploadWorkshopCommand);
87 |
88 |
89 | let updateWorkshopThumbnailCommand = vscode.commands.registerCommand('gmodSDK.updateAddonThumbnail', (targetWorkshopItem: GModWorkshopMenuItem | undefined) => {
90 | var targetWorkshopItemID = undefined;
91 | if (targetWorkshopItem != undefined && targetWorkshopItem.workshopFileId != undefined) {
92 | targetWorkshopItemID = targetWorkshopItem.workshopFileId;
93 | }
94 |
95 | new WorkshopThumbnailWizard(workshopManager).show(targetWorkshopItemID);
96 | });
97 | context.subscriptions.push(updateWorkshopThumbnailCommand);
98 |
99 |
100 |
101 | // INTERNAL COMMANDS
102 | let refreshAddonInfoCommand = vscode.commands.registerCommand('gmodAddonInfo.refresh', () => {
103 | gmodAddonInfoView.refresh();
104 | gmodAddonWeaponView.refresh();
105 | gmodWorkshopView.refresh();
106 | });
107 | context.subscriptions.push(refreshAddonInfoCommand);
108 |
109 | let setAddonTitle = vscode.commands.registerCommand('gmodAddonInfo.setTitle', () => {
110 | vscode.window.showInputBox({ prompt: "Enter the title of your addon. This is only used the first time you upload your addon. E.g. AK47 TTT weapon" })
111 | .then(response => {
112 | if (response == undefined)
113 | return;
114 |
115 | var addonInfo = addonManager.getAddonInfo();
116 | if (addonInfo == undefined) {
117 | vscode.window.showErrorMessage("addon.json is missing");
118 | return;
119 | }
120 |
121 | addonInfo.title = response;
122 | addonManager.save(addonInfo);
123 | gmodAddonInfoView.refresh();
124 | })
125 | });
126 | context.subscriptions.push(setAddonTitle);
127 |
128 | let setAddonDescription = vscode.commands.registerCommand('gmodAddonInfo.setDescription', () => {
129 | vscode.window.showInputBox({ prompt: "Enter the description of your addon. This is only used the first time you upload your addon." })
130 | .then(response => {
131 | if (response == undefined)
132 | return;
133 |
134 | var addonInfo = addonManager.getAddonInfo();
135 | if (addonInfo == undefined) {
136 | vscode.window.showErrorMessage("addon.json is missing");
137 | return;
138 | }
139 |
140 | addonInfo.description = response;
141 | addonManager.save(addonInfo);
142 | gmodAddonInfoView.refresh();
143 | })
144 | });
145 | context.subscriptions.push(setAddonDescription);
146 |
147 | let setAddonTypeCommand = vscode.commands.registerCommand('gmodAddonInfo.setType', () => {
148 | new AddonTypeWizard(addonManager)
149 | .show()
150 | .then(() => { gmodAddonInfoView.refresh(); });
151 | });
152 | context.subscriptions.push(setAddonTypeCommand);
153 |
154 | let setAddonTagsCommand = vscode.commands.registerCommand('gmodAddonInfo.setTags', () => {
155 | new AddonTagsWizard(addonManager)
156 | .show()
157 | .then(() => { gmodAddonInfoView.refresh(); });
158 | });
159 | context.subscriptions.push(setAddonTagsCommand);
160 |
161 |
162 | let editWeaponCommand = vscode.commands.registerCommand('gmodWeapon.edit', (item: GModWeaponMenuItem) => {
163 | if (item.weapon == undefined) return;
164 | weaponManager.editWeapon(item.weapon.pathToFile);
165 | });
166 | context.subscriptions.push(editWeaponCommand);
167 |
168 | let selectSteamIDCommand = vscode.commands.registerCommand('gmodWorkshop.selectSteamID', () => {
169 | vscode.window.showInputBox({ prompt: "Enter your long Steam ID (SteamID64)" })
170 | .then(response => {
171 | if (response == undefined)
172 | return;
173 |
174 | var steamID = response.trim();
175 | if (isNaN(Number(steamID))) {
176 | vscode.window.showInformationMessage(`"${steamID}" is not a valid Steam ID. E.g. 70561198021123456`);
177 | return;
178 | }
179 |
180 | vscode.workspace.getConfiguration('gmod-sdk')
181 | .update("steamID", steamID, vscode.ConfigurationTarget.Global)
182 | .then(() => {
183 | setTimeout(() => {
184 | gmodWorkshopView.refresh();
185 | }, 1000);
186 | });
187 | });
188 | });
189 | context.subscriptions.push(selectSteamIDCommand);
190 | }
191 |
192 |
193 | export function deactivate() { }
194 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/vsc-extension-quickstart.md:
--------------------------------------------------------------------------------
1 | # Welcome to your VS Code Extension
2 |
3 | ## What's in the folder
4 |
5 | * This folder contains all of the files necessary for your extension.
6 | * `package.json` - this is the manifest file in which you declare your extension and command.
7 | * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin.
8 | * `src/extension.ts` - 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 activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
10 | * We pass the function containing the implementation of the command as the second parameter to `registerCommand`.
11 |
12 | ## Get up and running straight away
13 |
14 | * Press `F5` to open a new window with your extension loaded.
15 | * Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`.
16 | * Set breakpoints in your code inside `src/extension.ts` to debug your extension.
17 | * Find output from your extension in the debug console.
18 |
19 | ## Make changes
20 |
21 | * You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`.
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 |
25 | ## Explore the API
26 |
27 | * You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`.
28 |
29 | ## Run tests
30 |
31 | * Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`.
32 | * Press `F5` to run the tests in a new window with your extension loaded.
33 | * See the output of the test result in the debug console.
34 | * Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder.
35 | * The provided test runner will only consider files matching the name pattern `**.test.ts`.
36 | * You can create folders inside the `test` folder to structure your tests any way you want.
37 |
38 | ## Go further
39 |
40 | * Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension).
41 | * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace.
42 | * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).
43 |
--------------------------------------------------------------------------------