├── .gitattributes
├── .gitignore
├── .prettierrc
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
└── tasks.json
├── .vscodeignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── resources
└── sentry-glyph.svg
├── src
├── commands
│ ├── base.ts
│ ├── builtin.ts
│ ├── index.ts
│ ├── openInBrowser.ts
│ ├── showIssueActions.ts
│ ├── showIssueResults.ts
│ ├── showIssueSearch.ts
│ ├── showProjectPick.ts
│ └── startDebugger.ts
├── config.ts
├── debugger
│ ├── index.ts
│ ├── indexMapper.ts
│ ├── launcher.ts
│ └── server.ts
├── extension.ts
├── paths.ts
├── pick.ts
├── sentry
│ ├── api.ts
│ ├── index.ts
│ ├── interfaces.ts
│ └── rc.ts
├── statusbar.ts
├── test
│ ├── extension.test.ts
│ └── index.ts
└── utils.ts
├── tsconfig.json
└── tslint.json
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set default behavior to automatically normalize line endings.
2 | * text=auto
3 |
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | node_modules
3 | .vscode-test/
4 | *.vsix
5 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 100,
3 | "proseWrap": "always",
4 | "singleQuote": true,
5 | "trailingComma": "all"
6 | }
7 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": ["esbenp.prettier-vscode", "eg2.tslint"]
5 | }
6 |
--------------------------------------------------------------------------------
/.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": "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": "npm: watch"
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"
29 | ],
30 | "outFiles": [
31 | "${workspaceFolder}/out/test/**/*.js"
32 | ],
33 | "preLaunchTask": "npm: watch"
34 | }
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "editor.codeActionsOnSave": {
4 | "source.organizeImports": true
5 | },
6 | "editor.formatOnType": true,
7 | "editor.formatOnPaste": false,
8 | "editor.formatOnSave": true,
9 | "editor.rulers": [100],
10 | "editor.tabSize": 2,
11 | "files.autoSave": "onWindowChange",
12 | "files.trimTrailingWhitespace": true,
13 | "files.insertFinalNewline": true,
14 |
15 | "files.exclude": {
16 | "out": false
17 | },
18 | "search.exclude": {
19 | "out": true
20 | },
21 |
22 | "typescript.tsc.autoDetect": "off",
23 | "tslint.autoFixOnSave": true,
24 |
25 | "[json]": {
26 | "editor.formatOnType": false,
27 | "editor.formatOnPaste": false,
28 | "editor.formatOnSave": false
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/.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 | }
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | .vscode/**
2 | .vscode-test/**
3 | out/test/**
4 | out/**/*.map
5 | src/**
6 | .gitignore
7 | tsconfig.json
8 | vsc-extension-quickstart.md
9 | tslint.json
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [Unreleased]
4 |
5 | Initial release 🎉
6 |
7 | - Browse Sentry issues from VSCode
8 | - Launch the debugger to navigate stack traces and see variables
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Sentry (https://sentry.io/) and individual contributors.
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 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | # Sentry Integration for Visual Studio Code
12 |
13 | VSCode extension to browse [Sentry](https://sentry.io) issues and navigate stack traces directly in
14 | VSCode.
15 |
16 | ## Features
17 |
18 | - Browse Sentry projects and issues from VSCode
19 | - Launch the debugger to navigate stack traces and see variables
20 |
21 | 
22 |
23 | ## Requirements
24 |
25 | This extension requires a Sentry account. You can [sign up for free](https://sentry.io/signup/) and
26 | then follow the [quickstart guide](https://docs.sentry.io/quickstart/) to set up a project and
27 | integrate it into your software.
28 |
29 | ## Installation
30 |
31 | For now:
32 |
33 | ```
34 | npm install -g vsce
35 | vsce package
36 | code --install-extension *.vsix
37 | ```
38 |
39 | ## Usage
40 |
41 | Install [sentry-cli](https://github.com/getsentry/sentry-cli) and set it up. The VSCode extension will pick up the authentication information from `sentry-cli`.
42 |
43 | Run the command _Sentry: Search Issues_ from the command palette (`CMD + Shift + P` or
44 | `Ctrl + Shift + P`) and enter a search term. You can also use all search filters that work on the
45 | Sentry issues page. Then, select an issue from the list.
46 |
47 | To start a debugging session, choose _Launch debugger on Issue_ from the actions panel. Please note
48 | that your workspace needs to contain the project sources or search paths have to be configured. See
49 | [Extension Settings](#extension-settings) for more information on configuration.
50 |
51 | ## Extension Settings
52 |
53 | This extension contributes the following settings:
54 |
55 | - `sentry.enabled`: Enable or disable this extension
56 | - `sentry.serverUrl`: Use a custom on-premise server
57 | - `sentry.projects`: Select projects for searching issues
58 | - `sentry.searchPaths`: Local paths to search for source files
59 |
60 | ## Development
61 |
62 | Please feel free to open issues or PRs. To build and run this configuration, open this repository in
63 | VSCode and run the _Extension_ target. To run tests, run the _Extension Tests_ target.
64 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vscode-sentry",
3 | "version": "0.0.1",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@sentry/typescript": {
8 | "version": "4.0.0-beta.12",
9 | "resolved": "https://registry.npmjs.org/@sentry/typescript/-/typescript-4.0.0-beta.12.tgz",
10 | "integrity": "sha512-ItdcmuZxtXzK0dKX4J3chNsnbf3spJ2B+CEp90t6nqI9sUQ7zILNHgdncNIFP1a8k67+VWijCRmZYTZ7F69yjA==",
11 | "dev": true,
12 | "requires": {
13 | "tslint-config-prettier": "^1.12.0"
14 | }
15 | },
16 | "@types/ini": {
17 | "version": "1.3.29",
18 | "resolved": "https://registry.npmjs.org/@types/ini/-/ini-1.3.29.tgz",
19 | "integrity": "sha1-EyXpgeBH1A0TzgNZuCFHW5d0HS8=",
20 | "dev": true
21 | },
22 | "@types/mocha": {
23 | "version": "2.2.48",
24 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.48.tgz",
25 | "integrity": "sha512-nlK/iyETgafGli8Zh9zJVCTicvU3iajSkRwOh3Hhiva598CMqNJ4NcVCGMTGKpGpTYj/9R8RLzS9NAykSSCqGw==",
26 | "dev": true
27 | },
28 | "@types/node": {
29 | "version": "7.0.68",
30 | "resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.68.tgz",
31 | "integrity": "sha512-ym3LNHwJQU0XDyPrTK6NHJTH5YmGKKe0k56in6pg+Wx4HD8fiKrt8xute6/unHvHujCfzmOQTGz1NoEKgFF5Mw==",
32 | "dev": true
33 | },
34 | "@types/util.promisify": {
35 | "version": "1.0.0",
36 | "resolved": "https://registry.npmjs.org/@types/util.promisify/-/util.promisify-1.0.0.tgz",
37 | "integrity": "sha512-JK7Ecs9ETHfYSoG5ZILe30Ar9fmMT7vZTirfZQQ9OAZDB8TfPVV6aQkYPtfx2MFfB+yrSY4jCfrvMdemv/9VHw==",
38 | "dev": true
39 | },
40 | "agent-base": {
41 | "version": "4.2.1",
42 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
43 | "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
44 | "requires": {
45 | "es6-promisify": "^5.0.0"
46 | }
47 | },
48 | "ajv": {
49 | "version": "5.5.2",
50 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
51 | "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
52 | "dev": true,
53 | "requires": {
54 | "co": "^4.6.0",
55 | "fast-deep-equal": "^1.0.0",
56 | "fast-json-stable-stringify": "^2.0.0",
57 | "json-schema-traverse": "^0.3.0"
58 | }
59 | },
60 | "ansi-cyan": {
61 | "version": "0.1.1",
62 | "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz",
63 | "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=",
64 | "dev": true,
65 | "requires": {
66 | "ansi-wrap": "0.1.0"
67 | }
68 | },
69 | "ansi-red": {
70 | "version": "0.1.1",
71 | "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz",
72 | "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=",
73 | "dev": true,
74 | "requires": {
75 | "ansi-wrap": "0.1.0"
76 | }
77 | },
78 | "ansi-regex": {
79 | "version": "2.1.1",
80 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
81 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
82 | "dev": true
83 | },
84 | "ansi-styles": {
85 | "version": "2.2.1",
86 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
87 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
88 | "dev": true
89 | },
90 | "ansi-wrap": {
91 | "version": "0.1.0",
92 | "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
93 | "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=",
94 | "dev": true
95 | },
96 | "argparse": {
97 | "version": "1.0.10",
98 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
99 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
100 | "dev": true,
101 | "requires": {
102 | "sprintf-js": "~1.0.2"
103 | }
104 | },
105 | "arr-diff": {
106 | "version": "1.1.0",
107 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz",
108 | "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=",
109 | "dev": true,
110 | "requires": {
111 | "arr-flatten": "^1.0.1",
112 | "array-slice": "^0.2.3"
113 | }
114 | },
115 | "arr-flatten": {
116 | "version": "1.1.0",
117 | "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
118 | "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
119 | "dev": true
120 | },
121 | "arr-union": {
122 | "version": "2.1.0",
123 | "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz",
124 | "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=",
125 | "dev": true
126 | },
127 | "array-differ": {
128 | "version": "1.0.0",
129 | "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
130 | "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=",
131 | "dev": true
132 | },
133 | "array-slice": {
134 | "version": "0.2.3",
135 | "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
136 | "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=",
137 | "dev": true
138 | },
139 | "array-union": {
140 | "version": "1.0.2",
141 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
142 | "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
143 | "dev": true,
144 | "requires": {
145 | "array-uniq": "^1.0.1"
146 | }
147 | },
148 | "array-uniq": {
149 | "version": "1.0.3",
150 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
151 | "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
152 | "dev": true
153 | },
154 | "array-unique": {
155 | "version": "0.2.1",
156 | "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
157 | "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
158 | "dev": true
159 | },
160 | "arrify": {
161 | "version": "1.0.1",
162 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
163 | "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
164 | "dev": true
165 | },
166 | "asn1": {
167 | "version": "0.2.4",
168 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
169 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
170 | "dev": true,
171 | "requires": {
172 | "safer-buffer": "~2.1.0"
173 | }
174 | },
175 | "assert-plus": {
176 | "version": "1.0.0",
177 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
178 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
179 | "dev": true
180 | },
181 | "asynckit": {
182 | "version": "0.4.0",
183 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
184 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
185 | "dev": true
186 | },
187 | "aws-sign2": {
188 | "version": "0.7.0",
189 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
190 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
191 | "dev": true
192 | },
193 | "aws4": {
194 | "version": "1.7.0",
195 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
196 | "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==",
197 | "dev": true
198 | },
199 | "babel-code-frame": {
200 | "version": "6.26.0",
201 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
202 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
203 | "dev": true,
204 | "requires": {
205 | "chalk": "^1.1.3",
206 | "esutils": "^2.0.2",
207 | "js-tokens": "^3.0.2"
208 | },
209 | "dependencies": {
210 | "chalk": {
211 | "version": "1.1.3",
212 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
213 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
214 | "dev": true,
215 | "requires": {
216 | "ansi-styles": "^2.2.1",
217 | "escape-string-regexp": "^1.0.2",
218 | "has-ansi": "^2.0.0",
219 | "strip-ansi": "^3.0.0",
220 | "supports-color": "^2.0.0"
221 | }
222 | }
223 | }
224 | },
225 | "balanced-match": {
226 | "version": "1.0.0",
227 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
228 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
229 | "dev": true
230 | },
231 | "bcrypt-pbkdf": {
232 | "version": "1.0.2",
233 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
234 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
235 | "dev": true,
236 | "optional": true,
237 | "requires": {
238 | "tweetnacl": "^0.14.3"
239 | }
240 | },
241 | "block-stream": {
242 | "version": "0.0.9",
243 | "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
244 | "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
245 | "dev": true,
246 | "requires": {
247 | "inherits": "~2.0.0"
248 | }
249 | },
250 | "brace-expansion": {
251 | "version": "1.1.11",
252 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
253 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
254 | "dev": true,
255 | "requires": {
256 | "balanced-match": "^1.0.0",
257 | "concat-map": "0.0.1"
258 | }
259 | },
260 | "braces": {
261 | "version": "1.8.5",
262 | "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
263 | "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
264 | "dev": true,
265 | "requires": {
266 | "expand-range": "^1.8.1",
267 | "preserve": "^0.2.0",
268 | "repeat-element": "^1.1.2"
269 | }
270 | },
271 | "browser-stdout": {
272 | "version": "1.3.0",
273 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz",
274 | "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=",
275 | "dev": true
276 | },
277 | "buffer-crc32": {
278 | "version": "0.2.13",
279 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
280 | "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
281 | "dev": true
282 | },
283 | "buffer-from": {
284 | "version": "1.1.1",
285 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
286 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
287 | "dev": true
288 | },
289 | "builtin-modules": {
290 | "version": "1.1.1",
291 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
292 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
293 | "dev": true
294 | },
295 | "caseless": {
296 | "version": "0.12.0",
297 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
298 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
299 | "dev": true
300 | },
301 | "chalk": {
302 | "version": "2.4.1",
303 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
304 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
305 | "dev": true,
306 | "requires": {
307 | "ansi-styles": "^3.2.1",
308 | "escape-string-regexp": "^1.0.5",
309 | "supports-color": "^5.3.0"
310 | },
311 | "dependencies": {
312 | "ansi-styles": {
313 | "version": "3.2.1",
314 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
315 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
316 | "dev": true,
317 | "requires": {
318 | "color-convert": "^1.9.0"
319 | }
320 | },
321 | "supports-color": {
322 | "version": "5.4.0",
323 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
324 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
325 | "dev": true,
326 | "requires": {
327 | "has-flag": "^3.0.0"
328 | }
329 | }
330 | }
331 | },
332 | "clone": {
333 | "version": "0.2.0",
334 | "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
335 | "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=",
336 | "dev": true
337 | },
338 | "clone-buffer": {
339 | "version": "1.0.0",
340 | "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
341 | "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=",
342 | "dev": true
343 | },
344 | "clone-stats": {
345 | "version": "0.0.1",
346 | "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
347 | "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=",
348 | "dev": true
349 | },
350 | "cloneable-readable": {
351 | "version": "1.1.2",
352 | "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz",
353 | "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==",
354 | "dev": true,
355 | "requires": {
356 | "inherits": "^2.0.1",
357 | "process-nextick-args": "^2.0.0",
358 | "readable-stream": "^2.3.5"
359 | }
360 | },
361 | "co": {
362 | "version": "4.6.0",
363 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
364 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
365 | "dev": true
366 | },
367 | "color-convert": {
368 | "version": "1.9.2",
369 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
370 | "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==",
371 | "dev": true,
372 | "requires": {
373 | "color-name": "1.1.1"
374 | }
375 | },
376 | "color-name": {
377 | "version": "1.1.1",
378 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz",
379 | "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=",
380 | "dev": true
381 | },
382 | "combined-stream": {
383 | "version": "1.0.6",
384 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
385 | "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
386 | "dev": true,
387 | "requires": {
388 | "delayed-stream": "~1.0.0"
389 | }
390 | },
391 | "commander": {
392 | "version": "2.17.0",
393 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.0.tgz",
394 | "integrity": "sha512-477o1hdVORiFlZxw8wgsXYCef3lh0zl/OV0FTftqiDxJSWw6dPQ2ipS4k20J2qBcsmsmLKSyr2iFrf9e3JGi4w==",
395 | "dev": true
396 | },
397 | "concat-map": {
398 | "version": "0.0.1",
399 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
400 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
401 | "dev": true
402 | },
403 | "convert-source-map": {
404 | "version": "1.5.1",
405 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
406 | "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
407 | "dev": true
408 | },
409 | "core-util-is": {
410 | "version": "1.0.2",
411 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
412 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
413 | "dev": true
414 | },
415 | "dashdash": {
416 | "version": "1.14.1",
417 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
418 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
419 | "dev": true,
420 | "requires": {
421 | "assert-plus": "^1.0.0"
422 | }
423 | },
424 | "debug": {
425 | "version": "3.1.0",
426 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
427 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
428 | "requires": {
429 | "ms": "2.0.0"
430 | }
431 | },
432 | "deep-assign": {
433 | "version": "1.0.0",
434 | "resolved": "https://registry.npmjs.org/deep-assign/-/deep-assign-1.0.0.tgz",
435 | "integrity": "sha1-sJJ0O+hCfcYh6gBnzex+cN0Z83s=",
436 | "dev": true,
437 | "requires": {
438 | "is-obj": "^1.0.0"
439 | }
440 | },
441 | "define-properties": {
442 | "version": "1.1.2",
443 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
444 | "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
445 | "requires": {
446 | "foreach": "^2.0.5",
447 | "object-keys": "^1.0.8"
448 | }
449 | },
450 | "delayed-stream": {
451 | "version": "1.0.0",
452 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
453 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
454 | "dev": true
455 | },
456 | "diff": {
457 | "version": "3.5.0",
458 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
459 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
460 | "dev": true
461 | },
462 | "duplexer": {
463 | "version": "0.1.1",
464 | "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
465 | "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
466 | "dev": true
467 | },
468 | "duplexify": {
469 | "version": "3.6.0",
470 | "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz",
471 | "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==",
472 | "dev": true,
473 | "requires": {
474 | "end-of-stream": "^1.0.0",
475 | "inherits": "^2.0.1",
476 | "readable-stream": "^2.0.0",
477 | "stream-shift": "^1.0.0"
478 | }
479 | },
480 | "ecc-jsbn": {
481 | "version": "0.1.2",
482 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
483 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
484 | "dev": true,
485 | "optional": true,
486 | "requires": {
487 | "jsbn": "~0.1.0",
488 | "safer-buffer": "^2.1.0"
489 | }
490 | },
491 | "end-of-stream": {
492 | "version": "1.4.1",
493 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
494 | "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
495 | "dev": true,
496 | "requires": {
497 | "once": "^1.4.0"
498 | }
499 | },
500 | "es-abstract": {
501 | "version": "1.12.0",
502 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
503 | "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
504 | "requires": {
505 | "es-to-primitive": "^1.1.1",
506 | "function-bind": "^1.1.1",
507 | "has": "^1.0.1",
508 | "is-callable": "^1.1.3",
509 | "is-regex": "^1.0.4"
510 | }
511 | },
512 | "es-to-primitive": {
513 | "version": "1.1.1",
514 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
515 | "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=",
516 | "requires": {
517 | "is-callable": "^1.1.1",
518 | "is-date-object": "^1.0.1",
519 | "is-symbol": "^1.0.1"
520 | }
521 | },
522 | "es6-promise": {
523 | "version": "4.2.4",
524 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz",
525 | "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ=="
526 | },
527 | "es6-promisify": {
528 | "version": "5.0.0",
529 | "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
530 | "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
531 | "requires": {
532 | "es6-promise": "^4.0.3"
533 | }
534 | },
535 | "escape-string-regexp": {
536 | "version": "1.0.5",
537 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
538 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
539 | "dev": true
540 | },
541 | "esprima": {
542 | "version": "4.0.1",
543 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
544 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
545 | "dev": true
546 | },
547 | "esutils": {
548 | "version": "2.0.2",
549 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
550 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
551 | "dev": true
552 | },
553 | "event-stream": {
554 | "version": "3.3.4",
555 | "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
556 | "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=",
557 | "dev": true,
558 | "requires": {
559 | "duplexer": "~0.1.1",
560 | "from": "~0",
561 | "map-stream": "~0.1.0",
562 | "pause-stream": "0.0.11",
563 | "split": "0.3",
564 | "stream-combiner": "~0.0.4",
565 | "through": "~2.3.1"
566 | }
567 | },
568 | "expand-brackets": {
569 | "version": "0.1.5",
570 | "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
571 | "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
572 | "dev": true,
573 | "requires": {
574 | "is-posix-bracket": "^0.1.0"
575 | }
576 | },
577 | "expand-range": {
578 | "version": "1.8.2",
579 | "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
580 | "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
581 | "dev": true,
582 | "requires": {
583 | "fill-range": "^2.1.0"
584 | }
585 | },
586 | "extend": {
587 | "version": "3.0.2",
588 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
589 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
590 | "dev": true
591 | },
592 | "extend-shallow": {
593 | "version": "1.1.4",
594 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz",
595 | "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=",
596 | "dev": true,
597 | "requires": {
598 | "kind-of": "^1.1.0"
599 | }
600 | },
601 | "extglob": {
602 | "version": "0.3.2",
603 | "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
604 | "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
605 | "dev": true,
606 | "requires": {
607 | "is-extglob": "^1.0.0"
608 | },
609 | "dependencies": {
610 | "is-extglob": {
611 | "version": "1.0.0",
612 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
613 | "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
614 | "dev": true
615 | }
616 | }
617 | },
618 | "extsprintf": {
619 | "version": "1.3.0",
620 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
621 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
622 | "dev": true
623 | },
624 | "fast-deep-equal": {
625 | "version": "1.1.0",
626 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
627 | "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
628 | "dev": true
629 | },
630 | "fast-json-stable-stringify": {
631 | "version": "2.0.0",
632 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
633 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
634 | "dev": true
635 | },
636 | "fd-slicer": {
637 | "version": "1.1.0",
638 | "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
639 | "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
640 | "dev": true,
641 | "requires": {
642 | "pend": "~1.2.0"
643 | }
644 | },
645 | "filename-regex": {
646 | "version": "2.0.1",
647 | "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
648 | "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
649 | "dev": true
650 | },
651 | "fill-range": {
652 | "version": "2.2.4",
653 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
654 | "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
655 | "dev": true,
656 | "requires": {
657 | "is-number": "^2.1.0",
658 | "isobject": "^2.0.0",
659 | "randomatic": "^3.0.0",
660 | "repeat-element": "^1.1.2",
661 | "repeat-string": "^1.5.2"
662 | }
663 | },
664 | "first-chunk-stream": {
665 | "version": "1.0.0",
666 | "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz",
667 | "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=",
668 | "dev": true
669 | },
670 | "for-in": {
671 | "version": "1.0.2",
672 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
673 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
674 | "dev": true
675 | },
676 | "for-own": {
677 | "version": "0.1.5",
678 | "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
679 | "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
680 | "dev": true,
681 | "requires": {
682 | "for-in": "^1.0.1"
683 | }
684 | },
685 | "foreach": {
686 | "version": "2.0.5",
687 | "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
688 | "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
689 | },
690 | "forever-agent": {
691 | "version": "0.6.1",
692 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
693 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
694 | "dev": true
695 | },
696 | "form-data": {
697 | "version": "2.3.2",
698 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
699 | "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
700 | "dev": true,
701 | "requires": {
702 | "asynckit": "^0.4.0",
703 | "combined-stream": "1.0.6",
704 | "mime-types": "^2.1.12"
705 | }
706 | },
707 | "from": {
708 | "version": "0.1.7",
709 | "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
710 | "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=",
711 | "dev": true
712 | },
713 | "fs.realpath": {
714 | "version": "1.0.0",
715 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
716 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
717 | "dev": true
718 | },
719 | "fstream": {
720 | "version": "1.0.11",
721 | "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
722 | "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
723 | "dev": true,
724 | "requires": {
725 | "graceful-fs": "^4.1.2",
726 | "inherits": "~2.0.0",
727 | "mkdirp": ">=0.5 0",
728 | "rimraf": "2"
729 | }
730 | },
731 | "function-bind": {
732 | "version": "1.1.1",
733 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
734 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
735 | },
736 | "getpass": {
737 | "version": "0.1.7",
738 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
739 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
740 | "dev": true,
741 | "requires": {
742 | "assert-plus": "^1.0.0"
743 | }
744 | },
745 | "glob": {
746 | "version": "7.1.2",
747 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
748 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
749 | "dev": true,
750 | "requires": {
751 | "fs.realpath": "^1.0.0",
752 | "inflight": "^1.0.4",
753 | "inherits": "2",
754 | "minimatch": "^3.0.4",
755 | "once": "^1.3.0",
756 | "path-is-absolute": "^1.0.0"
757 | }
758 | },
759 | "glob-base": {
760 | "version": "0.3.0",
761 | "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
762 | "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
763 | "dev": true,
764 | "requires": {
765 | "glob-parent": "^2.0.0",
766 | "is-glob": "^2.0.0"
767 | },
768 | "dependencies": {
769 | "glob-parent": {
770 | "version": "2.0.0",
771 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
772 | "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
773 | "dev": true,
774 | "requires": {
775 | "is-glob": "^2.0.0"
776 | }
777 | },
778 | "is-extglob": {
779 | "version": "1.0.0",
780 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
781 | "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
782 | "dev": true
783 | },
784 | "is-glob": {
785 | "version": "2.0.1",
786 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
787 | "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
788 | "dev": true,
789 | "requires": {
790 | "is-extglob": "^1.0.0"
791 | }
792 | }
793 | }
794 | },
795 | "glob-parent": {
796 | "version": "3.1.0",
797 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
798 | "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
799 | "dev": true,
800 | "requires": {
801 | "is-glob": "^3.1.0",
802 | "path-dirname": "^1.0.0"
803 | }
804 | },
805 | "glob-stream": {
806 | "version": "5.3.5",
807 | "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz",
808 | "integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=",
809 | "dev": true,
810 | "requires": {
811 | "extend": "^3.0.0",
812 | "glob": "^5.0.3",
813 | "glob-parent": "^3.0.0",
814 | "micromatch": "^2.3.7",
815 | "ordered-read-streams": "^0.3.0",
816 | "through2": "^0.6.0",
817 | "to-absolute-glob": "^0.1.1",
818 | "unique-stream": "^2.0.2"
819 | },
820 | "dependencies": {
821 | "glob": {
822 | "version": "5.0.15",
823 | "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
824 | "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
825 | "dev": true,
826 | "requires": {
827 | "inflight": "^1.0.4",
828 | "inherits": "2",
829 | "minimatch": "2 || 3",
830 | "once": "^1.3.0",
831 | "path-is-absolute": "^1.0.0"
832 | }
833 | },
834 | "isarray": {
835 | "version": "0.0.1",
836 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
837 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
838 | "dev": true
839 | },
840 | "readable-stream": {
841 | "version": "1.0.34",
842 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
843 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
844 | "dev": true,
845 | "requires": {
846 | "core-util-is": "~1.0.0",
847 | "inherits": "~2.0.1",
848 | "isarray": "0.0.1",
849 | "string_decoder": "~0.10.x"
850 | }
851 | },
852 | "string_decoder": {
853 | "version": "0.10.31",
854 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
855 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
856 | "dev": true
857 | },
858 | "through2": {
859 | "version": "0.6.5",
860 | "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
861 | "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
862 | "dev": true,
863 | "requires": {
864 | "readable-stream": ">=1.0.33-1 <1.1.0-0",
865 | "xtend": ">=4.0.0 <4.1.0-0"
866 | }
867 | }
868 | }
869 | },
870 | "graceful-fs": {
871 | "version": "4.1.11",
872 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
873 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
874 | "dev": true
875 | },
876 | "growl": {
877 | "version": "1.10.3",
878 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz",
879 | "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==",
880 | "dev": true
881 | },
882 | "gulp-chmod": {
883 | "version": "2.0.0",
884 | "resolved": "https://registry.npmjs.org/gulp-chmod/-/gulp-chmod-2.0.0.tgz",
885 | "integrity": "sha1-AMOQuSigeZslGsz2MaoJ4BzGKZw=",
886 | "dev": true,
887 | "requires": {
888 | "deep-assign": "^1.0.0",
889 | "stat-mode": "^0.2.0",
890 | "through2": "^2.0.0"
891 | }
892 | },
893 | "gulp-filter": {
894 | "version": "5.1.0",
895 | "resolved": "https://registry.npmjs.org/gulp-filter/-/gulp-filter-5.1.0.tgz",
896 | "integrity": "sha1-oF4Rr/sHz33PQafeHLe2OsN4PnM=",
897 | "dev": true,
898 | "requires": {
899 | "multimatch": "^2.0.0",
900 | "plugin-error": "^0.1.2",
901 | "streamfilter": "^1.0.5"
902 | }
903 | },
904 | "gulp-gunzip": {
905 | "version": "1.0.0",
906 | "resolved": "https://registry.npmjs.org/gulp-gunzip/-/gulp-gunzip-1.0.0.tgz",
907 | "integrity": "sha1-FbdBFF6Dqcb1CIYkG1fMWHHxUak=",
908 | "dev": true,
909 | "requires": {
910 | "through2": "~0.6.5",
911 | "vinyl": "~0.4.6"
912 | },
913 | "dependencies": {
914 | "isarray": {
915 | "version": "0.0.1",
916 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
917 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
918 | "dev": true
919 | },
920 | "readable-stream": {
921 | "version": "1.0.34",
922 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
923 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
924 | "dev": true,
925 | "requires": {
926 | "core-util-is": "~1.0.0",
927 | "inherits": "~2.0.1",
928 | "isarray": "0.0.1",
929 | "string_decoder": "~0.10.x"
930 | }
931 | },
932 | "string_decoder": {
933 | "version": "0.10.31",
934 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
935 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
936 | "dev": true
937 | },
938 | "through2": {
939 | "version": "0.6.5",
940 | "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
941 | "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
942 | "dev": true,
943 | "requires": {
944 | "readable-stream": ">=1.0.33-1 <1.1.0-0",
945 | "xtend": ">=4.0.0 <4.1.0-0"
946 | }
947 | }
948 | }
949 | },
950 | "gulp-remote-src-vscode": {
951 | "version": "0.5.0",
952 | "resolved": "https://registry.npmjs.org/gulp-remote-src-vscode/-/gulp-remote-src-vscode-0.5.0.tgz",
953 | "integrity": "sha512-/9vtSk9eI9DEWCqzGieglPqmx0WUQ9pwPHyHFpKmfxqdgqGJC2l0vFMdYs54hLdDsMDEZFLDL2J4ikjc4hQ5HQ==",
954 | "dev": true,
955 | "requires": {
956 | "event-stream": "^3.3.4",
957 | "node.extend": "^1.1.2",
958 | "request": "^2.79.0",
959 | "through2": "^2.0.3",
960 | "vinyl": "^2.0.1"
961 | },
962 | "dependencies": {
963 | "clone": {
964 | "version": "2.1.2",
965 | "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
966 | "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
967 | "dev": true
968 | },
969 | "clone-stats": {
970 | "version": "1.0.0",
971 | "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
972 | "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
973 | "dev": true
974 | },
975 | "vinyl": {
976 | "version": "2.2.0",
977 | "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
978 | "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
979 | "dev": true,
980 | "requires": {
981 | "clone": "^2.1.1",
982 | "clone-buffer": "^1.0.0",
983 | "clone-stats": "^1.0.0",
984 | "cloneable-readable": "^1.0.0",
985 | "remove-trailing-separator": "^1.0.1",
986 | "replace-ext": "^1.0.0"
987 | }
988 | }
989 | }
990 | },
991 | "gulp-sourcemaps": {
992 | "version": "1.6.0",
993 | "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz",
994 | "integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=",
995 | "dev": true,
996 | "requires": {
997 | "convert-source-map": "^1.1.1",
998 | "graceful-fs": "^4.1.2",
999 | "strip-bom": "^2.0.0",
1000 | "through2": "^2.0.0",
1001 | "vinyl": "^1.0.0"
1002 | },
1003 | "dependencies": {
1004 | "clone": {
1005 | "version": "1.0.4",
1006 | "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
1007 | "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
1008 | "dev": true
1009 | },
1010 | "replace-ext": {
1011 | "version": "0.0.1",
1012 | "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
1013 | "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=",
1014 | "dev": true
1015 | },
1016 | "vinyl": {
1017 | "version": "1.2.0",
1018 | "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
1019 | "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
1020 | "dev": true,
1021 | "requires": {
1022 | "clone": "^1.0.0",
1023 | "clone-stats": "^0.0.1",
1024 | "replace-ext": "0.0.1"
1025 | }
1026 | }
1027 | }
1028 | },
1029 | "gulp-symdest": {
1030 | "version": "1.1.0",
1031 | "resolved": "https://registry.npmjs.org/gulp-symdest/-/gulp-symdest-1.1.0.tgz",
1032 | "integrity": "sha1-wWUyBzLRks5W/ZQnH/oSMjS/KuA=",
1033 | "dev": true,
1034 | "requires": {
1035 | "event-stream": "^3.3.1",
1036 | "mkdirp": "^0.5.1",
1037 | "queue": "^3.1.0",
1038 | "vinyl-fs": "^2.4.3"
1039 | }
1040 | },
1041 | "gulp-untar": {
1042 | "version": "0.0.7",
1043 | "resolved": "https://registry.npmjs.org/gulp-untar/-/gulp-untar-0.0.7.tgz",
1044 | "integrity": "sha512-0QfbCH2a1k2qkTLWPqTX+QO4qNsHn3kC546YhAP3/n0h+nvtyGITDuDrYBMDZeW4WnFijmkOvBWa5HshTic1tw==",
1045 | "dev": true,
1046 | "requires": {
1047 | "event-stream": "~3.3.4",
1048 | "streamifier": "~0.1.1",
1049 | "tar": "^2.2.1",
1050 | "through2": "~2.0.3",
1051 | "vinyl": "^1.2.0"
1052 | },
1053 | "dependencies": {
1054 | "clone": {
1055 | "version": "1.0.4",
1056 | "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
1057 | "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
1058 | "dev": true
1059 | },
1060 | "replace-ext": {
1061 | "version": "0.0.1",
1062 | "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
1063 | "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=",
1064 | "dev": true
1065 | },
1066 | "vinyl": {
1067 | "version": "1.2.0",
1068 | "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
1069 | "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
1070 | "dev": true,
1071 | "requires": {
1072 | "clone": "^1.0.0",
1073 | "clone-stats": "^0.0.1",
1074 | "replace-ext": "0.0.1"
1075 | }
1076 | }
1077 | }
1078 | },
1079 | "gulp-vinyl-zip": {
1080 | "version": "2.1.0",
1081 | "resolved": "https://registry.npmjs.org/gulp-vinyl-zip/-/gulp-vinyl-zip-2.1.0.tgz",
1082 | "integrity": "sha1-JOQGhdwFtxSZlSRQmeBZAmO+ja0=",
1083 | "dev": true,
1084 | "requires": {
1085 | "event-stream": "^3.3.1",
1086 | "queue": "^4.2.1",
1087 | "through2": "^2.0.3",
1088 | "vinyl": "^2.0.2",
1089 | "vinyl-fs": "^2.0.0",
1090 | "yauzl": "^2.2.1",
1091 | "yazl": "^2.2.1"
1092 | },
1093 | "dependencies": {
1094 | "clone": {
1095 | "version": "2.1.2",
1096 | "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
1097 | "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
1098 | "dev": true
1099 | },
1100 | "clone-stats": {
1101 | "version": "1.0.0",
1102 | "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
1103 | "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
1104 | "dev": true
1105 | },
1106 | "queue": {
1107 | "version": "4.4.2",
1108 | "resolved": "https://registry.npmjs.org/queue/-/queue-4.4.2.tgz",
1109 | "integrity": "sha512-fSMRXbwhMwipcDZ08enW2vl+YDmAmhcNcr43sCJL8DIg+CFOsoRLG23ctxA+fwNk1w55SePSiS7oqQQSgQoVJQ==",
1110 | "dev": true,
1111 | "requires": {
1112 | "inherits": "~2.0.0"
1113 | }
1114 | },
1115 | "vinyl": {
1116 | "version": "2.2.0",
1117 | "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
1118 | "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
1119 | "dev": true,
1120 | "requires": {
1121 | "clone": "^2.1.1",
1122 | "clone-buffer": "^1.0.0",
1123 | "clone-stats": "^1.0.0",
1124 | "cloneable-readable": "^1.0.0",
1125 | "remove-trailing-separator": "^1.0.1",
1126 | "replace-ext": "^1.0.0"
1127 | }
1128 | }
1129 | }
1130 | },
1131 | "har-schema": {
1132 | "version": "2.0.0",
1133 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
1134 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
1135 | "dev": true
1136 | },
1137 | "har-validator": {
1138 | "version": "5.0.3",
1139 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
1140 | "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
1141 | "dev": true,
1142 | "requires": {
1143 | "ajv": "^5.1.0",
1144 | "har-schema": "^2.0.0"
1145 | }
1146 | },
1147 | "has": {
1148 | "version": "1.0.3",
1149 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
1150 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
1151 | "requires": {
1152 | "function-bind": "^1.1.1"
1153 | }
1154 | },
1155 | "has-ansi": {
1156 | "version": "2.0.0",
1157 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
1158 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
1159 | "dev": true,
1160 | "requires": {
1161 | "ansi-regex": "^2.0.0"
1162 | }
1163 | },
1164 | "has-flag": {
1165 | "version": "3.0.0",
1166 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
1167 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
1168 | "dev": true
1169 | },
1170 | "he": {
1171 | "version": "1.1.1",
1172 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
1173 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
1174 | "dev": true
1175 | },
1176 | "http-proxy-agent": {
1177 | "version": "2.1.0",
1178 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
1179 | "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
1180 | "requires": {
1181 | "agent-base": "4",
1182 | "debug": "3.1.0"
1183 | }
1184 | },
1185 | "http-signature": {
1186 | "version": "1.2.0",
1187 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
1188 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
1189 | "dev": true,
1190 | "requires": {
1191 | "assert-plus": "^1.0.0",
1192 | "jsprim": "^1.2.2",
1193 | "sshpk": "^1.7.0"
1194 | }
1195 | },
1196 | "https-proxy-agent": {
1197 | "version": "2.2.1",
1198 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
1199 | "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
1200 | "requires": {
1201 | "agent-base": "^4.1.0",
1202 | "debug": "^3.1.0"
1203 | }
1204 | },
1205 | "inflight": {
1206 | "version": "1.0.6",
1207 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
1208 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
1209 | "dev": true,
1210 | "requires": {
1211 | "once": "^1.3.0",
1212 | "wrappy": "1"
1213 | }
1214 | },
1215 | "inherits": {
1216 | "version": "2.0.3",
1217 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
1218 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
1219 | "dev": true
1220 | },
1221 | "ini": {
1222 | "version": "1.3.5",
1223 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
1224 | "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
1225 | },
1226 | "is": {
1227 | "version": "3.2.1",
1228 | "resolved": "https://registry.npmjs.org/is/-/is-3.2.1.tgz",
1229 | "integrity": "sha1-0Kwq1V63sL7JJqUmb2xmKqqD3KU=",
1230 | "dev": true
1231 | },
1232 | "is-buffer": {
1233 | "version": "1.1.6",
1234 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
1235 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
1236 | "dev": true
1237 | },
1238 | "is-callable": {
1239 | "version": "1.1.4",
1240 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
1241 | "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
1242 | },
1243 | "is-date-object": {
1244 | "version": "1.0.1",
1245 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
1246 | "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
1247 | },
1248 | "is-dotfile": {
1249 | "version": "1.0.3",
1250 | "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
1251 | "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
1252 | "dev": true
1253 | },
1254 | "is-equal-shallow": {
1255 | "version": "0.1.3",
1256 | "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
1257 | "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
1258 | "dev": true,
1259 | "requires": {
1260 | "is-primitive": "^2.0.0"
1261 | }
1262 | },
1263 | "is-extendable": {
1264 | "version": "0.1.1",
1265 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
1266 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
1267 | "dev": true
1268 | },
1269 | "is-extglob": {
1270 | "version": "2.1.1",
1271 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
1272 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
1273 | "dev": true
1274 | },
1275 | "is-glob": {
1276 | "version": "3.1.0",
1277 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
1278 | "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
1279 | "dev": true,
1280 | "requires": {
1281 | "is-extglob": "^2.1.0"
1282 | }
1283 | },
1284 | "is-number": {
1285 | "version": "2.1.0",
1286 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
1287 | "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
1288 | "dev": true,
1289 | "requires": {
1290 | "kind-of": "^3.0.2"
1291 | },
1292 | "dependencies": {
1293 | "kind-of": {
1294 | "version": "3.2.2",
1295 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
1296 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
1297 | "dev": true,
1298 | "requires": {
1299 | "is-buffer": "^1.1.5"
1300 | }
1301 | }
1302 | }
1303 | },
1304 | "is-obj": {
1305 | "version": "1.0.1",
1306 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
1307 | "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
1308 | "dev": true
1309 | },
1310 | "is-posix-bracket": {
1311 | "version": "0.1.1",
1312 | "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
1313 | "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
1314 | "dev": true
1315 | },
1316 | "is-primitive": {
1317 | "version": "2.0.0",
1318 | "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
1319 | "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
1320 | "dev": true
1321 | },
1322 | "is-regex": {
1323 | "version": "1.0.4",
1324 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
1325 | "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
1326 | "requires": {
1327 | "has": "^1.0.1"
1328 | }
1329 | },
1330 | "is-stream": {
1331 | "version": "1.1.0",
1332 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
1333 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
1334 | "dev": true
1335 | },
1336 | "is-symbol": {
1337 | "version": "1.0.1",
1338 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
1339 | "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI="
1340 | },
1341 | "is-typedarray": {
1342 | "version": "1.0.0",
1343 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
1344 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
1345 | "dev": true
1346 | },
1347 | "is-utf8": {
1348 | "version": "0.2.1",
1349 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
1350 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
1351 | "dev": true
1352 | },
1353 | "is-valid-glob": {
1354 | "version": "0.3.0",
1355 | "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-0.3.0.tgz",
1356 | "integrity": "sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=",
1357 | "dev": true
1358 | },
1359 | "isarray": {
1360 | "version": "1.0.0",
1361 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
1362 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
1363 | "dev": true
1364 | },
1365 | "isobject": {
1366 | "version": "2.1.0",
1367 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
1368 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
1369 | "dev": true,
1370 | "requires": {
1371 | "isarray": "1.0.0"
1372 | }
1373 | },
1374 | "isstream": {
1375 | "version": "0.1.2",
1376 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
1377 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
1378 | "dev": true
1379 | },
1380 | "js-tokens": {
1381 | "version": "3.0.2",
1382 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
1383 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
1384 | "dev": true
1385 | },
1386 | "js-yaml": {
1387 | "version": "3.12.0",
1388 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
1389 | "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
1390 | "dev": true,
1391 | "requires": {
1392 | "argparse": "^1.0.7",
1393 | "esprima": "^4.0.0"
1394 | }
1395 | },
1396 | "jsbn": {
1397 | "version": "0.1.1",
1398 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
1399 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
1400 | "dev": true,
1401 | "optional": true
1402 | },
1403 | "json-schema": {
1404 | "version": "0.2.3",
1405 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
1406 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
1407 | "dev": true
1408 | },
1409 | "json-schema-traverse": {
1410 | "version": "0.3.1",
1411 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
1412 | "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
1413 | "dev": true
1414 | },
1415 | "json-stable-stringify": {
1416 | "version": "1.0.1",
1417 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
1418 | "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
1419 | "dev": true,
1420 | "requires": {
1421 | "jsonify": "~0.0.0"
1422 | }
1423 | },
1424 | "json-stringify-safe": {
1425 | "version": "5.0.1",
1426 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
1427 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
1428 | "dev": true
1429 | },
1430 | "jsonify": {
1431 | "version": "0.0.0",
1432 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
1433 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
1434 | "dev": true
1435 | },
1436 | "jsprim": {
1437 | "version": "1.4.1",
1438 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
1439 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
1440 | "dev": true,
1441 | "requires": {
1442 | "assert-plus": "1.0.0",
1443 | "extsprintf": "1.3.0",
1444 | "json-schema": "0.2.3",
1445 | "verror": "1.10.0"
1446 | }
1447 | },
1448 | "kind-of": {
1449 | "version": "1.1.0",
1450 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
1451 | "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=",
1452 | "dev": true
1453 | },
1454 | "lazystream": {
1455 | "version": "1.0.0",
1456 | "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
1457 | "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
1458 | "dev": true,
1459 | "requires": {
1460 | "readable-stream": "^2.0.5"
1461 | }
1462 | },
1463 | "lodash.isequal": {
1464 | "version": "4.5.0",
1465 | "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
1466 | "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
1467 | "dev": true
1468 | },
1469 | "map-stream": {
1470 | "version": "0.1.0",
1471 | "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
1472 | "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=",
1473 | "dev": true
1474 | },
1475 | "math-random": {
1476 | "version": "1.0.1",
1477 | "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz",
1478 | "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=",
1479 | "dev": true
1480 | },
1481 | "merge-stream": {
1482 | "version": "1.0.1",
1483 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz",
1484 | "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=",
1485 | "dev": true,
1486 | "requires": {
1487 | "readable-stream": "^2.0.1"
1488 | }
1489 | },
1490 | "micromatch": {
1491 | "version": "2.3.11",
1492 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
1493 | "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
1494 | "dev": true,
1495 | "requires": {
1496 | "arr-diff": "^2.0.0",
1497 | "array-unique": "^0.2.1",
1498 | "braces": "^1.8.2",
1499 | "expand-brackets": "^0.1.4",
1500 | "extglob": "^0.3.1",
1501 | "filename-regex": "^2.0.0",
1502 | "is-extglob": "^1.0.0",
1503 | "is-glob": "^2.0.1",
1504 | "kind-of": "^3.0.2",
1505 | "normalize-path": "^2.0.1",
1506 | "object.omit": "^2.0.0",
1507 | "parse-glob": "^3.0.4",
1508 | "regex-cache": "^0.4.2"
1509 | },
1510 | "dependencies": {
1511 | "arr-diff": {
1512 | "version": "2.0.0",
1513 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
1514 | "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
1515 | "dev": true,
1516 | "requires": {
1517 | "arr-flatten": "^1.0.1"
1518 | }
1519 | },
1520 | "is-extglob": {
1521 | "version": "1.0.0",
1522 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
1523 | "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
1524 | "dev": true
1525 | },
1526 | "is-glob": {
1527 | "version": "2.0.1",
1528 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
1529 | "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
1530 | "dev": true,
1531 | "requires": {
1532 | "is-extglob": "^1.0.0"
1533 | }
1534 | },
1535 | "kind-of": {
1536 | "version": "3.2.2",
1537 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
1538 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
1539 | "dev": true,
1540 | "requires": {
1541 | "is-buffer": "^1.1.5"
1542 | }
1543 | }
1544 | }
1545 | },
1546 | "mime-db": {
1547 | "version": "1.35.0",
1548 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz",
1549 | "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==",
1550 | "dev": true
1551 | },
1552 | "mime-types": {
1553 | "version": "2.1.19",
1554 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz",
1555 | "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
1556 | "dev": true,
1557 | "requires": {
1558 | "mime-db": "~1.35.0"
1559 | }
1560 | },
1561 | "minimatch": {
1562 | "version": "3.0.4",
1563 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
1564 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
1565 | "dev": true,
1566 | "requires": {
1567 | "brace-expansion": "^1.1.7"
1568 | }
1569 | },
1570 | "minimist": {
1571 | "version": "0.0.8",
1572 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
1573 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
1574 | "dev": true
1575 | },
1576 | "mkdirp": {
1577 | "version": "0.5.1",
1578 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
1579 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
1580 | "dev": true,
1581 | "requires": {
1582 | "minimist": "0.0.8"
1583 | }
1584 | },
1585 | "mocha": {
1586 | "version": "4.1.0",
1587 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz",
1588 | "integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==",
1589 | "dev": true,
1590 | "requires": {
1591 | "browser-stdout": "1.3.0",
1592 | "commander": "2.11.0",
1593 | "debug": "3.1.0",
1594 | "diff": "3.3.1",
1595 | "escape-string-regexp": "1.0.5",
1596 | "glob": "7.1.2",
1597 | "growl": "1.10.3",
1598 | "he": "1.1.1",
1599 | "mkdirp": "0.5.1",
1600 | "supports-color": "4.4.0"
1601 | },
1602 | "dependencies": {
1603 | "commander": {
1604 | "version": "2.11.0",
1605 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
1606 | "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
1607 | "dev": true
1608 | },
1609 | "diff": {
1610 | "version": "3.3.1",
1611 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz",
1612 | "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==",
1613 | "dev": true
1614 | },
1615 | "has-flag": {
1616 | "version": "2.0.0",
1617 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
1618 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
1619 | "dev": true
1620 | },
1621 | "supports-color": {
1622 | "version": "4.4.0",
1623 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
1624 | "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
1625 | "dev": true,
1626 | "requires": {
1627 | "has-flag": "^2.0.0"
1628 | }
1629 | }
1630 | }
1631 | },
1632 | "ms": {
1633 | "version": "2.0.0",
1634 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
1635 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
1636 | },
1637 | "multimatch": {
1638 | "version": "2.1.0",
1639 | "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz",
1640 | "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=",
1641 | "dev": true,
1642 | "requires": {
1643 | "array-differ": "^1.0.0",
1644 | "array-union": "^1.0.1",
1645 | "arrify": "^1.0.0",
1646 | "minimatch": "^3.0.0"
1647 | }
1648 | },
1649 | "node.extend": {
1650 | "version": "1.1.6",
1651 | "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-1.1.6.tgz",
1652 | "integrity": "sha1-p7iCyC1sk6SGOlUEvV3o7IYli5Y=",
1653 | "dev": true,
1654 | "requires": {
1655 | "is": "^3.1.0"
1656 | }
1657 | },
1658 | "normalize-path": {
1659 | "version": "2.1.1",
1660 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
1661 | "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
1662 | "dev": true,
1663 | "requires": {
1664 | "remove-trailing-separator": "^1.0.1"
1665 | }
1666 | },
1667 | "oauth-sign": {
1668 | "version": "0.8.2",
1669 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
1670 | "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
1671 | "dev": true
1672 | },
1673 | "object-assign": {
1674 | "version": "4.1.1",
1675 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1676 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
1677 | "dev": true
1678 | },
1679 | "object-keys": {
1680 | "version": "1.0.12",
1681 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
1682 | "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag=="
1683 | },
1684 | "object.getownpropertydescriptors": {
1685 | "version": "2.0.3",
1686 | "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
1687 | "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
1688 | "requires": {
1689 | "define-properties": "^1.1.2",
1690 | "es-abstract": "^1.5.1"
1691 | }
1692 | },
1693 | "object.omit": {
1694 | "version": "2.0.1",
1695 | "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
1696 | "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
1697 | "dev": true,
1698 | "requires": {
1699 | "for-own": "^0.1.4",
1700 | "is-extendable": "^0.1.1"
1701 | }
1702 | },
1703 | "once": {
1704 | "version": "1.4.0",
1705 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1706 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
1707 | "dev": true,
1708 | "requires": {
1709 | "wrappy": "1"
1710 | }
1711 | },
1712 | "ordered-read-streams": {
1713 | "version": "0.3.0",
1714 | "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz",
1715 | "integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=",
1716 | "dev": true,
1717 | "requires": {
1718 | "is-stream": "^1.0.1",
1719 | "readable-stream": "^2.0.1"
1720 | }
1721 | },
1722 | "parse-glob": {
1723 | "version": "3.0.4",
1724 | "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
1725 | "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
1726 | "dev": true,
1727 | "requires": {
1728 | "glob-base": "^0.3.0",
1729 | "is-dotfile": "^1.0.0",
1730 | "is-extglob": "^1.0.0",
1731 | "is-glob": "^2.0.0"
1732 | },
1733 | "dependencies": {
1734 | "is-extglob": {
1735 | "version": "1.0.0",
1736 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
1737 | "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
1738 | "dev": true
1739 | },
1740 | "is-glob": {
1741 | "version": "2.0.1",
1742 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
1743 | "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
1744 | "dev": true,
1745 | "requires": {
1746 | "is-extglob": "^1.0.0"
1747 | }
1748 | }
1749 | }
1750 | },
1751 | "path-dirname": {
1752 | "version": "1.0.2",
1753 | "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
1754 | "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
1755 | "dev": true
1756 | },
1757 | "path-is-absolute": {
1758 | "version": "1.0.1",
1759 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
1760 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
1761 | "dev": true
1762 | },
1763 | "path-parse": {
1764 | "version": "1.0.6",
1765 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
1766 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
1767 | "dev": true
1768 | },
1769 | "pause-stream": {
1770 | "version": "0.0.11",
1771 | "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
1772 | "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
1773 | "dev": true,
1774 | "requires": {
1775 | "through": "~2.3"
1776 | }
1777 | },
1778 | "pend": {
1779 | "version": "1.2.0",
1780 | "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
1781 | "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
1782 | "dev": true
1783 | },
1784 | "performance-now": {
1785 | "version": "2.1.0",
1786 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
1787 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
1788 | "dev": true
1789 | },
1790 | "plugin-error": {
1791 | "version": "0.1.2",
1792 | "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz",
1793 | "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=",
1794 | "dev": true,
1795 | "requires": {
1796 | "ansi-cyan": "^0.1.1",
1797 | "ansi-red": "^0.1.1",
1798 | "arr-diff": "^1.0.1",
1799 | "arr-union": "^2.0.1",
1800 | "extend-shallow": "^1.1.2"
1801 | }
1802 | },
1803 | "preserve": {
1804 | "version": "0.2.0",
1805 | "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
1806 | "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
1807 | "dev": true
1808 | },
1809 | "process-nextick-args": {
1810 | "version": "2.0.0",
1811 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
1812 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
1813 | "dev": true
1814 | },
1815 | "punycode": {
1816 | "version": "1.4.1",
1817 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
1818 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
1819 | "dev": true
1820 | },
1821 | "qs": {
1822 | "version": "6.5.2",
1823 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
1824 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
1825 | "dev": true
1826 | },
1827 | "querystringify": {
1828 | "version": "2.0.0",
1829 | "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz",
1830 | "integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw==",
1831 | "dev": true
1832 | },
1833 | "queue": {
1834 | "version": "3.1.0",
1835 | "resolved": "https://registry.npmjs.org/queue/-/queue-3.1.0.tgz",
1836 | "integrity": "sha1-bEnQHwCeIlZ4h4nyv/rGuLmZBYU=",
1837 | "dev": true,
1838 | "requires": {
1839 | "inherits": "~2.0.0"
1840 | }
1841 | },
1842 | "randomatic": {
1843 | "version": "3.0.0",
1844 | "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz",
1845 | "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==",
1846 | "dev": true,
1847 | "requires": {
1848 | "is-number": "^4.0.0",
1849 | "kind-of": "^6.0.0",
1850 | "math-random": "^1.0.1"
1851 | },
1852 | "dependencies": {
1853 | "is-number": {
1854 | "version": "4.0.0",
1855 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
1856 | "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
1857 | "dev": true
1858 | },
1859 | "kind-of": {
1860 | "version": "6.0.2",
1861 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
1862 | "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
1863 | "dev": true
1864 | }
1865 | }
1866 | },
1867 | "readable-stream": {
1868 | "version": "2.3.6",
1869 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
1870 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
1871 | "dev": true,
1872 | "requires": {
1873 | "core-util-is": "~1.0.0",
1874 | "inherits": "~2.0.3",
1875 | "isarray": "~1.0.0",
1876 | "process-nextick-args": "~2.0.0",
1877 | "safe-buffer": "~5.1.1",
1878 | "string_decoder": "~1.1.1",
1879 | "util-deprecate": "~1.0.1"
1880 | }
1881 | },
1882 | "regex-cache": {
1883 | "version": "0.4.4",
1884 | "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
1885 | "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
1886 | "dev": true,
1887 | "requires": {
1888 | "is-equal-shallow": "^0.1.3"
1889 | }
1890 | },
1891 | "remove-trailing-separator": {
1892 | "version": "1.1.0",
1893 | "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
1894 | "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
1895 | "dev": true
1896 | },
1897 | "repeat-element": {
1898 | "version": "1.1.2",
1899 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
1900 | "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
1901 | "dev": true
1902 | },
1903 | "repeat-string": {
1904 | "version": "1.6.1",
1905 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
1906 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
1907 | "dev": true
1908 | },
1909 | "replace-ext": {
1910 | "version": "1.0.0",
1911 | "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
1912 | "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
1913 | "dev": true
1914 | },
1915 | "request": {
1916 | "version": "2.87.0",
1917 | "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz",
1918 | "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==",
1919 | "dev": true,
1920 | "requires": {
1921 | "aws-sign2": "~0.7.0",
1922 | "aws4": "^1.6.0",
1923 | "caseless": "~0.12.0",
1924 | "combined-stream": "~1.0.5",
1925 | "extend": "~3.0.1",
1926 | "forever-agent": "~0.6.1",
1927 | "form-data": "~2.3.1",
1928 | "har-validator": "~5.0.3",
1929 | "http-signature": "~1.2.0",
1930 | "is-typedarray": "~1.0.0",
1931 | "isstream": "~0.1.2",
1932 | "json-stringify-safe": "~5.0.1",
1933 | "mime-types": "~2.1.17",
1934 | "oauth-sign": "~0.8.2",
1935 | "performance-now": "^2.1.0",
1936 | "qs": "~6.5.1",
1937 | "safe-buffer": "^5.1.1",
1938 | "tough-cookie": "~2.3.3",
1939 | "tunnel-agent": "^0.6.0",
1940 | "uuid": "^3.1.0"
1941 | }
1942 | },
1943 | "request-light": {
1944 | "version": "0.2.3",
1945 | "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.2.3.tgz",
1946 | "integrity": "sha512-KUQTybUtB/WZl7wQGAKenEJkuUX1/DyYX6PJpNEaBVyxE4v6U4Q5P65cmjdKglzcNTGIPZG857JMEAiMWVsoIw==",
1947 | "requires": {
1948 | "http-proxy-agent": "^2.1.0",
1949 | "https-proxy-agent": "^2.2.1",
1950 | "vscode-nls": "^3.2.2"
1951 | }
1952 | },
1953 | "requires-port": {
1954 | "version": "1.0.0",
1955 | "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
1956 | "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
1957 | "dev": true
1958 | },
1959 | "resolve": {
1960 | "version": "1.8.1",
1961 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
1962 | "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
1963 | "dev": true,
1964 | "requires": {
1965 | "path-parse": "^1.0.5"
1966 | }
1967 | },
1968 | "rimraf": {
1969 | "version": "2.6.2",
1970 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
1971 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
1972 | "dev": true,
1973 | "requires": {
1974 | "glob": "^7.0.5"
1975 | }
1976 | },
1977 | "safe-buffer": {
1978 | "version": "5.1.2",
1979 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
1980 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
1981 | "dev": true
1982 | },
1983 | "safer-buffer": {
1984 | "version": "2.1.2",
1985 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1986 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
1987 | "dev": true
1988 | },
1989 | "semver": {
1990 | "version": "5.5.0",
1991 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
1992 | "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
1993 | "dev": true
1994 | },
1995 | "source-map": {
1996 | "version": "0.6.1",
1997 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
1998 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
1999 | "dev": true
2000 | },
2001 | "source-map-support": {
2002 | "version": "0.5.6",
2003 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.6.tgz",
2004 | "integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==",
2005 | "dev": true,
2006 | "requires": {
2007 | "buffer-from": "^1.0.0",
2008 | "source-map": "^0.6.0"
2009 | }
2010 | },
2011 | "split": {
2012 | "version": "0.3.3",
2013 | "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
2014 | "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=",
2015 | "dev": true,
2016 | "requires": {
2017 | "through": "2"
2018 | }
2019 | },
2020 | "sprintf-js": {
2021 | "version": "1.0.3",
2022 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
2023 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
2024 | "dev": true
2025 | },
2026 | "sshpk": {
2027 | "version": "1.14.2",
2028 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
2029 | "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
2030 | "dev": true,
2031 | "requires": {
2032 | "asn1": "~0.2.3",
2033 | "assert-plus": "^1.0.0",
2034 | "bcrypt-pbkdf": "^1.0.0",
2035 | "dashdash": "^1.12.0",
2036 | "ecc-jsbn": "~0.1.1",
2037 | "getpass": "^0.1.1",
2038 | "jsbn": "~0.1.0",
2039 | "safer-buffer": "^2.0.2",
2040 | "tweetnacl": "~0.14.0"
2041 | }
2042 | },
2043 | "stat-mode": {
2044 | "version": "0.2.2",
2045 | "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz",
2046 | "integrity": "sha1-5sgLYjEj19gM8TLOU480YokHJQI=",
2047 | "dev": true
2048 | },
2049 | "stream-combiner": {
2050 | "version": "0.0.4",
2051 | "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
2052 | "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=",
2053 | "dev": true,
2054 | "requires": {
2055 | "duplexer": "~0.1.1"
2056 | }
2057 | },
2058 | "stream-shift": {
2059 | "version": "1.0.0",
2060 | "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
2061 | "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
2062 | "dev": true
2063 | },
2064 | "streamfilter": {
2065 | "version": "1.0.7",
2066 | "resolved": "https://registry.npmjs.org/streamfilter/-/streamfilter-1.0.7.tgz",
2067 | "integrity": "sha512-Gk6KZM+yNA1JpW0KzlZIhjo3EaBJDkYfXtYSbOwNIQ7Zd6006E6+sCFlW1NDvFG/vnXhKmw6TJJgiEQg/8lXfQ==",
2068 | "dev": true,
2069 | "requires": {
2070 | "readable-stream": "^2.0.2"
2071 | }
2072 | },
2073 | "streamifier": {
2074 | "version": "0.1.1",
2075 | "resolved": "https://registry.npmjs.org/streamifier/-/streamifier-0.1.1.tgz",
2076 | "integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8=",
2077 | "dev": true
2078 | },
2079 | "string_decoder": {
2080 | "version": "1.1.1",
2081 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
2082 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
2083 | "dev": true,
2084 | "requires": {
2085 | "safe-buffer": "~5.1.0"
2086 | }
2087 | },
2088 | "strip-ansi": {
2089 | "version": "3.0.1",
2090 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
2091 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
2092 | "dev": true,
2093 | "requires": {
2094 | "ansi-regex": "^2.0.0"
2095 | }
2096 | },
2097 | "strip-bom": {
2098 | "version": "2.0.0",
2099 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
2100 | "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
2101 | "dev": true,
2102 | "requires": {
2103 | "is-utf8": "^0.2.0"
2104 | }
2105 | },
2106 | "strip-bom-stream": {
2107 | "version": "1.0.0",
2108 | "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz",
2109 | "integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=",
2110 | "dev": true,
2111 | "requires": {
2112 | "first-chunk-stream": "^1.0.0",
2113 | "strip-bom": "^2.0.0"
2114 | }
2115 | },
2116 | "supports-color": {
2117 | "version": "2.0.0",
2118 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
2119 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
2120 | "dev": true
2121 | },
2122 | "tar": {
2123 | "version": "2.2.1",
2124 | "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
2125 | "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
2126 | "dev": true,
2127 | "requires": {
2128 | "block-stream": "*",
2129 | "fstream": "^1.0.2",
2130 | "inherits": "2"
2131 | }
2132 | },
2133 | "through": {
2134 | "version": "2.3.8",
2135 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
2136 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
2137 | "dev": true
2138 | },
2139 | "through2": {
2140 | "version": "2.0.3",
2141 | "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
2142 | "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
2143 | "dev": true,
2144 | "requires": {
2145 | "readable-stream": "^2.1.5",
2146 | "xtend": "~4.0.1"
2147 | }
2148 | },
2149 | "through2-filter": {
2150 | "version": "2.0.0",
2151 | "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz",
2152 | "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=",
2153 | "dev": true,
2154 | "requires": {
2155 | "through2": "~2.0.0",
2156 | "xtend": "~4.0.0"
2157 | }
2158 | },
2159 | "to-absolute-glob": {
2160 | "version": "0.1.1",
2161 | "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz",
2162 | "integrity": "sha1-HN+kcqnvUMI57maZm2YsoOs5k38=",
2163 | "dev": true,
2164 | "requires": {
2165 | "extend-shallow": "^2.0.1"
2166 | },
2167 | "dependencies": {
2168 | "extend-shallow": {
2169 | "version": "2.0.1",
2170 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
2171 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
2172 | "dev": true,
2173 | "requires": {
2174 | "is-extendable": "^0.1.0"
2175 | }
2176 | }
2177 | }
2178 | },
2179 | "tough-cookie": {
2180 | "version": "2.3.4",
2181 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
2182 | "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
2183 | "dev": true,
2184 | "requires": {
2185 | "punycode": "^1.4.1"
2186 | }
2187 | },
2188 | "tslib": {
2189 | "version": "1.9.3",
2190 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
2191 | "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
2192 | "dev": true
2193 | },
2194 | "tslint": {
2195 | "version": "5.11.0",
2196 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.11.0.tgz",
2197 | "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=",
2198 | "dev": true,
2199 | "requires": {
2200 | "babel-code-frame": "^6.22.0",
2201 | "builtin-modules": "^1.1.1",
2202 | "chalk": "^2.3.0",
2203 | "commander": "^2.12.1",
2204 | "diff": "^3.2.0",
2205 | "glob": "^7.1.1",
2206 | "js-yaml": "^3.7.0",
2207 | "minimatch": "^3.0.4",
2208 | "resolve": "^1.3.2",
2209 | "semver": "^5.3.0",
2210 | "tslib": "^1.8.0",
2211 | "tsutils": "^2.27.2"
2212 | }
2213 | },
2214 | "tslint-config-prettier": {
2215 | "version": "1.14.0",
2216 | "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.14.0.tgz",
2217 | "integrity": "sha512-SomD+aLvAwoihMtyCfkhhWKt9wcpSY2ZpgDV6OuxLYi8+7uOwE2g03aa+jJLSmY0Ys8s3ZLM5Iwfuwu3giCSQQ==",
2218 | "dev": true
2219 | },
2220 | "tsutils": {
2221 | "version": "2.29.0",
2222 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
2223 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
2224 | "dev": true,
2225 | "requires": {
2226 | "tslib": "^1.8.1"
2227 | }
2228 | },
2229 | "tunnel-agent": {
2230 | "version": "0.6.0",
2231 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
2232 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
2233 | "dev": true,
2234 | "requires": {
2235 | "safe-buffer": "^5.0.1"
2236 | }
2237 | },
2238 | "tweetnacl": {
2239 | "version": "0.14.5",
2240 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
2241 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
2242 | "dev": true,
2243 | "optional": true
2244 | },
2245 | "typescript": {
2246 | "version": "2.9.2",
2247 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
2248 | "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
2249 | "dev": true
2250 | },
2251 | "unique-stream": {
2252 | "version": "2.2.1",
2253 | "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz",
2254 | "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=",
2255 | "dev": true,
2256 | "requires": {
2257 | "json-stable-stringify": "^1.0.0",
2258 | "through2-filter": "^2.0.0"
2259 | }
2260 | },
2261 | "url-parse": {
2262 | "version": "1.4.3",
2263 | "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.3.tgz",
2264 | "integrity": "sha512-rh+KuAW36YKo0vClhQzLLveoj8FwPJNu65xLb7Mrt+eZht0IPT0IXgSv8gcMegZ6NvjJUALf6Mf25POlMwD1Fw==",
2265 | "dev": true,
2266 | "requires": {
2267 | "querystringify": "^2.0.0",
2268 | "requires-port": "^1.0.0"
2269 | }
2270 | },
2271 | "util-deprecate": {
2272 | "version": "1.0.2",
2273 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
2274 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
2275 | "dev": true
2276 | },
2277 | "util.promisify": {
2278 | "version": "1.0.0",
2279 | "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
2280 | "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==",
2281 | "requires": {
2282 | "define-properties": "^1.1.2",
2283 | "object.getownpropertydescriptors": "^2.0.3"
2284 | }
2285 | },
2286 | "uuid": {
2287 | "version": "3.3.2",
2288 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
2289 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
2290 | "dev": true
2291 | },
2292 | "vali-date": {
2293 | "version": "1.0.0",
2294 | "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz",
2295 | "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=",
2296 | "dev": true
2297 | },
2298 | "verror": {
2299 | "version": "1.10.0",
2300 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
2301 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
2302 | "dev": true,
2303 | "requires": {
2304 | "assert-plus": "^1.0.0",
2305 | "core-util-is": "1.0.2",
2306 | "extsprintf": "^1.2.0"
2307 | }
2308 | },
2309 | "vinyl": {
2310 | "version": "0.4.6",
2311 | "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
2312 | "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=",
2313 | "dev": true,
2314 | "requires": {
2315 | "clone": "^0.2.0",
2316 | "clone-stats": "^0.0.1"
2317 | }
2318 | },
2319 | "vinyl-fs": {
2320 | "version": "2.4.4",
2321 | "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz",
2322 | "integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=",
2323 | "dev": true,
2324 | "requires": {
2325 | "duplexify": "^3.2.0",
2326 | "glob-stream": "^5.3.2",
2327 | "graceful-fs": "^4.0.0",
2328 | "gulp-sourcemaps": "1.6.0",
2329 | "is-valid-glob": "^0.3.0",
2330 | "lazystream": "^1.0.0",
2331 | "lodash.isequal": "^4.0.0",
2332 | "merge-stream": "^1.0.0",
2333 | "mkdirp": "^0.5.0",
2334 | "object-assign": "^4.0.0",
2335 | "readable-stream": "^2.0.4",
2336 | "strip-bom": "^2.0.0",
2337 | "strip-bom-stream": "^1.0.0",
2338 | "through2": "^2.0.0",
2339 | "through2-filter": "^2.0.0",
2340 | "vali-date": "^1.0.0",
2341 | "vinyl": "^1.0.0"
2342 | },
2343 | "dependencies": {
2344 | "clone": {
2345 | "version": "1.0.4",
2346 | "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
2347 | "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
2348 | "dev": true
2349 | },
2350 | "replace-ext": {
2351 | "version": "0.0.1",
2352 | "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
2353 | "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=",
2354 | "dev": true
2355 | },
2356 | "vinyl": {
2357 | "version": "1.2.0",
2358 | "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
2359 | "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
2360 | "dev": true,
2361 | "requires": {
2362 | "clone": "^1.0.0",
2363 | "clone-stats": "^0.0.1",
2364 | "replace-ext": "0.0.1"
2365 | }
2366 | }
2367 | }
2368 | },
2369 | "vinyl-source-stream": {
2370 | "version": "1.1.2",
2371 | "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-1.1.2.tgz",
2372 | "integrity": "sha1-YrU6E1YQqJbpjKlr7jqH8Aio54A=",
2373 | "dev": true,
2374 | "requires": {
2375 | "through2": "^2.0.3",
2376 | "vinyl": "^0.4.3"
2377 | }
2378 | },
2379 | "vscode": {
2380 | "version": "1.1.18",
2381 | "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.18.tgz",
2382 | "integrity": "sha512-SyDw4qFwZ+WthZX7RWp71PNiWLF7VhpM65j2oryY/6jtSORd8qH6J8vclwWZJ6Jvu0EH7JamO2RWNfBfsMR9Zw==",
2383 | "dev": true,
2384 | "requires": {
2385 | "glob": "^7.1.2",
2386 | "gulp-chmod": "^2.0.0",
2387 | "gulp-filter": "^5.0.1",
2388 | "gulp-gunzip": "1.0.0",
2389 | "gulp-remote-src-vscode": "^0.5.0",
2390 | "gulp-symdest": "^1.1.0",
2391 | "gulp-untar": "^0.0.7",
2392 | "gulp-vinyl-zip": "^2.1.0",
2393 | "mocha": "^4.0.1",
2394 | "request": "^2.83.0",
2395 | "semver": "^5.4.1",
2396 | "source-map-support": "^0.5.0",
2397 | "url-parse": "^1.1.9",
2398 | "vinyl-source-stream": "^1.1.0"
2399 | }
2400 | },
2401 | "vscode-debugadapter": {
2402 | "version": "1.27.0",
2403 | "resolved": "https://registry.npmjs.org/vscode-debugadapter/-/vscode-debugadapter-1.27.0.tgz",
2404 | "integrity": "sha512-JwE3fWmKnpjYnFqhff0umqIJi4c26gh/CXZ5LNb4gLIuPd5sEAEoEbGeCcAaajuTrVxFw6FlYEep9y+IQCf+ww==",
2405 | "requires": {
2406 | "vscode-debugprotocol": "1.27.0"
2407 | }
2408 | },
2409 | "vscode-debugprotocol": {
2410 | "version": "1.27.0",
2411 | "resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.27.0.tgz",
2412 | "integrity": "sha512-cg3lKqVwxNpO2pLBxSwkBvE7w06+bHfbA/s14u8izSWyhJtPgRu1lQwi5tEyTRuwfEugfoPwerYL4vtY6teQDw=="
2413 | },
2414 | "vscode-nls": {
2415 | "version": "3.2.4",
2416 | "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-3.2.4.tgz",
2417 | "integrity": "sha512-FTjdqa4jDDoBjJqr36O8lmmZf/55kQ2w4ZY/+GL6K92fq765BqO3aYw21atnXUno/P04V5DWagNl4ybDIndJsw=="
2418 | },
2419 | "wrappy": {
2420 | "version": "1.0.2",
2421 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
2422 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
2423 | "dev": true
2424 | },
2425 | "xtend": {
2426 | "version": "4.0.1",
2427 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
2428 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
2429 | "dev": true
2430 | },
2431 | "yauzl": {
2432 | "version": "2.10.0",
2433 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
2434 | "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
2435 | "dev": true,
2436 | "requires": {
2437 | "buffer-crc32": "~0.2.3",
2438 | "fd-slicer": "~1.1.0"
2439 | }
2440 | },
2441 | "yazl": {
2442 | "version": "2.4.3",
2443 | "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.4.3.tgz",
2444 | "integrity": "sha1-7CblzIfVYBud+EMtvdPNLlFzoHE=",
2445 | "dev": true,
2446 | "requires": {
2447 | "buffer-crc32": "~0.2.3"
2448 | }
2449 | }
2450 | }
2451 | }
2452 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vscode-sentry",
3 | "displayName": "Sentry",
4 | "description": "Editor integration for sentry.io",
5 | "version": "0.0.1",
6 | "repository": "https://github.com/getsentry/vscode-sentry",
7 | "publisher": "Sentry",
8 | "license": "MIT",
9 | "engines": {
10 | "vscode": "^1.25.0"
11 | },
12 | "categories": [
13 | "Other"
14 | ],
15 | "activationEvents": [
16 | "*"
17 | ],
18 | "main": "./out/extension",
19 | "contributes": {
20 | "configuration": {
21 | "type": "object",
22 | "title": "Sentry extension configuration",
23 | "properties": {
24 | "sentry.enabled": {
25 | "type": "boolean",
26 | "default": true,
27 | "description": "Enables or disables all Sentry functionality."
28 | },
29 | "sentry.serverUrl": {
30 | "type": "string",
31 | "default": "https://sentry.io",
32 | "description": "Sentry server URL for on-premise."
33 | },
34 | "sentry.projects": {
35 | "type": "array",
36 | "default": [],
37 | "items": {
38 | "type": "string"
39 | },
40 | "description": "Organization and project slugs used for searching issues (e.g. \"my-org/my-project\")"
41 | },
42 | "sentry.searchPaths": {
43 | "type": "array",
44 | "default": [],
45 | "items": {
46 | "type": "string"
47 | },
48 | "description": "Local paths to search for source files. The workspace directory and common system locations will be searched by default."
49 | }
50 | }
51 | },
52 | "commands": [
53 | {
54 | "command": "sentry.showProjectPick",
55 | "title": "Select Project",
56 | "category": "Sentry"
57 | },
58 | {
59 | "command": "sentry.showIssueSearch",
60 | "title": "Search Issues",
61 | "category": "Sentry"
62 | }
63 | ],
64 | "debuggers": [
65 | {
66 | "type": "sentry",
67 | "label": "Sentry Virtual Debugger",
68 | "program": "./out/debugger/launcher.js",
69 | "runtime": "node"
70 | }
71 | ],
72 | "menus": {
73 | "commandPalette": [
74 | {
75 | "command": "sentry.showProjectPick",
76 | "when": "sentry:enabled"
77 | },
78 | {
79 | "command": "sentry.showIssueSearch",
80 | "when": "sentry:enabled"
81 | }
82 | ]
83 | }
84 | },
85 | "scripts": {
86 | "vscode:prepublish": "npm run compile",
87 | "compile": "tsc -p ./",
88 | "watch": "tsc -watch -p ./",
89 | "postinstall": "node ./node_modules/vscode/bin/install",
90 | "test": "npm run compile && node ./node_modules/vscode/bin/test"
91 | },
92 | "devDependencies": {
93 | "@sentry/typescript": "^4.0.0-beta.12",
94 | "@types/ini": "^1.3.29",
95 | "@types/mocha": "^2.2.42",
96 | "@types/node": "^7.0.43",
97 | "@types/util.promisify": "^1.0.0",
98 | "tslint": "^5.8.0",
99 | "typescript": "^2.6.1",
100 | "vscode": "^1.1.6"
101 | },
102 | "dependencies": {
103 | "ini": "^1.3.5",
104 | "request-light": "^0.2.3",
105 | "util.promisify": "^1.0.0",
106 | "vscode-debugadapter": "1.27.0",
107 | "vscode-debugprotocol": "1.27.0"
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/resources/sentry-glyph.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/commands/base.ts:
--------------------------------------------------------------------------------
1 | import { commands, Disposable } from 'vscode';
2 |
3 | export abstract class SentryCommand {
4 | private command: string;
5 | private disposable?: Disposable;
6 |
7 | public constructor(command: string) {
8 | this.command = command;
9 | }
10 |
11 | protected abstract async run(args: A): Promise;
12 |
13 | public async execute(args: A): Promise {
14 | commands.executeCommand(this.command, args);
15 | }
16 |
17 | public register(): this {
18 | this.disposable = commands.registerCommand(this.command, (args: A) => this.run(args));
19 |
20 | return this;
21 | }
22 |
23 | public dispose(): void {
24 | if (this.disposable) {
25 | this.disposable.dispose();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/commands/builtin.ts:
--------------------------------------------------------------------------------
1 | import { commands, Uri } from 'vscode';
2 |
3 | enum VSCodeCommands {
4 | Open = 'vscode.open',
5 | SetContext = 'setContext',
6 | }
7 |
8 | export enum SentryContext {
9 | Enabled = 'sentry:enabled',
10 | }
11 |
12 | export function setContext(key: SentryContext | string, value: any): Thenable<{} | undefined> {
13 | return commands.executeCommand(VSCodeCommands.SetContext, key, value);
14 | }
15 |
16 | export function openUrl(url: Uri | string): Thenable<{} | undefined> {
17 | const uri = typeof url === 'string' ? Uri.parse(url) : url;
18 | return commands.executeCommand(VSCodeCommands.Open, uri);
19 | }
20 |
--------------------------------------------------------------------------------
/src/commands/index.ts:
--------------------------------------------------------------------------------
1 | import { ExtensionContext } from 'vscode';
2 | import { openInBrowser } from './openInBrowser';
3 | import { showIssueActions } from './showIssueActions';
4 | import { showIssueResults } from './showIssueResults';
5 | import { showIssueSearch } from './showIssueSearch';
6 | import { showProjectPick } from './showProjectPick';
7 | import { startDebugger } from './startDebugger';
8 |
9 | export function configureCommands(context: ExtensionContext): void {
10 | context.subscriptions.push(showProjectPick.register());
11 | context.subscriptions.push(showIssueSearch.register());
12 | context.subscriptions.push(showIssueResults.register());
13 | context.subscriptions.push(showIssueActions.register());
14 | context.subscriptions.push(startDebugger.register());
15 | context.subscriptions.push(openInBrowser.register());
16 | }
17 |
--------------------------------------------------------------------------------
/src/commands/openInBrowser.ts:
--------------------------------------------------------------------------------
1 | import { window } from 'vscode';
2 | import { Issue } from '../sentry';
3 | import { SentryCommand } from './base';
4 | import { openUrl } from './builtin';
5 |
6 | export const COMMAND_OPEN_IN_BROWSER = 'sentry.OpenInBrowser';
7 |
8 | export interface OpenInBrowserArgs {
9 | issue: Issue;
10 | }
11 |
12 | export class OpenInBrowserCommand extends SentryCommand {
13 | public constructor() {
14 | super(COMMAND_OPEN_IN_BROWSER);
15 | }
16 |
17 | protected async run(args: OpenInBrowserArgs): Promise {
18 | try {
19 | await openUrl(args.issue.permalink);
20 | } catch (e) {
21 | window.showErrorMessage(`Could not open Sentry issue: ${e}`);
22 | }
23 | }
24 | }
25 |
26 | export const openInBrowser = new OpenInBrowserCommand();
27 |
--------------------------------------------------------------------------------
/src/commands/showIssueActions.ts:
--------------------------------------------------------------------------------
1 | import { window } from 'vscode';
2 | import { CommandQuickPickItem } from '../pick';
3 | import { Issue } from '../sentry';
4 | import { SentryCommand } from './base';
5 | import { openInBrowser } from './openInBrowser';
6 | import { startDebugger } from './startDebugger';
7 |
8 | export const COMMAND_SHOW_ISSUE_ACTIONS = 'sentry.showIssueActions';
9 |
10 | export interface ShowIssueActionsArgs {
11 | issue: Issue;
12 | }
13 |
14 | export class ShowIssueActionsCommand extends SentryCommand {
15 | public constructor() {
16 | super(COMMAND_SHOW_ISSUE_ACTIONS);
17 | }
18 |
19 | protected async run(args: ShowIssueActionsArgs): Promise {
20 | const cmds = [
21 | CommandQuickPickItem.from({ label: 'Launch debugger on Issue' }, startDebugger, {
22 | issue: args.issue,
23 | }),
24 | CommandQuickPickItem.from({ label: 'Open issue in browser' }, openInBrowser, {
25 | issue: args.issue,
26 | }),
27 | ];
28 |
29 | const pick = await window.showQuickPick(cmds);
30 | if (!pick) {
31 | return;
32 | }
33 |
34 | pick.execute();
35 | }
36 | }
37 |
38 | export const showIssueActions = new ShowIssueActionsCommand();
39 |
--------------------------------------------------------------------------------
/src/commands/showIssueResults.ts:
--------------------------------------------------------------------------------
1 | import { CancellationTokenSource, window } from 'vscode';
2 | import { CommandQuickPickItem } from '../pick';
3 | import { Issue, searchIssues } from '../sentry';
4 | import { SentryCommand } from './base';
5 | import { showIssueActions } from './showIssueActions';
6 |
7 | export const COMMAND_SHOW_ISSUE_RESULTS = 'sentry.showIssueResults';
8 |
9 | export interface ShowIssueResultsArgs {
10 | search?: string;
11 | issues?: Issue[];
12 | }
13 |
14 | function makeIssueItem(issue: Issue): CommandQuickPickItem {
15 | const item = {
16 | description: issue.culprit,
17 | detail: issue.metadata.value,
18 | label: `${issue.shortId}: ${issue.metadata.type}`,
19 | };
20 | return CommandQuickPickItem.from(item, showIssueActions, { issue });
21 | }
22 |
23 | async function loadIssueResults(
24 | cancellation: CancellationTokenSource,
25 | search: string,
26 | ): Promise {
27 | try {
28 | const issues = await searchIssues(search);
29 |
30 | if (issues.length === 0) {
31 | cancellation.cancel();
32 | window.showInformationMessage('Sorry, no issues match your search.');
33 | }
34 |
35 | return issues.map(makeIssueItem);
36 | } catch (e) {
37 | cancellation.cancel();
38 | window.showErrorMessage(`Could not search issues: ${e}`);
39 | return [];
40 | } finally {
41 | cancellation.dispose();
42 | }
43 | }
44 |
45 | export class ShowIssueResultsCommand extends SentryCommand {
46 | public constructor() {
47 | super(COMMAND_SHOW_ISSUE_RESULTS);
48 | }
49 |
50 | protected async run(args: ShowIssueResultsArgs): Promise {
51 | let items;
52 | let cancellation;
53 |
54 | if (args.issues) {
55 | items = args.issues.map(makeIssueItem);
56 | } else if (args.search) {
57 | cancellation = new CancellationTokenSource();
58 | items = loadIssueResults(cancellation, args.search);
59 | } else {
60 | throw new Error('Missing issue search query');
61 | }
62 |
63 | const pick = await window.showQuickPick(
64 | items,
65 | {
66 | matchOnDescription: true,
67 | matchOnDetail: true,
68 | placeHolder: 'Please select an issue from the list',
69 | },
70 | cancellation && cancellation.token,
71 | );
72 |
73 | if (!pick) {
74 | return;
75 | }
76 |
77 | pick.execute();
78 | }
79 | }
80 |
81 | export const showIssueResults = new ShowIssueResultsCommand();
82 |
--------------------------------------------------------------------------------
/src/commands/showIssueSearch.ts:
--------------------------------------------------------------------------------
1 | import { window } from 'vscode';
2 | import { SentryCommand } from './base';
3 | import { showIssueResults } from './showIssueResults';
4 |
5 | export const COMMAND_SHOW_ISSUE_SEARCH = 'sentry.showIssueSearch';
6 | const DEFAULT_QUERY = 'is:unresolved ';
7 |
8 | export interface ShowIssueSearchArgs {
9 | search?: string;
10 | }
11 |
12 | function getValueSelection(query: string): [number, number] {
13 | if (query.startsWith(DEFAULT_QUERY)) {
14 | return [DEFAULT_QUERY.length, query.length];
15 | } else {
16 | return [0, query.length];
17 | }
18 | }
19 |
20 | export class ShowIssueSearchCommand extends SentryCommand {
21 | public constructor() {
22 | super(COMMAND_SHOW_ISSUE_SEARCH);
23 | }
24 |
25 | protected async run(args: ShowIssueSearchArgs = {}): Promise {
26 | // TODO: Perform auto-complete with a dynamic QuickPick instead.
27 | const initialQuery = args.search || DEFAULT_QUERY;
28 | const selection = getValueSelection(initialQuery);
29 |
30 | const search = await window.showInputBox({
31 | placeHolder: 'search by issue id, message, tags, status, or tag or paste an issue link',
32 | prompt: 'Please search for an issue',
33 | value: initialQuery,
34 | valueSelection: selection,
35 | });
36 |
37 | if (!search) {
38 | // Cancel silently also for empty strings. This is just like pressing ESC,
39 | // for now.
40 | return;
41 | }
42 |
43 | showIssueResults.execute({ search });
44 | }
45 | }
46 |
47 | export const showIssueSearch = new ShowIssueSearchCommand();
48 |
--------------------------------------------------------------------------------
/src/commands/showProjectPick.ts:
--------------------------------------------------------------------------------
1 | import { CancellationTokenSource, QuickPickItem, window } from 'vscode';
2 | import { configuration } from '../config';
3 | import { listProjects, Project } from '../sentry';
4 | import { SentryCommand } from './base';
5 |
6 | export const COMMAND_SHOW_PROJECT_PICK = 'sentry.showProjectPick';
7 |
8 | async function withCancellation(
9 | cancellation: CancellationTokenSource,
10 | func: () => Promise,
11 | ): Promise {
12 | try {
13 | return await func();
14 | } catch (e) {
15 | cancellation.cancel();
16 | window.showErrorMessage(`Could not load projects: ${e}`);
17 | return [];
18 | } finally {
19 | cancellation.dispose();
20 | }
21 | }
22 |
23 | function compareProjects(a: Project, b: Project): -1 | 0 | 1 {
24 | if (a.organization.slug < b.organization.slug) {
25 | return -1;
26 | }
27 | if (a.organization.slug > b.organization.slug) {
28 | return 1;
29 | }
30 |
31 | if (a.team.slug < b.team.slug) {
32 | return -1;
33 | }
34 | if (a.team.slug > b.team.slug) {
35 | return 1;
36 | }
37 |
38 | if (a.slug < b.slug) {
39 | return -1;
40 | }
41 | if (a.slug > b.slug) {
42 | return 1;
43 | }
44 |
45 | return 0;
46 | }
47 |
48 | interface ProjectQuickPickItem extends QuickPickItem {
49 | id: string;
50 | }
51 |
52 | async function loadProjects(): Promise {
53 | const projects = await listProjects();
54 | projects.sort(compareProjects);
55 |
56 | return projects.map(project => ({
57 | description: `#${project.team.slug}`,
58 | id: `${project.organization.slug}/${project.slug}`,
59 | label: `${project.organization.slug} / ${project.slug}`,
60 | }));
61 | }
62 |
63 | export class ShowProjectPickCommand extends SentryCommand {
64 | public constructor() {
65 | super(COMMAND_SHOW_PROJECT_PICK);
66 | }
67 |
68 | protected async run(): Promise {
69 | const cancellation = new CancellationTokenSource();
70 | const projects = withCancellation(cancellation, loadProjects);
71 |
72 | // TODO: Create multi select here
73 | const pick = await window.showQuickPick(
74 | projects,
75 | {
76 | matchOnDescription: true,
77 | matchOnDetail: true,
78 | placeHolder: 'Please select your Sentry project',
79 | },
80 | cancellation.token,
81 | );
82 |
83 | if (pick) {
84 | configuration.setProjects([pick.id]);
85 | }
86 | }
87 | }
88 |
89 | export const showProjectPick = new ShowProjectPickCommand();
90 |
--------------------------------------------------------------------------------
/src/commands/startDebugger.ts:
--------------------------------------------------------------------------------
1 | import { window } from 'vscode';
2 | import { startDebugging } from '../debugger';
3 | import { Issue, loadLatestEvent } from '../sentry';
4 | import { SentryCommand } from './base';
5 |
6 | export const COMMAND_START_DEBUGGER = 'sentry.startDebugger';
7 |
8 | export interface StartDebuggerArgs {
9 | issue: Issue;
10 | }
11 |
12 | export class StartDebuggerCommand extends SentryCommand {
13 | public constructor() {
14 | super(COMMAND_START_DEBUGGER);
15 | }
16 |
17 | protected async run(args: StartDebuggerArgs): Promise {
18 | try {
19 | // TODO: Show loading indicator and allow cancellation
20 | const event = await loadLatestEvent(args.issue);
21 | await startDebugging(event);
22 | } catch (e) {
23 | window.showErrorMessage(`Could not start debugger: ${e}`);
24 | }
25 | }
26 | }
27 |
28 | export const startDebugger = new StartDebuggerCommand();
29 |
--------------------------------------------------------------------------------
/src/config.ts:
--------------------------------------------------------------------------------
1 | import * as request from 'request-light';
2 | import { ConfigurationChangeEvent, Disposable, ExtensionContext, workspace } from 'vscode';
3 | import { SentryContext, setContext } from './commands/builtin';
4 | import { affectsSearchPaths, discoverSearchPaths } from './paths';
5 | import { statusbar } from './statusbar';
6 |
7 | const NAMESPACE = 'sentry';
8 |
9 | export enum SentryConfig {
10 | Enabled = 'enabled',
11 | ServerUrl = 'serverUrl',
12 | Projects = 'projects',
13 | SearchPaths = 'searchPaths',
14 | }
15 |
16 | function configName(config: SentryConfig): string {
17 | return `${NAMESPACE}.${config}`;
18 | }
19 |
20 | export class Configuration {
21 | private subscription?: Disposable;
22 |
23 | private serverUrl?: string;
24 | private projects?: string[];
25 | private searchPaths?: string[];
26 | private systemPaths?: string[];
27 |
28 | public configure(context: ExtensionContext): void {
29 | this.subscription = workspace.onDidChangeConfiguration(this.update, this);
30 | context.subscriptions.push(this);
31 |
32 | // Force initialization of all config variables
33 | this.update({ affectsConfiguration: () => true });
34 | }
35 |
36 | public getServerUrl(): string {
37 | return this.serverUrl || 'https://sentry.io';
38 | }
39 |
40 | public getProjects(): string[] {
41 | return this.projects || [];
42 | }
43 |
44 | public setProjects(projects: string[]): void {
45 | this.set(SentryConfig.Projects, projects);
46 | }
47 |
48 | public getSearchPaths(): string[] {
49 | return (this.searchPaths || []).concat(this.systemPaths || []);
50 | }
51 |
52 | public dispose(): void {
53 | if (this.subscription) {
54 | this.subscription.dispose();
55 | }
56 | }
57 |
58 | private get(config: SentryConfig): T | undefined;
59 |
60 | private get(config: SentryConfig, defaultValue: T): T;
61 |
62 | private get(config: SentryConfig, defaultValue?: T): T | undefined {
63 | return workspace.getConfiguration(NAMESPACE).get(config, defaultValue);
64 | }
65 |
66 | private set(config: SentryConfig, value: any): void {
67 | workspace.getConfiguration(NAMESPACE).update(config, value, false);
68 | }
69 |
70 | private update(event: ConfigurationChangeEvent): void {
71 | if (!event.affectsConfiguration(NAMESPACE)) {
72 | return;
73 | }
74 |
75 | if (event.affectsConfiguration(configName(SentryConfig.Enabled))) {
76 | const enabled = this.get(SentryConfig.Enabled, true);
77 | setContext(SentryContext.Enabled, enabled);
78 | }
79 |
80 | if (event.affectsConfiguration(configName(SentryConfig.ServerUrl))) {
81 | this.serverUrl = this.get(SentryConfig.ServerUrl);
82 | }
83 |
84 | if (event.affectsConfiguration(configName(SentryConfig.Projects))) {
85 | this.projects = this.get(SentryConfig.Projects, []);
86 | statusbar.updateFromProjects(this.projects);
87 | }
88 |
89 | if (event.affectsConfiguration(configName(SentryConfig.SearchPaths))) {
90 | this.searchPaths = this.get(SentryConfig.SearchPaths, []);
91 | }
92 |
93 | if (affectsSearchPaths(event)) {
94 | discoverSearchPaths()
95 | .then(paths => (this.systemPaths = paths))
96 | .catch(e => console.error('Error loading searchPaths:', e));
97 | }
98 |
99 | if (event.affectsConfiguration('http')) {
100 | const http = workspace.getConfiguration('http');
101 | const proxyUrl = http.get('proxy', '');
102 | const strictSSL = http.get('strictSSL', false);
103 | request.configure(proxyUrl, strictSSL);
104 | }
105 | }
106 | }
107 |
108 | export const configuration = new Configuration();
109 |
--------------------------------------------------------------------------------
/src/debugger/index.ts:
--------------------------------------------------------------------------------
1 | import * as Net from 'net';
2 | import {
3 | CancellationToken,
4 | debug,
5 | DebugConfiguration,
6 | DebugConfigurationProvider,
7 | ExtensionContext,
8 | ProviderResult,
9 | window,
10 | workspace,
11 | WorkspaceFolder,
12 | } from 'vscode';
13 | import { configuration } from '../config';
14 | import { Event } from '../sentry';
15 | import { exec, withTempFile } from '../utils';
16 | import { SentryDebugSession } from './server';
17 |
18 | /*
19 | * Set the following compile time flag to true if the
20 | * debug adapter should run inside the extension host.
21 | * Please note: the test suite does no longer work in this mode.
22 | */
23 | const EMBED_DEBUG_ADAPTER = true;
24 |
25 | class SentryConfigurationProvider implements DebugConfigurationProvider {
26 | private _server?: Net.Server;
27 |
28 | public resolveDebugConfiguration(
29 | _folder: WorkspaceFolder | undefined,
30 | config: DebugConfiguration,
31 | _token?: CancellationToken,
32 | ): ProviderResult {
33 | if (!config.event) {
34 | // The event is required. We need to abort if it is missing.
35 | return window.showInformationMessage('Missing event payload').then(() => undefined);
36 | }
37 |
38 | if (!config.searchPaths) {
39 | config.searchPaths = [];
40 | }
41 |
42 | // Start a debug server in-process to allow debugging in development.
43 | // In production, VSCode will spawn a separate process.
44 | if (EMBED_DEBUG_ADAPTER) {
45 | if (!this._server) {
46 | this._server = Net.createServer(socket => {
47 | const session = new SentryDebugSession();
48 | session.setRunAsServer(true);
49 | session.start(socket as NodeJS.ReadableStream, socket);
50 | }).listen(0);
51 | }
52 |
53 | // Make VS Code connect to debug server instead of launching debug adapter
54 | config.debugServer = this._server.address().port;
55 | }
56 |
57 | return config;
58 | }
59 |
60 | public dispose(): void {
61 | if (this._server) {
62 | this._server.close();
63 | }
64 | }
65 | }
66 |
67 | export async function startDebugging(event: Event): Promise {
68 | if (!(await checkRevision(event))) {
69 | return;
70 | }
71 | await withTempFile(JSON.stringify(event), tempFile =>
72 | debug.startDebugging(undefined, {
73 | // Interface arguments
74 | name: 'View',
75 | request: 'launch',
76 | type: 'sentry',
77 |
78 | // Custom arguments
79 | event: tempFile,
80 | searchPaths: configuration.getSearchPaths(),
81 | }),
82 | );
83 | }
84 |
85 | export function configureDebugger(context: ExtensionContext): void {
86 | const provider = new SentryConfigurationProvider();
87 | context.subscriptions.push(debug.registerDebugConfigurationProvider('sentry', provider));
88 | context.subscriptions.push(provider);
89 | }
90 |
91 | async function checkRevision(event: Event): Promise {
92 | if (!event.release || !event.release.version) {
93 | return true;
94 | }
95 |
96 | const version = event.release.version;
97 | for (const folder of workspace.workspaceFolders || []) {
98 | try {
99 | const output = await exec('git', ['rev-parse', 'HEAD'], { cwd: folder.uri.fsPath });
100 | if (output.startsWith(version)) {
101 | return true;
102 | }
103 | } catch (e) {
104 | continue;
105 | }
106 | }
107 |
108 | const buttonClicked = await window.showWarningMessage(
109 | getRevisionDescription(version),
110 | 'Continue Debugging',
111 | 'Cancel',
112 | );
113 |
114 | return buttonClicked === 'Continue Debugging';
115 | }
116 |
117 | function getRevisionDescription(version: string): string {
118 | return (
119 | `Mismatching revision: Event occurred at revision \`${version.substr(0, 7)} \`, ` +
120 | `but none of your workplace folders seem to have that revision checked out. Make ` +
121 | `sure the code checked out on your computer matches the code in production. For ` +
122 | `example, go to your project folder and run: \`git checkout ${version}\`. You ` +
123 | `might also have to reinstall dependencies for vscode-sentry to pick up the ` +
124 | `correct files.`
125 | );
126 | }
127 |
--------------------------------------------------------------------------------
/src/debugger/indexMapper.ts:
--------------------------------------------------------------------------------
1 | type Index = number | string;
2 |
3 | interface Map {
4 | id?: number;
5 | children: Record;
6 | }
7 |
8 | /**
9 | * Mapping between arrays and numbers. Useful for creating variableReferences, frameIds and whatnot.
10 | */
11 | export class IndexMapper {
12 | private toSingle: Map = { children: {} };
13 | private toMultiple: Record = [];
14 | private nextId: number = 1;
15 |
16 | public upsertArray(indices: Index[]): number {
17 | const id = this.addToMap(this.toSingle, indices);
18 | this.toMultiple[id] = indices;
19 | return id;
20 | }
21 |
22 | public getArray(id: number): Index[] {
23 | return this.toMultiple[id].slice();
24 | }
25 |
26 | private addToMap(map: Map, indices: Index[]): number {
27 | if (indices.length === 0) {
28 | map.id = map.id || this.nextId++;
29 | return map.id;
30 | } else {
31 | const newMap = (map.children[indices[0]] = map.children[indices[0]] || { children: {} });
32 | return this.addToMap(newMap, indices.slice(1));
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/debugger/launcher.ts:
--------------------------------------------------------------------------------
1 | import { SentryDebugSession } from './server';
2 |
3 | SentryDebugSession.run(SentryDebugSession);
4 |
--------------------------------------------------------------------------------
/src/debugger/server.ts:
--------------------------------------------------------------------------------
1 | import * as fs from 'fs';
2 | import * as path from 'path';
3 | import * as promisify from 'util.promisify';
4 | import { workspace } from 'vscode';
5 | import {
6 | InitializedEvent,
7 | Logger,
8 | logger,
9 | LoggingDebugSession,
10 | Scope,
11 | Source,
12 | StackFrame,
13 | StoppedEvent,
14 | Thread,
15 | } from 'vscode-debugadapter';
16 | import { DebugProtocol } from 'vscode-debugprotocol';
17 | import { Event, EventException, Frame } from '../sentry';
18 | import { IndexMapper } from './indexMapper';
19 |
20 | logger.setup(Logger.LogLevel.Verbose, false);
21 | const readFile = promisify(fs.readFile);
22 | const stat = promisify(fs.stat);
23 |
24 | async function isFile(filePath: string): Promise {
25 | try {
26 | const rv = await stat(filePath);
27 | return rv.isFile();
28 | } catch (error) {
29 | return false;
30 | }
31 | }
32 |
33 | function formatFrame(frame: Frame): string {
34 | return `${frame.fileName} in ${frame.function} at line ${frame.lineNo}:${frame.colNo}`;
35 | }
36 |
37 | function getExceptionDetails(
38 | exceptions: EventException[],
39 | ): DebugProtocol.ExceptionDetails | undefined {
40 | if (exceptions.length === 0) {
41 | return undefined;
42 | }
43 |
44 | const exception = exceptions[0];
45 | const inner = getExceptionDetails(exceptions.slice(1));
46 | return {
47 | innerException: inner ? [inner] : [],
48 | message: exception.value,
49 | stackTrace: exception.stacktrace.frames.map(formatFrame).join('\n'),
50 | typeName: exception.type,
51 | };
52 | }
53 |
54 | interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments {
55 | event: string;
56 | searchPaths: string[];
57 | }
58 |
59 | export class SentryDebugSession extends LoggingDebugSession {
60 | private event!: Event;
61 | private searchPaths!: string[];
62 |
63 | private exceptions: EventException[] = [];
64 | private exception?: EventException;
65 |
66 | /**
67 | * A mapping from arrays of the form [frameId, varName1, varField1, varField2, ...] to variableReferences.
68 | *
69 | * [1, "foo", "bar"] means for example that attribute "bar" of variable "foo" in frame 1 is accessed.
70 | */
71 | private varsMapper: IndexMapper = new IndexMapper();
72 |
73 | /**
74 | * Creates a new debug adapter that is used for one debug session.
75 | * We configure the default implementation of a debug adapter here.
76 | */
77 | public constructor() {
78 | super('mock-debug.txt');
79 |
80 | // this debugger uses zero-based lines and columns
81 | this.setDebuggerLinesStartAt1(false);
82 | this.setDebuggerColumnsStartAt1(false);
83 | }
84 |
85 | /**
86 | * The 'initialize' request is the first request called by the frontend
87 | * to interrogate the features the debug adapter provides.
88 | */
89 | protected initializeRequest(
90 | response: DebugProtocol.InitializeResponse,
91 | _args: DebugProtocol.InitializeRequestArguments,
92 | ): void {
93 | response.body = {
94 | ...response.body,
95 | supportsConfigurationDoneRequest: true,
96 | supportsExceptionInfoRequest: true,
97 | // supportsModulesRequest: true,
98 | };
99 |
100 | this.sendResponse(response);
101 |
102 | // since this debug adapter can accept configuration requests like 'setBreakpoint' at any time,
103 | // we request them early by sending an 'initializeRequest' to the frontend.
104 | // The frontend will end the configuration sequence by calling 'configurationDone' request.
105 | this.sendEvent(new InitializedEvent());
106 | }
107 |
108 | /**
109 | * Called at the end of the configuration sequence.
110 | * Indicates that all breakpoints etc. have been sent to the DA and that the 'launch' can start.
111 | */
112 | protected configurationDoneRequest(
113 | response: DebugProtocol.ConfigurationDoneResponse,
114 | args: DebugProtocol.ConfigurationDoneArguments,
115 | ): void {
116 | super.configurationDoneRequest(response, args);
117 |
118 | this.sendEvent(new StoppedEvent('exception', 1));
119 | }
120 |
121 | protected launchRequest(
122 | response: DebugProtocol.LaunchResponse,
123 | args: LaunchRequestArguments,
124 | ): void {
125 | this.handleAsyncResponse(this.launchRequestAsync, response, args);
126 | }
127 |
128 | protected async launchRequestAsync(
129 | _response: DebugProtocol.LaunchResponse,
130 | args: LaunchRequestArguments,
131 | ): Promise {
132 | const filename = args.event;
133 | this.event = JSON.parse(await readFile(filename, 'utf8'));
134 |
135 | this.exceptions = (this.event.entries || [])
136 | .filter(entry => entry.type === 'exception')
137 | .map(entry => entry.data.values)
138 | .reduce((all, next) => all.concat(next));
139 |
140 | this.exception = this.exceptions.shift();
141 |
142 | this.searchPaths = args.searchPaths;
143 | }
144 |
145 | protected threadsRequest(response: DebugProtocol.ThreadsResponse): void {
146 | response.body = {
147 | threads: [new Thread(1, 'fake thread')],
148 | };
149 |
150 | this.sendResponse(response);
151 | }
152 |
153 | protected sourceRequest(
154 | response: DebugProtocol.SourceResponse,
155 | args: DebugProtocol.SourceArguments,
156 | ): void {
157 | if (this.exception) {
158 | const frame = this.exception.stacktrace.frames[args.sourceReference - 1];
159 | const firstLine = frame.context.length ? frame.context[0][0] : frame.lineNo;
160 |
161 | const preContent = new Array(firstLine - 1).fill('\n').join('');
162 | const context = frame.context.map(([_, s]) => s).join('\n');
163 |
164 | response.body = { ...response.body, content: `${preContent}${context}\n` };
165 | }
166 |
167 | this.sendResponse(response);
168 | }
169 |
170 | protected stackTraceRequest(
171 | response: DebugProtocol.StackTraceResponse,
172 | args: DebugProtocol.StackTraceArguments,
173 | ): void {
174 | this.handleAsyncResponse(this.stackTraceRequestAsync, response, args);
175 | }
176 |
177 | private async stackTraceRequestAsync(
178 | response: DebugProtocol.StackTraceResponse,
179 | _args: DebugProtocol.StackTraceArguments,
180 | ): Promise {
181 | if (!this.exception) {
182 | return;
183 | }
184 |
185 | const frames = this.exception.stacktrace.frames;
186 | const forceNormal = frames.every(frame => frame.inApp) || frames.every(frame => !frame.inApp);
187 | const stackFrames: StackFrame[] = await Promise.all(
188 | frames
189 | .map(
190 | async (frame, i) =>
191 | new StackFrame(
192 | i,
193 | frame.function,
194 | await this.createSource(i, frame, forceNormal),
195 | frame.lineNo,
196 | frame.colNo,
197 | ),
198 | )
199 | .reverse(),
200 | );
201 |
202 | response.body = {
203 | stackFrames,
204 | totalFrames: stackFrames.length,
205 | };
206 | }
207 |
208 | protected scopesRequest(
209 | response: DebugProtocol.ScopesResponse,
210 | args: DebugProtocol.ScopesArguments,
211 | ): void {
212 | response.body = {
213 | scopes: [new Scope('Local', this.varsMapper.upsertArray([args.frameId]), false)],
214 | };
215 | this.sendResponse(response);
216 | }
217 |
218 | protected variablesRequest(
219 | response: DebugProtocol.VariablesResponse,
220 | args: DebugProtocol.VariablesArguments,
221 | ): void {
222 | if (this.exception) {
223 | const variablePath = this.varsMapper.getArray(args.variablesReference);
224 | const frameId = variablePath[0] as number;
225 | let vars = this.exception.stacktrace.frames[frameId].vars;
226 | for (const segment of variablePath.slice(1)) {
227 | vars = vars[segment];
228 | }
229 |
230 | const variables = Object.keys(vars).map(name => ({
231 | name,
232 | type: typeof vars[name],
233 | value: `${vars[name]}`,
234 | variablesReference:
235 | Object.prototype.toString.call(vars[name]) === '[object Object]' ||
236 | Object.prototype.toString.call(vars[name]) === '[object Array]'
237 | ? this.varsMapper.upsertArray(
238 | this.varsMapper.getArray(args.variablesReference).concat(name),
239 | )
240 | : 0,
241 | }));
242 |
243 | response.body = { ...response.body, variables };
244 | }
245 |
246 | this.sendResponse(response);
247 | }
248 |
249 | protected exceptionInfoRequest(
250 | response: DebugProtocol.ExceptionInfoResponse,
251 | _args: DebugProtocol.ExceptionInfoArguments,
252 | ): void {
253 | if (this.exception) {
254 | const handled = (this.exception.mechanism || {}).handled || false;
255 |
256 | response.body = {
257 | ...response.body,
258 | breakMode: handled ? 'always' : 'unhandled',
259 | description: `${this.exception.type}: ${this.exception.value}`,
260 | details: getExceptionDetails(this.exceptions),
261 | };
262 | }
263 |
264 | this.sendResponse(response);
265 | }
266 |
267 | // ---- helpers
268 | private async createSource(
269 | frameId: number,
270 | frame: Frame,
271 | forceNormal: boolean,
272 | ): Promise {
273 | const localPath = await convertEventPathToLocalPath(this.searchPaths, frame.absPath);
274 | if (!localPath && frame.context.length === 0) {
275 | return undefined;
276 | }
277 | const rv = new CustomSource(
278 | path.basename(frame.absPath),
279 | localPath && this.convertDebuggerPathToClient(localPath),
280 | localPath ? undefined : frameId + 1,
281 | frame.inApp || forceNormal ? 'normal' : 'deemphasize',
282 | );
283 | return rv;
284 | }
285 |
286 | private handleAsyncResponse(
287 | func: (r: R, a: A) => Promise,
288 | response: R,
289 | args: A,
290 | ): void {
291 | func
292 | .call(this, response, args)
293 | .catch((error: Error) => {
294 | logger.error(error.message);
295 | response.message = error.message;
296 | response.success = false;
297 | })
298 | .then(() => this.sendResponse(response));
299 | }
300 | }
301 |
302 | async function convertEventPathToLocalPath(
303 | searchPaths: string[],
304 | filePath: string,
305 | ): Promise {
306 | const segments = filePath
307 | .split(/\/+/g)
308 | .filter(segment => !segment.endsWith(':'))
309 | .filter(segment => segment !== '.');
310 |
311 | while (segments.length > 0) {
312 | for (const prefix of searchPaths) {
313 | if (path.isAbsolute(prefix)) {
314 | const absPath = path.resolve(prefix, ...segments);
315 | if (await isFile(absPath)) {
316 | return absPath;
317 | }
318 | } else {
319 | const folders = workspace.workspaceFolders || [];
320 | for (const folder of folders) {
321 | const absPath = path.resolve(folder.uri.fsPath, prefix, ...segments);
322 | if (await isFile(absPath)) {
323 | return absPath;
324 | }
325 | }
326 | }
327 | }
328 |
329 | segments.shift();
330 | }
331 |
332 | logger.warn(`Failed to map ${filePath} to the local fs.`);
333 | return undefined;
334 | }
335 |
336 | // tslint:disable-next-line:max-classes-per-file
337 | class CustomSource extends Source {
338 | public presentationHint?: 'normal' | 'emphasize' | 'deemphasize';
339 | public constructor(
340 | name: string,
341 | filePath?: string,
342 | sourceReference?: number,
343 | presentationHint?: 'normal' | 'emphasize' | 'deemphasize',
344 | ) {
345 | super(name, filePath, sourceReference);
346 | this.presentationHint = presentationHint;
347 | }
348 | }
349 |
--------------------------------------------------------------------------------
/src/extension.ts:
--------------------------------------------------------------------------------
1 | import { ExtensionContext } from 'vscode';
2 | import { configureCommands } from './commands';
3 | import { configuration } from './config';
4 | import { configureDebugger } from './debugger';
5 | import { statusbar } from './statusbar';
6 |
7 | export function activate(context: ExtensionContext): void {
8 | statusbar.configure(context);
9 | configureCommands(context);
10 | configureDebugger(context);
11 | configuration.configure(context);
12 | }
13 |
14 | export function deactivate(): void {
15 | // noop
16 | }
17 |
--------------------------------------------------------------------------------
/src/paths.ts:
--------------------------------------------------------------------------------
1 | import * as fs from 'fs';
2 | import * as promisify from 'util.promisify';
3 | import { ConfigurationChangeEvent, workspace } from 'vscode';
4 | import { exec } from './utils';
5 |
6 | const stat = promisify(fs.stat);
7 |
8 | const PYTHON_CONFIG = 'python.pythonPath';
9 |
10 | /**
11 | * Helper to filter an array with asynchronous callbacks.
12 | *
13 | * @param array An array containing items to filter.
14 | * @param predicate An async predicate evaluated on every item.
15 | * @param thisArg Optional value passed as "this" into the callback.
16 | * @returns An array containing only values where the callback returned true.
17 | */
18 | export async function filterAsync(
19 | array: T[],
20 | predicate: (item: T) => Promise | boolean,
21 | thisArg?: any,
22 | ): Promise {
23 | const verdicts = await Promise.all(array.map(predicate, thisArg));
24 | return array.filter((_, index) => verdicts[index]);
25 | }
26 |
27 | async function isDirectory(path: string): Promise {
28 | try {
29 | return (await stat(path)).isDirectory();
30 | } catch (e) {
31 | return false;
32 | }
33 | }
34 |
35 | async function getPythonPaths(): Promise {
36 | const pythonPath = workspace.getConfiguration('python').get('pythonPath', 'python');
37 |
38 | try {
39 | const json = await exec(
40 | pythonPath,
41 | ['-c', 'import sys; import json; json.dump(sys.path, sys.stdout)'],
42 | {},
43 | );
44 |
45 | return filterAsync(JSON.parse(json), isDirectory);
46 | } catch (e) {
47 | return [];
48 | }
49 | }
50 |
51 | export function affectsSearchPaths(event: ConfigurationChangeEvent): boolean {
52 | return event.affectsConfiguration(PYTHON_CONFIG);
53 | }
54 |
55 | export async function discoverSearchPaths(): Promise {
56 | // TODO: Workspace folders also need to be refreshed.
57 | // TODO: Maybe refactor this into a separate PathManager class?
58 | let paths = workspace.workspaceFolders
59 | ? workspace.workspaceFolders.map(folder => folder.uri.fsPath)
60 | : ['.'];
61 |
62 | // TODO: These should better be cached individually as good as possible.
63 | paths = paths.concat(await getPythonPaths());
64 |
65 | return paths;
66 | }
67 |
--------------------------------------------------------------------------------
/src/pick.ts:
--------------------------------------------------------------------------------
1 | import { QuickPickItem } from 'vscode';
2 | import { SentryCommand } from './commands/base';
3 |
4 | export class CommandQuickPickItem implements QuickPickItem {
5 | public label!: string;
6 | public description?: string;
7 | public detail?: string;
8 |
9 | private command: SentryCommand;
10 | private args: any[];
11 |
12 | public static from(
13 | item: QuickPickItem,
14 | command: SentryCommand,
15 | args: C,
16 | ): CommandQuickPickItem {
17 | return new CommandQuickPickItem(item, command, args);
18 | }
19 |
20 | private constructor(item: QuickPickItem, command: SentryCommand, args: any) {
21 | this.command = command;
22 | this.args = args;
23 |
24 | Object.assign(this, item);
25 | }
26 |
27 | public execute(): Promise {
28 | return this.command.execute(this.args);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/sentry/api.ts:
--------------------------------------------------------------------------------
1 | import * as request from 'request-light';
2 | import { Uri } from 'vscode';
3 | import { configuration } from '../config';
4 | import { Event, Issue, Organization, Project } from './interfaces';
5 | import { getToken } from './rc';
6 |
7 | async function xhr(options: request.XHROptions): Promise {
8 | const serverUrl = configuration.getServerUrl();
9 | const token = await getToken();
10 |
11 | if (!token) {
12 | throw new Error('Not authenticated with Sentry. Please provide an auth token.');
13 | }
14 |
15 | // Normalize the URL passed in options. If it is missing a scheme or
16 | // serverUrl, the value configured in "sentry.serverUrl" is used instead.
17 | const parsedUrl = Uri.parse(options.url || '');
18 | const mergedUrl = Uri.parse(serverUrl).with(parsedUrl.toJSON());
19 |
20 | return request.xhr({
21 | ...options,
22 | headers: {
23 | Authorization: `Bearer ${token}`,
24 | ...options.headers,
25 | },
26 | url: mergedUrl.toString(true),
27 | });
28 |
29 | // TODO: Handle common errors
30 | }
31 |
32 | async function get(url: string): Promise {
33 | const response = await xhr({ type: 'GET', url });
34 | return JSON.parse(response.responseText);
35 | }
36 |
37 | export async function searchIssues(input: string): Promise {
38 | // TODO: Allow customizing environments
39 | const params = '&limit=25&sort=date&shortIdLookup=1';
40 |
41 | const byProject = await Promise.all(
42 | configuration.getProjects().map(project => {
43 | const baseUrl = `/api/0/projects/${project}/issues/`;
44 | const url = `${baseUrl}?query=${encodeURIComponent(input)}${params}`;
45 | return get(url);
46 | }),
47 | );
48 |
49 | return byProject.reduce((all, next) => all.concat(next), []);
50 | }
51 |
52 | export async function loadLatestEvent(issue: Issue): Promise {
53 | const url = `/api/0/issues/${issue.id}/events/latest/`;
54 | return get(url);
55 | }
56 |
57 | export async function listProjects(): Promise {
58 | const organizations = await get('/api/0/organizations/');
59 | if (organizations.length === 0) {
60 | return [];
61 | }
62 |
63 | const orgs = await Promise.all(
64 | organizations.map(async organization => {
65 | const url = `/api/0/organizations/${organization.slug}/projects/`;
66 | const projects = await get(url);
67 | return projects.map(project => ({ ...project, organization }));
68 | }),
69 | );
70 |
71 | return orgs.reduce((all, next) => all.concat(next), []);
72 | }
73 |
--------------------------------------------------------------------------------
/src/sentry/index.ts:
--------------------------------------------------------------------------------
1 | export * from './api';
2 | export * from './interfaces';
3 | export * from './rc';
4 |
--------------------------------------------------------------------------------
/src/sentry/interfaces.ts:
--------------------------------------------------------------------------------
1 | export interface Issue {
2 | id: string;
3 | shortId: string;
4 | culprit: string;
5 | title: string;
6 | metadata: {
7 | type: string;
8 | value: string;
9 | };
10 | permalink: string;
11 | project: {
12 | slug: string;
13 | id: string;
14 | name: string;
15 | };
16 | }
17 |
18 | export interface Event {
19 | eventID: string;
20 | release?: { version: string };
21 | entries: EventEntry[];
22 | }
23 |
24 | export interface EventEntry {
25 | type: string;
26 | data: EventEntryData;
27 | }
28 |
29 | export interface EventEntryData {
30 | values: EventException[];
31 | }
32 |
33 | export interface EventException {
34 | stacktrace: Stacktrace;
35 | type: string;
36 | value: string;
37 | module: string;
38 | mechanism?: {
39 | type?: string;
40 | handled?: boolean;
41 | };
42 | }
43 |
44 | export interface Stacktrace {
45 | frames: Frame[];
46 | }
47 |
48 | export interface Frame {
49 | absPath: string;
50 | fileName: string;
51 | lineNo: number;
52 | colNo: number;
53 | inApp: boolean;
54 | function: string;
55 | vars: Record;
56 | context: Array<[number, string]>;
57 | }
58 |
59 | export interface Organization {
60 | id: string;
61 | name: string;
62 | slug: string;
63 | }
64 |
65 | export interface Project {
66 | id: string;
67 | slug: string;
68 | team: {
69 | id: string;
70 | name: string;
71 | slug: string;
72 | };
73 | organization: Organization;
74 | }
75 |
--------------------------------------------------------------------------------
/src/sentry/rc.ts:
--------------------------------------------------------------------------------
1 | import * as fs from 'fs';
2 | import * as ini from 'ini';
3 | import * as os from 'os';
4 | import * as path from 'path';
5 | import * as promisify from 'util.promisify';
6 |
7 | const readFile = promisify(fs.readFile);
8 |
9 | let token: string | undefined;
10 |
11 | async function loadRcToken(): Promise {
12 | const home = os.homedir();
13 | const rcpath = path.join(home, '.sentryclirc');
14 |
15 | try {
16 | const text = await readFile(rcpath, 'utf8');
17 | const rc = ini.parse(text);
18 | return rc.auth && rc.auth.token;
19 | } catch (e) {
20 | return undefined;
21 | }
22 | }
23 |
24 | async function loadPropertiesToken(): Promise {
25 | // TODO: Implement
26 | return undefined;
27 | }
28 |
29 | async function promptToken(): Promise {
30 | // TODO: Implement
31 | return undefined;
32 | }
33 |
34 | export async function getToken(): Promise {
35 | if (!token) {
36 | token = await loadRcToken();
37 | }
38 |
39 | if (!token) {
40 | token = await loadPropertiesToken();
41 | }
42 |
43 | if (!token) {
44 | // TODO: Add a way to set/refresh the token
45 | token = await promptToken();
46 | }
47 |
48 | return token;
49 | }
50 |
--------------------------------------------------------------------------------
/src/statusbar.ts:
--------------------------------------------------------------------------------
1 | import { ExtensionContext, StatusBarAlignment, StatusBarItem, ThemeColor, window } from 'vscode';
2 | import { COMMAND_SHOW_PROJECT_PICK } from './commands/showProjectPick';
3 |
4 | class StatusbarItems {
5 | public projectSelector!: StatusBarItem;
6 |
7 | public configure(context: ExtensionContext): void {
8 | context.subscriptions.push(this);
9 | this.projectSelector = window.createStatusBarItem(StatusBarAlignment.Left);
10 | this.projectSelector.command = COMMAND_SHOW_PROJECT_PICK;
11 | }
12 |
13 | public dispose(): void {
14 | this.projectSelector.dispose();
15 | }
16 |
17 | public updateFromProjects(projects: string[]): void {
18 | if (projects.length === 0) {
19 | this.projectSelector.color = 'yellow';
20 | this.projectSelector.text = '$(alert) Select Sentry Project';
21 | this.projectSelector.tooltip = undefined;
22 | } else {
23 | this.projectSelector.color = new ThemeColor('statusBar.foreground');
24 | this.projectSelector.text =
25 | projects.length === 1
26 | ? `Sentry: ${projects[0]}`
27 | : (this.projectSelector.text = `Sentry: ${projects.length} projects selected`);
28 | this.projectSelector.tooltip = projects.join('\n');
29 | }
30 |
31 | this.projectSelector.show();
32 | }
33 | }
34 |
35 | export const statusbar = new StatusbarItems();
36 |
--------------------------------------------------------------------------------
/src/test/extension.test.ts:
--------------------------------------------------------------------------------
1 | //
2 | // Note: This example test is leveraging the Mocha test framework.
3 | // Please refer to their documentation on https://mochajs.org/ for help.
4 | //
5 |
6 | // The module 'assert' provides assertion methods from node
7 | import * as assert from 'assert';
8 |
9 | // You can import and use all API from the 'vscode' module
10 | // as well as import your extension to test it
11 | // import * as vscode from 'vscode';
12 | // import * as myExtension from '../extension';
13 |
14 | // Defines a Mocha test suite to group tests of similar kind together
15 | suite('Extension Tests', () => {
16 | // Defines a Mocha unit test
17 | test('Something 1', () => {
18 | assert.equal(-1, [1, 2, 3].indexOf(5));
19 | assert.equal(-1, [1, 2, 3].indexOf(0));
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/src/test/index.ts:
--------------------------------------------------------------------------------
1 | //
2 | // PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
3 | //
4 | // This file is providing the test runner to use when running extension tests.
5 | // By default the test runner in use is Mocha based.
6 | //
7 | // You can provide your own test runner if you want to override it by exporting
8 | // a function run(testRoot: string, clb: (error:Error) => void) that the extension
9 | // host can call to run the tests. The test runner is expected to use console.log
10 | // to report the results back to the caller. When the tests are finished, return
11 | // a possible error to the callback or null if none.
12 |
13 | import * as testRunner from 'vscode/lib/testrunner';
14 |
15 | // You can directly control Mocha options by uncommenting the following lines
16 | // See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
17 | testRunner.configure({
18 | ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
19 | useColors: true, // colored output from test results
20 | });
21 |
22 | module.exports = testRunner;
23 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | import { execFile } from 'child_process';
2 | import * as fs from 'fs';
3 | import * as os from 'os';
4 | import * as path from 'path';
5 | import * as promisify from 'util.promisify';
6 |
7 | const writeFile = promisify(fs.writeFile);
8 | const unlink = promisify(fs.unlink);
9 |
10 | export async function withTempFile(
11 | contents: string,
12 | func: (filePath: string) => Thenable | T,
13 | ): Promise {
14 | const random = Math.random()
15 | .toString()
16 | .substr(2);
17 |
18 | const filePath = path.join(os.tmpdir(), `${random}.json`);
19 | await writeFile(filePath, contents);
20 |
21 | try {
22 | return await func(filePath);
23 | } finally {
24 | await unlink(filePath);
25 | }
26 | }
27 |
28 | export function exec(file: string, args: string[], options: any): Promise {
29 | return new Promise((resolve, reject) => {
30 | execFile(file, args, options, (error, stdout) => {
31 | if (error) {
32 | reject(error);
33 | } else {
34 | resolve(stdout);
35 | }
36 | });
37 | });
38 | }
39 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/@sentry/typescript/tsconfig.json",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "target": "es6",
6 | "outDir": "out",
7 | "lib": ["es6"],
8 | "rootDir": "src"
9 | },
10 | "include": ["src/**/*"],
11 | "exclude": ["node_modules", ".vscode-test"]
12 | }
13 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@sentry/typescript/tslint",
3 | "rules": {
4 | "no-implicit-dependencies": false
5 | }
6 | }
7 |
--------------------------------------------------------------------------------