├── .gitignore ├── .travis.yml ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── img ├── demo.gif ├── icon.png ├── r0.5.0 │ ├── example_highlight.png │ └── example_inner.png ├── r0.6.0 │ └── new_active_indent.png └── r0.7.0 │ ├── hover_with_highlight.png │ └── hover_without_highlight.png ├── package-lock.json ├── package.json ├── src └── extension.ts ├── test-fixtures └── demo │ └── demo.ts ├── test ├── runTest.ts └── suite │ ├── extension.test.ts │ └── index.ts ├── tsconfig.json └── vsc-extension-quickstart.md /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | 5 | node_js: "6" 6 | 7 | os: 8 | - osx 9 | - linux 10 | 11 | before_install: 12 | - if [ $TRAVIS_OS_NAME == "linux" ]; then 13 | export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0; 14 | sh -e /etc/init.d/xvfb start; 15 | sleep 3; 16 | fi 17 | 18 | install: 19 | - npm install 20 | - npm run vscode:prepublish 21 | 22 | script: 23 | - npm test -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.6.0", 4 | "configurations": [ 5 | { 6 | "name": "Launch Extension", 7 | "type": "extensionHost", 8 | "request": "launch", 9 | "runtimeExecutable": "${execPath}", 10 | "args": ["${workspaceRoot}/test-fixtures/demo", "--extensionDevelopmentPath=${workspaceRoot}" ], 11 | "stopOnEntry": false, 12 | "sourceMaps": true, 13 | "outFiles": [ 14 | "${workspaceFolder}/out/src/*.js" 15 | ], 16 | "preLaunchTask": "npm: compile" 17 | }, 18 | { 19 | "name": "Launch Tests", 20 | "type": "extensionHost", 21 | "request": "launch", 22 | "runtimeExecutable": "${execPath}", 23 | "args": [ 24 | "${workspaceRoot}/out/test/suite", 25 | "--extensionDevelopmentPath=${workspaceRoot}", 26 | "--extensionTestsPath=${workspaceRoot}/out/test/suite" ], 27 | "preLaunchTask": "npm: compile" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | "typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version 10 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | 9 | // See https://go.microsoft.com/fwlink/?LinkId=733558 10 | // for the documentation about the tasks.json format 11 | { 12 | "version": "2.0.0", 13 | "tasks": [ 14 | { 15 | "type": "npm", 16 | "script": "compile", 17 | "problemMatcher": "$tsc-watch", 18 | "isBackground": true, 19 | "presentation": { 20 | "reveal": "never" 21 | }, 22 | "group": { 23 | "kind": "build", 24 | "isDefault": true 25 | } 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | typings/** 3 | out/test/** 4 | test/** 5 | src/** 6 | **/*.map 7 | .gitignore 8 | tsconfig.json 9 | vsc-extension-quickstart.md 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.7.0 2 | 3 | ## Minor 4 | - Renamed settings: 5 | - **indenticator.showHighlight** changed to **indenticator.showIndentGuide** 6 | - **indenticator.inner.showHighlight** changed to **indenticator.inner.showIndentGuide** 7 | - At some point the behaviour for hovers in VS Code changed slightly: 8 | 9 | Now if the hover highlights a code block the content of the hover is shown above or below the highlighted block, rather than at the cursor position. Without highlighting a code block the hover will still be shown at the cursor position. 10 | 11 | To give the user control over how the peek feature should behave when hovering on the indent guides new settings were added: 12 | - **indenticator.hover.highlight** (default `true`): Controls wether hovering on the indent guide should highlight the code block 13 | - **indenticator.inner.hover.highlight** (default `true`): Controls wether hovering on the inner indent guide should highlight the code block 14 | - Hovering now works even if the indent guides themselves are disabled 15 | ## Patch 16 | - Fixes for #23, #25 & #26 17 | - Dependencies updated 18 | 19 | # 0.6.0 20 | 21 | ## Minor 22 | 23 | - Switched default border style from 'solid' to 'inset' 24 | - With VS Code 1.23.0 there seems to have been a change in the rendering of solid borders that makes them appear thicker than before. To offset that change the default style is now inset which should make the default borders somewhat slimmer again. 25 | - Updated README to reflect recent changes with new buildin active indent guide of VS Code 26 | 27 | ## Patch 28 | - additional checks before fetching lines from document to fix #20 29 | 30 | # 0.5.1 31 | 32 | ## Path 33 | 34 | - Fixed some typos 35 | 36 | # 0.5.0 37 | 38 | ## Minor 39 | 40 | - New Setting **indenticator.showHighlight** to toggle the Highlighting of the indent line. (default is `true`) 41 | - If this setting is `false` the hover options will be ignored 42 | - New Feature: Highlighting for inner indent as suggested in #14 43 | - highlights the indent guide of the block contained by the current cursor position 44 | - added settings **indenticator.inner.\*** allowing for all configuration options already present for the standard indent highlight to be configured for the new highlight of the inner indent. 45 | - To keep the extensions behaviour for existing users **indenticator.inner.showHighlight** defaults to `false` 46 | 47 | ![Indenticator demonstration](img/r0.5.0/example_inner.png) 48 | 49 | - Hover-Feature now also highlights the block it peeks around 50 | 51 | ![Indenticator demonstration](img/r0.5.0/example_highlight.png) 52 | 53 | - Setting **indenticator.languageSpecific** now allows configuration of multiple languages at once by naming them in a comma seperated list 54 | 55 | Example: 56 | ``` JS 57 | { 58 | "indenticator.languageSpecific": { 59 | "[json, jsonc]": { 60 | //... 61 | }, 62 | "[xml, html, xhtml]": { 63 | //... 64 | } 65 | } 66 | } 67 | ``` 68 | 69 | # 0.4.2 70 | 71 | ## Patch 72 | 73 | - Fixed Issue #6: include first and last line of file in hover 74 | 75 | # 0.4.1 76 | 77 | ## Patch 78 | 79 | - Fixed Issue #5: Language specific settings will now be applied correctly 80 | 81 | # 0.4.0 82 | 83 | ## Minor 84 | 85 | - More Configuration Options for hover on indent line 86 | - changed setting **indenticator.showHover** to accept boolean and number. If given a number the hover is active if the current indent block is at list that many lines long. (default is `false`) 87 | - added setting **indenticator.hover.peekBack** to set the number of lines to be peeked before the current indent block (default is `1`) 88 | - added setting **indenticator.hover.peekForward** to set the number of lines to be peeked after the current indent block (default is `0`) 89 | - added setting **indenticator.hover.trimLinesShorterThan** to remove lines at beginning and end of hover if they are shorter then the given value (default is `2`) 90 | - added setting **indenticator.hover.peekBlockPlaceholder** to set string to be shown between the peeked lines in the hover (default is "`...`") 91 | - Added option to specify language specific configurations 92 | - added setting **indenticator.languageSpecific** to specify language specific settings (default is `{}`) 93 | 94 | Accepts an object with language keys enclosed in square brackets (analogous to [language specific editor options](https://code.visualstudio.com/docs/getstarted/settings#_language-specific-editor-settings)) as property keys and any set of indenticator configuartion as values. 95 | 96 | Example: 97 | ``` JS 98 | { 99 | "indenticator.languageSpecific": { 100 | "[json]": { 101 | "indenticator.showHover": true, 102 | "indenticator.hover.peekBack": 1 103 | } 104 | } 105 | } 106 | ``` 107 | 108 | # 0.3.0 109 | 110 | ## Minor 111 | - New Feature: Hover on active indent line peeks first line (thanks to [rsbondi](https://github.com/rsbondi) on github) 112 | - added setting **indenticator.showHover** to activate the new Feature (default is `false`) 113 | 114 | ## Patch 115 | - Updated project to Typescript 2 116 | - Fixed Travis builds 117 | 118 | # 0.2.1 119 | 120 | ## Patch 121 | 122 | - Fixed Issue #1: The Extension will no longer add multiple Information Items into the Statusbar 123 | 124 | # 0.2.0 125 | 126 | ## Minor 127 | 128 | - First release to be published to the VS Marketplace -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 Fabian Krueger 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/SirTori/indenticator.svg?branch=master)](https://travis-ci.org/SirTori/indenticator) 2 | 3 | # Indenticator 4 | 5 | Visually highlights the current indent depth. 6 | 7 | This extension can be used by itself, but it's recommended to use it alongside the built-in indent guides (setting **editor.renderIndentGuides**). These show thin grey lines on *every* indent, while this extension highlights the indent on the indent depth the cursor is currently on. 8 | 9 | **Changes in Visual Studio Code 1.23.0**:
10 | With Version 1.23.0 VS Code introduced a new built-in active indent guide. For an explanation of differences and tips regarding the new feature and this extension please see [remarks section](#remarks) 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
Example using default settings
20 | 21 | 22 | ## Feature Highlights 23 | 24 | - **Peeking around the current indent block**: *Optionally* a hover can be added on the current indent marker to peek before and/or after the current indent block.
25 | *To activate set **indenticator.showHover** to `true`* 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
Example has indenticator.hover.peekBack & indenticator.hover.peekForward set to 1 and indenticator.hover.highlight set to trueExample has indenticator.hover.peekBack & indenticator.hover.peekForward set to 1 and indenticator.hover.highlight set to false
37 | 38 | - **Highlighting the the indent guide for the contained block**: *Optionally* a second indent guide can be configured to show the block *contained* by the current cursor position
39 | *To activate set **indenticator.inner.showIndentGuide** to `true`* 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Example has indenticator.inner.showIndentGuide set to true and indenticator.inner.color.dark set to #ff000
49 | 50 | 51 | - **Language specific settings**: The extension can be configured for each language separately to accommondate the requirements of different coding styles. 52 | 53 | Example: 54 | ``` JS 55 | { 56 | "indenticator.languageSpecific": { 57 | "[json, jsonc]": { 58 | //... 59 | }, 60 | "[xml, html, xhtml]": { 61 | //... 62 | } 63 | } 64 | } 65 | ``` 66 | 67 | - **Highlight Styling**: All indent highlighting can be styled individually by defining color, width and border style. 68 | 69 | ## Settings and defaults 70 | ``` JS 71 | { 72 | /******************************************************/ 73 | /********** Standard Indent Highlight Config **********/ 74 | /******************************************************/ 75 | /* Whether to highlight the indent of the block enclosing the current line */ 76 | "indenticator.showIndentGuide": true 77 | /* Color of the indent marker for dark themes */ 78 | "indenticator.color.dark": "#888", 79 | /* Color of the indent marker for light themes */ 80 | "indenticator.color.light": "#999", 81 | /* Width of the indent marker in pixels */ 82 | "indenticator.width": 1, 83 | /* Line style of the indent marker (e.g. "inset", "dashed", "dotted", ...) */ 84 | "indenticator.style": "inset", 85 | /* Whether to display the hover near the indent line */ 86 | "indenticator.showHover": false, 87 | /* Wether to highlight the contained code block when hovering the indent line. If activated, the peeked content will be shown at top or bottom of the block, otherwise it will be shown at cursor position.*/ 88 | "indenticator.hover.highlight": true, 89 | /* Lines before the current indent to be shown on hover */ 90 | "indenticator.hover.peekBack": 1, 91 | /* Lines after the current indent to be shown on hover */ 92 | "indenticator.hover.peekForward": 0, 93 | /* Remove lines from the hover at the beginning and end that have less characters than this */ 94 | "indenticator.hover.trimLinesShorterThan": 2, 95 | /* Block placeholder to be written between peeked lines */ 96 | "indenticator.hover.peekBlockPlaceholder": "...", 97 | 98 | /***************************************************/ 99 | /********** Inner Indent Highlight Config **********/ 100 | /***************************************************/ 101 | /* Whether to highlight the indent of the block enclosed by the current line */ 102 | "indenticator.inner.showHighlight": false 103 | /* Color of the indent marker for dark themes */ 104 | "indenticator.inner.color.dark": "#888", 105 | /* Color of the indent marker for light themes */ 106 | "indenticator.inner.color.light": "#999", 107 | /* Width of the indent marker in pixels */ 108 | "indenticator.inner.width": 1, 109 | /* Line style of the indent marker (e.g. "inset", "dashed", "dotted", ...) */ 110 | "indenticator.inner.style": "inset", 111 | /* Whether to display the hover near the inner indent line */ 112 | "indenticator.inner.showHover": false, 113 | /* Wether to highlight the contained code block when hovering the indent line. If activated, the peeked content will be shown at top or bottom of the block, otherwise it will be shown at cursor position.*/ 114 | "indenticator.inner.hover.highlight": true, 115 | /* Lines before the current inner indent to be shown on hover */ 116 | "indenticator.inner.hover.peekBack": 1, 117 | /* Lines after the current inner indent to be shown on hover */ 118 | "indenticator.inner.hover.peekForward": 0, 119 | /* Remove lines from the inner indent hover at the beginning and end that have less characters than this */ 120 | "indenticator.inner.hover.trimLinesShorterThan": 2, 121 | /* Block placeholder to be written between peeked lines */ 122 | "indenticator.inner.hover.peekBlockPlaceholder": "...", 123 | /* Whether to display the current indent depth on the statusbar */ 124 | 125 | /********************************************/ 126 | /********** Further Configurations **********/ 127 | /********************************************/ 128 | "indenticator.showCurrentDepthInStatusBar": true, 129 | /* A construct with language identifiers as properties containing a subset of indenticator options to be applied for that language */ 130 | "indenticator.languageSpecific": {} 131 | } 132 | ``` 133 | ### Remarks 134 | - **New Built-in active indent guide (VS Code 1.23.0)** 135 | - The built-in active indent guide always highlights the *highest* indent on the currently selected line, while this extensions highlights the indent depth the *cursor is currently at*. The difference can be seen in the following image: 136 | 137 | | ![Indenticator demonstration](img/r0.6.0/new_active_indent.png) | 138 | |- | 139 | | *yellow* is the new built-in active indent guide
*red* is the inner active indent guide of this extension
*grey* is the default active indent guide of this extension | 140 | 141 | - The built-in *active* indent guide can be configured through the setting: **editor.highlightActiveIndentGuide** 142 | 143 | - **indenticator.languageSpecific**: The language identifiers can be viewed by using [VS Codes language selection](https://code.visualstudio.com/docs/languages/overview#_language-id) in the statusbar. To be analogous to [language specific editor options](https://code.visualstudio.com/docs/getstarted/settings#_language-specific-editor-settings) of VS Code the key has to be put between square brackets. But to simplify configuration of similar languages multiple keys can be listed within the square brackets as a comma seperated list. 144 | 145 | Any setting for indenticator that can be set normally, can also be set for the language specific configuration. If any setting is not set for the specific language the overall configuration will be used. 146 | 147 | Example: 148 | ``` JS 149 | { 150 | "indenticator.languageSpecific": { 151 | "[json, jsonc]": { 152 | "indenticator.showHover": true, 153 | "indenticator.hover.peekBack": 1 154 | } 155 | } 156 | } 157 | ``` -------------------------------------------------------------------------------- /img/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SirTori/indenticator/2a8507f07425e19d6949cdb831614e9d57793ce1/img/demo.gif -------------------------------------------------------------------------------- /img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SirTori/indenticator/2a8507f07425e19d6949cdb831614e9d57793ce1/img/icon.png -------------------------------------------------------------------------------- /img/r0.5.0/example_highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SirTori/indenticator/2a8507f07425e19d6949cdb831614e9d57793ce1/img/r0.5.0/example_highlight.png -------------------------------------------------------------------------------- /img/r0.5.0/example_inner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SirTori/indenticator/2a8507f07425e19d6949cdb831614e9d57793ce1/img/r0.5.0/example_inner.png -------------------------------------------------------------------------------- /img/r0.6.0/new_active_indent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SirTori/indenticator/2a8507f07425e19d6949cdb831614e9d57793ce1/img/r0.6.0/new_active_indent.png -------------------------------------------------------------------------------- /img/r0.7.0/hover_with_highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SirTori/indenticator/2a8507f07425e19d6949cdb831614e9d57793ce1/img/r0.7.0/hover_with_highlight.png -------------------------------------------------------------------------------- /img/r0.7.0/hover_without_highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SirTori/indenticator/2a8507f07425e19d6949cdb831614e9d57793ce1/img/r0.7.0/hover_without_highlight.png -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "indenticator", 3 | "version": "0.7.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/glob": { 8 | "version": "7.1.3", 9 | "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", 10 | "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", 11 | "dev": true, 12 | "requires": { 13 | "@types/minimatch": "*", 14 | "@types/node": "*" 15 | } 16 | }, 17 | "@types/minimatch": { 18 | "version": "3.0.3", 19 | "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", 20 | "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", 21 | "dev": true 22 | }, 23 | "@types/mocha": { 24 | "version": "8.0.3", 25 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.0.3.tgz", 26 | "integrity": "sha512-vyxR57nv8NfcU0GZu8EUXZLTbCMupIUwy95LJ6lllN+JRPG25CwMHoB1q5xKh8YKhQnHYRAn4yW2yuHbf/5xgg==", 27 | "dev": true 28 | }, 29 | "@types/node": { 30 | "version": "12.12.54", 31 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.54.tgz", 32 | "integrity": "sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==", 33 | "dev": true 34 | }, 35 | "@types/vscode": { 36 | "version": "1.48.0", 37 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.48.0.tgz", 38 | "integrity": "sha512-sZJKzsJz1gSoFXcOJWw3fnKl2sseUgZmvB4AJZS+Fea+bC/jfGPVhmFL/FfQHld/TKtukVONsmoD3Pkyx9iadg==", 39 | "dev": true 40 | }, 41 | "agent-base": { 42 | "version": "4.3.0", 43 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", 44 | "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", 45 | "dev": true, 46 | "requires": { 47 | "es6-promisify": "^5.0.0" 48 | } 49 | }, 50 | "ansi-colors": { 51 | "version": "4.1.1", 52 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 53 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 54 | "dev": true 55 | }, 56 | "ansi-regex": { 57 | "version": "3.0.0", 58 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 59 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 60 | "dev": true 61 | }, 62 | "ansi-styles": { 63 | "version": "3.2.1", 64 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 65 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 66 | "dev": true, 67 | "requires": { 68 | "color-convert": "^1.9.0" 69 | } 70 | }, 71 | "anymatch": { 72 | "version": "3.1.1", 73 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", 74 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", 75 | "dev": true, 76 | "requires": { 77 | "normalize-path": "^3.0.0", 78 | "picomatch": "^2.0.4" 79 | } 80 | }, 81 | "argparse": { 82 | "version": "1.0.10", 83 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 84 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 85 | "dev": true, 86 | "requires": { 87 | "sprintf-js": "~1.0.2" 88 | } 89 | }, 90 | "array-filter": { 91 | "version": "1.0.0", 92 | "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", 93 | "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=", 94 | "dev": true 95 | }, 96 | "array.prototype.map": { 97 | "version": "1.0.2", 98 | "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz", 99 | "integrity": "sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw==", 100 | "dev": true, 101 | "requires": { 102 | "define-properties": "^1.1.3", 103 | "es-abstract": "^1.17.0-next.1", 104 | "es-array-method-boxes-properly": "^1.0.0", 105 | "is-string": "^1.0.4" 106 | } 107 | }, 108 | "assert": { 109 | "version": "2.0.0", 110 | "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", 111 | "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", 112 | "dev": true, 113 | "requires": { 114 | "es6-object-assign": "^1.1.0", 115 | "is-nan": "^1.2.1", 116 | "object-is": "^1.0.1", 117 | "util": "^0.12.0" 118 | } 119 | }, 120 | "available-typed-arrays": { 121 | "version": "1.0.2", 122 | "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", 123 | "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==", 124 | "dev": true, 125 | "requires": { 126 | "array-filter": "^1.0.0" 127 | } 128 | }, 129 | "balanced-match": { 130 | "version": "1.0.0", 131 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 132 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 133 | "dev": true 134 | }, 135 | "binary-extensions": { 136 | "version": "2.1.0", 137 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", 138 | "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", 139 | "dev": true 140 | }, 141 | "brace-expansion": { 142 | "version": "1.1.11", 143 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 144 | "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", 145 | "dev": true, 146 | "requires": { 147 | "balanced-match": "^1.0.0", 148 | "concat-map": "0.0.1" 149 | } 150 | }, 151 | "braces": { 152 | "version": "3.0.2", 153 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 154 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 155 | "dev": true, 156 | "requires": { 157 | "fill-range": "^7.0.1" 158 | } 159 | }, 160 | "browser-stdout": { 161 | "version": "1.3.1", 162 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 163 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 164 | "dev": true 165 | }, 166 | "camelcase": { 167 | "version": "5.3.1", 168 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", 169 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", 170 | "dev": true 171 | }, 172 | "chalk": { 173 | "version": "2.4.2", 174 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 175 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 176 | "dev": true, 177 | "requires": { 178 | "ansi-styles": "^3.2.1", 179 | "escape-string-regexp": "^1.0.5", 180 | "supports-color": "^5.3.0" 181 | }, 182 | "dependencies": { 183 | "supports-color": { 184 | "version": "5.5.0", 185 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 186 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 187 | "dev": true, 188 | "requires": { 189 | "has-flag": "^3.0.0" 190 | } 191 | } 192 | } 193 | }, 194 | "chokidar": { 195 | "version": "3.3.1", 196 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", 197 | "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", 198 | "dev": true, 199 | "requires": { 200 | "anymatch": "~3.1.1", 201 | "braces": "~3.0.2", 202 | "fsevents": "~2.1.2", 203 | "glob-parent": "~5.1.0", 204 | "is-binary-path": "~2.1.0", 205 | "is-glob": "~4.0.1", 206 | "normalize-path": "~3.0.0", 207 | "readdirp": "~3.3.0" 208 | } 209 | }, 210 | "cliui": { 211 | "version": "5.0.0", 212 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", 213 | "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", 214 | "dev": true, 215 | "requires": { 216 | "string-width": "^3.1.0", 217 | "strip-ansi": "^5.2.0", 218 | "wrap-ansi": "^5.1.0" 219 | }, 220 | "dependencies": { 221 | "ansi-regex": { 222 | "version": "4.1.0", 223 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 224 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 225 | "dev": true 226 | }, 227 | "string-width": { 228 | "version": "3.1.0", 229 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 230 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 231 | "dev": true, 232 | "requires": { 233 | "emoji-regex": "^7.0.1", 234 | "is-fullwidth-code-point": "^2.0.0", 235 | "strip-ansi": "^5.1.0" 236 | } 237 | }, 238 | "strip-ansi": { 239 | "version": "5.2.0", 240 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 241 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 242 | "dev": true, 243 | "requires": { 244 | "ansi-regex": "^4.1.0" 245 | } 246 | } 247 | } 248 | }, 249 | "color-convert": { 250 | "version": "1.9.3", 251 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 252 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 253 | "dev": true, 254 | "requires": { 255 | "color-name": "1.1.3" 256 | } 257 | }, 258 | "color-name": { 259 | "version": "1.1.3", 260 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 261 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 262 | "dev": true 263 | }, 264 | "concat-map": { 265 | "version": "0.0.1", 266 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 267 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 268 | "dev": true 269 | }, 270 | "debug": { 271 | "version": "3.2.6", 272 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 273 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 274 | "dev": true, 275 | "requires": { 276 | "ms": "^2.1.1" 277 | } 278 | }, 279 | "decamelize": { 280 | "version": "1.2.0", 281 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 282 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 283 | "dev": true 284 | }, 285 | "define-properties": { 286 | "version": "1.1.3", 287 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 288 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 289 | "dev": true, 290 | "requires": { 291 | "object-keys": "^1.0.12" 292 | } 293 | }, 294 | "diff": { 295 | "version": "4.0.2", 296 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 297 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 298 | "dev": true 299 | }, 300 | "emoji-regex": { 301 | "version": "7.0.3", 302 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 303 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 304 | "dev": true 305 | }, 306 | "es-abstract": { 307 | "version": "1.17.6", 308 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", 309 | "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", 310 | "dev": true, 311 | "requires": { 312 | "es-to-primitive": "^1.2.1", 313 | "function-bind": "^1.1.1", 314 | "has": "^1.0.3", 315 | "has-symbols": "^1.0.1", 316 | "is-callable": "^1.2.0", 317 | "is-regex": "^1.1.0", 318 | "object-inspect": "^1.7.0", 319 | "object-keys": "^1.1.1", 320 | "object.assign": "^4.1.0", 321 | "string.prototype.trimend": "^1.0.1", 322 | "string.prototype.trimstart": "^1.0.1" 323 | } 324 | }, 325 | "es-array-method-boxes-properly": { 326 | "version": "1.0.0", 327 | "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", 328 | "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", 329 | "dev": true 330 | }, 331 | "es-get-iterator": { 332 | "version": "1.1.0", 333 | "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz", 334 | "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==", 335 | "dev": true, 336 | "requires": { 337 | "es-abstract": "^1.17.4", 338 | "has-symbols": "^1.0.1", 339 | "is-arguments": "^1.0.4", 340 | "is-map": "^2.0.1", 341 | "is-set": "^2.0.1", 342 | "is-string": "^1.0.5", 343 | "isarray": "^2.0.5" 344 | } 345 | }, 346 | "es-to-primitive": { 347 | "version": "1.2.1", 348 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", 349 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", 350 | "dev": true, 351 | "requires": { 352 | "is-callable": "^1.1.4", 353 | "is-date-object": "^1.0.1", 354 | "is-symbol": "^1.0.2" 355 | } 356 | }, 357 | "es6-object-assign": { 358 | "version": "1.1.0", 359 | "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", 360 | "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", 361 | "dev": true 362 | }, 363 | "es6-promise": { 364 | "version": "4.2.8", 365 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", 366 | "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", 367 | "dev": true 368 | }, 369 | "es6-promisify": { 370 | "version": "5.0.0", 371 | "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", 372 | "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", 373 | "dev": true, 374 | "requires": { 375 | "es6-promise": "^4.0.3" 376 | } 377 | }, 378 | "escape-string-regexp": { 379 | "version": "1.0.5", 380 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 381 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 382 | "dev": true 383 | }, 384 | "esprima": { 385 | "version": "4.0.1", 386 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 387 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 388 | "dev": true 389 | }, 390 | "fill-range": { 391 | "version": "7.0.1", 392 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 393 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 394 | "dev": true, 395 | "requires": { 396 | "to-regex-range": "^5.0.1" 397 | } 398 | }, 399 | "find-up": { 400 | "version": "4.1.0", 401 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 402 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 403 | "dev": true, 404 | "requires": { 405 | "locate-path": "^5.0.0", 406 | "path-exists": "^4.0.0" 407 | } 408 | }, 409 | "flat": { 410 | "version": "4.1.0", 411 | "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", 412 | "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", 413 | "dev": true, 414 | "requires": { 415 | "is-buffer": "~2.0.3" 416 | } 417 | }, 418 | "foreach": { 419 | "version": "2.0.5", 420 | "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", 421 | "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", 422 | "dev": true 423 | }, 424 | "fs.realpath": { 425 | "version": "1.0.0", 426 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 427 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 428 | "dev": true 429 | }, 430 | "fsevents": { 431 | "version": "2.1.3", 432 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", 433 | "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", 434 | "dev": true, 435 | "optional": true 436 | }, 437 | "function-bind": { 438 | "version": "1.1.1", 439 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 440 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 441 | "dev": true 442 | }, 443 | "get-caller-file": { 444 | "version": "2.0.5", 445 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 446 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 447 | "dev": true 448 | }, 449 | "glob": { 450 | "version": "7.1.6", 451 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 452 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 453 | "dev": true, 454 | "requires": { 455 | "fs.realpath": "^1.0.0", 456 | "inflight": "^1.0.4", 457 | "inherits": "2", 458 | "minimatch": "^3.0.4", 459 | "once": "^1.3.0", 460 | "path-is-absolute": "^1.0.0" 461 | } 462 | }, 463 | "glob-parent": { 464 | "version": "5.1.1", 465 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", 466 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", 467 | "dev": true, 468 | "requires": { 469 | "is-glob": "^4.0.1" 470 | } 471 | }, 472 | "growl": { 473 | "version": "1.10.5", 474 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 475 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 476 | "dev": true 477 | }, 478 | "has": { 479 | "version": "1.0.3", 480 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 481 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 482 | "dev": true, 483 | "requires": { 484 | "function-bind": "^1.1.1" 485 | } 486 | }, 487 | "has-flag": { 488 | "version": "3.0.0", 489 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 490 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 491 | "dev": true 492 | }, 493 | "has-symbols": { 494 | "version": "1.0.1", 495 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", 496 | "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", 497 | "dev": true 498 | }, 499 | "he": { 500 | "version": "1.2.0", 501 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 502 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 503 | "dev": true 504 | }, 505 | "http-proxy-agent": { 506 | "version": "2.1.0", 507 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", 508 | "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", 509 | "dev": true, 510 | "requires": { 511 | "agent-base": "4", 512 | "debug": "3.1.0" 513 | }, 514 | "dependencies": { 515 | "debug": { 516 | "version": "3.1.0", 517 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 518 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 519 | "dev": true, 520 | "requires": { 521 | "ms": "2.0.0" 522 | } 523 | }, 524 | "ms": { 525 | "version": "2.0.0", 526 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 527 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 528 | "dev": true 529 | } 530 | } 531 | }, 532 | "https-proxy-agent": { 533 | "version": "2.2.4", 534 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", 535 | "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", 536 | "dev": true, 537 | "requires": { 538 | "agent-base": "^4.3.0", 539 | "debug": "^3.1.0" 540 | }, 541 | "dependencies": { 542 | "debug": { 543 | "version": "3.2.6", 544 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 545 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 546 | "dev": true, 547 | "requires": { 548 | "ms": "^2.1.1" 549 | } 550 | }, 551 | "ms": { 552 | "version": "2.1.2", 553 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 554 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 555 | "dev": true 556 | } 557 | } 558 | }, 559 | "inflight": { 560 | "version": "1.0.6", 561 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 562 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 563 | "dev": true, 564 | "requires": { 565 | "once": "^1.3.0", 566 | "wrappy": "1" 567 | } 568 | }, 569 | "inherits": { 570 | "version": "2.0.1", 571 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", 572 | "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", 573 | "dev": true 574 | }, 575 | "is-arguments": { 576 | "version": "1.0.4", 577 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", 578 | "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", 579 | "dev": true 580 | }, 581 | "is-binary-path": { 582 | "version": "2.1.0", 583 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 584 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 585 | "dev": true, 586 | "requires": { 587 | "binary-extensions": "^2.0.0" 588 | } 589 | }, 590 | "is-buffer": { 591 | "version": "2.0.4", 592 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", 593 | "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", 594 | "dev": true 595 | }, 596 | "is-callable": { 597 | "version": "1.2.0", 598 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", 599 | "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", 600 | "dev": true 601 | }, 602 | "is-date-object": { 603 | "version": "1.0.2", 604 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", 605 | "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", 606 | "dev": true 607 | }, 608 | "is-extglob": { 609 | "version": "2.1.1", 610 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 611 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 612 | "dev": true 613 | }, 614 | "is-fullwidth-code-point": { 615 | "version": "2.0.0", 616 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 617 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 618 | "dev": true 619 | }, 620 | "is-generator-function": { 621 | "version": "1.0.7", 622 | "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", 623 | "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==", 624 | "dev": true 625 | }, 626 | "is-glob": { 627 | "version": "4.0.1", 628 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 629 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 630 | "dev": true, 631 | "requires": { 632 | "is-extglob": "^2.1.1" 633 | } 634 | }, 635 | "is-map": { 636 | "version": "2.0.1", 637 | "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", 638 | "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", 639 | "dev": true 640 | }, 641 | "is-nan": { 642 | "version": "1.3.0", 643 | "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.0.tgz", 644 | "integrity": "sha512-z7bbREymOqt2CCaZVly8aC4ML3Xhfi0ekuOnjO2L8vKdl+CttdVoGZQhd4adMFAsxQ5VeRVwORs4tU8RH+HFtQ==", 645 | "dev": true, 646 | "requires": { 647 | "define-properties": "^1.1.3" 648 | } 649 | }, 650 | "is-number": { 651 | "version": "7.0.0", 652 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 653 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 654 | "dev": true 655 | }, 656 | "is-plain-obj": { 657 | "version": "1.1.0", 658 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", 659 | "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", 660 | "dev": true 661 | }, 662 | "is-regex": { 663 | "version": "1.1.1", 664 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", 665 | "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", 666 | "dev": true, 667 | "requires": { 668 | "has-symbols": "^1.0.1" 669 | } 670 | }, 671 | "is-set": { 672 | "version": "2.0.1", 673 | "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", 674 | "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==", 675 | "dev": true 676 | }, 677 | "is-string": { 678 | "version": "1.0.5", 679 | "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", 680 | "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", 681 | "dev": true 682 | }, 683 | "is-symbol": { 684 | "version": "1.0.3", 685 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", 686 | "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", 687 | "dev": true, 688 | "requires": { 689 | "has-symbols": "^1.0.1" 690 | } 691 | }, 692 | "is-typed-array": { 693 | "version": "1.1.3", 694 | "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.3.tgz", 695 | "integrity": "sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ==", 696 | "dev": true, 697 | "requires": { 698 | "available-typed-arrays": "^1.0.0", 699 | "es-abstract": "^1.17.4", 700 | "foreach": "^2.0.5", 701 | "has-symbols": "^1.0.1" 702 | } 703 | }, 704 | "isarray": { 705 | "version": "2.0.5", 706 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", 707 | "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", 708 | "dev": true 709 | }, 710 | "isexe": { 711 | "version": "2.0.0", 712 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 713 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 714 | "dev": true 715 | }, 716 | "iterate-iterator": { 717 | "version": "1.0.1", 718 | "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", 719 | "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==", 720 | "dev": true 721 | }, 722 | "iterate-value": { 723 | "version": "1.0.2", 724 | "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", 725 | "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", 726 | "dev": true, 727 | "requires": { 728 | "es-get-iterator": "^1.0.2", 729 | "iterate-iterator": "^1.0.1" 730 | } 731 | }, 732 | "js-yaml": { 733 | "version": "3.13.1", 734 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 735 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 736 | "dev": true, 737 | "requires": { 738 | "argparse": "^1.0.7", 739 | "esprima": "^4.0.0" 740 | } 741 | }, 742 | "locate-path": { 743 | "version": "5.0.0", 744 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 745 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 746 | "dev": true, 747 | "requires": { 748 | "p-locate": "^4.1.0" 749 | } 750 | }, 751 | "log-symbols": { 752 | "version": "3.0.0", 753 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", 754 | "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", 755 | "dev": true, 756 | "requires": { 757 | "chalk": "^2.4.2" 758 | } 759 | }, 760 | "minimatch": { 761 | "version": "3.0.4", 762 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 763 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 764 | "dev": true, 765 | "requires": { 766 | "brace-expansion": "^1.1.7" 767 | } 768 | }, 769 | "mocha": { 770 | "version": "8.1.1", 771 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.1.1.tgz", 772 | "integrity": "sha512-p7FuGlYH8t7gaiodlFreseLxEmxTgvyG9RgPHODFPySNhwUehu8NIb0vdSt3WFckSneswZ0Un5typYcWElk7HQ==", 773 | "dev": true, 774 | "requires": { 775 | "ansi-colors": "4.1.1", 776 | "browser-stdout": "1.3.1", 777 | "chokidar": "3.3.1", 778 | "debug": "3.2.6", 779 | "diff": "4.0.2", 780 | "escape-string-regexp": "1.0.5", 781 | "find-up": "4.1.0", 782 | "glob": "7.1.6", 783 | "growl": "1.10.5", 784 | "he": "1.2.0", 785 | "js-yaml": "3.13.1", 786 | "log-symbols": "3.0.0", 787 | "minimatch": "3.0.4", 788 | "ms": "2.1.2", 789 | "object.assign": "4.1.0", 790 | "promise.allsettled": "1.0.2", 791 | "serialize-javascript": "4.0.0", 792 | "strip-json-comments": "3.0.1", 793 | "supports-color": "7.1.0", 794 | "which": "2.0.2", 795 | "wide-align": "1.1.3", 796 | "workerpool": "6.0.0", 797 | "yargs": "13.3.2", 798 | "yargs-parser": "13.1.2", 799 | "yargs-unparser": "1.6.1" 800 | } 801 | }, 802 | "ms": { 803 | "version": "2.1.2", 804 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 805 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 806 | "dev": true 807 | }, 808 | "normalize-path": { 809 | "version": "3.0.0", 810 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 811 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 812 | "dev": true 813 | }, 814 | "object-inspect": { 815 | "version": "1.8.0", 816 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", 817 | "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", 818 | "dev": true 819 | }, 820 | "object-is": { 821 | "version": "1.1.2", 822 | "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", 823 | "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", 824 | "dev": true, 825 | "requires": { 826 | "define-properties": "^1.1.3", 827 | "es-abstract": "^1.17.5" 828 | } 829 | }, 830 | "object-keys": { 831 | "version": "1.1.1", 832 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 833 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 834 | "dev": true 835 | }, 836 | "object.assign": { 837 | "version": "4.1.0", 838 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", 839 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", 840 | "dev": true, 841 | "requires": { 842 | "define-properties": "^1.1.2", 843 | "function-bind": "^1.1.1", 844 | "has-symbols": "^1.0.0", 845 | "object-keys": "^1.0.11" 846 | } 847 | }, 848 | "once": { 849 | "version": "1.4.0", 850 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 851 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 852 | "dev": true, 853 | "requires": { 854 | "wrappy": "1" 855 | } 856 | }, 857 | "p-limit": { 858 | "version": "2.3.0", 859 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 860 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 861 | "dev": true, 862 | "requires": { 863 | "p-try": "^2.0.0" 864 | } 865 | }, 866 | "p-locate": { 867 | "version": "4.1.0", 868 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 869 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 870 | "dev": true, 871 | "requires": { 872 | "p-limit": "^2.2.0" 873 | } 874 | }, 875 | "p-try": { 876 | "version": "2.2.0", 877 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 878 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 879 | "dev": true 880 | }, 881 | "path-exists": { 882 | "version": "4.0.0", 883 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 884 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 885 | "dev": true 886 | }, 887 | "path-is-absolute": { 888 | "version": "1.0.1", 889 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 890 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 891 | "dev": true 892 | }, 893 | "picomatch": { 894 | "version": "2.2.2", 895 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", 896 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", 897 | "dev": true 898 | }, 899 | "promise.allsettled": { 900 | "version": "1.0.2", 901 | "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz", 902 | "integrity": "sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg==", 903 | "dev": true, 904 | "requires": { 905 | "array.prototype.map": "^1.0.1", 906 | "define-properties": "^1.1.3", 907 | "es-abstract": "^1.17.0-next.1", 908 | "function-bind": "^1.1.1", 909 | "iterate-value": "^1.0.0" 910 | } 911 | }, 912 | "randombytes": { 913 | "version": "2.1.0", 914 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 915 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 916 | "dev": true, 917 | "requires": { 918 | "safe-buffer": "^5.1.0" 919 | } 920 | }, 921 | "readdirp": { 922 | "version": "3.3.0", 923 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", 924 | "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", 925 | "dev": true, 926 | "requires": { 927 | "picomatch": "^2.0.7" 928 | } 929 | }, 930 | "require-directory": { 931 | "version": "2.1.1", 932 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 933 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 934 | "dev": true 935 | }, 936 | "require-main-filename": { 937 | "version": "2.0.0", 938 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", 939 | "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", 940 | "dev": true 941 | }, 942 | "rimraf": { 943 | "version": "2.7.1", 944 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 945 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 946 | "dev": true, 947 | "requires": { 948 | "glob": "^7.1.3" 949 | }, 950 | "dependencies": { 951 | "glob": { 952 | "version": "7.1.6", 953 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 954 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 955 | "dev": true, 956 | "requires": { 957 | "fs.realpath": "^1.0.0", 958 | "inflight": "^1.0.4", 959 | "inherits": "2", 960 | "minimatch": "^3.0.4", 961 | "once": "^1.3.0", 962 | "path-is-absolute": "^1.0.0" 963 | } 964 | }, 965 | "minimatch": { 966 | "version": "3.0.4", 967 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 968 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 969 | "dev": true, 970 | "requires": { 971 | "brace-expansion": "^1.1.7" 972 | } 973 | } 974 | } 975 | }, 976 | "safe-buffer": { 977 | "version": "5.2.1", 978 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 979 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 980 | "dev": true 981 | }, 982 | "serialize-javascript": { 983 | "version": "4.0.0", 984 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", 985 | "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", 986 | "dev": true, 987 | "requires": { 988 | "randombytes": "^2.1.0" 989 | } 990 | }, 991 | "set-blocking": { 992 | "version": "2.0.0", 993 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 994 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 995 | "dev": true 996 | }, 997 | "sprintf-js": { 998 | "version": "1.0.3", 999 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1000 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1001 | "dev": true 1002 | }, 1003 | "string-width": { 1004 | "version": "2.1.1", 1005 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1006 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1007 | "dev": true, 1008 | "requires": { 1009 | "is-fullwidth-code-point": "^2.0.0", 1010 | "strip-ansi": "^4.0.0" 1011 | } 1012 | }, 1013 | "string.prototype.trimend": { 1014 | "version": "1.0.1", 1015 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", 1016 | "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", 1017 | "dev": true, 1018 | "requires": { 1019 | "define-properties": "^1.1.3", 1020 | "es-abstract": "^1.17.5" 1021 | } 1022 | }, 1023 | "string.prototype.trimstart": { 1024 | "version": "1.0.1", 1025 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", 1026 | "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", 1027 | "dev": true, 1028 | "requires": { 1029 | "define-properties": "^1.1.3", 1030 | "es-abstract": "^1.17.5" 1031 | } 1032 | }, 1033 | "strip-ansi": { 1034 | "version": "4.0.0", 1035 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1036 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1037 | "dev": true, 1038 | "requires": { 1039 | "ansi-regex": "^3.0.0" 1040 | } 1041 | }, 1042 | "strip-json-comments": { 1043 | "version": "3.0.1", 1044 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", 1045 | "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", 1046 | "dev": true 1047 | }, 1048 | "supports-color": { 1049 | "version": "7.1.0", 1050 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", 1051 | "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", 1052 | "dev": true, 1053 | "requires": { 1054 | "has-flag": "^4.0.0" 1055 | }, 1056 | "dependencies": { 1057 | "has-flag": { 1058 | "version": "4.0.0", 1059 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1060 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1061 | "dev": true 1062 | } 1063 | } 1064 | }, 1065 | "to-regex-range": { 1066 | "version": "5.0.1", 1067 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1068 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1069 | "dev": true, 1070 | "requires": { 1071 | "is-number": "^7.0.0" 1072 | } 1073 | }, 1074 | "typescript": { 1075 | "version": "3.9.7", 1076 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", 1077 | "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", 1078 | "dev": true 1079 | }, 1080 | "util": { 1081 | "version": "0.12.3", 1082 | "resolved": "https://registry.npmjs.org/util/-/util-0.12.3.tgz", 1083 | "integrity": "sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog==", 1084 | "dev": true, 1085 | "requires": { 1086 | "inherits": "^2.0.3", 1087 | "is-arguments": "^1.0.4", 1088 | "is-generator-function": "^1.0.7", 1089 | "is-typed-array": "^1.1.3", 1090 | "safe-buffer": "^5.1.2", 1091 | "which-typed-array": "^1.1.2" 1092 | }, 1093 | "dependencies": { 1094 | "inherits": { 1095 | "version": "2.0.4", 1096 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1097 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1098 | "dev": true 1099 | } 1100 | } 1101 | }, 1102 | "vscode-test": { 1103 | "version": "1.4.0", 1104 | "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.4.0.tgz", 1105 | "integrity": "sha512-Jt7HNGvSE0+++Tvtq5wc4hiXLIr2OjDShz/gbAfM/mahQpy4rKBnmOK33D+MR67ATWviQhl+vpmU3p/qwSH/Pg==", 1106 | "dev": true, 1107 | "requires": { 1108 | "http-proxy-agent": "^2.1.0", 1109 | "https-proxy-agent": "^2.2.4", 1110 | "rimraf": "^2.6.3" 1111 | } 1112 | }, 1113 | "which": { 1114 | "version": "2.0.2", 1115 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1116 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1117 | "dev": true, 1118 | "requires": { 1119 | "isexe": "^2.0.0" 1120 | } 1121 | }, 1122 | "which-module": { 1123 | "version": "2.0.0", 1124 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", 1125 | "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", 1126 | "dev": true 1127 | }, 1128 | "which-typed-array": { 1129 | "version": "1.1.2", 1130 | "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.2.tgz", 1131 | "integrity": "sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ==", 1132 | "dev": true, 1133 | "requires": { 1134 | "available-typed-arrays": "^1.0.2", 1135 | "es-abstract": "^1.17.5", 1136 | "foreach": "^2.0.5", 1137 | "function-bind": "^1.1.1", 1138 | "has-symbols": "^1.0.1", 1139 | "is-typed-array": "^1.1.3" 1140 | } 1141 | }, 1142 | "wide-align": { 1143 | "version": "1.1.3", 1144 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", 1145 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", 1146 | "dev": true, 1147 | "requires": { 1148 | "string-width": "^1.0.2 || 2" 1149 | } 1150 | }, 1151 | "workerpool": { 1152 | "version": "6.0.0", 1153 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.0.tgz", 1154 | "integrity": "sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA==", 1155 | "dev": true 1156 | }, 1157 | "wrap-ansi": { 1158 | "version": "5.1.0", 1159 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", 1160 | "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", 1161 | "dev": true, 1162 | "requires": { 1163 | "ansi-styles": "^3.2.0", 1164 | "string-width": "^3.0.0", 1165 | "strip-ansi": "^5.0.0" 1166 | }, 1167 | "dependencies": { 1168 | "ansi-regex": { 1169 | "version": "4.1.0", 1170 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 1171 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 1172 | "dev": true 1173 | }, 1174 | "string-width": { 1175 | "version": "3.1.0", 1176 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1177 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1178 | "dev": true, 1179 | "requires": { 1180 | "emoji-regex": "^7.0.1", 1181 | "is-fullwidth-code-point": "^2.0.0", 1182 | "strip-ansi": "^5.1.0" 1183 | } 1184 | }, 1185 | "strip-ansi": { 1186 | "version": "5.2.0", 1187 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1188 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1189 | "dev": true, 1190 | "requires": { 1191 | "ansi-regex": "^4.1.0" 1192 | } 1193 | } 1194 | } 1195 | }, 1196 | "wrappy": { 1197 | "version": "1.0.2", 1198 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1199 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1200 | "dev": true 1201 | }, 1202 | "y18n": { 1203 | "version": "4.0.0", 1204 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", 1205 | "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", 1206 | "dev": true 1207 | }, 1208 | "yargs": { 1209 | "version": "13.3.2", 1210 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", 1211 | "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", 1212 | "dev": true, 1213 | "requires": { 1214 | "cliui": "^5.0.0", 1215 | "find-up": "^3.0.0", 1216 | "get-caller-file": "^2.0.1", 1217 | "require-directory": "^2.1.1", 1218 | "require-main-filename": "^2.0.0", 1219 | "set-blocking": "^2.0.0", 1220 | "string-width": "^3.0.0", 1221 | "which-module": "^2.0.0", 1222 | "y18n": "^4.0.0", 1223 | "yargs-parser": "^13.1.2" 1224 | }, 1225 | "dependencies": { 1226 | "ansi-regex": { 1227 | "version": "4.1.0", 1228 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 1229 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 1230 | "dev": true 1231 | }, 1232 | "find-up": { 1233 | "version": "3.0.0", 1234 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", 1235 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", 1236 | "dev": true, 1237 | "requires": { 1238 | "locate-path": "^3.0.0" 1239 | } 1240 | }, 1241 | "locate-path": { 1242 | "version": "3.0.0", 1243 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", 1244 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", 1245 | "dev": true, 1246 | "requires": { 1247 | "p-locate": "^3.0.0", 1248 | "path-exists": "^3.0.0" 1249 | } 1250 | }, 1251 | "p-locate": { 1252 | "version": "3.0.0", 1253 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", 1254 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", 1255 | "dev": true, 1256 | "requires": { 1257 | "p-limit": "^2.0.0" 1258 | } 1259 | }, 1260 | "path-exists": { 1261 | "version": "3.0.0", 1262 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 1263 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 1264 | "dev": true 1265 | }, 1266 | "string-width": { 1267 | "version": "3.1.0", 1268 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1269 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1270 | "dev": true, 1271 | "requires": { 1272 | "emoji-regex": "^7.0.1", 1273 | "is-fullwidth-code-point": "^2.0.0", 1274 | "strip-ansi": "^5.1.0" 1275 | } 1276 | }, 1277 | "strip-ansi": { 1278 | "version": "5.2.0", 1279 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1280 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1281 | "dev": true, 1282 | "requires": { 1283 | "ansi-regex": "^4.1.0" 1284 | } 1285 | } 1286 | } 1287 | }, 1288 | "yargs-parser": { 1289 | "version": "13.1.2", 1290 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", 1291 | "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", 1292 | "dev": true, 1293 | "requires": { 1294 | "camelcase": "^5.0.0", 1295 | "decamelize": "^1.2.0" 1296 | } 1297 | }, 1298 | "yargs-unparser": { 1299 | "version": "1.6.1", 1300 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.1.tgz", 1301 | "integrity": "sha512-qZV14lK9MWsGCmcr7u5oXGH0dbGqZAIxTDrWXZDo5zUr6b6iUmelNKO6x6R1dQT24AH3LgRxJpr8meWy2unolA==", 1302 | "dev": true, 1303 | "requires": { 1304 | "camelcase": "^5.3.1", 1305 | "decamelize": "^1.2.0", 1306 | "flat": "^4.1.0", 1307 | "is-plain-obj": "^1.1.0", 1308 | "yargs": "^14.2.3" 1309 | }, 1310 | "dependencies": { 1311 | "ansi-regex": { 1312 | "version": "4.1.0", 1313 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 1314 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 1315 | "dev": true 1316 | }, 1317 | "find-up": { 1318 | "version": "3.0.0", 1319 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", 1320 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", 1321 | "dev": true, 1322 | "requires": { 1323 | "locate-path": "^3.0.0" 1324 | } 1325 | }, 1326 | "locate-path": { 1327 | "version": "3.0.0", 1328 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", 1329 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", 1330 | "dev": true, 1331 | "requires": { 1332 | "p-locate": "^3.0.0", 1333 | "path-exists": "^3.0.0" 1334 | } 1335 | }, 1336 | "p-locate": { 1337 | "version": "3.0.0", 1338 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", 1339 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", 1340 | "dev": true, 1341 | "requires": { 1342 | "p-limit": "^2.0.0" 1343 | } 1344 | }, 1345 | "path-exists": { 1346 | "version": "3.0.0", 1347 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 1348 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 1349 | "dev": true 1350 | }, 1351 | "string-width": { 1352 | "version": "3.1.0", 1353 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1354 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1355 | "dev": true, 1356 | "requires": { 1357 | "emoji-regex": "^7.0.1", 1358 | "is-fullwidth-code-point": "^2.0.0", 1359 | "strip-ansi": "^5.1.0" 1360 | } 1361 | }, 1362 | "strip-ansi": { 1363 | "version": "5.2.0", 1364 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1365 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1366 | "dev": true, 1367 | "requires": { 1368 | "ansi-regex": "^4.1.0" 1369 | } 1370 | }, 1371 | "yargs": { 1372 | "version": "14.2.3", 1373 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", 1374 | "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", 1375 | "dev": true, 1376 | "requires": { 1377 | "cliui": "^5.0.0", 1378 | "decamelize": "^1.2.0", 1379 | "find-up": "^3.0.0", 1380 | "get-caller-file": "^2.0.1", 1381 | "require-directory": "^2.1.1", 1382 | "require-main-filename": "^2.0.0", 1383 | "set-blocking": "^2.0.0", 1384 | "string-width": "^3.0.0", 1385 | "which-module": "^2.0.0", 1386 | "y18n": "^4.0.0", 1387 | "yargs-parser": "^15.0.1" 1388 | } 1389 | }, 1390 | "yargs-parser": { 1391 | "version": "15.0.1", 1392 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", 1393 | "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", 1394 | "dev": true, 1395 | "requires": { 1396 | "camelcase": "^5.0.0", 1397 | "decamelize": "^1.2.0" 1398 | } 1399 | } 1400 | } 1401 | } 1402 | } 1403 | } 1404 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "indenticator", 3 | "displayName": "Indenticator", 4 | "description": "Highlights your current indent depth", 5 | "version": "0.7.0", 6 | "publisher": "SirTori", 7 | "homepage": "https://github.com/SirTori/indenticator/blob/master/README.md", 8 | "license": "SEE LICENSE IN LICENSE.txt", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/SirTori/indenticator" 12 | }, 13 | "icon": "img/icon.png", 14 | "galleryBanner": { 15 | "color": "#877d88", 16 | "theme": "dark" 17 | }, 18 | "badges": [ 19 | { 20 | "url": "https://david-dm.org/sirtori/indenticator.svg", 21 | "href": "https://david-dm.org/sirtori/indenticator", 22 | "description": "Dependency Status" 23 | }, 24 | { 25 | "url": "https://travis-ci.org/SirTori/indenticator.svg?branch=master", 26 | "href": "https://travis-ci.org/SirTori/indenticator", 27 | "description": "Build Status" 28 | } 29 | ], 30 | "bugs": { 31 | "url": "https://github.com/SirTori/indenticator/issues" 32 | }, 33 | "engines": { 34 | "vscode": "^1.48.0" 35 | }, 36 | "categories": [ 37 | "Other" 38 | ], 39 | "keywords": [ 40 | "guides", 41 | "indentation", 42 | "indentation guides", 43 | "indent", 44 | "indent guides", 45 | "block highlight", 46 | "vertical block line" 47 | ], 48 | "activationEvents": [ 49 | "*" 50 | ], 51 | "main": "./out/src/extension", 52 | "scripts": { 53 | "vscode:prepublish": "npm run compile", 54 | "compile": "tsc -p ./", 55 | "lint": "eslint . --ext .ts,.tsx", 56 | "watch": "tsc -watch -p ./", 57 | "pretest": "npm run compile", 58 | "test": "node ./out/test/runTest.js" 59 | }, 60 | "devDependencies": { 61 | "@types/glob": "^7.1.1", 62 | "@types/mocha": "^8.0.0", 63 | "@types/node": "^12.0.0", 64 | "@types/vscode": "^1.48.0", 65 | "vscode-test": "^1.4.0", 66 | "glob": "^7.1.4", 67 | "assert": "^2.0.0", 68 | "mocha": "^8.0.0", 69 | "typescript": "^3.3.1" 70 | }, 71 | "contributes": { 72 | "configuration": { 73 | "type": "object", 74 | "title": "Indenticator Configuration", 75 | "properties": { 76 | "indenticator.showIndentGuide": { 77 | "type": "boolean", 78 | "default": true, 79 | "description": "Whether to highlight the indent of the block enclosing the current line" 80 | }, 81 | "indenticator.color.dark": { 82 | "type": "string", 83 | "default": "#888", 84 | "description": "Color of the indent marker for dark themes" 85 | }, 86 | "indenticator.color.light": { 87 | "type": "string", 88 | "default": "#999", 89 | "description": "Color of the indent marker for light themes" 90 | }, 91 | "indenticator.width": { 92 | "type": "number", 93 | "default": 1, 94 | "description": "Width of the indent marker in pixels" 95 | }, 96 | "indenticator.style": { 97 | "type": "string", 98 | "default": "inset", 99 | "description": "Line style of the indent marker" 100 | }, 101 | "indenticator.inner.showIndentGuide": { 102 | "type": "boolean", 103 | "default": false, 104 | "description": "Whether to highlight the indent of the block enclosed by the current line" 105 | }, 106 | "indenticator.inner.color.dark": { 107 | "type": "string", 108 | "description": "Color of the inner indent marker for dark themes" 109 | }, 110 | "indenticator.inner.color.light": { 111 | "type": "string", 112 | "default": "#999", 113 | "description": "Color of the inner indent marker for light themes" 114 | }, 115 | "indenticator.inner.width": { 116 | "type": "number", 117 | "default": 1, 118 | "description": "Width of the inner indent marker in pixels" 119 | }, 120 | "indenticator.inner.style": { 121 | "type": "string", 122 | "default": "inset", 123 | "description": "Line style of the inner indent marker" 124 | }, 125 | "indenticator.showCurrentDepthInStatusBar": { 126 | "type": "boolean", 127 | "default": true, 128 | "description": "Whether to display the current indent depth on the statusbar" 129 | }, 130 | "indenticator.showHover": { 131 | "type": [ 132 | "boolean", 133 | "number" 134 | ], 135 | "default": false, 136 | "description": "Whether to display the hover near the indent line, or minimum number of lines in current indent block to activate the hover." 137 | }, 138 | "indenticator.hover.highlight": { 139 | "type": "boolean", 140 | "default": true, 141 | "description": "Wether to highlight the contained code block when hovering the indent line. If activated, the peeked content will be shown at top or bottom of the block, otherwise it will be shown at cursor position." 142 | }, 143 | "indenticator.hover.peekBack": { 144 | "type": "number", 145 | "default": 1, 146 | "description": "Lines before the current indent to be shown on hover" 147 | }, 148 | "indenticator.hover.peekForward": { 149 | "type": "number", 150 | "default": 0, 151 | "description": "Lines after the current indent to be shown on hover" 152 | }, 153 | "indenticator.hover.trimLinesShorterThan": { 154 | "type": "number", 155 | "default": 2, 156 | "description": "Remove lines from the hover at the beginning and end that have less characters than this" 157 | }, 158 | "indenticator.hover.peekBlockPlaceholder": { 159 | "type": "string", 160 | "default": "...", 161 | "description": "Block placeholder to be written between peeked lines" 162 | }, 163 | "indenticator.inner.showHover": { 164 | "type": [ 165 | "boolean", 166 | "number" 167 | ], 168 | "default": false, 169 | "description": "Whether to display the hover near the inner indent line, or minimum number of lines in current indent block to activate the hover." 170 | }, 171 | "indenticator.inner.hover.highlight": { 172 | "type": "boolean", 173 | "default": true, 174 | "description": "Wether to highlight the contained code block when hovering the inner indent line. If activated, the peeked content will be shown at top or bottom of the block, otherwise it will be shown at cursor position." 175 | }, 176 | "indenticator.inner.hover.peekBack": { 177 | "type": "number", 178 | "default": 1, 179 | "description": "Lines before the current inner indent to be shown on hover" 180 | }, 181 | "indenticator.inner.hover.peekForward": { 182 | "type": "number", 183 | "default": 0, 184 | "description": "Lines after the current inner indent to be shown on hover" 185 | }, 186 | "indenticator.inner.hover.trimLinesShorterThan": { 187 | "type": "number", 188 | "default": 2, 189 | "description": "Remove lines from the inner indent hover at the beginning and end that have less characters than this" 190 | }, 191 | "indenticator.inner.hover.peekBlockPlaceholder": { 192 | "type": "string", 193 | "default": "...", 194 | "description": "Block placeholder to be written between peeked lines for the hover of the inner indent" 195 | }, 196 | "indenticator.languageSpecific": { 197 | "type": [ 198 | "object" 199 | ], 200 | "default": {}, 201 | "description": "A construct with language identifiers as properties containing a subset of indenticator options to be applied to that language", 202 | "additionalProperties": false, 203 | "patternProperties": { 204 | "^\\[(\\w+,?\\s*)+\\]$": { 205 | "type": [ 206 | "object" 207 | ], 208 | "description": "Language Specific config", 209 | "additionalProperties": false, 210 | "properties": { 211 | "indenticator.showHighlight": { 212 | "type": "boolean", 213 | "default": true, 214 | "description": "Whether to highlight the indent of the block enclosing the current line" 215 | }, 216 | "indenticator.color.dark": { 217 | "type": "string", 218 | "default": "#888", 219 | "description": "Color of the indent marker for dark themes" 220 | }, 221 | "indenticator.color.light": { 222 | "type": "string", 223 | "default": "#999", 224 | "description": "Color of the indent marker for light themes" 225 | }, 226 | "indenticator.width": { 227 | "type": "number", 228 | "default": 1, 229 | "description": "Width of the indent marker in pixels" 230 | }, 231 | "indenticator.style": { 232 | "type": "string", 233 | "default": "inset", 234 | "description": "Line style of the indent marker" 235 | }, 236 | "indenticator.inner.showHighlight": { 237 | "type": "boolean", 238 | "default": false, 239 | "description": "Whether to highlight the indent of the block enclosed by the current line" 240 | }, 241 | "indenticator.inner.color.dark": { 242 | "type": "string", 243 | "default": "#888", 244 | "description": "Color of the indent marker for dark themes" 245 | }, 246 | "indenticator.inner.color.light": { 247 | "type": "string", 248 | "default": "#999", 249 | "description": "Color of the indent marker for light themes" 250 | }, 251 | "indenticator.inner.width": { 252 | "type": "number", 253 | "default": 1, 254 | "description": "Width of the indent marker in pixels" 255 | }, 256 | "indenticator.inner.style": { 257 | "type": "string", 258 | "default": "inset", 259 | "description": "Line style of the indent marker" 260 | }, 261 | "indenticator.showCurrentDepthInStatusBar": { 262 | "type": "boolean", 263 | "default": true, 264 | "description": "Whether to display the current indent depth on the statusbar" 265 | }, 266 | "indenticator.showHover": { 267 | "type": [ 268 | "boolean", 269 | "number" 270 | ], 271 | "default": false, 272 | "description": "Whether to display the hover near the indent line, or minimum number of lines in current indent block to activate the hover." 273 | }, 274 | "indenticator.hover.highlight": { 275 | "type": "boolean", 276 | "default": true, 277 | "description": "Wether to highlight the contained code block when hovering the indent line. If activated, the peeked content will be shown at top or bottom of the block, otherwise it will be shown at cursor position." 278 | }, 279 | "indenticator.hover.peekBack": { 280 | "type": "number", 281 | "default": 1, 282 | "description": "Lines before the current indent to be shown on hover" 283 | }, 284 | "indenticator.hover.peekForward": { 285 | "type": "number", 286 | "default": 0, 287 | "description": "Lines after the current indent to be shown on hover" 288 | }, 289 | "indenticator.hover.trimLinesShorterThan": { 290 | "type": "number", 291 | "default": 2, 292 | "description": "Remove lines from the hover at the beginning and end that have less characters than this" 293 | }, 294 | "indenticator.hover.peekBlockPlaceholder": { 295 | "type": "string", 296 | "default": "...", 297 | "description": "Block placeholder to be written between peeked lines" 298 | }, 299 | "indenticator.inner.showHover": { 300 | "type": [ 301 | "boolean", 302 | "number" 303 | ], 304 | "default": false, 305 | "description": "Whether to display the hover near the inner indent line, or minimum number of lines in current indent block to activate the hover." 306 | }, 307 | "indenticator.inner.hover.highlight": { 308 | "type": "boolean", 309 | "default": true, 310 | "description": "Wether to highlight the contained code block when hovering the inner indent line. If activated, the peeked content will be shown at top or bottom of the block, otherwise it will be shown at cursor position." 311 | }, 312 | "indenticator.inner.hover.peekBack": { 313 | "type": "number", 314 | "default": 1, 315 | "description": "Lines before the current inner indent to be shown on hover" 316 | }, 317 | "indenticator.inner.hover.peekForward": { 318 | "type": "number", 319 | "default": 0, 320 | "description": "Lines after the current inner indent to be shown on hover" 321 | }, 322 | "indenticator.inner.hover.trimLinesShorterThan": { 323 | "type": "number", 324 | "default": 2, 325 | "description": "Remove lines from the inner indent hover at the beginning and end that have less characters than this" 326 | }, 327 | "indenticator.inner.hover.peekBlockPlaceholder": { 328 | "type": "string", 329 | "default": "...", 330 | "description": "Block placeholder to be written between peeked lines for the hover of the inner indent" 331 | } 332 | } 333 | } 334 | } 335 | } 336 | } 337 | } 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // The module 'vscode' contains the VS Code extensibility API 3 | // Import the module and reference it with the alias vscode in your code below 4 | import {window, Disposable, ExtensionContext, StatusBarAlignment, 5 | StatusBarItem, TextDocument, TextEditor, TextEditorOptions, 6 | TextEditorDecorationType, TextLine, Selection, Range, 7 | Position, workspace, env, languages, WorkspaceConfiguration, Hover 8 | } from 'vscode'; 9 | // this method is called when your extension is activated 10 | // your extension is activated the very first time the command is executed 11 | export function activate(context: ExtensionContext) { 12 | 13 | let indentSpy = new IndentSpy(); 14 | let indentSpyController = new IndentSpyController(indentSpy); 15 | 16 | context.subscriptions.push(indentSpy); 17 | context.subscriptions.push(indentSpyController); 18 | } 19 | 20 | // this method is called when your extension is deactivated 21 | export function deactivate() { 22 | } 23 | 24 | class LanguageConfig { 25 | constructor(public langConfig: any, 26 | public config: WorkspaceConfiguration) {} 27 | 28 | get(name: string, defaultValue?:T ): T { 29 | let v = this.langConfig[`indenticator.${name}`]; 30 | if(v !== undefined) { 31 | return v; 32 | } 33 | return this.config.get(name, defaultValue); 34 | } 35 | } 36 | 37 | class IndentConfiguration { 38 | show: boolean; 39 | style: TextEditorDecorationType; 40 | hover: number; 41 | hoverConf: { 42 | highlight: boolean, 43 | peekBack: number, 44 | peekForward: number, 45 | trimLinesShorterThan: number, 46 | peekBlockPlaceholder: string 47 | }; 48 | hoverProvider: Disposable 49 | firstLine: number; 50 | lastLine: number; 51 | indentPos: number; 52 | } 53 | 54 | export class IndentSpy { 55 | _locales: Object; 56 | _currentLocale: Object; 57 | _statusBarItem: StatusBarItem; 58 | _outerConf: IndentConfiguration = new IndentConfiguration(); 59 | _innerConf: IndentConfiguration = new IndentConfiguration(); 60 | 61 | constructor() { 62 | this._locales = { 63 | en: {statusText: `Indents: {indent}`, 64 | statusTooltip: `current indent depth: {indent}`}, 65 | de: {statusText: `Einzüge: {indent}`, 66 | statusTooltip: `aktuelle Einzugtiefe: {indent}`}, 67 | ja: {statusText: `字下げ: {indent}`, 68 | statusTooltip: `現在のインデントの深さ: {indent}`}, 69 | default: {statusText: `Indents: {indent}`, 70 | statusTooltip: `current indent depth: {indent}`}, 71 | }; 72 | this.updateConfig(); 73 | } 74 | 75 | public updateConfig() { 76 | this._clearDecorators(); 77 | 78 | let locale = env.language; 79 | let multipartLocale = env.language.indexOf('-'); 80 | if(multipartLocale >= 0) { 81 | locale = locale.substring(0, multipartLocale); 82 | } 83 | 84 | if(!this._locales[locale]) { 85 | this._currentLocale = this._locales['default']; 86 | } else { 87 | this._currentLocale = this._locales[locale]; 88 | } 89 | let langConfig = {}; 90 | let config = workspace.getConfiguration('indenticator'); 91 | if(window.activeTextEditor) { 92 | let docLang = window.activeTextEditor.document.languageId 93 | let allLangConfig = config.get("languageSpecific", {}); 94 | let docLangKey = Object.keys(allLangConfig).find(k => { 95 | return k.match(`^\\[(.*,\\s*)?${docLang}(,.*)?\\]$`) !== null; 96 | }); 97 | if(docLangKey) { 98 | langConfig = allLangConfig[docLangKey] || {}; 99 | } 100 | } 101 | let myConf = new LanguageConfig(langConfig, config); 102 | 103 | if(myConf.get('showCurrentDepthInStatusBar')) { 104 | if(!this._statusBarItem) { 105 | this._statusBarItem = window.createStatusBarItem( 106 | StatusBarAlignment.Right, 100); 107 | } 108 | } else if(this._statusBarItem) { 109 | this._statusBarItem.dispose(); 110 | this._statusBarItem = undefined; 111 | } 112 | 113 | this._outerConf.show = myConf.get('showIndentGuide'); 114 | this._innerConf.show = myConf.get('inner.showIndentGuide'); 115 | 116 | this._outerConf.style = window.createTextEditorDecorationType({ 117 | dark: { 118 | borderColor: myConf.get('color.dark', '#888'), 119 | borderStyle: myConf.get('style', 'inset'), 120 | borderWidth: myConf.get('width', 1) + "px" 121 | }, 122 | light: { 123 | borderColor: myConf.get('color.light', '#999'), 124 | borderStyle: myConf.get('style', 'inset'), 125 | borderWidth: myConf.get('width', 1) + "px" 126 | } 127 | }); 128 | 129 | this._innerConf.style = window.createTextEditorDecorationType({ 130 | dark: { 131 | borderColor: myConf.get('inner.color.dark', '#888'), 132 | borderStyle: myConf.get('inner.style', 'inset'), 133 | borderWidth: myConf.get('inner.width', 1) + "px" 134 | }, 135 | light: { 136 | borderColor: myConf.get('inner.color.light', '#999'), 137 | borderStyle: myConf.get('inner.style', 'inset'), 138 | borderWidth: myConf.get('inner.width', 1) + "px" 139 | } 140 | }); 141 | 142 | let showHover:boolean|number = myConf.get('showHover', false); 143 | if(typeof showHover === 'boolean') { 144 | this._outerConf.hover = showHover ? 1 : 0; 145 | } else { 146 | this._outerConf.hover = showHover; 147 | } 148 | if(this._outerConf.hover) { 149 | this._outerConf.hoverConf = { 150 | highlight: myConf.get('hover.highlight', true), 151 | peekBack: myConf.get('hover.peekBack', 1), 152 | peekForward: myConf.get('hover.peekForward', 0), 153 | trimLinesShorterThan: myConf.get( 154 | 'hover.trimLinesShorterThan', 2), 155 | peekBlockPlaceholder: myConf.get( 156 | 'hover.peekBlockPlaceholder', '...') 157 | }; 158 | } else if (this._outerConf.hoverProvider) { 159 | this._outerConf.hoverProvider.dispose(); 160 | } 161 | 162 | showHover = myConf.get('inner.showHover', false); 163 | if(typeof showHover === 'boolean') { 164 | this._innerConf.hover = showHover ? 1 : 0; 165 | } else { 166 | this._innerConf.hover = showHover; 167 | } 168 | if(this._innerConf.hover) { 169 | this._innerConf.hoverConf = { 170 | highlight: myConf.get('inner.hover.highlight', true), 171 | peekBack: myConf.get('inner.hover.peekBack', 1), 172 | peekForward: myConf.get('inner.hover.peekForward', 0), 173 | trimLinesShorterThan: myConf.get( 174 | 'inner.hover.trimLinesShorterThan', 2), 175 | peekBlockPlaceholder: myConf.get( 176 | 'inner.hover.peekBlockPlaceholder', '...') 177 | }; 178 | } else if (this._innerConf.hoverProvider) { 179 | this._innerConf.hoverProvider.dispose(); 180 | } 181 | 182 | this.updateCurrentIndent(); 183 | } 184 | 185 | public updateCurrentIndent() { 186 | let hideStatusbarIfPossible = () => { 187 | if(this._statusBarItem) { 188 | this._statusBarItem.hide(); 189 | } 190 | } 191 | 192 | let editor = window.activeTextEditor; 193 | if (!editor) { 194 | hideStatusbarIfPossible(); 195 | return; 196 | } 197 | 198 | let document = editor.document; 199 | if (!document) { 200 | hideStatusbarIfPossible(); 201 | return; 202 | } 203 | 204 | let selection = editor.selection; 205 | if (!selection) { 206 | hideStatusbarIfPossible(); 207 | return; 208 | } 209 | 210 | let tabSize = this._getTabSize(editor.options); 211 | let selectedIndent = this._getSelectedIndentDepth(document, selection, tabSize); 212 | if(this._outerConf.show || this._outerConf.hover || this._innerConf.show || this._innerConf.hover) { 213 | let activeRanges = this._getActiveIndentRanges(document, selection, selectedIndent, tabSize); 214 | if(this._outerConf.show) { 215 | editor.setDecorations(this._outerConf.style, activeRanges.outer); 216 | } 217 | if(this._outerConf.hover && activeRanges.outer.length >= this._outerConf.hover) { 218 | this._buildHover(editor, tabSize, this._outerConf); 219 | } else if(this._outerConf.hoverProvider) { 220 | this._outerConf.hoverProvider.dispose(); 221 | } 222 | if(this._innerConf.show) { 223 | editor.setDecorations(this._innerConf.style, activeRanges.inner); 224 | } 225 | if(this._innerConf.hover && activeRanges.inner.length >= this._innerConf.hover) { 226 | this._buildHover(editor, tabSize, this._innerConf); 227 | } else if(this._innerConf.hoverProvider) { 228 | this._innerConf.hoverProvider.dispose(); 229 | } 230 | } 231 | 232 | if(this._statusBarItem){ 233 | this._statusBarItem.text = this._currentLocale['statusText'] 234 | .replace('{indent}', selectedIndent); 235 | this._statusBarItem.tooltip = this._currentLocale['statusTooltip'] 236 | .replace('{indent}', selectedIndent); 237 | this._statusBarItem.show(); 238 | } 239 | } 240 | 241 | _buildHover(editor: TextEditor, tabSize: number, conf: IndentConfiguration) { 242 | if (conf.hoverProvider) { 243 | conf.hoverProvider.dispose(); 244 | } 245 | conf.hoverProvider = languages.registerHoverProvider( 246 | editor.document.languageId, 247 | { 248 | provideHover: (doc, position) => { 249 | return this._buildHoverprovider(position, editor, tabSize, conf); 250 | } 251 | } 252 | ); 253 | } 254 | 255 | _buildHoverprovider(position: Position, editor: TextEditor, 256 | tabSize: number, conf: IndentConfiguration): Hover { 257 | let char = conf.indentPos 258 | if(position.character > char - 1 259 | && position.character < char + 1 260 | && position.line >= conf.firstLine 261 | && position.line <= conf.lastLine) { 262 | let str = this._buildHoverString(editor, tabSize, conf); 263 | let range; 264 | if (conf.hoverConf.highlight) { 265 | range = new Range(conf.firstLine, conf.indentPos, 266 | conf.lastLine, conf.indentPos) 267 | } 268 | if(str) { 269 | return { 270 | range: range, 271 | contents: [ 272 | { 273 | language: editor.document.languageId, 274 | value: str 275 | } 276 | ] 277 | }; 278 | } 279 | return null; 280 | } 281 | } 282 | 283 | _buildHoverString(editor: TextEditor, tabSize: number, 284 | conf: IndentConfiguration): string { 285 | let hoverLines = []; 286 | let document = editor.document; 287 | let refDepth = this._getLinesIndentDepth( 288 | document.lineAt(conf.firstLine), tabSize); 289 | 290 | let backHoverLines = this._peekBack(editor.document, tabSize, refDepth, conf); 291 | let forwardHoverLines = this._peekForward(editor.document, tabSize, refDepth, conf); 292 | 293 | hoverLines.push(...backHoverLines); 294 | if(forwardHoverLines.length > 0 || backHoverLines.length > 0) { 295 | hoverLines.push(this._buildHoverPlaceholder(editor, tabSize, conf)); 296 | } 297 | hoverLines.push(...forwardHoverLines); 298 | return hoverLines.join('\n'); 299 | } 300 | 301 | _buildHoverPlaceholder(editor: TextEditor, tabSize: number, 302 | conf: IndentConfiguration): string { 303 | let tabChar = editor.options.insertSpaces?' ':'\t'; 304 | let spacing = tabChar.repeat(tabSize); 305 | return `${spacing}${conf.hoverConf.peekBlockPlaceholder}`; 306 | } 307 | 308 | _peekBack(document: TextDocument, tabSize: number, 309 | refDepth: number, conf: IndentConfiguration): Array { 310 | let backHoverLines = []; 311 | if(conf && conf.hoverConf && conf.hoverConf.peekBack > 0) { 312 | let firstPeekLine = Math.max( 313 | conf.firstLine - (conf.hoverConf.peekBack - 1), 0); 314 | let pushedOnce = false; 315 | for(let i = firstPeekLine; i <= conf.firstLine; i++) { 316 | let line = document.lineAt(i) 317 | let lineStr = line.text.trim(); 318 | if(!pushedOnce && 319 | lineStr.length < conf.hoverConf.trimLinesShorterThan) { 320 | continue; 321 | } 322 | let lineDepth = this._getLinesIndentDepth(line, tabSize); 323 | if(lineDepth != refDepth) { 324 | backHoverLines.splice(0); 325 | continue; 326 | } 327 | backHoverLines.push(lineStr); 328 | pushedOnce = true; 329 | } 330 | } 331 | return backHoverLines; 332 | } 333 | 334 | _peekForward(document: TextDocument, tabSize: number, 335 | refDepth: number, conf: IndentConfiguration): Array { 336 | let forwardHoverLines = []; 337 | if(conf && conf.hoverConf && conf.hoverConf.peekForward > 0) { 338 | let lastPeekLine = Math.min( 339 | conf.lastLine + (conf.hoverConf.peekForward - 1), 340 | document.lineCount - 1); 341 | let pushedOnce = false; 342 | for(let i = lastPeekLine; i >= conf.lastLine; i--) { 343 | let line = document.lineAt(i) 344 | let lineStr = line.text.trim(); 345 | if(!pushedOnce && 346 | lineStr.length < conf.hoverConf.trimLinesShorterThan) { 347 | continue; 348 | } 349 | let lineDepth = this._getLinesIndentDepth(line, tabSize); 350 | if(lineDepth != refDepth) { 351 | forwardHoverLines.splice(0); 352 | continue; 353 | } 354 | forwardHoverLines.push(lineStr); 355 | pushedOnce = true; 356 | } 357 | } 358 | return forwardHoverLines.reverse(); 359 | } 360 | 361 | _clearDecorators() { 362 | if(this._outerConf.style) { 363 | for(let i = 0; i < window.visibleTextEditors.length; i++) { 364 | window.visibleTextEditors[i].setDecorations( 365 | this._outerConf.style, []); 366 | } 367 | 368 | } 369 | if(this._innerConf.style) { 370 | for(let i = 0; i < window.visibleTextEditors.length; i++) { 371 | window.visibleTextEditors[i].setDecorations( 372 | this._innerConf.style, []); 373 | } 374 | 375 | } 376 | } 377 | 378 | _getTabSize(options: TextEditorOptions) { 379 | return options.insertSpaces?Number(options.tabSize):1; 380 | } 381 | 382 | _getIndentDepth(index: number, tabSize: number) { 383 | return Math.ceil(index / tabSize); 384 | } 385 | 386 | _getLinesIndentDepth(line: TextLine, tabSize: number) { 387 | return this._getIndentDepth(line.firstNonWhitespaceCharacterIndex, 388 | tabSize); 389 | } 390 | 391 | _createIndicatorRange(line: number, character: number) { 392 | return new Range(new Position(line, character), 393 | new Position(line, character)); 394 | } 395 | 396 | _getSelectedIndentDepth(document: TextDocument, selection: Selection, 397 | tabSize: number) { 398 | if(selection.isSingleLine) { 399 | let maxlineNum = document.lineCount - 1; 400 | let line = document.lineAt(Math.min(selection.start.line, maxlineNum)); 401 | return this._getIndentDepth( 402 | Math.min(selection.start.character, 403 | line.firstNonWhitespaceCharacterIndex), 404 | tabSize); 405 | } 406 | let selectedIndent = Number.MAX_VALUE; 407 | let maxlineNum = Math.min(selection.end.line,document.lineCount - 1); 408 | for(let i = selection.start.line; i <= maxlineNum; i++) { 409 | let line = document.lineAt(i); 410 | if(line.isEmptyOrWhitespace) { 411 | continue; 412 | } 413 | selectedIndent = Math.min(selectedIndent, 414 | this._getLinesIndentDepth(line, tabSize)); 415 | } 416 | return selectedIndent; 417 | } 418 | 419 | _getActiveIndentRanges(document: TextDocument, selection: Selection, 420 | selectedIndent: number, tabSize: number){ 421 | let activeRanges = []; 422 | let activeInnerRanges = []; 423 | let line: TextLine; 424 | let innerDeactivated: boolean; 425 | 426 | this._outerConf.firstLine = selection.start.line; 427 | this._outerConf.lastLine = selection.end.line; 428 | this._outerConf.indentPos = (selectedIndent - 1) * tabSize; 429 | 430 | this._innerConf.firstLine = selection.start.line; 431 | this._innerConf.lastLine = selection.end.line; 432 | this._innerConf.indentPos = selectedIndent * tabSize; 433 | 434 | let addRanges = (i: number, line: TextLine) => { 435 | let lineAdded = false; 436 | let innerAdded = false; 437 | let lineIndent = this._getLinesIndentDepth(line, tabSize); 438 | if(!innerDeactivated && ( 439 | lineIndent > selectedIndent || ( 440 | line.isEmptyOrWhitespace && selectedIndent === lineIndent && 441 | (i !== selection.end.line || selection.end.character !== this._innerConf.indentPos)))) { 442 | activeInnerRanges.push( 443 | this._createIndicatorRange(i, this._innerConf.indentPos)); 444 | lineAdded = true; 445 | innerAdded = true; 446 | } 447 | if(this._outerConf.indentPos >= 0 && ( 448 | lineIndent >= selectedIndent || ( 449 | line.isEmptyOrWhitespace && selectedIndent === 1))) { 450 | activeRanges.push(this._createIndicatorRange(i, this._outerConf.indentPos)); 451 | lineAdded = true; 452 | } 453 | return { 454 | 'lineAdded': lineAdded, 455 | 'innerAdded': innerAdded 456 | }; 457 | }; 458 | 459 | // add ranges for preceeding lines on same indent 460 | innerDeactivated = false; 461 | for(let i = selection.start.line; i >= 0; i--) { 462 | line = document.lineAt(i); 463 | let result = addRanges(i, line) 464 | if(!result.innerAdded && !line.isEmptyOrWhitespace && !innerDeactivated) { 465 | innerDeactivated = true; 466 | this._innerConf.firstLine = i; 467 | } 468 | if(!result.lineAdded && !line.isEmptyOrWhitespace) { 469 | this._outerConf.firstLine = i; 470 | break; 471 | } 472 | } 473 | // add ranges for following lines on same indent 474 | innerDeactivated = false; 475 | for(let i = selection.start.line + 1; i < document.lineCount; i++) { 476 | line = document.lineAt(i); 477 | let result = addRanges(i, line) 478 | if(!result.innerAdded && !line.isEmptyOrWhitespace && !innerDeactivated) { 479 | innerDeactivated = true; 480 | this._innerConf.lastLine = i; 481 | } 482 | if(!result.lineAdded && !line.isEmptyOrWhitespace) { 483 | this._outerConf.lastLine = i; 484 | break; 485 | } 486 | } 487 | return { 488 | outer: activeRanges, 489 | inner: activeInnerRanges 490 | }; 491 | } 492 | 493 | dispose() { 494 | if(this._statusBarItem){ 495 | this._statusBarItem.dispose(); 496 | } 497 | if(this._outerConf.hoverProvider) { 498 | this._outerConf.hoverProvider.dispose(); 499 | } 500 | if (this._innerConf.hoverProvider) { 501 | this._innerConf.hoverProvider.dispose(); 502 | } 503 | } 504 | } 505 | 506 | class IndentSpyController { 507 | 508 | private _indentSpy: IndentSpy; 509 | private _disposable: Disposable; 510 | 511 | constructor(indentSpy: IndentSpy) { 512 | this._indentSpy = indentSpy; 513 | this._indentSpy.updateCurrentIndent(); 514 | 515 | // subscribe to selection change and editor activation events 516 | let subscriptions: Disposable[] = []; 517 | window.onDidChangeTextEditorSelection( 518 | this._onUpdateEvent, this, subscriptions); 519 | window.onDidChangeActiveTextEditor( 520 | this._onChangedEditor, this, subscriptions); 521 | 522 | // subscribe to configuration change events 523 | workspace.onDidChangeConfiguration( 524 | this._onChangedConfigEvent, this, subscriptions); 525 | 526 | this._disposable = Disposable.from(...subscriptions); 527 | } 528 | 529 | dispose() { 530 | this._disposable.dispose(); 531 | } 532 | 533 | private _onUpdateEvent(e) { 534 | this._indentSpy.updateCurrentIndent(); 535 | } 536 | 537 | private _onChangedEditor(e) { 538 | this._indentSpy.updateConfig(); 539 | this._indentSpy.updateCurrentIndent(); 540 | } 541 | 542 | private _onChangedConfigEvent(e) { 543 | this._indentSpy.updateConfig(); 544 | } 545 | } -------------------------------------------------------------------------------- /test-fixtures/demo/demo.ts: -------------------------------------------------------------------------------- 1 | class Foobar { 2 | constructor() { 3 | let iterations = Math.floor(Math.random() * 100); 4 | for(let i = 0; i < iterations; i++) { 5 | if(i % 3) { 6 | this.foo(); 7 | /* 8 | Lorem ipsum dolor sit amet, 9 | consetetur sadipscing elitr, 10 | sed diam nonumy eirmod tempor 11 | invidunt ut labore et dolore 12 | magna aliquyam erat... 13 | */ 14 | } else if(i % 2) { 15 | this.bar(); 16 | } 17 | } 18 | } 19 | 20 | foo() { 21 | //do something 22 | } 23 | 24 | bar() { 25 | // do something else 26 | } 27 | } -------------------------------------------------------------------------------- /test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import { runTests } from 'vscode-test'; 3 | 4 | async function go() { 5 | try { 6 | 7 | const extensionDevelopmentPath = path.resolve(__dirname, '../../') 8 | const extensionTestsPath = path.resolve(__dirname, './suite') 9 | const testWorkspace = path.resolve(__dirname, '../../test-fixtures') 10 | runTests({ 11 | extensionDevelopmentPath, 12 | extensionTestsPath: extensionTestsPath, 13 | launchArgs: [testWorkspace] 14 | }); 15 | } catch (err) { 16 | console.error('Failed to run tests'); 17 | process.exit(1); 18 | } 19 | } 20 | 21 | go(); -------------------------------------------------------------------------------- /test/suite/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 | import * as path from "path"; 9 | 10 | // You can import and use all API from the 'vscode' module 11 | // as well as import your extension to test it 12 | import * as vscode from 'vscode'; 13 | import * as myExtension from '../../src/extension'; 14 | 15 | let fs = require('fs'); 16 | 17 | 18 | let setEditorContent = (editor: vscode.TextEditor, text: string) => { 19 | return editor.edit((e) => { 20 | e.delete(editor.document.validateRange( 21 | new vscode.Range(0, 0, Number.MAX_VALUE, Number.MAX_VALUE))); 22 | e.insert(new vscode.Position(0,0), text); 23 | }); 24 | }; 25 | 26 | 27 | suite("Extension Tests", () => { 28 | let tmpFilePath = path.resolve(__dirname) + "/tmp.txt"; 29 | let document : vscode.TextDocument; 30 | 31 | suiteSetup(() => { 32 | fs.writeFileSync(tmpFilePath, "foo"); 33 | return vscode.workspace.openTextDocument(tmpFilePath).then( 34 | (doc) => document = doc 35 | ); 36 | }); 37 | 38 | suiteSetup(() => { 39 | return vscode.window.showTextDocument(document); 40 | }); 41 | 42 | suiteTeardown(() => { 43 | let fileStatus = fs.statSync(tmpFilePath); 44 | if(fileStatus.isFile()) { 45 | fs.unlinkSync(tmpFilePath); 46 | } 47 | }); 48 | 49 | // Defines a Mocha unit test 50 | suite("IndentSpy", () => { 51 | let IndentSpy : myExtension.IndentSpy; 52 | 53 | setup(() => { 54 | IndentSpy = new myExtension.IndentSpy(); 55 | }); 56 | 57 | suite("_getTabSize", () => { 58 | let options; 59 | let initialValues; 60 | 61 | setup(() => { 62 | options = vscode.window.activeTextEditor.options; 63 | initialValues = { 64 | insertSpaces: options.insertSpaces, 65 | tabSize: options.tabSize 66 | }; 67 | }); 68 | 69 | teardown(() => { 70 | options.insertSpaces = initialValues.insertSpaces; 71 | options.tabSize = initialValues.tabSize; 72 | }) 73 | 74 | test("returns 1 if insertSpaces option is false", () => { 75 | options.insertSpaces = false; 76 | options.tabSize = 5; 77 | 78 | let result = IndentSpy._getTabSize(options); 79 | 80 | assert.strictEqual(result, 1); 81 | }); 82 | 83 | test("returns tabSize if insertSpaces option is true", () => { 84 | options.insertSpaces = true; 85 | options.tabSize = 5; 86 | 87 | let result = IndentSpy._getTabSize(options); 88 | 89 | assert.strictEqual(result, 5); 90 | }); 91 | }); 92 | 93 | suite("_getIndentDepth", () => { 94 | 95 | test("returns the quotient of given parameters", () => { 96 | let index = 12, tabSize = 3; 97 | 98 | let result = IndentSpy._getIndentDepth(index, tabSize); 99 | 100 | assert.strictEqual(result, 4); 101 | }); 102 | 103 | test("always rounds up", () => { 104 | let index = 11, tabSize = 5; 105 | 106 | let result = IndentSpy._getIndentDepth(index, tabSize); 107 | 108 | assert.strictEqual(result, 3); 109 | }); 110 | }); 111 | 112 | suite("_getLinesIndentDepth", () => { 113 | 114 | let editor : vscode.TextEditor; 115 | 116 | suiteSetup(() => { 117 | editor = vscode.window.activeTextEditor; 118 | return setEditorContent(editor, " test"); 119 | }); 120 | 121 | test("returns the quotient of given leading whitespace" + 122 | " chararcters and tabSize", () => { 123 | 124 | let line = editor.document.lineAt(0); 125 | let tabSize = 3; 126 | 127 | let result = IndentSpy._getLinesIndentDepth( 128 | line, tabSize); 129 | 130 | assert.strictEqual(result, 4); 131 | }); 132 | 133 | test("always rounds up", () => { 134 | let line = editor.document.lineAt(0); 135 | let tabSize = 5; 136 | 137 | let result = IndentSpy._getLinesIndentDepth(line, tabSize); 138 | 139 | assert.strictEqual(result, 3); 140 | }); 141 | }); 142 | 143 | suite("_createIndicatorRange", () => { 144 | test("creates Range object with start equal to start", () => { 145 | let result = IndentSpy._createIndicatorRange(3, 4); 146 | assert.strictEqual(result.start.line, 3); 147 | assert.strictEqual(result.start.line, result.end.line); 148 | assert.strictEqual(result.start.character, 4); 149 | assert.strictEqual(result.start.character, result.end.character); 150 | }); 151 | }); 152 | 153 | suite("_getSelectedIndentDepth", () => { 154 | let document : vscode.TextDocument, tabSize; 155 | 156 | suiteSetup(() => { 157 | // set tabSize to 2 with whitespaces 158 | vscode.window.activeTextEditor.options.insertSpaces = true; 159 | vscode.window.activeTextEditor.options.tabSize = 2; 160 | tabSize = IndentSpy._getTabSize( 161 | vscode.window.activeTextEditor.options); 162 | 163 | // build stub for TextDocument: 164 | let editor = vscode.window.activeTextEditor; 165 | document = editor.document; 166 | return setEditorContent(editor, 167 | "() => {\n" + 168 | " if(foo()) {\n" + 169 | " bar();\n" + 170 | " return;\n" + 171 | " }\n" + 172 | "}\n" 173 | ); 174 | }); 175 | 176 | test("returns indent depth of selection start if single line" + 177 | " selected and start before first nonwhitespace character", 178 | () => { 179 | let selection = new vscode.Selection(2, 1, 2, 2); 180 | 181 | let result = IndentSpy._getSelectedIndentDepth( 182 | document, selection, tabSize); 183 | 184 | assert.strictEqual(result, 1); 185 | } 186 | ); 187 | 188 | test("returns indent depth of first nonwhitespace character if" + 189 | " single line and selections starts after first" + 190 | " nonwhitespace character", 191 | () => { 192 | let selection = new vscode.Selection(2, 6, 2, 7); 193 | 194 | let result = IndentSpy._getSelectedIndentDepth( 195 | document, selection, tabSize); 196 | 197 | assert.strictEqual(result, 2); 198 | } 199 | ); 200 | 201 | test("returns lowest indent depth of the first nonwhitespace" + 202 | " character of any selected line if multiple are selected" , 203 | () => { 204 | let selection = new vscode.Selection(1, 0, 2, 0); 205 | 206 | let result = IndentSpy._getSelectedIndentDepth( 207 | document, selection, tabSize); 208 | 209 | assert.strictEqual(result, 1); 210 | } 211 | ); 212 | }); 213 | 214 | suite("_getActiveIndentRanges", () => { 215 | let document : vscode.TextDocument, tabSize; 216 | 217 | let findRangePredicate = (expected) => { 218 | return (value, idx, obj) => { 219 | return ( 220 | value.start.line === expected.start.line && 221 | value.start.character == expected.start.character 222 | ); 223 | } 224 | } 225 | 226 | suiteSetup(() => { 227 | // set tabSize to 2 with whitespaces 228 | vscode.window.activeTextEditor.options.insertSpaces = true; 229 | vscode.window.activeTextEditor.options.tabSize = 2; 230 | tabSize = IndentSpy._getTabSize( 231 | vscode.window.activeTextEditor.options); 232 | 233 | let editor = vscode.window.activeTextEditor; 234 | document = editor.document; 235 | return setEditorContent(editor, 236 | "() => {\n" + 237 | " if(foo()) {\n" + 238 | " bar();\n" + 239 | " bar();\n" + 240 | " return;\n" + 241 | " } else {\n" + 242 | " foo();\n" + 243 | " }\n" + 244 | "}\n" 245 | ); 246 | }); 247 | 248 | test("returns a set of ranges for all lines enclosing the" + 249 | " selection with the same or higher indent as outer" + 250 | " and following line higher indent as inner" + 251 | " and updates configs first/last line and indentPos", 252 | () => { 253 | IndentSpy._innerConf.show = true; 254 | let selection = new vscode.Selection(5, 9, 5, 9); 255 | let selectedIndent = 1; 256 | let result = IndentSpy._getActiveIndentRanges( 257 | document, selection, selectedIndent, tabSize); 258 | 259 | let expectedRanges = [ 260 | IndentSpy._createIndicatorRange(1, 0), 261 | IndentSpy._createIndicatorRange(2, 0), 262 | IndentSpy._createIndicatorRange(3, 0), 263 | IndentSpy._createIndicatorRange(4, 0), 264 | IndentSpy._createIndicatorRange(5, 0), 265 | IndentSpy._createIndicatorRange(6, 0), 266 | IndentSpy._createIndicatorRange(7, 0), 267 | ]; 268 | let expectedInnerRanges = [ 269 | IndentSpy._createIndicatorRange(6, tabSize), 270 | ]; 271 | 272 | assert.strictEqual(IndentSpy._innerConf.firstLine, 5); 273 | assert.strictEqual(IndentSpy._innerConf.lastLine, 7); 274 | assert.strictEqual(IndentSpy._innerConf.indentPos, tabSize); 275 | 276 | assert.strictEqual(IndentSpy._outerConf.firstLine, 0); 277 | assert.strictEqual(IndentSpy._outerConf.lastLine, 8); 278 | assert.strictEqual(IndentSpy._outerConf.indentPos, 0); 279 | 280 | assert.strictEqual(result.outer.length, expectedRanges.length); 281 | assert.strictEqual(result.inner.length, expectedInnerRanges.length); 282 | for(let i = 0; i < expectedRanges.length; i++) { 283 | assert(result.outer.find(findRangePredicate(expectedRanges[i])), 284 | `(${expectedRanges[i].start.line}, ${expectedRanges[i].start.character})`); 285 | } 286 | for(let i = 0; i < expectedInnerRanges.length; i++) { 287 | assert(result.inner.find(findRangePredicate(expectedInnerRanges[i])), 288 | `(${expectedInnerRanges[i].start.line}, ${expectedInnerRanges[i].start.character})`); 289 | } 290 | } 291 | ); 292 | 293 | test("returns a set of ranges for all lines enclosing the" + 294 | " selection with the same or higher indent stopping at lower" + 295 | " indets as outer", 296 | () => { 297 | IndentSpy._innerConf.show = true; 298 | let selection = new vscode.Selection(3, 6, 3, 6); 299 | let selectedIndent = 2; 300 | let result = IndentSpy._getActiveIndentRanges( 301 | document, selection, selectedIndent, tabSize); 302 | 303 | let expectedRanges = [ 304 | IndentSpy._createIndicatorRange(2, tabSize), 305 | IndentSpy._createIndicatorRange(3, tabSize), 306 | IndentSpy._createIndicatorRange(4, tabSize), 307 | ]; 308 | 309 | assert.strictEqual(IndentSpy._outerConf.firstLine, 1); 310 | assert.strictEqual(IndentSpy._outerConf.lastLine, 5); 311 | assert.strictEqual(IndentSpy._outerConf.indentPos, 2); 312 | 313 | assert.strictEqual(result.outer.length, expectedRanges.length); 314 | assert.strictEqual(result.inner.length, 0); 315 | 316 | for(let i = 0; i < expectedRanges.length; i++) { 317 | assert(result.outer.find(findRangePredicate(expectedRanges[i])), 318 | `(${expectedRanges[i].start.line}, ${expectedRanges[i].start.character}) not in generated ranges`); 319 | } 320 | } 321 | ); 322 | 323 | test("returns a set of ranges for all lines enclosing the" + 324 | " selection with the same or higher indent as outer" + 325 | " and the same ident as inner stopping on lower indent", 326 | () => { 327 | IndentSpy._innerConf.show = true; 328 | let selection = new vscode.Selection(3, 2, 3, 2); 329 | let selectedIndent = 1; 330 | let result = IndentSpy._getActiveIndentRanges( 331 | document, selection, selectedIndent, tabSize); 332 | 333 | let expectedRanges = [ 334 | IndentSpy._createIndicatorRange(1, 0), 335 | IndentSpy._createIndicatorRange(2, 0), 336 | IndentSpy._createIndicatorRange(3, 0), 337 | IndentSpy._createIndicatorRange(4, 0), 338 | IndentSpy._createIndicatorRange(5, 0), 339 | IndentSpy._createIndicatorRange(6, 0), 340 | IndentSpy._createIndicatorRange(7, 0) 341 | ]; 342 | let expectedInnerRanges = [ 343 | IndentSpy._createIndicatorRange(2, tabSize), 344 | IndentSpy._createIndicatorRange(3, tabSize), 345 | IndentSpy._createIndicatorRange(4, tabSize), 346 | ]; 347 | 348 | assert.strictEqual(IndentSpy._innerConf.firstLine, 1); 349 | assert.strictEqual(IndentSpy._innerConf.lastLine, 5); 350 | assert.strictEqual(IndentSpy._innerConf.indentPos, tabSize); 351 | 352 | assert.strictEqual(IndentSpy._outerConf.firstLine, 0); 353 | assert.strictEqual(IndentSpy._outerConf.lastLine, 8); 354 | assert.strictEqual(IndentSpy._outerConf.indentPos, 0); 355 | 356 | assert.strictEqual(result.outer.length, expectedRanges.length); 357 | assert.strictEqual(result.inner.length, expectedInnerRanges.length); 358 | for(let i = 0; i < expectedRanges.length; i++) { 359 | assert(result.outer.find(findRangePredicate(expectedRanges[i])), 360 | `(${expectedRanges[i].start.line}, ${expectedRanges[i].start.character})`); 361 | } 362 | for(let i = 0; i < expectedInnerRanges.length; i++) { 363 | assert(result.inner.find(findRangePredicate(expectedInnerRanges[i])), 364 | `(${expectedInnerRanges[i].start.line}, ${expectedInnerRanges[i].start.character})`); 365 | } 366 | } 367 | ); 368 | 369 | test("does return a set of ranges for inner even if disabled" + 370 | " to enable peeking", 371 | () => { 372 | IndentSpy._innerConf.show = false; 373 | IndentSpy._outerConf.show = true; 374 | let selection = new vscode.Selection(3, 2, 3, 2); 375 | let selectedIndent = 1; 376 | let result = IndentSpy._getActiveIndentRanges( 377 | document, selection, selectedIndent, tabSize); 378 | 379 | let expectedRanges = [ 380 | IndentSpy._createIndicatorRange(1, 0), 381 | IndentSpy._createIndicatorRange(2, 0), 382 | IndentSpy._createIndicatorRange(3, 0), 383 | IndentSpy._createIndicatorRange(4, 0), 384 | IndentSpy._createIndicatorRange(5, 0), 385 | IndentSpy._createIndicatorRange(6, 0), 386 | IndentSpy._createIndicatorRange(7, 0) 387 | ]; 388 | let expectedInnerRanges = [ 389 | IndentSpy._createIndicatorRange(2, tabSize), 390 | IndentSpy._createIndicatorRange(3, tabSize), 391 | IndentSpy._createIndicatorRange(4, tabSize),]; 392 | 393 | assert.strictEqual(IndentSpy._outerConf.firstLine, 0); 394 | assert.strictEqual(IndentSpy._outerConf.lastLine, 8); 395 | assert.strictEqual(IndentSpy._outerConf.indentPos, 0); 396 | 397 | assert.strictEqual(result.outer.length, expectedRanges.length); 398 | assert.strictEqual(result.inner.length, expectedInnerRanges.length); 399 | for(let i = 0; i < expectedRanges.length; i++) { 400 | assert(result.outer.find(findRangePredicate(expectedRanges[i])), 401 | `(${expectedRanges[i].start.line}, ${expectedRanges[i].start.character})`); 402 | } 403 | } 404 | ); 405 | 406 | test("does return a set of ranges for outer even if disabled" + 407 | " to enable peeking", 408 | () => { 409 | IndentSpy._innerConf.show = true; 410 | IndentSpy._outerConf.show = false; 411 | let selection = new vscode.Selection(3, 2, 3, 2); 412 | let selectedIndent = 1; 413 | let result = IndentSpy._getActiveIndentRanges( 414 | document, selection, selectedIndent, tabSize); 415 | 416 | let expectedRanges = [ 417 | IndentSpy._createIndicatorRange(1, 0), 418 | IndentSpy._createIndicatorRange(2, 0), 419 | IndentSpy._createIndicatorRange(3, 0), 420 | IndentSpy._createIndicatorRange(4, 0), 421 | IndentSpy._createIndicatorRange(5, 0), 422 | IndentSpy._createIndicatorRange(6, 0), 423 | IndentSpy._createIndicatorRange(7, 0) 424 | ]; 425 | let expectedInnerRanges = [ 426 | IndentSpy._createIndicatorRange(2, tabSize), 427 | IndentSpy._createIndicatorRange(3, tabSize), 428 | IndentSpy._createIndicatorRange(4, tabSize), 429 | ]; 430 | 431 | assert.strictEqual(IndentSpy._innerConf.firstLine, 1); 432 | assert.strictEqual(IndentSpy._innerConf.lastLine, 5); 433 | assert.strictEqual(IndentSpy._innerConf.indentPos, tabSize); 434 | 435 | assert.strictEqual(result.outer.length, expectedRanges.length); 436 | assert.strictEqual(result.inner.length, expectedInnerRanges.length); 437 | for(let i = 0; i < expectedInnerRanges.length; i++) { 438 | assert(result.inner.find(findRangePredicate(expectedInnerRanges[i])), 439 | `(${expectedInnerRanges[i].start.line}, ${expectedInnerRanges[i].start.character})`); 440 | } 441 | } 442 | ); 443 | 444 | test("does return all ranges evem if both disabled", 445 | () => { 446 | IndentSpy._innerConf.show = false; 447 | IndentSpy._outerConf.show = false; 448 | let selection = new vscode.Selection(3, 2, 3, 2); 449 | let selectedIndent = 1; 450 | let result = IndentSpy._getActiveIndentRanges( 451 | document, selection, selectedIndent, tabSize); 452 | 453 | let expectedRanges = [ 454 | IndentSpy._createIndicatorRange(1, 0), 455 | IndentSpy._createIndicatorRange(2, 0), 456 | IndentSpy._createIndicatorRange(3, 0), 457 | IndentSpy._createIndicatorRange(4, 0), 458 | IndentSpy._createIndicatorRange(5, 0), 459 | IndentSpy._createIndicatorRange(6, 0), 460 | IndentSpy._createIndicatorRange(7, 0) 461 | ]; 462 | let expectedInnerRanges = [ 463 | IndentSpy._createIndicatorRange(2, tabSize), 464 | IndentSpy._createIndicatorRange(3, tabSize), 465 | IndentSpy._createIndicatorRange(4, tabSize), 466 | ]; 467 | 468 | assert.strictEqual(result.outer.length, expectedRanges.length); 469 | assert.strictEqual(result.inner.length, expectedInnerRanges.length); 470 | } 471 | ); 472 | }); 473 | 474 | suite("_peekBack", () => { 475 | let editor : vscode.TextEditor, tabSize; 476 | 477 | suiteSetup(() => { 478 | // set tabSize to 2 with whitespaces 479 | vscode.window.activeTextEditor.options.insertSpaces = true; 480 | vscode.window.activeTextEditor.options.tabSize = 2; 481 | tabSize = IndentSpy._getTabSize( 482 | vscode.window.activeTextEditor.options); 483 | 484 | editor = vscode.window.activeTextEditor; 485 | return setEditorContent(editor, 486 | "() => {\n" + 487 | " //foo?\n" + 488 | " //\n" + 489 | " foo();\n" + 490 | " if(foo()) {\n" + 491 | " bar();\n" + 492 | " return;\n" + 493 | " } else {\n" + 494 | " foo();\n" + 495 | " }\n" + 496 | "}\n" 497 | ); 498 | }); 499 | 500 | setup(() => { 501 | IndentSpy._outerConf.hoverConf = { 502 | highlight: true, 503 | peekBack: 3, 504 | peekForward: 0, 505 | trimLinesShorterThan: 2, 506 | peekBlockPlaceholder: '...' 507 | }; 508 | IndentSpy._outerConf.firstLine = 4; 509 | IndentSpy._outerConf.lastLine = 7; 510 | IndentSpy._outerConf.indentPos = 4; 511 | }) 512 | 513 | test("returns empty list if peekBack is lower than 1", 514 | () => { 515 | IndentSpy._outerConf.hoverConf.peekBack = -1; 516 | let lines = IndentSpy._peekBack(editor.document, 2, 1, IndentSpy._outerConf); 517 | assert.strictEqual(lines.length, 0); 518 | }); 519 | test("reutrns a list containing the configured number of" + 520 | " lines from before the currently active indent block and" + 521 | " trims their leading whitespace characters", 522 | () => { 523 | let lines = IndentSpy._peekBack(editor.document, 2, 1, IndentSpy._outerConf); 524 | assert.strictEqual(lines.length, 3); 525 | assert.strictEqual(lines[0], "//"); 526 | assert.strictEqual(lines[1], "foo();"); 527 | assert.strictEqual(lines[2], "if(foo()) {"); 528 | }); 529 | test("peeks at maximum the confgiured number of lines", 530 | () => { 531 | IndentSpy._outerConf.hoverConf.peekBack = 1; 532 | let lines = IndentSpy._peekBack(editor.document, 2, 1, IndentSpy._outerConf); 533 | assert.strictEqual(lines.length, 1); 534 | assert.strictEqual(lines[0], "if(foo()) {"); 535 | }); 536 | test("stops at changing indent depth", 537 | () => { 538 | IndentSpy._outerConf.hoverConf.peekBack = 5; 539 | let lines = IndentSpy._peekBack(editor.document, 2, 1, IndentSpy._outerConf); 540 | assert.strictEqual(lines.length, 4); 541 | assert.strictEqual(lines[0], "//foo?"); 542 | assert.strictEqual(lines[1], "//"); 543 | assert.strictEqual(lines[2], "foo();"); 544 | assert.strictEqual(lines[3], "if(foo()) {"); 545 | }); 546 | test("trims lines shorter than configured value", 547 | () => { 548 | IndentSpy._outerConf.hoverConf.trimLinesShorterThan = 3; 549 | let lines = IndentSpy._peekBack(editor.document, 2, 1, IndentSpy._outerConf); 550 | assert.strictEqual(lines.length, 2); 551 | assert.strictEqual(lines[0], "foo();"); 552 | assert.strictEqual(lines[1], "if(foo()) {"); 553 | }); 554 | test("doesn't trim lines shorter than configured value if" + 555 | " another before line is already peeked", 556 | () => { 557 | IndentSpy._outerConf.hoverConf.peekBack = 4; 558 | IndentSpy._outerConf.hoverConf.trimLinesShorterThan = 4; 559 | let lines = IndentSpy._peekBack(editor.document, 2, 1, IndentSpy._outerConf); 560 | assert.strictEqual(lines.length, 4); 561 | assert.strictEqual(lines[0], "//foo?"); 562 | assert.strictEqual(lines[1], "//"); 563 | assert.strictEqual(lines[2], "foo();"); 564 | assert.strictEqual(lines[3], "if(foo()) {"); 565 | }); 566 | test("includes first line of file (issue #6)", 567 | () => { 568 | IndentSpy._outerConf.hoverConf.peekBack = 1; 569 | IndentSpy._outerConf.firstLine = 0; 570 | let lines = IndentSpy._peekBack(editor.document, 2, 0, IndentSpy._outerConf); 571 | assert.strictEqual(lines.length, 1); 572 | assert.strictEqual(lines[0], "() => {"); 573 | }); 574 | }); 575 | 576 | suite("_peekForward", () => { 577 | let editor : vscode.TextEditor, tabSize; 578 | 579 | suiteSetup(() => { 580 | // set tabSize to 2 with whitespaces 581 | vscode.window.activeTextEditor.options.insertSpaces = true; 582 | vscode.window.activeTextEditor.options.tabSize = 2; 583 | tabSize = IndentSpy._getTabSize( 584 | vscode.window.activeTextEditor.options); 585 | 586 | editor = vscode.window.activeTextEditor; 587 | return setEditorContent(editor, 588 | "() => {\n" + 589 | " if(foo()) {\n" + 590 | " bar();\n" + 591 | " return;\n" + 592 | " }\n" + 593 | " //foo?\n" + 594 | " //\n" + 595 | " foo();\n" + 596 | "}\n" 597 | ); 598 | }); 599 | 600 | setup(() => { 601 | IndentSpy._outerConf.hoverConf = { 602 | highlight: true, 603 | peekBack: 0, 604 | peekForward: 3, 605 | trimLinesShorterThan: 2, 606 | peekBlockPlaceholder: '...' 607 | }; 608 | IndentSpy._outerConf.firstLine = 1; 609 | IndentSpy._outerConf.lastLine = 4; 610 | IndentSpy._outerConf.indentPos = 4 611 | }) 612 | 613 | test("returns empty list if peekForward is lower than 1", 614 | () => { 615 | IndentSpy._outerConf.hoverConf.peekForward = -1; 616 | let lines = IndentSpy._peekForward(editor.document, 2, 1, IndentSpy._outerConf); 617 | assert.strictEqual(lines.length, 0); 618 | }); 619 | test("reutrns a list containing the configured number of" + 620 | " lines from after the currently active indent block in " + 621 | " reverse order and trims their leading whitespace characters", 622 | () => { 623 | let lines = IndentSpy._peekForward(editor.document, 2, 1, IndentSpy._outerConf); 624 | assert.strictEqual(lines.length, 3); 625 | assert.strictEqual(lines[0], "}"); 626 | assert.strictEqual(lines[1], "//foo?"); 627 | assert.strictEqual(lines[2], "//"); 628 | }); 629 | test("peeks at maximum the confgiured number of lines", 630 | () => { 631 | IndentSpy._outerConf.hoverConf.peekForward = 2; 632 | let lines = IndentSpy._peekForward(editor.document, 2, 1, IndentSpy._outerConf); 633 | assert.strictEqual(lines.length, 2); 634 | assert.strictEqual(lines[0], "}"); 635 | assert.strictEqual(lines[1], "//foo?"); 636 | }); 637 | test("stops at changing indent depth", 638 | () => { 639 | IndentSpy._outerConf.hoverConf.peekForward = 5; 640 | let lines = IndentSpy._peekForward(editor.document, 2, 1, IndentSpy._outerConf); 641 | assert.strictEqual(lines.length, 4); 642 | assert.strictEqual(lines[0], "}"); 643 | assert.strictEqual(lines[1], "//foo?"); 644 | assert.strictEqual(lines[2], "//"); 645 | assert.strictEqual(lines[3], "foo();"); 646 | }); 647 | test("trims lines shorter than configured value", 648 | () => { 649 | IndentSpy._outerConf.hoverConf.trimLinesShorterThan = 3; 650 | let lines = IndentSpy._peekForward(editor.document, 2, 1, IndentSpy._outerConf); 651 | assert.strictEqual(lines.length, 2); 652 | assert.strictEqual(lines[0], "}"); 653 | assert.strictEqual(lines[1], "//foo?"); 654 | }); 655 | test("doesn't trim lines shorter than configured value if" + 656 | " another before line is already peeked", 657 | () => { 658 | IndentSpy._outerConf.hoverConf.peekForward = 4; 659 | IndentSpy._outerConf.hoverConf.trimLinesShorterThan = 4; 660 | let lines = IndentSpy._peekForward(editor.document, 2, 1, IndentSpy._outerConf); 661 | assert.strictEqual(lines.length, 4); 662 | assert.strictEqual(lines[0], "}"); 663 | assert.strictEqual(lines[1], "//foo?"); 664 | assert.strictEqual(lines[2], "//"); 665 | assert.strictEqual(lines[3], "foo();"); 666 | }); 667 | test("includes last line of file (issue #6)", 668 | () => { 669 | IndentSpy._outerConf.hoverConf.peekForward = 1; 670 | IndentSpy._outerConf.hoverConf.trimLinesShorterThan = 0; 671 | IndentSpy._outerConf.firstLine = 0; 672 | IndentSpy._outerConf.lastLine = 8; 673 | let lines = IndentSpy._peekForward(editor.document, 2, 0, IndentSpy._outerConf); 674 | assert.strictEqual(lines.length, 1); 675 | assert.strictEqual(lines[0], "}"); 676 | }); 677 | }); 678 | 679 | suite("_buildHoverPlaceholder", () => { 680 | let editor : vscode.TextEditor, tabSize; 681 | 682 | suiteSetup(() => { 683 | editor = vscode.window.activeTextEditor; 684 | }); 685 | 686 | setup(() => { 687 | IndentSpy._outerConf.hoverConf = { 688 | highlight: true, 689 | peekBack: 0, 690 | peekForward: 3, 691 | trimLinesShorterThan: 2, 692 | peekBlockPlaceholder: '...' 693 | }; 694 | }) 695 | 696 | test("returns string with configured peekBlockPlaceholder" + 697 | " with one indent placed before",() => { 698 | editor.options.insertSpaces = true; 699 | editor.options.tabSize = 2; 700 | tabSize = IndentSpy._getTabSize( 701 | vscode.window.activeTextEditor.options); 702 | IndentSpy._outerConf.hoverConf.peekBlockPlaceholder = 'foo!'; 703 | let result = IndentSpy._buildHoverPlaceholder(editor, tabSize, IndentSpy._outerConf); 704 | assert.strictEqual(result, " foo!"); 705 | }); 706 | 707 | test("uses configured indent",() => { 708 | editor.options.insertSpaces = false; 709 | editor.options.tabSize = 3; 710 | tabSize = IndentSpy._getTabSize( 711 | vscode.window.activeTextEditor.options); 712 | IndentSpy._outerConf.hoverConf.peekBlockPlaceholder = 'bar!'; 713 | let result = IndentSpy._buildHoverPlaceholder(editor, tabSize, IndentSpy._outerConf); 714 | assert.strictEqual(result, "\tbar!"); 715 | }); 716 | }); 717 | 718 | suite("_buildHoverString", () => { 719 | let editor : vscode.TextEditor, tabSize; 720 | 721 | suiteSetup(() => { 722 | // set tabSize to 2 with whitespaces 723 | vscode.window.activeTextEditor.options.insertSpaces = true; 724 | vscode.window.activeTextEditor.options.tabSize = 2; 725 | tabSize = IndentSpy._getTabSize( 726 | vscode.window.activeTextEditor.options); 727 | 728 | editor = vscode.window.activeTextEditor; 729 | return setEditorContent(editor, 730 | "() => {\n" + 731 | " //foo?\n" + 732 | " //\n" + 733 | " foo();\n" + 734 | " if(foo()) {\n" + 735 | " bar();\n" + 736 | " return;\n" + 737 | " }\n" + 738 | " //foo?\n" + 739 | " //\n" + 740 | " foo();\n" + 741 | "}\n" 742 | ); 743 | }); 744 | 745 | setup(() => { 746 | IndentSpy._outerConf.hoverConf = { 747 | highlight: true, 748 | peekBack: 3, 749 | peekForward: 3, 750 | trimLinesShorterThan: 3, 751 | peekBlockPlaceholder: '// my indent block' 752 | }; 753 | IndentSpy._outerConf.firstLine = 4; 754 | IndentSpy._outerConf.lastLine = 7; 755 | IndentSpy._outerConf.indentPos = 4; 756 | }) 757 | 758 | test("returns a block using the configured peek options", 759 | () => { 760 | let block = IndentSpy._buildHoverString(editor, tabSize, IndentSpy._outerConf); 761 | assert.strictEqual( 762 | block, 763 | "foo();\n" + 764 | "if(foo()) {\n" + 765 | " // my indent block\n" + 766 | "}\n" + 767 | "//foo?" 768 | ); 769 | }); 770 | }); 771 | }); 772 | }); -------------------------------------------------------------------------------- /test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 13 | if (err) { 14 | return cb(err); 15 | } 16 | 17 | // Add files to the test suite 18 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 19 | 20 | try { 21 | // Run the mocha test 22 | mocha.run(failures => { 23 | cb(null, failures); 24 | }); 25 | } catch (err) { 26 | console.error(err); 27 | cb(err); 28 | } 29 | }); 30 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "." 11 | }, 12 | "include": [ 13 | "src", 14 | "test" 15 | ], 16 | "exclude": [ 17 | "node_modules", 18 | ".vscode-test" 19 | ] 20 | } -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your first VS Code Extension 2 | 3 | ## What's in the folder 4 | * This folder contains all of the files necessary for your extension 5 | * `package.json` - this is the manifest file in which you declare your extension and command. 6 | The sample plugin registers a command and defines its title and command name. With this information 7 | VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | * `src/extension.ts` - this is the main file where you will provide the implementation of your command. 9 | The file exports one function, `activate`, which is called the very first time your extension is 10 | activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 11 | We pass the function containing the implementation of the command as the second parameter to 12 | `registerCommand`. 13 | 14 | ## Get up and running straight away 15 | * press `F5` to open a new window with your extension loaded 16 | * run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World` 17 | * set breakpoints in your code inside `src/extension.ts` to debug your extension 18 | * find output from your extension in the debug console 19 | 20 | ## Make changes 21 | * you can relaunch the extension from the debug toolbar after changing code in `src/extension.ts` 22 | * you can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes 23 | 24 | ## Explore the API 25 | * you can open the full set of our API when you open the file `node_modules/vscode/vscode.d.ts` 26 | 27 | ## Run tests 28 | * open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Launch Tests` 29 | * press `F5` to run the tests in a new window with your extension loaded 30 | * see the output of the test result in the debug console 31 | * make changes to `test/extension.test.ts` or create new test files inside the `test` folder 32 | * by convention, the test runner will only consider files matching the name pattern `**.test.ts` 33 | * you can create folders inside the `test` folder to structure your tests any way you want --------------------------------------------------------------------------------