├── .gitignore ├── .vscode ├── launch.json ├── settings.json ├── tasks.json └── tasks.json.old ├── .vscodeignore ├── LICENSE ├── README.md ├── images ├── Character_Diona_Portrait.png ├── Character_Fischl_Portrait.png ├── Character_Ganyu_Portrait.png ├── Character_Hu_Tao_Portrait.png ├── Character_Keqing_Portrait.png ├── Character_Klee_Portrait.png ├── Character_Qiqi_Portrait.png ├── demo-osu.gif ├── icon-large.png └── icon.png ├── package-lock.json ├── package.json ├── releases ├── vscode-osu-3.1.0.vsix ├── vscode-osu-3.2.3.vsix └── vscode-osu-3.3.0.vsix ├── src ├── combo-meter.ts ├── config │ ├── alphabet_map.ts │ ├── config.ts │ └── ridiculous.ts ├── cursor-exploder │ └── cursor-exploder.ts ├── extension.ts ├── plugin.ts └── test │ ├── runTest.ts │ └── suite │ ├── extension.test.ts │ └── index.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | 4 | .idea/* 5 | .vscode/* 6 | .vscode-test/* -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.1.0", 4 | "configurations": [ 5 | { 6 | "name": "Launch Extension", 7 | "type": "extensionHost", 8 | "request": "launch", 9 | "runtimeExecutable": "${execPath}", 10 | "args": ["--extensionDevelopmentPath=${workspaceRoot}"], 11 | "stopOnEntry": false, 12 | "sourceMaps": true, 13 | "outFiles": [ "${workspaceRoot}/out/src/**/*.js" ], 14 | "preLaunchTask": "npm" 15 | }, 16 | { 17 | "name": "Launch Tests", 18 | "type": "extensionHost", 19 | "request": "launch", 20 | "runtimeExecutable": "${execPath}", 21 | "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], 22 | "stopOnEntry": false, 23 | "sourceMaps": true, 24 | "outFiles": [ "${workspaceRoot}/out/test/**/*.js" ], 25 | "preLaunchTask": "npm" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /.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 | // A task runner that calls a custom npm script that compiles the extension. 10 | { 11 | "version": "2.0.0", 12 | 13 | // we want to run npm 14 | "command": "npm", 15 | 16 | // we run the custom script "compile" as defined in package.json 17 | "args": ["run", "compile", "--loglevel", "silent"], 18 | 19 | // The tsc compiler is started in watching mode 20 | "isBackground": true, 21 | 22 | // use the standard tsc in watch mode problem matcher to find compile problems in the output. 23 | "problemMatcher": "$tsc-watch", 24 | "tasks": [ 25 | { 26 | "label": "npm", 27 | "type": "shell", 28 | "command": "npm", 29 | "args": [ 30 | "run", 31 | "compile", 32 | "--loglevel", 33 | "silent" 34 | ], 35 | "isBackground": true, 36 | "problemMatcher": "$tsc-watch", 37 | "group": { 38 | "_id": "build", 39 | "isDefault": false 40 | } 41 | } 42 | ] 43 | } -------------------------------------------------------------------------------- /.vscode/tasks.json.old: -------------------------------------------------------------------------------- 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 | // A task runner that calls a custom npm script that compiles the extension. 10 | { 11 | "version": "0.1.0", 12 | 13 | // we want to run npm 14 | "command": "npm", 15 | 16 | // the command is a shell script 17 | "isShellCommand": true, 18 | 19 | // show the output window only if unrecognized errors occur. 20 | "showOutput": "silent", 21 | 22 | // we run the custom script "compile" as defined in package.json 23 | "args": ["run", "compile", "--loglevel", "silent"], 24 | 25 | // The tsc compiler is started in watching mode 26 | "isBackground": true, 27 | 28 | // use the standard tsc in watch mode problem matcher to find compile problems in the output. 29 | "problemMatcher": "$tsc-watch" 30 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | test/** 5 | src/** 6 | **/*.map 7 | .gitignore 8 | tsconfig.json 9 | vsc-extension-quickstart.md 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Cody Hoover 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VSCODE OSU Mode!!! 2 | 3 | OSU Mode is a fork of Power Mode, they said it shouldn't be done... 4 | 5 | However, after being bored and realizing that VSCode was not the only modern editor without it, I knew I didn't have to try, but I couldn't let VSCode live in the shadow of its big brother or Atom. 6 | 7 | I present you, **VSCODE OSU MODE**!!! (now with Genshin Impact Characters!) 8 | 9 | ![DEMO](https://raw.githubusercontent.com/ao-shen/vscode-power-mode/master/images/demo-osu.gif) 10 | 11 | #### General Settings 12 | To disable OSU mode, add `"osumode.enabled": false` to your settings. 13 | 14 | To disable combo counter, add `"osumode.enableComboCounter": false,` to your settings. 15 | 16 | To disable combo image, add `"osumode.enableComboImage": false,` to your settings. 17 | 18 | To disable letter explosions at the cursor when you type, add `"osumode.enableCursorExplosions": false,` to your settings. 19 | 20 | To make delete reset the combo, and also add a timer to reset the combo after 8 seconds of inactivity, add `"osumode.deleteResetsCombo": true,` to your settings. 21 | 22 | #### Customize Images 23 | To change the number of combo between every image, change `"osumode.comboImageInterval"` in your settings. 24 | 25 | You can also specify custom images to use instead of default ones. Change `"osumode.customComboImages"` in your settings to a list of URLs to your custom images. Note: local images don't work, they have to be from https (for security reasons?) 26 | 27 | ```json 28 | "osumode.customComboImages": [ 29 | "https://imgur.com/t4XQPkJ.png", 30 | "https://imgur.com/9TYZgzm.png", 31 | "https://imgur.com/YAUseUb.png", 32 | ] 33 | ``` 34 | 35 | 36 | ## Features: 37 | * NEW: COMBO COUNTER 38 | * NEW: COMBO IMAGES 39 | * NEW: PER CHARACTER CURSOR EXPLOSIONS 40 | 41 | ## Acknowledgements: 42 | * Thanks to [@hoovercj](https://github.com/hoovercj) for [Powermode](https://github.com/hoovercj/vscode-power-mode) 43 | 44 | ## Changelog: 45 | - v3.3.0 46 | - Fixed flickering bug! 47 | - v3.2.3 48 | - Updated name to OSU MODE 3! 49 | - Did I actually change anything? No. So why? You know, 3 is such a cool number. In fact, I would even say it's greater than 2. 50 | - v3.2.2 51 | - Changed "CONTROL+V" explosion to say "MULTI-CHAR", since idk of a way to detect the difference between a paste and a code completion! 52 | - Changed so that combo doesn't reset from delete (Thanks to [@盐焗乳鸽还要砂锅](https://github.com/1360151219) for the suggestion)! 53 | - Added config that enables the old behavior of delete resets combo! 54 | - v3.2.1 55 | - Fixed readme error! 56 | - v3.2.0 57 | - Added settings for combo image interval! 58 | - Added ability to customize combo images! 59 | - Changed default settings so that all features are enabled by default! 60 | - Removed some useless settings! 61 | - v3.1.0 62 | - Updated Settings to be "osumode" instead of "powermode"! 63 | - Removed existing powermode presets, now you can install Osumode and Powermode separately! 64 | - Removed extra settings that only pertained to Powermode features! 65 | - Removed status bar combo counter! 66 | - v3.0.1 67 | - Updated Readme! 68 | - v3.0.0 69 | - Forked from Power Mode! 70 | - Added per character cursor explosions! 71 | - Added combo counter animations! 72 | - Added combo images! -------------------------------------------------------------------------------- /images/Character_Diona_Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/images/Character_Diona_Portrait.png -------------------------------------------------------------------------------- /images/Character_Fischl_Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/images/Character_Fischl_Portrait.png -------------------------------------------------------------------------------- /images/Character_Ganyu_Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/images/Character_Ganyu_Portrait.png -------------------------------------------------------------------------------- /images/Character_Hu_Tao_Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/images/Character_Hu_Tao_Portrait.png -------------------------------------------------------------------------------- /images/Character_Keqing_Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/images/Character_Keqing_Portrait.png -------------------------------------------------------------------------------- /images/Character_Klee_Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/images/Character_Klee_Portrait.png -------------------------------------------------------------------------------- /images/Character_Qiqi_Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/images/Character_Qiqi_Portrait.png -------------------------------------------------------------------------------- /images/demo-osu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/images/demo-osu.gif -------------------------------------------------------------------------------- /images/icon-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/images/icon-large.png -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/images/icon.png -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-osu", 3 | "version": "3.2.3", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "vscode-osu", 9 | "version": "3.2.3", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@types/vscode": "^1.34.0", 13 | "@vscode/test-electron": "^2.2.3" 14 | }, 15 | "devDependencies": { 16 | "@types/mocha": "^9.0.0", 17 | "@types/node": "^16.10.2", 18 | "@types/vscode": "^1.34.0", 19 | "mocha": "^9.1.2", 20 | "typescript": "^4.4.3" 21 | }, 22 | "engines": { 23 | "vscode": "^1.75.1" 24 | } 25 | }, 26 | "node_modules/@tootallnate/once": { 27 | "version": "1.1.2", 28 | "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", 29 | "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", 30 | "engines": { 31 | "node": ">= 6" 32 | } 33 | }, 34 | "node_modules/@types/mocha": { 35 | "version": "9.0.0", 36 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz", 37 | "integrity": "sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==", 38 | "dev": true 39 | }, 40 | "node_modules/@types/node": { 41 | "version": "16.10.2", 42 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.2.tgz", 43 | "integrity": "sha512-zCclL4/rx+W5SQTzFs9wyvvyCwoK9QtBpratqz2IYJ3O8Umrn0m3nsTv0wQBk9sRGpvUe9CwPDrQFB10f1FIjQ==", 44 | "dev": true 45 | }, 46 | "node_modules/@types/vscode": { 47 | "version": "1.34.0", 48 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.34.0.tgz", 49 | "integrity": "sha512-t81rGr6aFw8TMap7UJdikC5ilOtL0yNr/pkovyyTy31fZ4XJehrxLMRh8nJuoOF3+g4rG9ljmtQo7tm6wyoaYA==", 50 | "dev": true 51 | }, 52 | "node_modules/@ungap/promise-all-settled": { 53 | "version": "1.1.2", 54 | "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", 55 | "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", 56 | "dev": true 57 | }, 58 | "node_modules/@vscode/test-electron": { 59 | "version": "2.2.3", 60 | "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.2.3.tgz", 61 | "integrity": "sha512-7DmdGYQTqRNaLHKG3j56buc9DkstriY4aV0S3Zj32u0U9/T0L8vwWAC9QGCh1meu1VXDEla1ze27TkqysHGP0Q==", 62 | "dependencies": { 63 | "http-proxy-agent": "^4.0.1", 64 | "https-proxy-agent": "^5.0.0", 65 | "rimraf": "^3.0.2", 66 | "unzipper": "^0.10.11" 67 | }, 68 | "engines": { 69 | "node": ">=16" 70 | } 71 | }, 72 | "node_modules/agent-base": { 73 | "version": "6.0.2", 74 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", 75 | "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", 76 | "dependencies": { 77 | "debug": "4" 78 | }, 79 | "engines": { 80 | "node": ">= 6.0.0" 81 | } 82 | }, 83 | "node_modules/ansi-colors": { 84 | "version": "4.1.1", 85 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 86 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 87 | "dev": true, 88 | "engines": { 89 | "node": ">=6" 90 | } 91 | }, 92 | "node_modules/ansi-styles": { 93 | "version": "4.3.0", 94 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 95 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 96 | "dev": true, 97 | "dependencies": { 98 | "color-convert": "^2.0.1" 99 | }, 100 | "engines": { 101 | "node": ">=8" 102 | }, 103 | "funding": { 104 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 105 | } 106 | }, 107 | "node_modules/anymatch": { 108 | "version": "3.1.3", 109 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 110 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 111 | "dev": true, 112 | "dependencies": { 113 | "normalize-path": "^3.0.0", 114 | "picomatch": "^2.0.4" 115 | }, 116 | "engines": { 117 | "node": ">= 8" 118 | } 119 | }, 120 | "node_modules/argparse": { 121 | "version": "2.0.1", 122 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 123 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 124 | "dev": true 125 | }, 126 | "node_modules/balanced-match": { 127 | "version": "1.0.2", 128 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 129 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 130 | }, 131 | "node_modules/big-integer": { 132 | "version": "1.6.51", 133 | "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", 134 | "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", 135 | "engines": { 136 | "node": ">=0.6" 137 | } 138 | }, 139 | "node_modules/binary": { 140 | "version": "0.3.0", 141 | "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", 142 | "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", 143 | "dependencies": { 144 | "buffers": "~0.1.1", 145 | "chainsaw": "~0.1.0" 146 | }, 147 | "engines": { 148 | "node": "*" 149 | } 150 | }, 151 | "node_modules/binary-extensions": { 152 | "version": "2.2.0", 153 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 154 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 155 | "dev": true, 156 | "engines": { 157 | "node": ">=8" 158 | } 159 | }, 160 | "node_modules/bluebird": { 161 | "version": "3.4.7", 162 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", 163 | "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==" 164 | }, 165 | "node_modules/brace-expansion": { 166 | "version": "1.1.11", 167 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 168 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 169 | "dependencies": { 170 | "balanced-match": "^1.0.0", 171 | "concat-map": "0.0.1" 172 | } 173 | }, 174 | "node_modules/braces": { 175 | "version": "3.0.2", 176 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 177 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 178 | "dev": true, 179 | "dependencies": { 180 | "fill-range": "^7.0.1" 181 | }, 182 | "engines": { 183 | "node": ">=8" 184 | } 185 | }, 186 | "node_modules/browser-stdout": { 187 | "version": "1.3.1", 188 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 189 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 190 | "dev": true 191 | }, 192 | "node_modules/buffer-indexof-polyfill": { 193 | "version": "1.0.2", 194 | "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", 195 | "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", 196 | "engines": { 197 | "node": ">=0.10" 198 | } 199 | }, 200 | "node_modules/buffers": { 201 | "version": "0.1.1", 202 | "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", 203 | "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", 204 | "engines": { 205 | "node": ">=0.2.0" 206 | } 207 | }, 208 | "node_modules/camelcase": { 209 | "version": "6.2.0", 210 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", 211 | "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", 212 | "dev": true, 213 | "engines": { 214 | "node": ">=10" 215 | }, 216 | "funding": { 217 | "url": "https://github.com/sponsors/sindresorhus" 218 | } 219 | }, 220 | "node_modules/chainsaw": { 221 | "version": "0.1.0", 222 | "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", 223 | "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", 224 | "dependencies": { 225 | "traverse": ">=0.3.0 <0.4" 226 | }, 227 | "engines": { 228 | "node": "*" 229 | } 230 | }, 231 | "node_modules/chalk": { 232 | "version": "4.1.2", 233 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 234 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 235 | "dev": true, 236 | "dependencies": { 237 | "ansi-styles": "^4.1.0", 238 | "supports-color": "^7.1.0" 239 | }, 240 | "engines": { 241 | "node": ">=10" 242 | }, 243 | "funding": { 244 | "url": "https://github.com/chalk/chalk?sponsor=1" 245 | } 246 | }, 247 | "node_modules/chalk/node_modules/supports-color": { 248 | "version": "7.2.0", 249 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 250 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 251 | "dev": true, 252 | "dependencies": { 253 | "has-flag": "^4.0.0" 254 | }, 255 | "engines": { 256 | "node": ">=8" 257 | } 258 | }, 259 | "node_modules/chokidar": { 260 | "version": "3.5.3", 261 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 262 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 263 | "dev": true, 264 | "funding": [ 265 | { 266 | "type": "individual", 267 | "url": "https://paulmillr.com/funding/" 268 | } 269 | ], 270 | "dependencies": { 271 | "anymatch": "~3.1.2", 272 | "braces": "~3.0.2", 273 | "glob-parent": "~5.1.2", 274 | "is-binary-path": "~2.1.0", 275 | "is-glob": "~4.0.1", 276 | "normalize-path": "~3.0.0", 277 | "readdirp": "~3.6.0" 278 | }, 279 | "engines": { 280 | "node": ">= 8.10.0" 281 | }, 282 | "optionalDependencies": { 283 | "fsevents": "~2.3.2" 284 | } 285 | }, 286 | "node_modules/cliui": { 287 | "version": "7.0.4", 288 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 289 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 290 | "dev": true, 291 | "dependencies": { 292 | "string-width": "^4.2.0", 293 | "strip-ansi": "^6.0.0", 294 | "wrap-ansi": "^7.0.0" 295 | } 296 | }, 297 | "node_modules/cliui/node_modules/ansi-regex": { 298 | "version": "5.0.1", 299 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 300 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 301 | "dev": true, 302 | "engines": { 303 | "node": ">=8" 304 | } 305 | }, 306 | "node_modules/cliui/node_modules/is-fullwidth-code-point": { 307 | "version": "3.0.0", 308 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 309 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 310 | "dev": true, 311 | "engines": { 312 | "node": ">=8" 313 | } 314 | }, 315 | "node_modules/cliui/node_modules/string-width": { 316 | "version": "4.2.3", 317 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 318 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 319 | "dev": true, 320 | "dependencies": { 321 | "emoji-regex": "^8.0.0", 322 | "is-fullwidth-code-point": "^3.0.0", 323 | "strip-ansi": "^6.0.1" 324 | }, 325 | "engines": { 326 | "node": ">=8" 327 | } 328 | }, 329 | "node_modules/cliui/node_modules/strip-ansi": { 330 | "version": "6.0.1", 331 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 332 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 333 | "dev": true, 334 | "dependencies": { 335 | "ansi-regex": "^5.0.1" 336 | }, 337 | "engines": { 338 | "node": ">=8" 339 | } 340 | }, 341 | "node_modules/color-convert": { 342 | "version": "2.0.1", 343 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 344 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 345 | "dev": true, 346 | "dependencies": { 347 | "color-name": "~1.1.4" 348 | }, 349 | "engines": { 350 | "node": ">=7.0.0" 351 | } 352 | }, 353 | "node_modules/color-name": { 354 | "version": "1.1.4", 355 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 356 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 357 | "dev": true 358 | }, 359 | "node_modules/concat-map": { 360 | "version": "0.0.1", 361 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 362 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 363 | }, 364 | "node_modules/core-util-is": { 365 | "version": "1.0.3", 366 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 367 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" 368 | }, 369 | "node_modules/debug": { 370 | "version": "4.3.3", 371 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", 372 | "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", 373 | "dependencies": { 374 | "ms": "2.1.2" 375 | }, 376 | "engines": { 377 | "node": ">=6.0" 378 | }, 379 | "peerDependenciesMeta": { 380 | "supports-color": { 381 | "optional": true 382 | } 383 | } 384 | }, 385 | "node_modules/debug/node_modules/ms": { 386 | "version": "2.1.2", 387 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 388 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 389 | }, 390 | "node_modules/decamelize": { 391 | "version": "4.0.0", 392 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 393 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 394 | "dev": true, 395 | "engines": { 396 | "node": ">=10" 397 | }, 398 | "funding": { 399 | "url": "https://github.com/sponsors/sindresorhus" 400 | } 401 | }, 402 | "node_modules/diff": { 403 | "version": "5.0.0", 404 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 405 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 406 | "dev": true, 407 | "engines": { 408 | "node": ">=0.3.1" 409 | } 410 | }, 411 | "node_modules/duplexer2": { 412 | "version": "0.1.4", 413 | "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", 414 | "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", 415 | "dependencies": { 416 | "readable-stream": "^2.0.2" 417 | } 418 | }, 419 | "node_modules/emoji-regex": { 420 | "version": "8.0.0", 421 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 422 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 423 | "dev": true 424 | }, 425 | "node_modules/escalade": { 426 | "version": "3.1.1", 427 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 428 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 429 | "dev": true, 430 | "engines": { 431 | "node": ">=6" 432 | } 433 | }, 434 | "node_modules/fill-range": { 435 | "version": "7.0.1", 436 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 437 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 438 | "dev": true, 439 | "dependencies": { 440 | "to-regex-range": "^5.0.1" 441 | }, 442 | "engines": { 443 | "node": ">=8" 444 | } 445 | }, 446 | "node_modules/find-up": { 447 | "version": "5.0.0", 448 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 449 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 450 | "dev": true, 451 | "dependencies": { 452 | "locate-path": "^6.0.0", 453 | "path-exists": "^4.0.0" 454 | }, 455 | "engines": { 456 | "node": ">=10" 457 | }, 458 | "funding": { 459 | "url": "https://github.com/sponsors/sindresorhus" 460 | } 461 | }, 462 | "node_modules/flat": { 463 | "version": "5.0.2", 464 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 465 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 466 | "dev": true, 467 | "bin": { 468 | "flat": "cli.js" 469 | } 470 | }, 471 | "node_modules/fs.realpath": { 472 | "version": "1.0.0", 473 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 474 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 475 | }, 476 | "node_modules/fsevents": { 477 | "version": "2.3.2", 478 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 479 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 480 | "dev": true, 481 | "hasInstallScript": true, 482 | "optional": true, 483 | "os": [ 484 | "darwin" 485 | ], 486 | "engines": { 487 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 488 | } 489 | }, 490 | "node_modules/fstream": { 491 | "version": "1.0.12", 492 | "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", 493 | "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", 494 | "dependencies": { 495 | "graceful-fs": "^4.1.2", 496 | "inherits": "~2.0.0", 497 | "mkdirp": ">=0.5 0", 498 | "rimraf": "2" 499 | }, 500 | "engines": { 501 | "node": ">=0.6" 502 | } 503 | }, 504 | "node_modules/fstream/node_modules/rimraf": { 505 | "version": "2.7.1", 506 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 507 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 508 | "dependencies": { 509 | "glob": "^7.1.3" 510 | }, 511 | "bin": { 512 | "rimraf": "bin.js" 513 | } 514 | }, 515 | "node_modules/get-caller-file": { 516 | "version": "2.0.5", 517 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 518 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 519 | "dev": true, 520 | "engines": { 521 | "node": "6.* || 8.* || >= 10.*" 522 | } 523 | }, 524 | "node_modules/glob": { 525 | "version": "7.2.0", 526 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 527 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 528 | "dependencies": { 529 | "fs.realpath": "^1.0.0", 530 | "inflight": "^1.0.4", 531 | "inherits": "2", 532 | "minimatch": "^3.0.4", 533 | "once": "^1.3.0", 534 | "path-is-absolute": "^1.0.0" 535 | }, 536 | "engines": { 537 | "node": "*" 538 | }, 539 | "funding": { 540 | "url": "https://github.com/sponsors/isaacs" 541 | } 542 | }, 543 | "node_modules/glob-parent": { 544 | "version": "5.1.2", 545 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 546 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 547 | "dev": true, 548 | "dependencies": { 549 | "is-glob": "^4.0.1" 550 | }, 551 | "engines": { 552 | "node": ">= 6" 553 | } 554 | }, 555 | "node_modules/graceful-fs": { 556 | "version": "4.2.10", 557 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", 558 | "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" 559 | }, 560 | "node_modules/growl": { 561 | "version": "1.10.5", 562 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 563 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 564 | "dev": true, 565 | "engines": { 566 | "node": ">=4.x" 567 | } 568 | }, 569 | "node_modules/has-flag": { 570 | "version": "4.0.0", 571 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 572 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 573 | "dev": true, 574 | "engines": { 575 | "node": ">=8" 576 | } 577 | }, 578 | "node_modules/he": { 579 | "version": "1.2.0", 580 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 581 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 582 | "dev": true, 583 | "bin": { 584 | "he": "bin/he" 585 | } 586 | }, 587 | "node_modules/http-proxy-agent": { 588 | "version": "4.0.1", 589 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", 590 | "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", 591 | "dependencies": { 592 | "@tootallnate/once": "1", 593 | "agent-base": "6", 594 | "debug": "4" 595 | }, 596 | "engines": { 597 | "node": ">= 6" 598 | } 599 | }, 600 | "node_modules/https-proxy-agent": { 601 | "version": "5.0.1", 602 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", 603 | "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", 604 | "dependencies": { 605 | "agent-base": "6", 606 | "debug": "4" 607 | }, 608 | "engines": { 609 | "node": ">= 6" 610 | } 611 | }, 612 | "node_modules/inflight": { 613 | "version": "1.0.6", 614 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 615 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 616 | "dependencies": { 617 | "once": "^1.3.0", 618 | "wrappy": "1" 619 | } 620 | }, 621 | "node_modules/inherits": { 622 | "version": "2.0.4", 623 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 624 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 625 | }, 626 | "node_modules/is-binary-path": { 627 | "version": "2.1.0", 628 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 629 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 630 | "dev": true, 631 | "dependencies": { 632 | "binary-extensions": "^2.0.0" 633 | }, 634 | "engines": { 635 | "node": ">=8" 636 | } 637 | }, 638 | "node_modules/is-extglob": { 639 | "version": "2.1.1", 640 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 641 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 642 | "dev": true, 643 | "engines": { 644 | "node": ">=0.10.0" 645 | } 646 | }, 647 | "node_modules/is-glob": { 648 | "version": "4.0.3", 649 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 650 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 651 | "dev": true, 652 | "dependencies": { 653 | "is-extglob": "^2.1.1" 654 | }, 655 | "engines": { 656 | "node": ">=0.10.0" 657 | } 658 | }, 659 | "node_modules/is-number": { 660 | "version": "7.0.0", 661 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 662 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 663 | "dev": true, 664 | "engines": { 665 | "node": ">=0.12.0" 666 | } 667 | }, 668 | "node_modules/is-plain-obj": { 669 | "version": "2.1.0", 670 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 671 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 672 | "dev": true, 673 | "engines": { 674 | "node": ">=8" 675 | } 676 | }, 677 | "node_modules/is-unicode-supported": { 678 | "version": "0.1.0", 679 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 680 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 681 | "dev": true, 682 | "engines": { 683 | "node": ">=10" 684 | }, 685 | "funding": { 686 | "url": "https://github.com/sponsors/sindresorhus" 687 | } 688 | }, 689 | "node_modules/isarray": { 690 | "version": "1.0.0", 691 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 692 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" 693 | }, 694 | "node_modules/isexe": { 695 | "version": "2.0.0", 696 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 697 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 698 | "dev": true 699 | }, 700 | "node_modules/listenercount": { 701 | "version": "1.0.1", 702 | "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", 703 | "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==" 704 | }, 705 | "node_modules/locate-path": { 706 | "version": "6.0.0", 707 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 708 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 709 | "dev": true, 710 | "dependencies": { 711 | "p-locate": "^5.0.0" 712 | }, 713 | "engines": { 714 | "node": ">=10" 715 | }, 716 | "funding": { 717 | "url": "https://github.com/sponsors/sindresorhus" 718 | } 719 | }, 720 | "node_modules/minimatch": { 721 | "version": "3.1.2", 722 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 723 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 724 | "dependencies": { 725 | "brace-expansion": "^1.1.7" 726 | }, 727 | "engines": { 728 | "node": "*" 729 | } 730 | }, 731 | "node_modules/minimist": { 732 | "version": "1.2.8", 733 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 734 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 735 | "funding": { 736 | "url": "https://github.com/sponsors/ljharb" 737 | } 738 | }, 739 | "node_modules/mkdirp": { 740 | "version": "0.5.6", 741 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", 742 | "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", 743 | "dependencies": { 744 | "minimist": "^1.2.6" 745 | }, 746 | "bin": { 747 | "mkdirp": "bin/cmd.js" 748 | } 749 | }, 750 | "node_modules/mocha": { 751 | "version": "9.2.2", 752 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", 753 | "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", 754 | "dev": true, 755 | "dependencies": { 756 | "@ungap/promise-all-settled": "1.1.2", 757 | "ansi-colors": "4.1.1", 758 | "browser-stdout": "1.3.1", 759 | "chokidar": "3.5.3", 760 | "debug": "4.3.3", 761 | "diff": "5.0.0", 762 | "escape-string-regexp": "4.0.0", 763 | "find-up": "5.0.0", 764 | "glob": "7.2.0", 765 | "growl": "1.10.5", 766 | "he": "1.2.0", 767 | "js-yaml": "4.1.0", 768 | "log-symbols": "4.1.0", 769 | "minimatch": "4.2.1", 770 | "ms": "2.1.3", 771 | "nanoid": "3.3.1", 772 | "serialize-javascript": "6.0.0", 773 | "strip-json-comments": "3.1.1", 774 | "supports-color": "8.1.1", 775 | "which": "2.0.2", 776 | "workerpool": "6.2.0", 777 | "yargs": "16.2.0", 778 | "yargs-parser": "20.2.4", 779 | "yargs-unparser": "2.0.0" 780 | }, 781 | "bin": { 782 | "_mocha": "bin/_mocha", 783 | "mocha": "bin/mocha" 784 | }, 785 | "engines": { 786 | "node": ">= 12.0.0" 787 | }, 788 | "funding": { 789 | "type": "opencollective", 790 | "url": "https://opencollective.com/mochajs" 791 | } 792 | }, 793 | "node_modules/mocha/node_modules/escape-string-regexp": { 794 | "version": "4.0.0", 795 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 796 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 797 | "dev": true, 798 | "engines": { 799 | "node": ">=10" 800 | }, 801 | "funding": { 802 | "url": "https://github.com/sponsors/sindresorhus" 803 | } 804 | }, 805 | "node_modules/mocha/node_modules/js-yaml": { 806 | "version": "4.1.0", 807 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 808 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 809 | "dev": true, 810 | "dependencies": { 811 | "argparse": "^2.0.1" 812 | }, 813 | "bin": { 814 | "js-yaml": "bin/js-yaml.js" 815 | } 816 | }, 817 | "node_modules/mocha/node_modules/log-symbols": { 818 | "version": "4.1.0", 819 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 820 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 821 | "dev": true, 822 | "dependencies": { 823 | "chalk": "^4.1.0", 824 | "is-unicode-supported": "^0.1.0" 825 | }, 826 | "engines": { 827 | "node": ">=10" 828 | }, 829 | "funding": { 830 | "url": "https://github.com/sponsors/sindresorhus" 831 | } 832 | }, 833 | "node_modules/mocha/node_modules/minimatch": { 834 | "version": "4.2.1", 835 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", 836 | "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", 837 | "dev": true, 838 | "dependencies": { 839 | "brace-expansion": "^1.1.7" 840 | }, 841 | "engines": { 842 | "node": ">=10" 843 | } 844 | }, 845 | "node_modules/mocha/node_modules/serialize-javascript": { 846 | "version": "6.0.0", 847 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", 848 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", 849 | "dev": true, 850 | "dependencies": { 851 | "randombytes": "^2.1.0" 852 | } 853 | }, 854 | "node_modules/ms": { 855 | "version": "2.1.3", 856 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 857 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 858 | "dev": true 859 | }, 860 | "node_modules/nanoid": { 861 | "version": "3.3.1", 862 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", 863 | "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", 864 | "dev": true, 865 | "bin": { 866 | "nanoid": "bin/nanoid.cjs" 867 | }, 868 | "engines": { 869 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 870 | } 871 | }, 872 | "node_modules/normalize-path": { 873 | "version": "3.0.0", 874 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 875 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 876 | "dev": true, 877 | "engines": { 878 | "node": ">=0.10.0" 879 | } 880 | }, 881 | "node_modules/once": { 882 | "version": "1.4.0", 883 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 884 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 885 | "dependencies": { 886 | "wrappy": "1" 887 | } 888 | }, 889 | "node_modules/p-limit": { 890 | "version": "3.1.0", 891 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 892 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 893 | "dev": true, 894 | "dependencies": { 895 | "yocto-queue": "^0.1.0" 896 | }, 897 | "engines": { 898 | "node": ">=10" 899 | }, 900 | "funding": { 901 | "url": "https://github.com/sponsors/sindresorhus" 902 | } 903 | }, 904 | "node_modules/p-locate": { 905 | "version": "5.0.0", 906 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 907 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 908 | "dev": true, 909 | "dependencies": { 910 | "p-limit": "^3.0.2" 911 | }, 912 | "engines": { 913 | "node": ">=10" 914 | }, 915 | "funding": { 916 | "url": "https://github.com/sponsors/sindresorhus" 917 | } 918 | }, 919 | "node_modules/path-exists": { 920 | "version": "4.0.0", 921 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 922 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 923 | "dev": true, 924 | "engines": { 925 | "node": ">=8" 926 | } 927 | }, 928 | "node_modules/path-is-absolute": { 929 | "version": "1.0.1", 930 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 931 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 932 | "engines": { 933 | "node": ">=0.10.0" 934 | } 935 | }, 936 | "node_modules/picomatch": { 937 | "version": "2.3.1", 938 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 939 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 940 | "dev": true, 941 | "engines": { 942 | "node": ">=8.6" 943 | }, 944 | "funding": { 945 | "url": "https://github.com/sponsors/jonschlinkert" 946 | } 947 | }, 948 | "node_modules/process-nextick-args": { 949 | "version": "2.0.1", 950 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 951 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 952 | }, 953 | "node_modules/randombytes": { 954 | "version": "2.1.0", 955 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 956 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 957 | "dev": true, 958 | "dependencies": { 959 | "safe-buffer": "^5.1.0" 960 | } 961 | }, 962 | "node_modules/readable-stream": { 963 | "version": "2.3.7", 964 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 965 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 966 | "dependencies": { 967 | "core-util-is": "~1.0.0", 968 | "inherits": "~2.0.3", 969 | "isarray": "~1.0.0", 970 | "process-nextick-args": "~2.0.0", 971 | "safe-buffer": "~5.1.1", 972 | "string_decoder": "~1.1.1", 973 | "util-deprecate": "~1.0.1" 974 | } 975 | }, 976 | "node_modules/readdirp": { 977 | "version": "3.6.0", 978 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 979 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 980 | "dev": true, 981 | "dependencies": { 982 | "picomatch": "^2.2.1" 983 | }, 984 | "engines": { 985 | "node": ">=8.10.0" 986 | } 987 | }, 988 | "node_modules/require-directory": { 989 | "version": "2.1.1", 990 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 991 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 992 | "dev": true, 993 | "engines": { 994 | "node": ">=0.10.0" 995 | } 996 | }, 997 | "node_modules/rimraf": { 998 | "version": "3.0.2", 999 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 1000 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 1001 | "dependencies": { 1002 | "glob": "^7.1.3" 1003 | }, 1004 | "bin": { 1005 | "rimraf": "bin.js" 1006 | }, 1007 | "funding": { 1008 | "url": "https://github.com/sponsors/isaacs" 1009 | } 1010 | }, 1011 | "node_modules/safe-buffer": { 1012 | "version": "5.1.2", 1013 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1014 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1015 | }, 1016 | "node_modules/setimmediate": { 1017 | "version": "1.0.5", 1018 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", 1019 | "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" 1020 | }, 1021 | "node_modules/string_decoder": { 1022 | "version": "1.1.1", 1023 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1024 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1025 | "dependencies": { 1026 | "safe-buffer": "~5.1.0" 1027 | } 1028 | }, 1029 | "node_modules/strip-json-comments": { 1030 | "version": "3.1.1", 1031 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1032 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1033 | "dev": true, 1034 | "engines": { 1035 | "node": ">=8" 1036 | }, 1037 | "funding": { 1038 | "url": "https://github.com/sponsors/sindresorhus" 1039 | } 1040 | }, 1041 | "node_modules/supports-color": { 1042 | "version": "8.1.1", 1043 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 1044 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 1045 | "dev": true, 1046 | "dependencies": { 1047 | "has-flag": "^4.0.0" 1048 | }, 1049 | "engines": { 1050 | "node": ">=10" 1051 | }, 1052 | "funding": { 1053 | "url": "https://github.com/chalk/supports-color?sponsor=1" 1054 | } 1055 | }, 1056 | "node_modules/to-regex-range": { 1057 | "version": "5.0.1", 1058 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1059 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1060 | "dev": true, 1061 | "dependencies": { 1062 | "is-number": "^7.0.0" 1063 | }, 1064 | "engines": { 1065 | "node": ">=8.0" 1066 | } 1067 | }, 1068 | "node_modules/traverse": { 1069 | "version": "0.3.9", 1070 | "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", 1071 | "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", 1072 | "engines": { 1073 | "node": "*" 1074 | } 1075 | }, 1076 | "node_modules/typescript": { 1077 | "version": "4.4.3", 1078 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", 1079 | "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", 1080 | "dev": true, 1081 | "bin": { 1082 | "tsc": "bin/tsc", 1083 | "tsserver": "bin/tsserver" 1084 | }, 1085 | "engines": { 1086 | "node": ">=4.2.0" 1087 | } 1088 | }, 1089 | "node_modules/unzipper": { 1090 | "version": "0.10.11", 1091 | "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", 1092 | "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", 1093 | "dependencies": { 1094 | "big-integer": "^1.6.17", 1095 | "binary": "~0.3.0", 1096 | "bluebird": "~3.4.1", 1097 | "buffer-indexof-polyfill": "~1.0.0", 1098 | "duplexer2": "~0.1.4", 1099 | "fstream": "^1.0.12", 1100 | "graceful-fs": "^4.2.2", 1101 | "listenercount": "~1.0.1", 1102 | "readable-stream": "~2.3.6", 1103 | "setimmediate": "~1.0.4" 1104 | } 1105 | }, 1106 | "node_modules/util-deprecate": { 1107 | "version": "1.0.2", 1108 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1109 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" 1110 | }, 1111 | "node_modules/which": { 1112 | "version": "2.0.2", 1113 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1114 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1115 | "dev": true, 1116 | "dependencies": { 1117 | "isexe": "^2.0.0" 1118 | }, 1119 | "bin": { 1120 | "node-which": "bin/node-which" 1121 | }, 1122 | "engines": { 1123 | "node": ">= 8" 1124 | } 1125 | }, 1126 | "node_modules/workerpool": { 1127 | "version": "6.2.0", 1128 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", 1129 | "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", 1130 | "dev": true 1131 | }, 1132 | "node_modules/wrap-ansi": { 1133 | "version": "7.0.0", 1134 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1135 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1136 | "dev": true, 1137 | "dependencies": { 1138 | "ansi-styles": "^4.0.0", 1139 | "string-width": "^4.1.0", 1140 | "strip-ansi": "^6.0.0" 1141 | }, 1142 | "engines": { 1143 | "node": ">=10" 1144 | }, 1145 | "funding": { 1146 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1147 | } 1148 | }, 1149 | "node_modules/wrap-ansi/node_modules/ansi-regex": { 1150 | "version": "5.0.1", 1151 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1152 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 1153 | "dev": true, 1154 | "engines": { 1155 | "node": ">=8" 1156 | } 1157 | }, 1158 | "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { 1159 | "version": "3.0.0", 1160 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1161 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1162 | "dev": true, 1163 | "engines": { 1164 | "node": ">=8" 1165 | } 1166 | }, 1167 | "node_modules/wrap-ansi/node_modules/string-width": { 1168 | "version": "4.2.3", 1169 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1170 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1171 | "dev": true, 1172 | "dependencies": { 1173 | "emoji-regex": "^8.0.0", 1174 | "is-fullwidth-code-point": "^3.0.0", 1175 | "strip-ansi": "^6.0.1" 1176 | }, 1177 | "engines": { 1178 | "node": ">=8" 1179 | } 1180 | }, 1181 | "node_modules/wrap-ansi/node_modules/strip-ansi": { 1182 | "version": "6.0.1", 1183 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1184 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1185 | "dev": true, 1186 | "dependencies": { 1187 | "ansi-regex": "^5.0.1" 1188 | }, 1189 | "engines": { 1190 | "node": ">=8" 1191 | } 1192 | }, 1193 | "node_modules/wrappy": { 1194 | "version": "1.0.2", 1195 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1196 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1197 | }, 1198 | "node_modules/y18n": { 1199 | "version": "5.0.8", 1200 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1201 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 1202 | "dev": true, 1203 | "engines": { 1204 | "node": ">=10" 1205 | } 1206 | }, 1207 | "node_modules/yargs": { 1208 | "version": "16.2.0", 1209 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 1210 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 1211 | "dev": true, 1212 | "dependencies": { 1213 | "cliui": "^7.0.2", 1214 | "escalade": "^3.1.1", 1215 | "get-caller-file": "^2.0.5", 1216 | "require-directory": "^2.1.1", 1217 | "string-width": "^4.2.0", 1218 | "y18n": "^5.0.5", 1219 | "yargs-parser": "^20.2.2" 1220 | }, 1221 | "engines": { 1222 | "node": ">=10" 1223 | } 1224 | }, 1225 | "node_modules/yargs-parser": { 1226 | "version": "20.2.4", 1227 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", 1228 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", 1229 | "dev": true, 1230 | "engines": { 1231 | "node": ">=10" 1232 | } 1233 | }, 1234 | "node_modules/yargs-unparser": { 1235 | "version": "2.0.0", 1236 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 1237 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 1238 | "dev": true, 1239 | "dependencies": { 1240 | "camelcase": "^6.0.0", 1241 | "decamelize": "^4.0.0", 1242 | "flat": "^5.0.2", 1243 | "is-plain-obj": "^2.1.0" 1244 | }, 1245 | "engines": { 1246 | "node": ">=10" 1247 | } 1248 | }, 1249 | "node_modules/yargs/node_modules/ansi-regex": { 1250 | "version": "5.0.1", 1251 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1252 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 1253 | "dev": true, 1254 | "engines": { 1255 | "node": ">=8" 1256 | } 1257 | }, 1258 | "node_modules/yargs/node_modules/is-fullwidth-code-point": { 1259 | "version": "3.0.0", 1260 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1261 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1262 | "dev": true, 1263 | "engines": { 1264 | "node": ">=8" 1265 | } 1266 | }, 1267 | "node_modules/yargs/node_modules/string-width": { 1268 | "version": "4.2.3", 1269 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1270 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1271 | "dev": true, 1272 | "dependencies": { 1273 | "emoji-regex": "^8.0.0", 1274 | "is-fullwidth-code-point": "^3.0.0", 1275 | "strip-ansi": "^6.0.1" 1276 | }, 1277 | "engines": { 1278 | "node": ">=8" 1279 | } 1280 | }, 1281 | "node_modules/yargs/node_modules/strip-ansi": { 1282 | "version": "6.0.1", 1283 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1284 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1285 | "dev": true, 1286 | "dependencies": { 1287 | "ansi-regex": "^5.0.1" 1288 | }, 1289 | "engines": { 1290 | "node": ">=8" 1291 | } 1292 | }, 1293 | "node_modules/yocto-queue": { 1294 | "version": "0.1.0", 1295 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1296 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1297 | "dev": true, 1298 | "engines": { 1299 | "node": ">=10" 1300 | }, 1301 | "funding": { 1302 | "url": "https://github.com/sponsors/sindresorhus" 1303 | } 1304 | } 1305 | } 1306 | } 1307 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-osu", 3 | "displayName": "OSU Mode 3", 4 | "description": "Hit the code to the beat", 5 | "version": "3.3.0", 6 | "publisher": "AlexShenVSCode", 7 | "icon": "images/icon-large.png", 8 | "author": { 9 | "name": "Alex Shen", 10 | "email": "ao.shen@gmail.com", 11 | "url": "https://github.com/ao-shen" 12 | }, 13 | "license": "MIT", 14 | "bugs": { 15 | "url": "https://github.com/ao-shen/vscode-power-mode/issues" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/ao-shen/vscode-power-mode.git" 20 | }, 21 | "homepage": "https://github.com/ao-shen/vscode-power-mode", 22 | "engines": { 23 | "vscode": "^1.75.1" 24 | }, 25 | "categories": [ 26 | "Themes", 27 | "Other" 28 | ], 29 | "activationEvents": [ 30 | "*" 31 | ], 32 | "main": "./out/src/extension", 33 | "scripts": { 34 | "vscode:prepublish": "tsc -p ./", 35 | "compile": "tsc -watch -p ./", 36 | "test": "node ./out/src/test/runTest.js" 37 | }, 38 | "devDependencies": { 39 | "@types/mocha": "^9.0.0", 40 | "@types/node": "^16.10.2", 41 | "@types/vscode": "^1.34.0", 42 | "mocha": "^9.1.2", 43 | "typescript": "^4.4.3" 44 | }, 45 | "contributes": { 46 | "configuration": { 47 | "title": "OSU Mode", 48 | "properties": { 49 | "osumode.enabled": { 50 | "default": true, 51 | "type": "boolean", 52 | "description": "Set to false to disable OSU MODE!!!" 53 | }, 54 | "osumode.enableCursorExplosions": { 55 | "type": "boolean", 56 | "default": true, 57 | "description": "Set to false to disable letter explosions at the cursor while typing" 58 | }, 59 | "osumode.enableComboCounter": { 60 | "type": "boolean", 61 | "default": true, 62 | "description": "Set to false to disable showing the combo counter in the editor" 63 | }, 64 | "osumode.deleteResetsCombo": { 65 | "type": "boolean", 66 | "default": false, 67 | "description": "Set to true to make delete reset the combo, and also add a timer to reset the combo after 8 seconds of inactivity" 68 | }, 69 | "osumode.enableComboImage": { 70 | "type": "boolean", 71 | "default": true, 72 | "description": "Set to false to disable showing the combo image in the editor" 73 | }, 74 | "osumode.comboImageInterval": { 75 | "type": "number", 76 | "default": 50, 77 | "description": "The number of combo between displaying a combo image" 78 | }, 79 | "osumode.customComboImages": { 80 | "type": "array", 81 | "default": [], 82 | "description": "A list of URLs of your custom images. LOCAL IMAGES WILL NOT WORK" 83 | }, 84 | "osumode.maxExplosions": { 85 | "type": "number", 86 | "default": 1, 87 | "description": "The maximum number of simultaneous explosions" 88 | }, 89 | "osumode.explosionSize": { 90 | "type": "number", 91 | "default": 6, 92 | "description": "The size of the explosions. For value X, the height is set to X rem and the width to X ch" 93 | } 94 | } 95 | } 96 | }, 97 | "dependencies": { 98 | "@types/vscode": "^1.34.0", 99 | "@vscode/test-electron": "^2.2.3" 100 | } 101 | } -------------------------------------------------------------------------------- /releases/vscode-osu-3.1.0.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/releases/vscode-osu-3.1.0.vsix -------------------------------------------------------------------------------- /releases/vscode-osu-3.2.3.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/releases/vscode-osu-3.2.3.vsix -------------------------------------------------------------------------------- /releases/vscode-osu-3.3.0.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ao-shen/vscode-osu-mode/8690e5fdfa77249987f1ce19cd417b46fb1e8caf/releases/vscode-osu-3.3.0.vsix -------------------------------------------------------------------------------- /src/combo-meter.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { Plugin } from './plugin'; 3 | 4 | export interface ComboMeterConfig { 5 | enableComboCounter?: boolean; 6 | enableComboImage?: boolean; 7 | comboImageInterval?: number; 8 | customComboImages?: string[]; 9 | } 10 | 11 | export class ComboMeter implements Plugin { 12 | 13 | private config: ComboMeterConfig = {}; 14 | private comboTitleDecoration: vscode.TextEditorDecorationType; 15 | private comboCountDecoration: vscode.TextEditorDecorationType; 16 | 17 | private renderedComboCount: number = undefined; 18 | private combo: number = 0; 19 | private renderedImageCount: number = -1; 20 | // TODO: Currently unused. Use this to style the combo 21 | private osumode: boolean = false; 22 | private enabled: boolean = false; 23 | 24 | private disposeTimer = undefined; 25 | 26 | private comboCountAnimationTimer = undefined; 27 | private comboImageAnimationTimer = undefined; 28 | 29 | private orange: vscode.OutputChannel = undefined; 30 | 31 | private static readonly DEFAULT_CSS = ComboMeter.objectToCssString({ 32 | position: 'absolute', 33 | right: "5%", 34 | top: "20px", 35 | 36 | ['font-family']: "monospace", 37 | ['font-weight']: "900", 38 | 39 | // width: "50px", 40 | ['z-index']: 1, 41 | ['pointer-events']: 'none', 42 | ["text-align"]: "right", 43 | }); 44 | 45 | constructor() { 46 | this.activate(); 47 | } 48 | 49 | public activate = () => { 50 | vscode.window.onDidChangeTextEditorVisibleRanges((e: vscode.TextEditorVisibleRangesChangeEvent) => { 51 | this.updateDecorations(e.textEditor); 52 | }); 53 | 54 | /*if(this.orange) { 55 | } else { 56 | this.orange = vscode.window.createOutputChannel("Orange"); 57 | }*/ 58 | } 59 | 60 | dispose = () => { 61 | if (this.comboCountDecoration) { 62 | clearTimeout(this.comboCountAnimationTimer); 63 | this.comboCountDecoration.dispose(); 64 | this.comboCountDecoration = null; 65 | } 66 | 67 | if (this.comboTitleDecoration) { 68 | clearTimeout(this.comboImageAnimationTimer); 69 | this.comboTitleDecoration.dispose(); 70 | this.comboTitleDecoration = null; 71 | } 72 | } 73 | 74 | public onOsumodeStart = (combo: number) => { 75 | this.osumode = true; 76 | } 77 | 78 | public onOsumodeStop = (combo: number) => { 79 | this.osumode = false; 80 | } 81 | 82 | public onComboStart = (combo: number) => { 83 | this.combo = combo; 84 | this.updateDecorations(); 85 | } 86 | 87 | public onComboStop = (combo: number) => { 88 | this.combo = combo; 89 | this.updateDecorations(); 90 | } 91 | 92 | public onDidChangeTextDocument = (combo: number, osumode: boolean, event: vscode.TextDocumentChangeEvent) => { 93 | this.combo = combo; 94 | this.osumode = osumode; 95 | this.updateDecorations(); 96 | } 97 | 98 | public onDidChangeConfiguration = (config: vscode.WorkspaceConfiguration) => { 99 | this.config.enableComboCounter = config.get('enableComboCounter', true); 100 | this.config.enableComboImage = config.get('enableComboImage', true); 101 | this.config.comboImageInterval = config.get('comboImageInterval', 50); 102 | this.config.customComboImages = config.get('customComboImages', []); 103 | if (this.config.enableComboCounter) { 104 | this.enabled = true; 105 | this.activate(); 106 | } else { 107 | this.enabled = false; 108 | this.dispose(); 109 | } 110 | } 111 | 112 | private updateDecorations = (editor: vscode.TextEditor = vscode.window.activeTextEditor) => { 113 | if (!this.enabled) { 114 | return; 115 | } 116 | 117 | const firstVisibleRange = editor.visibleRanges.sort()[0]; 118 | 119 | if (!firstVisibleRange || this.combo < 2) { //^^^ hide title if combo less than.. 120 | this.dispose(); 121 | return; 122 | } 123 | 124 | clearTimeout(this.disposeTimer); 125 | this.disposeTimer = setTimeout(()=>{ 126 | this.dispose(); 127 | },10000); 128 | 129 | const position = firstVisibleRange.start; 130 | const ranges = [new vscode.Range(position, position)]; 131 | 132 | // The combo title doesn't ever change, so only create it once 133 | // !!this.comboTitleDecoration || this.createComboTitleDecoration(); 134 | // If the combo count changes, however, create a new decoration 135 | if (this.combo !== this.renderedComboCount) { 136 | this.renderedComboCount = this.combo; 137 | this.createComboCountDecoration(this.combo, ranges, editor); 138 | this.createComboTitleDecoration(this.combo, ranges, editor); //^^^ add counter value for change title 139 | } 140 | 141 | } 142 | 143 | private createComboTitleDecoration(count: number, ranges: vscode.Range[], editor: vscode.TextEditor = vscode.window.activeTextEditor) { 144 | 145 | const comboImageInterval = this.config.comboImageInterval; 146 | 147 | let comboImages = [ 148 | "https://raw.githubusercontent.com/ao-shen/vscode-power-mode/master/images/Character_Diona_Portrait.png", 149 | "https://raw.githubusercontent.com/ao-shen/vscode-power-mode/master/images/Character_Qiqi_Portrait.png", 150 | "https://raw.githubusercontent.com/ao-shen/vscode-power-mode/master/images/Character_Klee_Portrait.png", 151 | "https://raw.githubusercontent.com/ao-shen/vscode-power-mode/master/images/Character_Fischl_Portrait.png", 152 | "https://raw.githubusercontent.com/ao-shen/vscode-power-mode/master/images/Character_Hu_Tao_Portrait.png", 153 | "https://raw.githubusercontent.com/ao-shen/vscode-power-mode/master/images/Character_Ganyu_Portrait.png", 154 | "https://raw.githubusercontent.com/ao-shen/vscode-power-mode/master/images/Character_Keqing_Portrait.png", 155 | ]; 156 | 157 | if(this.config.customComboImages.length !== 0) { 158 | comboImages = this.config.customComboImages; 159 | } 160 | 161 | const imageCount = (Math.floor( count / comboImageInterval ) - 1); 162 | 163 | const imgIdx = imageCount % comboImages.length; 164 | 165 | const imgUrl = imgIdx === -1 ? "" : comboImages[imgIdx]; 166 | 167 | if(this.renderedImageCount != imageCount) { 168 | this.renderedImageCount = imageCount; 169 | 170 | const thisObj = this; 171 | 172 | let animateComboImageDecoration = function(frameCount: number) { 173 | 174 | let posX = 0; 175 | let delay = 10; 176 | 177 | if(frameCount < 15) { 178 | posX = 15 - frameCount; 179 | delay = 10; 180 | } else if(frameCount < 16) { 181 | posX = 0; 182 | delay = 1000; 183 | } else { 184 | posX = 0.005*Math.pow(frameCount-16,2); 185 | delay = 20; 186 | } 187 | 188 | let backgroundImageCss = { 189 | ["width"]: `60vh`, 190 | ["height"]: `80vh`, 191 | ["background-repeat"]: 'no-repeat', 192 | ["background-size"]: 'contain', 193 | ["background-position"]: 'right', 194 | ['z-index']: -1, 195 | //["background-color"]: `#ff000010`, 196 | ["right"]: `${-posX}vh`, 197 | }; 198 | 199 | if(imgUrl.length !== 0) { 200 | backgroundImageCss["background-image"] = `url("${imgUrl}")`; 201 | } 202 | 203 | const titleCss = ComboMeter.objectToCssString(backgroundImageCss); 204 | 205 | let newComboTitleDecoration = vscode.window.createTextEditorDecorationType({ 206 | // Title and Count cannot use the same pseudoelement 207 | before: { 208 | contentText: "", 209 | color: "#fff", 210 | textDecoration: `none; ${ComboMeter.DEFAULT_CSS} ${titleCss}`, 211 | }, 212 | rangeBehavior: vscode.DecorationRangeBehavior.ClosedClosed, 213 | }); 214 | 215 | editor.setDecorations(newComboTitleDecoration, ranges); 216 | 217 | thisObj.comboTitleDecoration && thisObj.comboTitleDecoration.dispose(); 218 | thisObj.comboTitleDecoration = newComboTitleDecoration; 219 | 220 | if(frameCount < 150) { 221 | thisObj.comboImageAnimationTimer = setTimeout(()=>{ 222 | animateComboImageDecoration(frameCount+1); 223 | }, delay); 224 | } 225 | } 226 | 227 | clearTimeout(this.comboImageAnimationTimer); 228 | animateComboImageDecoration(0); 229 | } 230 | } 231 | 232 | private createComboCountDecoration(count: number, ranges: vscode.Range[], editor: vscode.TextEditor = vscode.window.activeTextEditor) { 233 | 234 | const thisObj = this; 235 | 236 | let animateComboCountDecoration = function(frameCount: number) { 237 | 238 | const styleCount = count > 100 ? 100 : count; 239 | const styleColor = 'hsl(' + (100 - count * 1.2) + ', 100%, 45%)'; 240 | 241 | let textSize = ((styleCount*6)/100*Math.pow(0.5,frameCount*0.2)+6); 242 | 243 | const countCss = ComboMeter.objectToCssString({ 244 | ["font-size"]: `${textSize}em`, 245 | ["text-align"]: "center", 246 | ["text-shadow"]: `0px 0px 15px ${styleColor}`, 247 | }); 248 | 249 | let newComboCountDecoration = vscode.window.createTextEditorDecorationType({ 250 | // Title and Count cannot use the same pseudoelement 251 | after: { 252 | margin: ".8em 0 0 0", 253 | contentText: `${count}×`, 254 | color: "#ffffff", 255 | textDecoration: `none; ${ComboMeter.DEFAULT_CSS} ${countCss}`, 256 | }, 257 | rangeBehavior: vscode.DecorationRangeBehavior.ClosedClosed, 258 | }); 259 | 260 | editor.setDecorations(newComboCountDecoration, ranges); 261 | 262 | thisObj.comboCountDecoration && thisObj.comboCountDecoration.dispose(); 263 | thisObj.comboCountDecoration = newComboCountDecoration 264 | 265 | if(frameCount < 100) { 266 | thisObj.comboCountAnimationTimer = setTimeout(()=>{ 267 | animateComboCountDecoration(frameCount+1); 268 | }, 20 + 0.5 * frameCount); 269 | } 270 | } 271 | 272 | clearTimeout(this.comboCountAnimationTimer); 273 | animateComboCountDecoration(0); 274 | } 275 | 276 | private static objectToCssString(settings: any): string { 277 | let value = ''; 278 | const cssString = Object.keys(settings).map(setting => { 279 | value = settings[setting]; 280 | if (typeof value === 'string' || typeof value === 'number') { 281 | return `${setting}: ${value};` 282 | } 283 | }).join(' '); 284 | 285 | return cssString; 286 | } 287 | } -------------------------------------------------------------------------------- /src/config/config.ts: -------------------------------------------------------------------------------- 1 | import { WorkspaceConfiguration} from 'vscode'; 2 | import { ExplosionConfig } from '../cursor-exploder/cursor-exploder' 3 | 4 | export const CSS_LEFT = "margin-left"; 5 | export const CSS_TOP = "top"; 6 | 7 | export interface ThemeConfig extends ExplosionConfig { } 8 | 9 | export interface ExtensionConfig extends ThemeConfig { 10 | enabled?: boolean; 11 | comboThreshold?: number; 12 | comboTimeout?: number; 13 | } 14 | 15 | export function getConfigValue(key: string, vscodeConfig: WorkspaceConfiguration, themeConfig: any): T { 16 | // If the config is explicitly set, use that value 17 | if (isConfigSet(key, vscodeConfig)) { 18 | return vscodeConfig.get(key); 19 | } 20 | 21 | // Use the themeConfig value if set, 22 | const themeValue = themeConfig[key]; 23 | if (!isNullOrUndefined(themeValue)) { 24 | return themeValue; 25 | } 26 | 27 | // Fall back to the package.json default value 28 | // as a last resort 29 | return vscodeConfig.get(key); 30 | } 31 | 32 | function isNullOrUndefined(value: any) { 33 | return value === null || value === undefined; 34 | } 35 | 36 | function isConfigSet(key: string, config: WorkspaceConfiguration): boolean { 37 | const inspectionResults = config.inspect(key); 38 | return !isNullOrUndefined(inspectionResults.globalValue) || 39 | !isNullOrUndefined(inspectionResults.workspaceValue); 40 | } -------------------------------------------------------------------------------- /src/config/ridiculous.ts: -------------------------------------------------------------------------------- 1 | import { ThemeConfig } from './config'; 2 | import { alphabetGifMap } from './alphabet_map'; 3 | 4 | export const Ridiculous: ThemeConfig = { 5 | 6 | enableCursorExplosions: true, 7 | maxExplosions: 25, 8 | explosionSize: 10, 9 | explosionFrequency: 1, 10 | explosionOrder: 'sequential', 11 | gifMode: 'restart', 12 | explosionDuration: 1350, 13 | explosionOffset: 0.5, 14 | backgroundMode: 'image', 15 | customExplosions: alphabetGifMap, 16 | } -------------------------------------------------------------------------------- /src/cursor-exploder/cursor-exploder.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { Plugin } from '../plugin'; 3 | import { ThemeConfig, getConfigValue, CSS_LEFT, CSS_TOP } from '../config/config'; 4 | 5 | const alphabetIdxMap = { "A": 0, "a": 0, "B": 1, "b": 1, "C": 2, "c": 2, "D": 3, "d": 3, "E": 4, "e": 4, "F": 5, "f": 5, "G": 6, "g": 6, "H": 7, "h": 7, "I": 8, "i": 8, "J": 9, "j": 9, "K": 10, "k": 10, "L": 11, "l": 11, "M": 12, "m": 12, "N": 13, "n": 13, "O": 14, "o": 14, "P": 15, "p": 15, "Q": 16, "q": 16, "R": 17, "r": 17, "S": 18, "s": 18, "T": 19, "t": 19, "U": 20, "u": 20, "V": 21, "v": 21, "W": 22, "w": 22, "X": 23, "x": 23, "Y": 24, "y": 24, "Z": 25, "z": 25, "1": 26, "2": 27, "3": 28, "4": 29, "5": 30, "6": 31, "7": 32, "8": 33, "9": 34, "0": 35, "`": 36, "!": 37, "$": 38, "%": 39, "^": 40, "*": 41, "(": 42, ")": 43, "-": 44, "=": 45, "_": 46, "+": 47, "[": 48, "]": 49, "\\": 50, "|": 51, ";": 52, "'": 53, ":": 54, "\"": 55, ",": 56, ".": 57, "/": 58, "<": 59, ">": 60, "?": 61, "DELETE": 62, "SPACE": 63, "NEWLINE": 64, "MULTI-CHAR": 65}; 6 | 7 | export type ExplosionOrder = 'random' | 'sequential' | number; 8 | export type BackgroundMode = 'mask' | 'image'; 9 | export type GifMode = 'continue' | 'restart'; 10 | export interface ExplosionConfig { 11 | enableCursorExplosions: boolean; 12 | maxExplosions: number; 13 | explosionSize: number; 14 | explosionFrequency: number; 15 | explosionOffset: number; 16 | explosionDuration: number; 17 | customExplosions: string[]; 18 | explosionOrder: ExplosionOrder; 19 | backgroundMode: BackgroundMode; 20 | gifMode: GifMode 21 | customCss?: { [key: string]: string }; 22 | } 23 | 24 | export class CursorExploder implements Plugin { 25 | 26 | private config: ExplosionConfig = {} as ExplosionConfig; 27 | private activeDecorations: vscode.TextEditorDecorationType[] = []; 28 | private keystrokeCounter = -1; 29 | private explosionIndex = -1; 30 | private counterTimeout: NodeJS.Timer; 31 | 32 | constructor(public themeConfig: ThemeConfig) { } 33 | 34 | onThemeChanged = (theme: ThemeConfig) => { 35 | this.themeConfig = theme; 36 | this.initialize(); 37 | } 38 | 39 | activate = () => { 40 | this.initialize(); 41 | } 42 | 43 | dispose = () => { 44 | this.onOsumodeStop(); 45 | } 46 | 47 | public onOsumodeStart = (combo?: number) => { 48 | // Do nothing 49 | } 50 | 51 | public onOsumodeStop = (combo?: number) => { 52 | // Dispose all explosions 53 | while (this.activeDecorations.length > 0) { 54 | this.activeDecorations.shift().dispose(); 55 | } 56 | } 57 | 58 | public onDidChangeTextDocument = (combo: number, osumode: boolean, event: vscode.TextDocumentChangeEvent) => { 59 | if (!this.config.enableCursorExplosions || !osumode) { 60 | return; 61 | } 62 | 63 | // If the content change is empty then it was likely a delete 64 | // This means there may not be text after the cursor, so do the 65 | // explosion before instead. 66 | const changes = event.contentChanges[0]; 67 | const left = changes && changes.text.length === 0; 68 | this.explode(left, changes.text); 69 | } 70 | 71 | public onDidChangeConfiguration = (config: vscode.WorkspaceConfiguration) => { 72 | 73 | const newConfig: ExplosionConfig = { 74 | customExplosions: getConfigValue('customExplosions', config, this.themeConfig), 75 | enableCursorExplosions: getConfigValue('enableCursorExplosions', config, this.themeConfig), 76 | maxExplosions: getConfigValue('maxExplosions', config, this.themeConfig), 77 | explosionSize: getConfigValue('explosionSize', config, this.themeConfig), 78 | explosionFrequency: getConfigValue('explosionFrequency', config, this.themeConfig), 79 | explosionOffset: getConfigValue('explosionOffset', config, this.themeConfig), 80 | explosionOrder: getConfigValue('explosionOrder', config, this.themeConfig), 81 | explosionDuration: getConfigValue('explosionDuration', config, this.themeConfig), 82 | backgroundMode: getConfigValue('backgroundMode', config, this.themeConfig), 83 | gifMode: getConfigValue('gifMode', config, this.themeConfig), 84 | customCss: getConfigValue('customCss', config, this.themeConfig), 85 | } 86 | 87 | let changed = false; 88 | Object.keys(newConfig).forEach(key => { 89 | if (this.config[key] !== newConfig[key]) { 90 | changed = true; 91 | } 92 | }); 93 | 94 | if (!changed) { 95 | return; 96 | } 97 | 98 | this.config = newConfig; 99 | 100 | this.initialize(); 101 | } 102 | 103 | public initialize = () => { 104 | this.dispose(); 105 | 106 | if (!this.config.enableCursorExplosions) { 107 | return; 108 | } 109 | 110 | this.explosionIndex = -1; 111 | this.keystrokeCounter = -1; 112 | } 113 | 114 | private getExplosionDecoration = (position: vscode.Position, changes: string): vscode.TextEditorDecorationType => { 115 | let explosions = this.config.customExplosions; 116 | let explosion: string = null; 117 | 118 | let explosionSizeMultiplier: number = 1; 119 | let stripped_changes = changes.replace(/ +?/g, ''); 120 | // vscode.window.showInformationMessage(changes); 121 | if (changes.length == 1 && changes[0] in alphabetIdxMap) { 122 | explosion = explosions[alphabetIdxMap[changes[0]]]; 123 | } 124 | else if (changes.length == 0) { 125 | explosion = explosions[alphabetIdxMap["DELETE"]]; 126 | explosionSizeMultiplier = 1.5; 127 | } else if (stripped_changes.length == 0) { 128 | explosion = explosions[alphabetIdxMap["SPACE"]]; 129 | } 130 | else { 131 | if (stripped_changes == "\n" || stripped_changes == "\r\n") { 132 | explosion = explosions[alphabetIdxMap["NEWLINE"]]; 133 | explosionSizeMultiplier = 1.5; 134 | } // Code completion judge in vscode 135 | else if (changes.length > 0) { 136 | explosion = explosions[alphabetIdxMap["MULTI-CHAR"]]; 137 | explosionSizeMultiplier = 2; 138 | } 139 | else { 140 | explosion = explosions[alphabetIdxMap["A"]]; 141 | explosionSizeMultiplier = 2; 142 | } 143 | } 144 | 145 | if (!explosion) { 146 | return null; 147 | } 148 | 149 | return this.createExplosionDecorationType(explosion, explosionSizeMultiplier, position, changes); 150 | } 151 | 152 | private pickExplosion(explosions: string[]): string { 153 | if (!explosions) { 154 | return null; 155 | } 156 | switch (typeof this.config.explosionOrder) { 157 | case 'string': 158 | switch (this.config.explosionOrder) { 159 | case 'random': 160 | this.explosionIndex = getRandomInt(0, explosions.length); 161 | break; 162 | case 'sequential': 163 | this.explosionIndex = (this.explosionIndex + 1) % explosions.length; 164 | break; 165 | default: 166 | this.explosionIndex = 0; 167 | } 168 | break; 169 | case 'number': 170 | this.explosionIndex = Math.min(explosions.length - 1, Math.floor(Math.abs(this.config.explosionOrder as number))); 171 | default: 172 | break; 173 | } 174 | return explosions[this.explosionIndex]; 175 | } 176 | 177 | /** 178 | * @returns an decoration type with the configured background image 179 | */ 180 | private createExplosionDecorationType = (explosion: string, explosionSizeMultiplier: number, editorPosition: vscode.Position, changes: string): vscode.TextEditorDecorationType => { 181 | 182 | let explosionSize = this.config.explosionSize * (Math.random() * 0.7 + 0.5); 183 | let explosionSizeHor = explosionSize; 184 | 185 | if (changes.length == 1 && changes[0] in alphabetIdxMap) { 186 | 187 | } else { 188 | explosionSize *= 1.5; 189 | explosionSizeHor = explosionSize * 6; 190 | } 191 | 192 | // subtract 1 ch to account for the character and divide by two to make it centered 193 | // Use Math.floor to skew to the right which especially helps when deleting chars 194 | const leftValue = Math.floor((explosionSizeHor - 1) / 2); 195 | // By default, the top of the gif will be at the top of the text. 196 | // Setting the top to a negative value will raise it up. 197 | // The default gifs are "tall" and the bottom halves are empty. 198 | // Lowering them makes them appear in a more natural position, 199 | // but limiting the top to the line number keeps it from going 200 | // off the top of the editor 201 | const topValue = explosionSize * this.config.explosionOffset; 202 | 203 | const explosionUrl = this.getExplosionUrl(explosion); 204 | 205 | const backgroundCss = this.config.backgroundMode === 'mask' ? 206 | this.getMaskCssSettings(explosionUrl) : 207 | this.getBackgroundCssSettings(explosionUrl); 208 | 209 | const defaultCss = { 210 | position: 'absolute', 211 | [CSS_LEFT]: `-${leftValue}ch`, 212 | [CSS_TOP]: `-${topValue}rem`, 213 | width: `${explosionSizeHor}ch`, 214 | height: `${explosionSize}rem`, 215 | display: `inline-block`, 216 | ['z-index']: 1, 217 | ['pointer-events']: 'none', 218 | }; 219 | 220 | const backgroundCssString = this.objectToCssString(backgroundCss); 221 | const defaultCssString = this.objectToCssString(defaultCss); 222 | const customCssString = this.objectToCssString(this.config.customCss || {}); 223 | 224 | return vscode.window.createTextEditorDecorationType({ 225 | before: { 226 | contentText: "", 227 | textDecoration: `none; ${defaultCssString} ${backgroundCssString} ${customCssString}`, 228 | }, 229 | textDecoration: `none; position: relative;`, 230 | rangeBehavior: vscode.DecorationRangeBehavior.ClosedClosed, 231 | }); 232 | } 233 | 234 | private getExplosionUrl(explosion: string): string { 235 | if (this.config.gifMode !== 'restart') { 236 | return explosion; 237 | } 238 | 239 | if (this.isUrl(explosion)) { 240 | return `${explosion}?timestamp=${Date.now()}`; 241 | } else { 242 | // https://tools.ietf.org/html/rfc2397 243 | return explosion.replace('base64,', `timestamp=${Date.now()};base64,`); 244 | } 245 | } 246 | 247 | private isUrl(value: string): boolean { 248 | return value.startsWith('https'); 249 | } 250 | 251 | private getBackgroundCssSettings(explosion: string) { 252 | return { 253 | 'background-repeat': 'no-repeat', 254 | 'background-size': 'contain', 255 | 'background-image': `url("${explosion}")`, 256 | } 257 | } 258 | 259 | private getMaskCssSettings(explosion: string): any { 260 | return { 261 | 'background-color': 'currentColor', 262 | '-webkit-mask-repeat': 'no-repeat', 263 | '-webkit-mask-size': 'contain', 264 | '-webkit-mask-image': `url("${explosion}")`, 265 | filter: 'saturate(150%)', 266 | } 267 | } 268 | 269 | private objectToCssString(settings: any): string { 270 | let value = ''; 271 | const cssString = Object.keys(settings).map(setting => { 272 | value = settings[setting]; 273 | if (typeof value === 'string' || typeof value === 'number') { 274 | return `${setting}: ${value};` 275 | } 276 | }).join(' '); 277 | 278 | return cssString; 279 | } 280 | 281 | /** 282 | * "Explodes" where the cursor is by setting a text decoration 283 | * that contains a base64 encoded gif as the background image. 284 | * The gif is then removed 1 second later 285 | * 286 | * @param {boolean} [left=false] place the decoration to 287 | * the left or the right of the cursor 288 | */ 289 | private explode = (left = false, changes = "") => { 290 | // To give the explosions space, only explode every X strokes 291 | // Where X is the configured explosion frequency 292 | // This counter resets if the user does not type for 1 second. 293 | clearTimeout(this.counterTimeout); 294 | this.counterTimeout = setTimeout(() => { 295 | this.keystrokeCounter = -1; 296 | }, 1000); 297 | 298 | if (++this.keystrokeCounter % this.config.explosionFrequency !== 0) { 299 | return; 300 | } 301 | 302 | const activeEditor = vscode.window.activeTextEditor; 303 | const cursorPosition = vscode.window.activeTextEditor.selection.active; 304 | // The delta is greater to the left than to the right because otherwise the gif doesn't appear 305 | const delta = left ? -2 : 1; 306 | const newRange = new vscode.Range( 307 | cursorPosition.with(cursorPosition.line, cursorPosition.character), 308 | // Value can't be negative 309 | cursorPosition.with(cursorPosition.line, Math.max(0, cursorPosition.character + delta)) 310 | ); 311 | 312 | // Dispose excess explosions 313 | while (this.activeDecorations.length >= this.config.maxExplosions) { 314 | this.activeDecorations.shift().dispose(); 315 | } 316 | 317 | // A new decoration is used each time because otherwise adjacent 318 | // gifs will all be identical. This helps them be at least a little 319 | // offset. 320 | const decoration = this.getExplosionDecoration(newRange.end, changes); 321 | if (!decoration) { 322 | return; 323 | } 324 | 325 | this.activeDecorations.push(decoration); 326 | 327 | if (this.config.explosionDuration !== 0) { 328 | setTimeout(() => { 329 | decoration.dispose(); 330 | }, this.config.explosionDuration); 331 | } 332 | activeEditor.setDecorations(decoration, [newRange]); 333 | } 334 | } 335 | 336 | function getRandomInt(min, max) { 337 | min = Math.ceil(min); 338 | max = Math.floor(max); 339 | return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive 340 | } 341 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { Plugin } from './plugin'; 3 | import { ThemeConfig, getConfigValue } from './config/config'; 4 | import { CursorExploder } from './cursor-exploder/cursor-exploder'; 5 | import { ComboMeter } from './combo-meter'; 6 | import { Ridiculous } from './config/ridiculous'; 7 | 8 | const DEFAULT_THEME_ID = 'particles'; 9 | const DEFAULT_THEME_CONFIG = Ridiculous; 10 | 11 | // Config values 12 | let documentChangeListenerDisposer: vscode.Disposable = null; 13 | let enabled = false; 14 | let comboThreshold: number; 15 | let deleteResetsCombo = false; 16 | 17 | // Native plugins 18 | let cursorExploder: CursorExploder; 19 | let comboMeter: ComboMeter; 20 | 21 | // OsuMode components 22 | let plugins: Plugin[] = []; 23 | 24 | // Themes 25 | let themes: { [key: string]: ThemeConfig } = { 26 | ["ridiculous"]: Ridiculous, 27 | }; 28 | 29 | // Current combo count 30 | let combo = 0; 31 | 32 | export function activate(context: vscode.ExtensionContext) { 33 | vscode.workspace.onDidChangeConfiguration(onDidChangeConfiguration); 34 | onDidChangeConfiguration(); 35 | } 36 | 37 | function init(config: vscode.WorkspaceConfiguration, activeTheme: ThemeConfig) { 38 | // Just in case something was left behind, clean it up 39 | deactivate(); 40 | combo = 0; 41 | 42 | // The native plugins need this special theme, a subset of the config 43 | cursorExploder = new CursorExploder(activeTheme), 44 | comboMeter = new ComboMeter(); 45 | 46 | plugins.push( 47 | cursorExploder, 48 | comboMeter, 49 | ); 50 | 51 | plugins.forEach(plugin => plugin.onDidChangeConfiguration(config)); 52 | 53 | documentChangeListenerDisposer = vscode.workspace.onDidChangeTextDocument(onDidChangeTextDocument); 54 | } 55 | 56 | /** 57 | * Note: this method is also called automatically 58 | * when the extension is deactivated 59 | */ 60 | export function deactivate() { 61 | 62 | combo = 0; 63 | 64 | if (documentChangeListenerDisposer) { 65 | documentChangeListenerDisposer.dispose(); 66 | documentChangeListenerDisposer = null; 67 | } 68 | 69 | while (plugins.length > 0) { 70 | plugins.shift().dispose(); 71 | } 72 | } 73 | 74 | function onDidChangeConfiguration() { 75 | const config = vscode.workspace.getConfiguration('osumode'); 76 | const theme = Ridiculous; 77 | 78 | const oldEnabled = enabled; 79 | 80 | enabled = config.get('enabled', false); 81 | comboThreshold = config.get('comboThreshold', 0); 82 | deleteResetsCombo = config.get('deleteResetsCombo', false); 83 | 84 | // Switching from disabled to enabled 85 | if (!oldEnabled && enabled) { 86 | init(config, theme); 87 | return; 88 | } 89 | 90 | // Switching from enabled to disabled 91 | if (oldEnabled && !enabled) { 92 | deactivate(); 93 | return; 94 | } 95 | 96 | // If not enabled, nothing matters 97 | // because it will be taken care of 98 | // when it gets reenabled 99 | if (!enabled) { 100 | return; 101 | } 102 | 103 | // The theme needs set BEFORE onDidChangeConfiguration is called 104 | cursorExploder.themeConfig = theme; 105 | 106 | plugins.forEach(plugin => plugin.onDidChangeConfiguration(config)); 107 | } 108 | 109 | // This will be exposed so other extensions can contribute their own themes 110 | // function registerTheme(themeId: string, config: ThemeConfig) { 111 | // themes[themeId] = config; 112 | // } 113 | 114 | function getThemeConfig(themeId: string): ThemeConfig { 115 | return themes[themeId]; 116 | } 117 | 118 | const onComboEnd = () => { 119 | plugins.forEach(plugin => plugin.onOsumodeStop(combo)); 120 | 121 | // TODO: Evaluate if this event is needed 122 | // plugins.forEach(plugin => plugin.onComboReset(combo)); 123 | 124 | combo = 0; 125 | } 126 | 127 | function isOsumode() { 128 | return enabled && combo >= comboThreshold; 129 | } 130 | 131 | 132 | let timer: NodeJS.Timeout; 133 | function onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { 134 | 135 | if(event.document != vscode.window.activeTextEditor.document) { 136 | return; 137 | } 138 | 139 | if(deleteResetsCombo) { 140 | timer = setTimeout(() => { 141 | onComboEnd() 142 | }, 8000); 143 | } 144 | const changes = event.contentChanges[0].text; 145 | 146 | if(deleteResetsCombo && changes.length == 0) { 147 | onComboEnd(); 148 | } else { 149 | combo++; 150 | } 151 | 152 | const osumode = isOsumode(); 153 | plugins.forEach(plugin => plugin.onDidChangeTextDocument(combo, osumode, event)); 154 | } 155 | 156 | 157 | -------------------------------------------------------------------------------- /src/plugin.ts: -------------------------------------------------------------------------------- 1 | import { TextDocumentChangeEvent, WorkspaceConfiguration } from 'vscode'; 2 | 3 | export interface Plugin { 4 | dispose(): void; 5 | onOsumodeStart(combo: number): void; 6 | onOsumodeStop(combo: number): void; 7 | onDidChangeTextDocument(combo: number, osumode: boolean, event: TextDocumentChangeEvent): void; 8 | onDidChangeConfiguration(osumodeConfig: WorkspaceConfiguration): void; 9 | } -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from '@vscode/test-electron'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to the extension test script 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.strictEqual([1, 2, 3].indexOf(5), -1); 13 | assert.strictEqual([1, 2, 3].indexOf(0), -1); 14 | }); 15 | }); -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd' 9 | }); 10 | 11 | const testsRoot = path.resolve(__dirname, '..'); 12 | 13 | return new Promise((c, e) => { 14 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 15 | if (err) { 16 | return e(err); 17 | } 18 | 19 | // Add files to the test suite 20 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 21 | 22 | try { 23 | // Run the mocha test 24 | mocha.run(failures => { 25 | if (failures > 0) { 26 | e(new Error(`${failures} tests failed.`)); 27 | } else { 28 | c(); 29 | } 30 | }); 31 | } catch (err) { 32 | console.error(err); 33 | e(err); 34 | } 35 | }); 36 | }); 37 | } -------------------------------------------------------------------------------- /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 | "alwaysStrict": true 12 | }, 13 | "exclude": [ 14 | "node_modules", 15 | ".vscode-test" 16 | ] 17 | } --------------------------------------------------------------------------------