├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── test └── wgsl-preprocessor.test.js └── wgsl-preprocessor.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Brandon Jones 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 | # WGSL Preprocessor 2 | 3 | This library provides a dirt-simple way of adding simple preprocessor macros to 4 | your WGSL shaders via [tagged templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates). It supports: 5 | 6 | - `#if` 7 | - `#elif` 8 | - `#else` 9 | - `#endif` 10 | 11 | Most other typical preprocessor functionality can be supported via JavaScript's 12 | [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals). 13 | 14 | ## Installation 15 | 16 | You can install from npm: 17 | 18 | `npm install wgsl-preprocessor` 19 | 20 | And then import into your code as a standard ES6 module: 21 | 22 | ```js 23 | import { wgsl } from './node-modules/wgsl-preprocessor/wgsl-preprocessor.js'; 24 | ``` 25 | 26 | Or use without an install step by loading it from a CDN like jsdelivr: 27 | 28 | ```js 29 | import { wgsl } from 'https://cdn.jsdelivr.net/npm/wgsl-preprocessor@1.0/wgsl-preprocessor.js'; 30 | ``` 31 | 32 | Or, you know, just copy and paste the contents of `wgsl-preprocessor.js` where ever is convenient for you. It's less 33 | than a 100 lines of code, we really don't need to overthink it! 34 | 35 | ## Usage 36 | 37 | Import the `wgsl` symbol from wherever you've installed `wgsl-preprocessor.js` and use it as a tag for a template 38 | literal string: 39 | 40 | ```js 41 | import { wgsl } from 'https://cdn.jsdelivr.net/npm/wgsl-preprocessor@1.0/wgsl-preprocessor.js'; 42 | 43 | function getDebugShader(sRGB = false) { 44 | return wgsl` 45 | @stage(fragment) 46 | fn main() -> @location(0) vec4 { 47 | let color = vec4(1.0, 0.0, 0.0, 1.0); 48 | #if ${sRGB} 49 | let rgb = pow(color.rgb, vec3(1.0 / 2.2)); 50 | return vec4(rgb, color.a); 51 | #else 52 | return color; 53 | #endif 54 | }`; 55 | } 56 | ` 57 | ``` 58 | 59 | When using `#if` or `#elif` the preprocessor symbol _must_ be followed by a substitution expression that will be 60 | evaluated as a boolean. 61 | 62 | ```js 63 | wgsl` 64 | #if ${someVar} // Valid 65 | #endif 66 | 67 | #if ${x > 5} // Valid 68 | #endif 69 | 70 | #if ${someFunction()} // Valid 71 | #endif 72 | 73 | #if true // Invalid 74 | #endif 75 | 76 | #if 1 // Invalid 77 | #endif 78 | `; 79 | ``` 80 | 81 | If the result of the expression is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) then the string 82 | contents between the opening and closing tags will be returned as part of the string, otherwise it will be omitted. 83 | 84 | ```js 85 | const x = 1; 86 | const source = wgsl` 87 | #if ${x < 3} 88 | let a = 1; 89 | #endif 90 | 91 | #if ${x > 3} 92 | let b = 2; 93 | #endif 94 | 95 | #if ${x == 3} 96 | let c = 3; 97 | #else 98 | let c = 0; 99 | #endif 100 | 101 | #if ${x == 4} 102 | let d = 4; 103 | #elif ${x == 1} 104 | let d = 1; 105 | #else 106 | let d = 0; 107 | #endif 108 | `; 109 | 110 | // source will be: 111 | // let a = 1 112 | // 113 | // 114 | // let c = 0; 115 | // 116 | // let d = 1; 117 | ``` 118 | 119 | `#if`/`#elif` statements may be nested any number of levels deep: 120 | 121 | ```js 122 | wgsl` 123 | #if ${shadowsEnabled} 124 | #if ${lightType == 'point'} 125 | let shadowAmount = computePointLightShadow(); 126 | #elif ${lightType == 'spot'} 127 | let shadowAmount = computeSpotLightShadow(); 128 | #else 129 | let shadowAmount = computeDirectionalShadow(); 130 | #endif 131 | lightFactor = lightFactor - shadowAmount; 132 | #endif 133 | `; 134 | ``` 135 | 136 | And any number of `#elif`s may be chained: 137 | 138 | ```js 139 | wgsl` 140 | #if ${sampleCount == 1} 141 | var sampleOffsets : array, 1> = array, 1>( 142 | vec2(0.0, 0.0) 143 | ); 144 | #elif ${sampleCount == 2} 145 | var sampleOffsets : array, 2> = array, 2>( 146 | vec2(-0.5, -0.5), vec2(0.5, 0.5) 147 | ); 148 | #elif ${sampleCount == 4} 149 | var sampleOffsets : array, 4> = array, 4>( 150 | vec2(-0.5, -0.5), vec2(-0.5, 0.5), vec2(0.5, -0.5), vec2(0.5, 0.5), 151 | ); 152 | #elif ${sampleCount == 8} 153 | // Etc... 154 | #endif 155 | `; 156 | ``` 157 | 158 | ## Why no `#define`? 159 | 160 | If you need something to approximate a `#define` statement from other preprocessors, simply use JavaScript's built-in substitution expressions! You don't even need the `wgsl` tag! 161 | 162 | ```js 163 | const ambientFactor = 1.0; 164 | const sampleCount = 2; 165 | 166 | const source = ` 167 | let ambientFactor = f32(${ambientFactor}); 168 | 169 | for (var i = 0u; i < ${sampleCount}u; i = i + 1u) { 170 | // Etc... 171 | } 172 | `; 173 | ``` 174 | 175 | But of course, they play nicely with the `wgsl` tag too: 176 | 177 | ```js 178 | const useApproximateSRGB = true; 179 | const approxGamma = 2.2; 180 | 181 | export const colorConversions = wgsl` 182 | fn linearTosRGB(linear : vec3) -> vec3 { 183 | #if ${useApproximateSRGB} 184 | let INV_GAMMA = 1.0 / ${approxGamma}; 185 | return pow(linear, vec3(INV_GAMMA)); 186 | #else 187 | if (all(linear <= vec3(0.0031308))) { 188 | return linear * 12.92; 189 | } 190 | return (pow(abs(linear), vec3(1.0/2.4)) * 1.055) - vec3(0.055); 191 | #endif 192 | } 193 | `; 194 | ``` 195 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wgsl-preprocessor", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "wgsl-preprocessor", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "chai": "^4.3.6", 13 | "mocha": "^9.2.0" 14 | } 15 | }, 16 | "node_modules/@ungap/promise-all-settled": { 17 | "version": "1.1.2", 18 | "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", 19 | "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", 20 | "dev": true 21 | }, 22 | "node_modules/ansi-colors": { 23 | "version": "4.1.1", 24 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 25 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 26 | "dev": true, 27 | "engines": { 28 | "node": ">=6" 29 | } 30 | }, 31 | "node_modules/ansi-regex": { 32 | "version": "5.0.1", 33 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 34 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 35 | "dev": true, 36 | "engines": { 37 | "node": ">=8" 38 | } 39 | }, 40 | "node_modules/ansi-styles": { 41 | "version": "4.3.0", 42 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 43 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 44 | "dev": true, 45 | "dependencies": { 46 | "color-convert": "^2.0.1" 47 | }, 48 | "engines": { 49 | "node": ">=8" 50 | }, 51 | "funding": { 52 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 53 | } 54 | }, 55 | "node_modules/anymatch": { 56 | "version": "3.1.2", 57 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 58 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 59 | "dev": true, 60 | "dependencies": { 61 | "normalize-path": "^3.0.0", 62 | "picomatch": "^2.0.4" 63 | }, 64 | "engines": { 65 | "node": ">= 8" 66 | } 67 | }, 68 | "node_modules/assertion-error": { 69 | "version": "1.1.0", 70 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 71 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 72 | "dev": true, 73 | "engines": { 74 | "node": "*" 75 | } 76 | }, 77 | "node_modules/balanced-match": { 78 | "version": "1.0.2", 79 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 80 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 81 | "dev": true 82 | }, 83 | "node_modules/binary-extensions": { 84 | "version": "2.2.0", 85 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 86 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 87 | "dev": true, 88 | "engines": { 89 | "node": ">=8" 90 | } 91 | }, 92 | "node_modules/brace-expansion": { 93 | "version": "1.1.11", 94 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 95 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 96 | "dev": true, 97 | "dependencies": { 98 | "balanced-match": "^1.0.0", 99 | "concat-map": "0.0.1" 100 | } 101 | }, 102 | "node_modules/braces": { 103 | "version": "3.0.2", 104 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 105 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 106 | "dev": true, 107 | "dependencies": { 108 | "fill-range": "^7.0.1" 109 | }, 110 | "engines": { 111 | "node": ">=8" 112 | } 113 | }, 114 | "node_modules/browser-stdout": { 115 | "version": "1.3.1", 116 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 117 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 118 | "dev": true 119 | }, 120 | "node_modules/chai": { 121 | "version": "4.3.6", 122 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", 123 | "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", 124 | "dev": true, 125 | "dependencies": { 126 | "assertion-error": "^1.1.0", 127 | "check-error": "^1.0.2", 128 | "deep-eql": "^3.0.1", 129 | "get-func-name": "^2.0.0", 130 | "loupe": "^2.3.1", 131 | "pathval": "^1.1.1", 132 | "type-detect": "^4.0.5" 133 | }, 134 | "engines": { 135 | "node": ">=4" 136 | } 137 | }, 138 | "node_modules/chalk": { 139 | "version": "4.1.2", 140 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 141 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 142 | "dev": true, 143 | "dependencies": { 144 | "ansi-styles": "^4.1.0", 145 | "supports-color": "^7.1.0" 146 | }, 147 | "engines": { 148 | "node": ">=10" 149 | }, 150 | "funding": { 151 | "url": "https://github.com/chalk/chalk?sponsor=1" 152 | } 153 | }, 154 | "node_modules/check-error": { 155 | "version": "1.0.2", 156 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 157 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 158 | "dev": true, 159 | "engines": { 160 | "node": "*" 161 | } 162 | }, 163 | "node_modules/chokidar": { 164 | "version": "3.5.3", 165 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 166 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 167 | "dev": true, 168 | "funding": [ 169 | { 170 | "type": "individual", 171 | "url": "https://paulmillr.com/funding/" 172 | } 173 | ], 174 | "dependencies": { 175 | "anymatch": "~3.1.2", 176 | "braces": "~3.0.2", 177 | "glob-parent": "~5.1.2", 178 | "is-binary-path": "~2.1.0", 179 | "is-glob": "~4.0.1", 180 | "normalize-path": "~3.0.0", 181 | "readdirp": "~3.6.0" 182 | }, 183 | "engines": { 184 | "node": ">= 8.10.0" 185 | }, 186 | "optionalDependencies": { 187 | "fsevents": "~2.3.2" 188 | } 189 | }, 190 | "node_modules/cliui": { 191 | "version": "7.0.4", 192 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 193 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 194 | "dev": true, 195 | "dependencies": { 196 | "string-width": "^4.2.0", 197 | "strip-ansi": "^6.0.0", 198 | "wrap-ansi": "^7.0.0" 199 | } 200 | }, 201 | "node_modules/color-convert": { 202 | "version": "2.0.1", 203 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 204 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 205 | "dev": true, 206 | "dependencies": { 207 | "color-name": "~1.1.4" 208 | }, 209 | "engines": { 210 | "node": ">=7.0.0" 211 | } 212 | }, 213 | "node_modules/color-name": { 214 | "version": "1.1.4", 215 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 216 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 217 | "dev": true 218 | }, 219 | "node_modules/concat-map": { 220 | "version": "0.0.1", 221 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 222 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 223 | "dev": true 224 | }, 225 | "node_modules/debug": { 226 | "version": "4.3.3", 227 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", 228 | "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", 229 | "dev": true, 230 | "dependencies": { 231 | "ms": "2.1.2" 232 | }, 233 | "engines": { 234 | "node": ">=6.0" 235 | }, 236 | "peerDependenciesMeta": { 237 | "supports-color": { 238 | "optional": true 239 | } 240 | } 241 | }, 242 | "node_modules/decamelize": { 243 | "version": "4.0.0", 244 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 245 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 246 | "dev": true, 247 | "engines": { 248 | "node": ">=10" 249 | }, 250 | "funding": { 251 | "url": "https://github.com/sponsors/sindresorhus" 252 | } 253 | }, 254 | "node_modules/deep-eql": { 255 | "version": "3.0.1", 256 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 257 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 258 | "dev": true, 259 | "dependencies": { 260 | "type-detect": "^4.0.0" 261 | }, 262 | "engines": { 263 | "node": ">=0.12" 264 | } 265 | }, 266 | "node_modules/diff": { 267 | "version": "5.0.0", 268 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 269 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 270 | "dev": true, 271 | "engines": { 272 | "node": ">=0.3.1" 273 | } 274 | }, 275 | "node_modules/emoji-regex": { 276 | "version": "8.0.0", 277 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 278 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 279 | "dev": true 280 | }, 281 | "node_modules/escalade": { 282 | "version": "3.1.1", 283 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 284 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 285 | "dev": true, 286 | "engines": { 287 | "node": ">=6" 288 | } 289 | }, 290 | "node_modules/fill-range": { 291 | "version": "7.0.1", 292 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 293 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 294 | "dev": true, 295 | "dependencies": { 296 | "to-regex-range": "^5.0.1" 297 | }, 298 | "engines": { 299 | "node": ">=8" 300 | } 301 | }, 302 | "node_modules/flat": { 303 | "version": "5.0.2", 304 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 305 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 306 | "dev": true, 307 | "bin": { 308 | "flat": "cli.js" 309 | } 310 | }, 311 | "node_modules/fs.realpath": { 312 | "version": "1.0.0", 313 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 314 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 315 | "dev": true 316 | }, 317 | "node_modules/fsevents": { 318 | "version": "2.3.2", 319 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 320 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 321 | "dev": true, 322 | "hasInstallScript": true, 323 | "optional": true, 324 | "os": [ 325 | "darwin" 326 | ], 327 | "engines": { 328 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 329 | } 330 | }, 331 | "node_modules/get-caller-file": { 332 | "version": "2.0.5", 333 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 334 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 335 | "dev": true, 336 | "engines": { 337 | "node": "6.* || 8.* || >= 10.*" 338 | } 339 | }, 340 | "node_modules/get-func-name": { 341 | "version": "2.0.0", 342 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 343 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 344 | "dev": true, 345 | "engines": { 346 | "node": "*" 347 | } 348 | }, 349 | "node_modules/glob": { 350 | "version": "7.2.0", 351 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 352 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 353 | "dev": true, 354 | "dependencies": { 355 | "fs.realpath": "^1.0.0", 356 | "inflight": "^1.0.4", 357 | "inherits": "2", 358 | "minimatch": "^3.0.4", 359 | "once": "^1.3.0", 360 | "path-is-absolute": "^1.0.0" 361 | }, 362 | "engines": { 363 | "node": "*" 364 | }, 365 | "funding": { 366 | "url": "https://github.com/sponsors/isaacs" 367 | } 368 | }, 369 | "node_modules/glob-parent": { 370 | "version": "5.1.2", 371 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 372 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 373 | "dev": true, 374 | "dependencies": { 375 | "is-glob": "^4.0.1" 376 | }, 377 | "engines": { 378 | "node": ">= 6" 379 | } 380 | }, 381 | "node_modules/growl": { 382 | "version": "1.10.5", 383 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 384 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 385 | "dev": true, 386 | "engines": { 387 | "node": ">=4.x" 388 | } 389 | }, 390 | "node_modules/has-flag": { 391 | "version": "4.0.0", 392 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 393 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 394 | "dev": true, 395 | "engines": { 396 | "node": ">=8" 397 | } 398 | }, 399 | "node_modules/he": { 400 | "version": "1.2.0", 401 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 402 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 403 | "dev": true, 404 | "bin": { 405 | "he": "bin/he" 406 | } 407 | }, 408 | "node_modules/inflight": { 409 | "version": "1.0.6", 410 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 411 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 412 | "dev": true, 413 | "dependencies": { 414 | "once": "^1.3.0", 415 | "wrappy": "1" 416 | } 417 | }, 418 | "node_modules/inherits": { 419 | "version": "2.0.4", 420 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 421 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 422 | "dev": true 423 | }, 424 | "node_modules/is-binary-path": { 425 | "version": "2.1.0", 426 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 427 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 428 | "dev": true, 429 | "dependencies": { 430 | "binary-extensions": "^2.0.0" 431 | }, 432 | "engines": { 433 | "node": ">=8" 434 | } 435 | }, 436 | "node_modules/is-extglob": { 437 | "version": "2.1.1", 438 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 439 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 440 | "dev": true, 441 | "engines": { 442 | "node": ">=0.10.0" 443 | } 444 | }, 445 | "node_modules/is-fullwidth-code-point": { 446 | "version": "3.0.0", 447 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 448 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 449 | "dev": true, 450 | "engines": { 451 | "node": ">=8" 452 | } 453 | }, 454 | "node_modules/is-glob": { 455 | "version": "4.0.3", 456 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 457 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 458 | "dev": true, 459 | "dependencies": { 460 | "is-extglob": "^2.1.1" 461 | }, 462 | "engines": { 463 | "node": ">=0.10.0" 464 | } 465 | }, 466 | "node_modules/is-number": { 467 | "version": "7.0.0", 468 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 469 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 470 | "dev": true, 471 | "engines": { 472 | "node": ">=0.12.0" 473 | } 474 | }, 475 | "node_modules/is-plain-obj": { 476 | "version": "2.1.0", 477 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 478 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 479 | "dev": true, 480 | "engines": { 481 | "node": ">=8" 482 | } 483 | }, 484 | "node_modules/is-unicode-supported": { 485 | "version": "0.1.0", 486 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 487 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 488 | "dev": true, 489 | "engines": { 490 | "node": ">=10" 491 | }, 492 | "funding": { 493 | "url": "https://github.com/sponsors/sindresorhus" 494 | } 495 | }, 496 | "node_modules/isexe": { 497 | "version": "2.0.0", 498 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 499 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 500 | "dev": true 501 | }, 502 | "node_modules/log-symbols": { 503 | "version": "4.1.0", 504 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 505 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 506 | "dev": true, 507 | "dependencies": { 508 | "chalk": "^4.1.0", 509 | "is-unicode-supported": "^0.1.0" 510 | }, 511 | "engines": { 512 | "node": ">=10" 513 | }, 514 | "funding": { 515 | "url": "https://github.com/sponsors/sindresorhus" 516 | } 517 | }, 518 | "node_modules/loupe": { 519 | "version": "2.3.2", 520 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.2.tgz", 521 | "integrity": "sha512-QgVamnvj0jX1LMPlCAq0MK6hATORFtGqHoUKXTkwNe13BqlN6aePQCKnnTcFvdDYEEITcJ+gBl4mTW7YJtJbyQ==", 522 | "dev": true, 523 | "dependencies": { 524 | "get-func-name": "^2.0.0" 525 | } 526 | }, 527 | "node_modules/minimatch": { 528 | "version": "3.0.4", 529 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 530 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 531 | "dev": true, 532 | "dependencies": { 533 | "brace-expansion": "^1.1.7" 534 | }, 535 | "engines": { 536 | "node": "*" 537 | } 538 | }, 539 | "node_modules/mocha": { 540 | "version": "9.2.0", 541 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.0.tgz", 542 | "integrity": "sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q==", 543 | "dev": true, 544 | "dependencies": { 545 | "@ungap/promise-all-settled": "1.1.2", 546 | "ansi-colors": "4.1.1", 547 | "browser-stdout": "1.3.1", 548 | "chokidar": "3.5.3", 549 | "debug": "4.3.3", 550 | "diff": "5.0.0", 551 | "escape-string-regexp": "4.0.0", 552 | "find-up": "5.0.0", 553 | "glob": "7.2.0", 554 | "growl": "1.10.5", 555 | "he": "1.2.0", 556 | "js-yaml": "4.1.0", 557 | "log-symbols": "4.1.0", 558 | "minimatch": "3.0.4", 559 | "ms": "2.1.3", 560 | "nanoid": "3.2.0", 561 | "serialize-javascript": "6.0.0", 562 | "strip-json-comments": "3.1.1", 563 | "supports-color": "8.1.1", 564 | "which": "2.0.2", 565 | "workerpool": "6.2.0", 566 | "yargs": "16.2.0", 567 | "yargs-parser": "20.2.4", 568 | "yargs-unparser": "2.0.0" 569 | }, 570 | "bin": { 571 | "_mocha": "bin/_mocha", 572 | "mocha": "bin/mocha" 573 | }, 574 | "engines": { 575 | "node": ">= 12.0.0" 576 | }, 577 | "funding": { 578 | "type": "opencollective", 579 | "url": "https://opencollective.com/mochajs" 580 | } 581 | }, 582 | "node_modules/mocha/node_modules/argparse": { 583 | "version": "2.0.1", 584 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 585 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 586 | "dev": true 587 | }, 588 | "node_modules/mocha/node_modules/escape-string-regexp": { 589 | "version": "4.0.0", 590 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 591 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 592 | "dev": true, 593 | "engines": { 594 | "node": ">=10" 595 | }, 596 | "funding": { 597 | "url": "https://github.com/sponsors/sindresorhus" 598 | } 599 | }, 600 | "node_modules/mocha/node_modules/find-up": { 601 | "version": "5.0.0", 602 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 603 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 604 | "dev": true, 605 | "dependencies": { 606 | "locate-path": "^6.0.0", 607 | "path-exists": "^4.0.0" 608 | }, 609 | "engines": { 610 | "node": ">=10" 611 | }, 612 | "funding": { 613 | "url": "https://github.com/sponsors/sindresorhus" 614 | } 615 | }, 616 | "node_modules/mocha/node_modules/js-yaml": { 617 | "version": "4.1.0", 618 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 619 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 620 | "dev": true, 621 | "dependencies": { 622 | "argparse": "^2.0.1" 623 | }, 624 | "bin": { 625 | "js-yaml": "bin/js-yaml.js" 626 | } 627 | }, 628 | "node_modules/mocha/node_modules/locate-path": { 629 | "version": "6.0.0", 630 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 631 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 632 | "dev": true, 633 | "dependencies": { 634 | "p-locate": "^5.0.0" 635 | }, 636 | "engines": { 637 | "node": ">=10" 638 | }, 639 | "funding": { 640 | "url": "https://github.com/sponsors/sindresorhus" 641 | } 642 | }, 643 | "node_modules/mocha/node_modules/ms": { 644 | "version": "2.1.3", 645 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 646 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 647 | "dev": true 648 | }, 649 | "node_modules/mocha/node_modules/p-limit": { 650 | "version": "3.1.0", 651 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 652 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 653 | "dev": true, 654 | "dependencies": { 655 | "yocto-queue": "^0.1.0" 656 | }, 657 | "engines": { 658 | "node": ">=10" 659 | }, 660 | "funding": { 661 | "url": "https://github.com/sponsors/sindresorhus" 662 | } 663 | }, 664 | "node_modules/mocha/node_modules/p-locate": { 665 | "version": "5.0.0", 666 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 667 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 668 | "dev": true, 669 | "dependencies": { 670 | "p-limit": "^3.0.2" 671 | }, 672 | "engines": { 673 | "node": ">=10" 674 | }, 675 | "funding": { 676 | "url": "https://github.com/sponsors/sindresorhus" 677 | } 678 | }, 679 | "node_modules/mocha/node_modules/supports-color": { 680 | "version": "8.1.1", 681 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 682 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 683 | "dev": true, 684 | "dependencies": { 685 | "has-flag": "^4.0.0" 686 | }, 687 | "engines": { 688 | "node": ">=10" 689 | }, 690 | "funding": { 691 | "url": "https://github.com/chalk/supports-color?sponsor=1" 692 | } 693 | }, 694 | "node_modules/mocha/node_modules/yargs-parser": { 695 | "version": "20.2.4", 696 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", 697 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", 698 | "dev": true, 699 | "engines": { 700 | "node": ">=10" 701 | } 702 | }, 703 | "node_modules/ms": { 704 | "version": "2.1.2", 705 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 706 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 707 | "dev": true 708 | }, 709 | "node_modules/nanoid": { 710 | "version": "3.2.0", 711 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", 712 | "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", 713 | "dev": true, 714 | "bin": { 715 | "nanoid": "bin/nanoid.cjs" 716 | }, 717 | "engines": { 718 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 719 | } 720 | }, 721 | "node_modules/normalize-path": { 722 | "version": "3.0.0", 723 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 724 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 725 | "dev": true, 726 | "engines": { 727 | "node": ">=0.10.0" 728 | } 729 | }, 730 | "node_modules/once": { 731 | "version": "1.4.0", 732 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 733 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 734 | "dev": true, 735 | "dependencies": { 736 | "wrappy": "1" 737 | } 738 | }, 739 | "node_modules/path-exists": { 740 | "version": "4.0.0", 741 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 742 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 743 | "dev": true, 744 | "engines": { 745 | "node": ">=8" 746 | } 747 | }, 748 | "node_modules/path-is-absolute": { 749 | "version": "1.0.1", 750 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 751 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 752 | "dev": true, 753 | "engines": { 754 | "node": ">=0.10.0" 755 | } 756 | }, 757 | "node_modules/pathval": { 758 | "version": "1.1.1", 759 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 760 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 761 | "dev": true, 762 | "engines": { 763 | "node": "*" 764 | } 765 | }, 766 | "node_modules/picomatch": { 767 | "version": "2.3.1", 768 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 769 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 770 | "dev": true, 771 | "engines": { 772 | "node": ">=8.6" 773 | }, 774 | "funding": { 775 | "url": "https://github.com/sponsors/jonschlinkert" 776 | } 777 | }, 778 | "node_modules/randombytes": { 779 | "version": "2.1.0", 780 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 781 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 782 | "dev": true, 783 | "dependencies": { 784 | "safe-buffer": "^5.1.0" 785 | } 786 | }, 787 | "node_modules/readdirp": { 788 | "version": "3.6.0", 789 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 790 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 791 | "dev": true, 792 | "dependencies": { 793 | "picomatch": "^2.2.1" 794 | }, 795 | "engines": { 796 | "node": ">=8.10.0" 797 | } 798 | }, 799 | "node_modules/require-directory": { 800 | "version": "2.1.1", 801 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 802 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 803 | "dev": true, 804 | "engines": { 805 | "node": ">=0.10.0" 806 | } 807 | }, 808 | "node_modules/safe-buffer": { 809 | "version": "5.1.2", 810 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 811 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 812 | "dev": true 813 | }, 814 | "node_modules/serialize-javascript": { 815 | "version": "6.0.0", 816 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", 817 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", 818 | "dev": true, 819 | "dependencies": { 820 | "randombytes": "^2.1.0" 821 | } 822 | }, 823 | "node_modules/string-width": { 824 | "version": "4.2.3", 825 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 826 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 827 | "dev": true, 828 | "dependencies": { 829 | "emoji-regex": "^8.0.0", 830 | "is-fullwidth-code-point": "^3.0.0", 831 | "strip-ansi": "^6.0.1" 832 | }, 833 | "engines": { 834 | "node": ">=8" 835 | } 836 | }, 837 | "node_modules/strip-ansi": { 838 | "version": "6.0.1", 839 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 840 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 841 | "dev": true, 842 | "dependencies": { 843 | "ansi-regex": "^5.0.1" 844 | }, 845 | "engines": { 846 | "node": ">=8" 847 | } 848 | }, 849 | "node_modules/strip-json-comments": { 850 | "version": "3.1.1", 851 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 852 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 853 | "dev": true, 854 | "engines": { 855 | "node": ">=8" 856 | }, 857 | "funding": { 858 | "url": "https://github.com/sponsors/sindresorhus" 859 | } 860 | }, 861 | "node_modules/supports-color": { 862 | "version": "7.2.0", 863 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 864 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 865 | "dev": true, 866 | "dependencies": { 867 | "has-flag": "^4.0.0" 868 | }, 869 | "engines": { 870 | "node": ">=8" 871 | } 872 | }, 873 | "node_modules/to-regex-range": { 874 | "version": "5.0.1", 875 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 876 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 877 | "dev": true, 878 | "dependencies": { 879 | "is-number": "^7.0.0" 880 | }, 881 | "engines": { 882 | "node": ">=8.0" 883 | } 884 | }, 885 | "node_modules/type-detect": { 886 | "version": "4.0.8", 887 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 888 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 889 | "dev": true, 890 | "engines": { 891 | "node": ">=4" 892 | } 893 | }, 894 | "node_modules/which": { 895 | "version": "2.0.2", 896 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 897 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 898 | "dev": true, 899 | "dependencies": { 900 | "isexe": "^2.0.0" 901 | }, 902 | "bin": { 903 | "node-which": "bin/node-which" 904 | }, 905 | "engines": { 906 | "node": ">= 8" 907 | } 908 | }, 909 | "node_modules/workerpool": { 910 | "version": "6.2.0", 911 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", 912 | "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", 913 | "dev": true 914 | }, 915 | "node_modules/wrap-ansi": { 916 | "version": "7.0.0", 917 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 918 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 919 | "dev": true, 920 | "dependencies": { 921 | "ansi-styles": "^4.0.0", 922 | "string-width": "^4.1.0", 923 | "strip-ansi": "^6.0.0" 924 | }, 925 | "engines": { 926 | "node": ">=10" 927 | }, 928 | "funding": { 929 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 930 | } 931 | }, 932 | "node_modules/wrappy": { 933 | "version": "1.0.2", 934 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 935 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 936 | "dev": true 937 | }, 938 | "node_modules/y18n": { 939 | "version": "5.0.8", 940 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 941 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 942 | "dev": true, 943 | "engines": { 944 | "node": ">=10" 945 | } 946 | }, 947 | "node_modules/yargs": { 948 | "version": "16.2.0", 949 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 950 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 951 | "dev": true, 952 | "dependencies": { 953 | "cliui": "^7.0.2", 954 | "escalade": "^3.1.1", 955 | "get-caller-file": "^2.0.5", 956 | "require-directory": "^2.1.1", 957 | "string-width": "^4.2.0", 958 | "y18n": "^5.0.5", 959 | "yargs-parser": "^20.2.2" 960 | }, 961 | "engines": { 962 | "node": ">=10" 963 | } 964 | }, 965 | "node_modules/yargs-parser": { 966 | "version": "20.2.9", 967 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", 968 | "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", 969 | "dev": true, 970 | "engines": { 971 | "node": ">=10" 972 | } 973 | }, 974 | "node_modules/yargs-unparser": { 975 | "version": "2.0.0", 976 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 977 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 978 | "dev": true, 979 | "dependencies": { 980 | "camelcase": "^6.0.0", 981 | "decamelize": "^4.0.0", 982 | "flat": "^5.0.2", 983 | "is-plain-obj": "^2.1.0" 984 | }, 985 | "engines": { 986 | "node": ">=10" 987 | } 988 | }, 989 | "node_modules/yargs-unparser/node_modules/camelcase": { 990 | "version": "6.3.0", 991 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", 992 | "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", 993 | "dev": true, 994 | "engines": { 995 | "node": ">=10" 996 | }, 997 | "funding": { 998 | "url": "https://github.com/sponsors/sindresorhus" 999 | } 1000 | }, 1001 | "node_modules/yocto-queue": { 1002 | "version": "0.1.0", 1003 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1004 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1005 | "dev": true, 1006 | "engines": { 1007 | "node": ">=10" 1008 | }, 1009 | "funding": { 1010 | "url": "https://github.com/sponsors/sindresorhus" 1011 | } 1012 | } 1013 | }, 1014 | "dependencies": { 1015 | "@ungap/promise-all-settled": { 1016 | "version": "1.1.2", 1017 | "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", 1018 | "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", 1019 | "dev": true 1020 | }, 1021 | "ansi-colors": { 1022 | "version": "4.1.1", 1023 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 1024 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 1025 | "dev": true 1026 | }, 1027 | "ansi-regex": { 1028 | "version": "5.0.1", 1029 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1030 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 1031 | "dev": true 1032 | }, 1033 | "ansi-styles": { 1034 | "version": "4.3.0", 1035 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1036 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1037 | "dev": true, 1038 | "requires": { 1039 | "color-convert": "^2.0.1" 1040 | } 1041 | }, 1042 | "anymatch": { 1043 | "version": "3.1.2", 1044 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 1045 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 1046 | "dev": true, 1047 | "requires": { 1048 | "normalize-path": "^3.0.0", 1049 | "picomatch": "^2.0.4" 1050 | } 1051 | }, 1052 | "assertion-error": { 1053 | "version": "1.1.0", 1054 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 1055 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 1056 | "dev": true 1057 | }, 1058 | "balanced-match": { 1059 | "version": "1.0.2", 1060 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1061 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1062 | "dev": true 1063 | }, 1064 | "binary-extensions": { 1065 | "version": "2.2.0", 1066 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 1067 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 1068 | "dev": true 1069 | }, 1070 | "brace-expansion": { 1071 | "version": "1.1.11", 1072 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1073 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1074 | "dev": true, 1075 | "requires": { 1076 | "balanced-match": "^1.0.0", 1077 | "concat-map": "0.0.1" 1078 | } 1079 | }, 1080 | "braces": { 1081 | "version": "3.0.2", 1082 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 1083 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 1084 | "dev": true, 1085 | "requires": { 1086 | "fill-range": "^7.0.1" 1087 | } 1088 | }, 1089 | "browser-stdout": { 1090 | "version": "1.3.1", 1091 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 1092 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 1093 | "dev": true 1094 | }, 1095 | "chai": { 1096 | "version": "4.3.6", 1097 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", 1098 | "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", 1099 | "dev": true, 1100 | "requires": { 1101 | "assertion-error": "^1.1.0", 1102 | "check-error": "^1.0.2", 1103 | "deep-eql": "^3.0.1", 1104 | "get-func-name": "^2.0.0", 1105 | "loupe": "^2.3.1", 1106 | "pathval": "^1.1.1", 1107 | "type-detect": "^4.0.5" 1108 | } 1109 | }, 1110 | "chalk": { 1111 | "version": "4.1.2", 1112 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 1113 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 1114 | "dev": true, 1115 | "requires": { 1116 | "ansi-styles": "^4.1.0", 1117 | "supports-color": "^7.1.0" 1118 | } 1119 | }, 1120 | "check-error": { 1121 | "version": "1.0.2", 1122 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 1123 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 1124 | "dev": true 1125 | }, 1126 | "chokidar": { 1127 | "version": "3.5.3", 1128 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 1129 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 1130 | "dev": true, 1131 | "requires": { 1132 | "anymatch": "~3.1.2", 1133 | "braces": "~3.0.2", 1134 | "fsevents": "~2.3.2", 1135 | "glob-parent": "~5.1.2", 1136 | "is-binary-path": "~2.1.0", 1137 | "is-glob": "~4.0.1", 1138 | "normalize-path": "~3.0.0", 1139 | "readdirp": "~3.6.0" 1140 | } 1141 | }, 1142 | "cliui": { 1143 | "version": "7.0.4", 1144 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 1145 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 1146 | "dev": true, 1147 | "requires": { 1148 | "string-width": "^4.2.0", 1149 | "strip-ansi": "^6.0.0", 1150 | "wrap-ansi": "^7.0.0" 1151 | } 1152 | }, 1153 | "color-convert": { 1154 | "version": "2.0.1", 1155 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1156 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1157 | "dev": true, 1158 | "requires": { 1159 | "color-name": "~1.1.4" 1160 | } 1161 | }, 1162 | "color-name": { 1163 | "version": "1.1.4", 1164 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1165 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 1166 | "dev": true 1167 | }, 1168 | "concat-map": { 1169 | "version": "0.0.1", 1170 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1171 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 1172 | "dev": true 1173 | }, 1174 | "debug": { 1175 | "version": "4.3.3", 1176 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", 1177 | "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", 1178 | "dev": true, 1179 | "requires": { 1180 | "ms": "2.1.2" 1181 | } 1182 | }, 1183 | "decamelize": { 1184 | "version": "4.0.0", 1185 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 1186 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 1187 | "dev": true 1188 | }, 1189 | "deep-eql": { 1190 | "version": "3.0.1", 1191 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 1192 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 1193 | "dev": true, 1194 | "requires": { 1195 | "type-detect": "^4.0.0" 1196 | } 1197 | }, 1198 | "diff": { 1199 | "version": "5.0.0", 1200 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 1201 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 1202 | "dev": true 1203 | }, 1204 | "emoji-regex": { 1205 | "version": "8.0.0", 1206 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 1207 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 1208 | "dev": true 1209 | }, 1210 | "escalade": { 1211 | "version": "3.1.1", 1212 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 1213 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 1214 | "dev": true 1215 | }, 1216 | "fill-range": { 1217 | "version": "7.0.1", 1218 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1219 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1220 | "dev": true, 1221 | "requires": { 1222 | "to-regex-range": "^5.0.1" 1223 | } 1224 | }, 1225 | "flat": { 1226 | "version": "5.0.2", 1227 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 1228 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 1229 | "dev": true 1230 | }, 1231 | "fs.realpath": { 1232 | "version": "1.0.0", 1233 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1234 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 1235 | "dev": true 1236 | }, 1237 | "fsevents": { 1238 | "version": "2.3.2", 1239 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1240 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1241 | "dev": true, 1242 | "optional": true 1243 | }, 1244 | "get-caller-file": { 1245 | "version": "2.0.5", 1246 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 1247 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 1248 | "dev": true 1249 | }, 1250 | "get-func-name": { 1251 | "version": "2.0.0", 1252 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 1253 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 1254 | "dev": true 1255 | }, 1256 | "glob": { 1257 | "version": "7.2.0", 1258 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 1259 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 1260 | "dev": true, 1261 | "requires": { 1262 | "fs.realpath": "^1.0.0", 1263 | "inflight": "^1.0.4", 1264 | "inherits": "2", 1265 | "minimatch": "^3.0.4", 1266 | "once": "^1.3.0", 1267 | "path-is-absolute": "^1.0.0" 1268 | } 1269 | }, 1270 | "glob-parent": { 1271 | "version": "5.1.2", 1272 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1273 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1274 | "dev": true, 1275 | "requires": { 1276 | "is-glob": "^4.0.1" 1277 | } 1278 | }, 1279 | "growl": { 1280 | "version": "1.10.5", 1281 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 1282 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 1283 | "dev": true 1284 | }, 1285 | "has-flag": { 1286 | "version": "4.0.0", 1287 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1288 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1289 | "dev": true 1290 | }, 1291 | "he": { 1292 | "version": "1.2.0", 1293 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 1294 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 1295 | "dev": true 1296 | }, 1297 | "inflight": { 1298 | "version": "1.0.6", 1299 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1300 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1301 | "dev": true, 1302 | "requires": { 1303 | "once": "^1.3.0", 1304 | "wrappy": "1" 1305 | } 1306 | }, 1307 | "inherits": { 1308 | "version": "2.0.4", 1309 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1310 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1311 | "dev": true 1312 | }, 1313 | "is-binary-path": { 1314 | "version": "2.1.0", 1315 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1316 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1317 | "dev": true, 1318 | "requires": { 1319 | "binary-extensions": "^2.0.0" 1320 | } 1321 | }, 1322 | "is-extglob": { 1323 | "version": "2.1.1", 1324 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1325 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 1326 | "dev": true 1327 | }, 1328 | "is-fullwidth-code-point": { 1329 | "version": "3.0.0", 1330 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1331 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1332 | "dev": true 1333 | }, 1334 | "is-glob": { 1335 | "version": "4.0.3", 1336 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1337 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1338 | "dev": true, 1339 | "requires": { 1340 | "is-extglob": "^2.1.1" 1341 | } 1342 | }, 1343 | "is-number": { 1344 | "version": "7.0.0", 1345 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1346 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1347 | "dev": true 1348 | }, 1349 | "is-plain-obj": { 1350 | "version": "2.1.0", 1351 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 1352 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 1353 | "dev": true 1354 | }, 1355 | "is-unicode-supported": { 1356 | "version": "0.1.0", 1357 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 1358 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 1359 | "dev": true 1360 | }, 1361 | "isexe": { 1362 | "version": "2.0.0", 1363 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1364 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1365 | "dev": true 1366 | }, 1367 | "log-symbols": { 1368 | "version": "4.1.0", 1369 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 1370 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 1371 | "dev": true, 1372 | "requires": { 1373 | "chalk": "^4.1.0", 1374 | "is-unicode-supported": "^0.1.0" 1375 | } 1376 | }, 1377 | "loupe": { 1378 | "version": "2.3.2", 1379 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.2.tgz", 1380 | "integrity": "sha512-QgVamnvj0jX1LMPlCAq0MK6hATORFtGqHoUKXTkwNe13BqlN6aePQCKnnTcFvdDYEEITcJ+gBl4mTW7YJtJbyQ==", 1381 | "dev": true, 1382 | "requires": { 1383 | "get-func-name": "^2.0.0" 1384 | } 1385 | }, 1386 | "minimatch": { 1387 | "version": "3.0.4", 1388 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1389 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1390 | "dev": true, 1391 | "requires": { 1392 | "brace-expansion": "^1.1.7" 1393 | } 1394 | }, 1395 | "mocha": { 1396 | "version": "9.2.0", 1397 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.0.tgz", 1398 | "integrity": "sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q==", 1399 | "dev": true, 1400 | "requires": { 1401 | "@ungap/promise-all-settled": "1.1.2", 1402 | "ansi-colors": "4.1.1", 1403 | "browser-stdout": "1.3.1", 1404 | "chokidar": "3.5.3", 1405 | "debug": "4.3.3", 1406 | "diff": "5.0.0", 1407 | "escape-string-regexp": "4.0.0", 1408 | "find-up": "5.0.0", 1409 | "glob": "7.2.0", 1410 | "growl": "1.10.5", 1411 | "he": "1.2.0", 1412 | "js-yaml": "4.1.0", 1413 | "log-symbols": "4.1.0", 1414 | "minimatch": "3.0.4", 1415 | "ms": "2.1.3", 1416 | "nanoid": "3.2.0", 1417 | "serialize-javascript": "6.0.0", 1418 | "strip-json-comments": "3.1.1", 1419 | "supports-color": "8.1.1", 1420 | "which": "2.0.2", 1421 | "workerpool": "6.2.0", 1422 | "yargs": "16.2.0", 1423 | "yargs-parser": "20.2.4", 1424 | "yargs-unparser": "2.0.0" 1425 | }, 1426 | "dependencies": { 1427 | "argparse": { 1428 | "version": "2.0.1", 1429 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 1430 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 1431 | "dev": true 1432 | }, 1433 | "escape-string-regexp": { 1434 | "version": "4.0.0", 1435 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 1436 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 1437 | "dev": true 1438 | }, 1439 | "find-up": { 1440 | "version": "5.0.0", 1441 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 1442 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 1443 | "dev": true, 1444 | "requires": { 1445 | "locate-path": "^6.0.0", 1446 | "path-exists": "^4.0.0" 1447 | } 1448 | }, 1449 | "js-yaml": { 1450 | "version": "4.1.0", 1451 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 1452 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 1453 | "dev": true, 1454 | "requires": { 1455 | "argparse": "^2.0.1" 1456 | } 1457 | }, 1458 | "locate-path": { 1459 | "version": "6.0.0", 1460 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 1461 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 1462 | "dev": true, 1463 | "requires": { 1464 | "p-locate": "^5.0.0" 1465 | } 1466 | }, 1467 | "ms": { 1468 | "version": "2.1.3", 1469 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1470 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1471 | "dev": true 1472 | }, 1473 | "p-limit": { 1474 | "version": "3.1.0", 1475 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 1476 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 1477 | "dev": true, 1478 | "requires": { 1479 | "yocto-queue": "^0.1.0" 1480 | } 1481 | }, 1482 | "p-locate": { 1483 | "version": "5.0.0", 1484 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 1485 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 1486 | "dev": true, 1487 | "requires": { 1488 | "p-limit": "^3.0.2" 1489 | } 1490 | }, 1491 | "supports-color": { 1492 | "version": "8.1.1", 1493 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 1494 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 1495 | "dev": true, 1496 | "requires": { 1497 | "has-flag": "^4.0.0" 1498 | } 1499 | }, 1500 | "yargs-parser": { 1501 | "version": "20.2.4", 1502 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", 1503 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", 1504 | "dev": true 1505 | } 1506 | } 1507 | }, 1508 | "ms": { 1509 | "version": "2.1.2", 1510 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1511 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1512 | "dev": true 1513 | }, 1514 | "nanoid": { 1515 | "version": "3.2.0", 1516 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", 1517 | "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", 1518 | "dev": true 1519 | }, 1520 | "normalize-path": { 1521 | "version": "3.0.0", 1522 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1523 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1524 | "dev": true 1525 | }, 1526 | "once": { 1527 | "version": "1.4.0", 1528 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1529 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1530 | "dev": true, 1531 | "requires": { 1532 | "wrappy": "1" 1533 | } 1534 | }, 1535 | "path-exists": { 1536 | "version": "4.0.0", 1537 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1538 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 1539 | "dev": true 1540 | }, 1541 | "path-is-absolute": { 1542 | "version": "1.0.1", 1543 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1544 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1545 | "dev": true 1546 | }, 1547 | "pathval": { 1548 | "version": "1.1.1", 1549 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 1550 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 1551 | "dev": true 1552 | }, 1553 | "picomatch": { 1554 | "version": "2.3.1", 1555 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1556 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1557 | "dev": true 1558 | }, 1559 | "randombytes": { 1560 | "version": "2.1.0", 1561 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 1562 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 1563 | "dev": true, 1564 | "requires": { 1565 | "safe-buffer": "^5.1.0" 1566 | } 1567 | }, 1568 | "readdirp": { 1569 | "version": "3.6.0", 1570 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1571 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1572 | "dev": true, 1573 | "requires": { 1574 | "picomatch": "^2.2.1" 1575 | } 1576 | }, 1577 | "require-directory": { 1578 | "version": "2.1.1", 1579 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1580 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 1581 | "dev": true 1582 | }, 1583 | "safe-buffer": { 1584 | "version": "5.1.2", 1585 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1586 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1587 | "dev": true 1588 | }, 1589 | "serialize-javascript": { 1590 | "version": "6.0.0", 1591 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", 1592 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", 1593 | "dev": true, 1594 | "requires": { 1595 | "randombytes": "^2.1.0" 1596 | } 1597 | }, 1598 | "string-width": { 1599 | "version": "4.2.3", 1600 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1601 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1602 | "dev": true, 1603 | "requires": { 1604 | "emoji-regex": "^8.0.0", 1605 | "is-fullwidth-code-point": "^3.0.0", 1606 | "strip-ansi": "^6.0.1" 1607 | } 1608 | }, 1609 | "strip-ansi": { 1610 | "version": "6.0.1", 1611 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1612 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1613 | "dev": true, 1614 | "requires": { 1615 | "ansi-regex": "^5.0.1" 1616 | } 1617 | }, 1618 | "strip-json-comments": { 1619 | "version": "3.1.1", 1620 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1621 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1622 | "dev": true 1623 | }, 1624 | "supports-color": { 1625 | "version": "7.2.0", 1626 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1627 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1628 | "dev": true, 1629 | "requires": { 1630 | "has-flag": "^4.0.0" 1631 | } 1632 | }, 1633 | "to-regex-range": { 1634 | "version": "5.0.1", 1635 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1636 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1637 | "dev": true, 1638 | "requires": { 1639 | "is-number": "^7.0.0" 1640 | } 1641 | }, 1642 | "type-detect": { 1643 | "version": "4.0.8", 1644 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 1645 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 1646 | "dev": true 1647 | }, 1648 | "which": { 1649 | "version": "2.0.2", 1650 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1651 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1652 | "dev": true, 1653 | "requires": { 1654 | "isexe": "^2.0.0" 1655 | } 1656 | }, 1657 | "workerpool": { 1658 | "version": "6.2.0", 1659 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", 1660 | "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", 1661 | "dev": true 1662 | }, 1663 | "wrap-ansi": { 1664 | "version": "7.0.0", 1665 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1666 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1667 | "dev": true, 1668 | "requires": { 1669 | "ansi-styles": "^4.0.0", 1670 | "string-width": "^4.1.0", 1671 | "strip-ansi": "^6.0.0" 1672 | } 1673 | }, 1674 | "wrappy": { 1675 | "version": "1.0.2", 1676 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1677 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1678 | "dev": true 1679 | }, 1680 | "y18n": { 1681 | "version": "5.0.8", 1682 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1683 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 1684 | "dev": true 1685 | }, 1686 | "yargs": { 1687 | "version": "16.2.0", 1688 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 1689 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 1690 | "dev": true, 1691 | "requires": { 1692 | "cliui": "^7.0.2", 1693 | "escalade": "^3.1.1", 1694 | "get-caller-file": "^2.0.5", 1695 | "require-directory": "^2.1.1", 1696 | "string-width": "^4.2.0", 1697 | "y18n": "^5.0.5", 1698 | "yargs-parser": "^20.2.2" 1699 | } 1700 | }, 1701 | "yargs-parser": { 1702 | "version": "20.2.9", 1703 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", 1704 | "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", 1705 | "dev": true 1706 | }, 1707 | "yargs-unparser": { 1708 | "version": "2.0.0", 1709 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 1710 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 1711 | "dev": true, 1712 | "requires": { 1713 | "camelcase": "^6.0.0", 1714 | "decamelize": "^4.0.0", 1715 | "flat": "^5.0.2", 1716 | "is-plain-obj": "^2.1.0" 1717 | }, 1718 | "dependencies": { 1719 | "camelcase": { 1720 | "version": "6.3.0", 1721 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", 1722 | "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", 1723 | "dev": true 1724 | } 1725 | } 1726 | }, 1727 | "yocto-queue": { 1728 | "version": "0.1.0", 1729 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1730 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1731 | "dev": true 1732 | } 1733 | } 1734 | } 1735 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wgsl-preprocessor", 3 | "version": "1.0.0", 4 | "repository": "https://github.com/toji/wgsl-preprocessor", 5 | "authors": [ 6 | "Brandon Jones " 7 | ], 8 | "description": "A simple, template literals-based preprocessor for WGSL shaders", 9 | "license": "MIT", 10 | "type": "module", 11 | "scripts": { 12 | "test": "mocha" 13 | }, 14 | "devDependencies": { 15 | "chai": "^4.3.6", 16 | "mocha": "^9.2.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/wgsl-preprocessor.test.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { wgsl } from "../wgsl-preprocessor.js" 3 | 4 | describe('wgsl tag', () => { 5 | it('should return strings without preprocessor symbols unchanged', () => { 6 | expect(wgsl`test`).to.equal(`test`); 7 | expect(wgsl`${1}`).to.equal(`1`); 8 | }); 9 | 10 | it('should return unknown preprocessor symbols unchanged', () => { 11 | expect(wgsl`#foo`).to.equal(`#foo`); 12 | expect(wgsl`#☠️`).to.equal(`#☠️`); 13 | }); 14 | 15 | describe('#if', () => { 16 | 17 | it('should include the contents of an #if block if the expression is truthy', () => { 18 | const x = 3; 19 | const f = () => 3; 20 | expect(wgsl`#if ${true} Yes #endif`).to.equal(` Yes `); 21 | expect(wgsl`#if ${1} Yes #endif`).to.equal(` Yes `); 22 | expect(wgsl`#if ${12} Yes #endif`).to.equal(` Yes `); 23 | expect(wgsl`#if ${'string'} Yes #endif`).to.equal(` Yes `); 24 | expect(wgsl`#if ${new Float32Array(1)} Yes #endif`).to.equal(` Yes `); 25 | expect(wgsl`#if ${x} Yes #endif`).to.equal(` Yes `); 26 | expect(wgsl`#if ${x > 1} Yes #endif`).to.equal(` Yes `); 27 | expect(wgsl`#if ${x == 3} Yes #endif`).to.equal(` Yes `); 28 | expect(wgsl`#if ${f()} Yes #endif`).to.equal(` Yes `); 29 | expect(wgsl`#if ${f() > 1} Yes #endif`).to.equal(` Yes `); 30 | expect(wgsl`#if ${f() == 3} Yes #endif`).to.equal(` Yes `); 31 | }); 32 | 33 | it('should omit the contents of an #if block if the expression is not truthy', () => { 34 | const x = 0; 35 | const f = () => 0; 36 | expect(wgsl`#if ${false} No #endif`).to.equal(``); 37 | expect(wgsl`#if ${0} No #endif`).to.equal(``); 38 | expect(wgsl`#if ${null} No #endif`).to.equal(``); 39 | expect(wgsl`#if ${undefined} No #endif`).to.equal(``); 40 | expect(wgsl`#if ${''} No #endif`).to.equal(``); 41 | expect(wgsl`#if ${x} No #endif`).to.equal(``); 42 | expect(wgsl`#if ${x > 1} No #endif`).to.equal(``); 43 | expect(wgsl`#if ${x != 0} No #endif`).to.equal(``); 44 | expect(wgsl`#if ${f()} No #endif`).to.equal(``); 45 | expect(wgsl`#if ${f() > 1} No #endif`).to.equal(``); 46 | expect(wgsl`#if ${f() != 0} No #endif`).to.equal(``); 47 | }); 48 | 49 | it('should include content before and after the #if block', () => { 50 | expect(wgsl`Yes #if ${true} Yes #endif Yes`).to.equal(`Yes Yes Yes`); 51 | expect(wgsl`Yes #if ${false} No #endif Yes`).to.equal(`Yes Yes`); 52 | }); 53 | 54 | it('should work across multiple lines', () => { 55 | expect(wgsl`#if ${true} 56 | Yes 57 | #endif`).to.equal(` 58 | Yes 59 | `); 60 | }); 61 | 62 | it('should work with any amount of whitespace between the #if and the expression', () => { 63 | expect(wgsl`#if${true}Yes#endif`).to.equal(`Yes`); 64 | 65 | // Spaces 66 | expect(wgsl`#if ${true} Yes #endif`).to.equal(` Yes `); 67 | expect(wgsl`#if ${true} Yes #endif`).to.equal(` Yes `); 68 | expect(wgsl`#if ${true} Yes #endif`).to.equal(` Yes `); 69 | expect(wgsl`#if ${true} Yes #endif`).to.equal(` Yes `); 70 | expect(wgsl`#if ${true} Yes #endif`).to.equal(` Yes `); 71 | 72 | // Tabs 73 | expect(wgsl`#if ${true} Yes #endif`).to.equal(` Yes `); 74 | expect(wgsl`#if ${true} Yes #endif`).to.equal(` Yes `); 75 | expect(wgsl`#if ${true} Yes #endif`).to.equal(` Yes `); 76 | expect(wgsl`#if ${true} Yes #endif`).to.equal(` Yes `); 77 | }); 78 | 79 | it('should work mid-line', () => { 80 | expect(wgsl`Test #if ${true} Yes #endif`).to.equal(`Test Yes `); 81 | expect(wgsl`Test#if ${true} Yes #endif`).to.equal(`Test Yes `); 82 | }); 83 | 84 | it('should nest', () => { 85 | expect(wgsl` 86 | #if ${true} 87 | #if ${true} 88 | Yes 89 | #endif 90 | #endif`.trim()).to.equal(`Yes`); 91 | 92 | expect(wgsl` 93 | #if ${false} 94 | #if ${true} 95 | Yes 96 | #endif 97 | #endif`.trim()).to.equal(``); 98 | 99 | expect(wgsl` 100 | #if ${true} 101 | #if ${true} 102 | #if ${false} 103 | No 104 | #if ${true} 105 | No 106 | #endif 107 | #endif 108 | #if ${true} 109 | Yes 110 | #if ${false} 111 | No 112 | #endif 113 | #endif 114 | #endif 115 | #if ${false} 116 | No 117 | #endif 118 | #endif`.trim()).to.equal(`Yes`); 119 | 120 | // From https://github.com/toji/wgsl-preprocessor/issues/2 121 | // Thanks @typio! 122 | expect(wgsl` 123 | #if ${true} 124 | Yes 125 | #elif ${false} 126 | No1 127 | #if ${false} 128 | No2 129 | #else 130 | No3 131 | #endif 132 | No4 133 | #if ${false} 134 | No5 135 | #else 136 | No6 137 | #endif 138 | #endif`.trim()).to.equal(`Yes`); 139 | }); 140 | 141 | }); 142 | 143 | describe('#elif', () => { 144 | 145 | it('should include the contents of an #elif block if the expression is truthy', () => { 146 | const x = 3; 147 | const f = () => 3; 148 | expect(wgsl`#if ${false} No #elif ${true} Yes #endif`).to.equal(` Yes `); 149 | expect(wgsl`#if ${false} No #elif ${1} Yes #endif`).to.equal(` Yes `); 150 | expect(wgsl`#if ${false} No #elif ${12} Yes #endif`).to.equal(` Yes `); 151 | expect(wgsl`#if ${false} No #elif ${'string'} Yes #endif`).to.equal(` Yes `); 152 | expect(wgsl`#if ${false} No #elif ${new Float32Array(1)} Yes #endif`).to.equal(` Yes `); 153 | expect(wgsl`#if ${false} No #elif ${x} Yes #endif`).to.equal(` Yes `); 154 | expect(wgsl`#if ${false} No #elif ${x > 1} Yes #endif`).to.equal(` Yes `); 155 | expect(wgsl`#if ${false} No #elif ${x == 3} Yes #endif`).to.equal(` Yes `); 156 | expect(wgsl`#if ${false} No #elif ${f()} Yes #endif`).to.equal(` Yes `); 157 | expect(wgsl`#if ${false} No #elif ${f() > 1} Yes #endif`).to.equal(` Yes `); 158 | expect(wgsl`#if ${false} No #elif ${f() == 3} Yes #endif`).to.equal(` Yes `); 159 | }); 160 | 161 | it('should omit the contents of an #elif block if the expression is not truthy', () => { 162 | const x = 0; 163 | const f = () => 0; 164 | expect(wgsl`#if ${false} No #elif ${false} No #endif`).to.equal(``); 165 | expect(wgsl`#if ${false} No #elif ${0} No #endif`).to.equal(``); 166 | expect(wgsl`#if ${false} No #elif ${null} No #endif`).to.equal(``); 167 | expect(wgsl`#if ${false} No #elif ${undefined} No #endif`).to.equal(``); 168 | expect(wgsl`#if ${false} No #elif ${''} No #endif`).to.equal(``); 169 | expect(wgsl`#if ${false} No #elif ${x} No #endif`).to.equal(``); 170 | expect(wgsl`#if ${false} No #elif ${x > 1} No #endif`).to.equal(``); 171 | expect(wgsl`#if ${false} No #elif ${x != 0} No #endif`).to.equal(``); 172 | expect(wgsl`#if ${false} No #elif ${f()} No #endif`).to.equal(``); 173 | expect(wgsl`#if ${false} No #elif ${f() > 1} No #endif`).to.equal(``); 174 | expect(wgsl`#if ${false} No #elif ${f() != 0} No #endif`).to.equal(``); 175 | }); 176 | 177 | it('should include the contents of the block if the expression is truthy the preceeding #if was not truthy', () => { 178 | expect(wgsl`#if ${false} No #elif ${true} Yes #endif`).to.equal(` Yes `); 179 | expect(wgsl`#if ${true} Yes #elif ${true} No #endif`).to.equal(` Yes `); 180 | expect(wgsl`#if ${true} Yes #elif ${false} No #endif`).to.equal(` Yes `); 181 | expect(wgsl`#if ${false} No #elif ${false} No #endif`).to.equal(``); 182 | }); 183 | 184 | it('should allow for any number of chained #elif blocks', () => { 185 | expect(wgsl`#if ${false} No #elif ${false} No #elif ${true} Yes #endif`).to.equal(` Yes `); 186 | expect(wgsl`#if ${false} No #elif ${true} Yes #elif ${true} No #endif`).to.equal(` Yes `); 187 | expect(wgsl`#if ${false} No #elif ${true} Yes #elif ${false} No #endif`).to.equal(` Yes `); 188 | expect(wgsl`#if ${true} Yes #elif ${true} No #elif ${true} No #endif`).to.equal(` Yes `); 189 | expect(wgsl`#if ${true} Yes #elif ${false} No #elif ${true} No #endif`).to.equal(` Yes `); 190 | 191 | expect(wgsl`#if ${false} No #elif ${false} No #elif ${false} No #elif ${true} Yes #endif`).to.equal(` Yes `); 192 | expect(wgsl`#if ${false} No #elif ${true} Yes #elif ${true} No #elif ${true} No #endif`).to.equal(` Yes `); 193 | expect(wgsl`#if ${false} No #elif ${true} Yes #elif ${false} No #elif ${false} No #endif`).to.equal(` Yes `); 194 | expect(wgsl`#if ${true} Yes #elif ${true} No #elif ${true} No #elif ${true} No #endif`).to.equal(` Yes `); 195 | expect(wgsl`#if ${true} Yes #elif ${false} No #elif ${true} No #elif ${true} No #endif`).to.equal(` Yes `); 196 | expect(wgsl`#if ${true} Yes #elif ${false} No #elif ${false} No #elif ${false} No #endif`).to.equal(` Yes `); 197 | }); 198 | 199 | it('should nest', () => { 200 | expect(wgsl` 201 | #if ${true} 202 | #if ${false} 203 | No 204 | #elif ${true} 205 | Yes 206 | #endif 207 | #endif`.trim()).to.equal(`Yes`); 208 | 209 | expect(wgsl` 210 | #if ${false} 211 | No 212 | #elif ${true} 213 | #if ${true} 214 | Yes 215 | #endif 216 | #endif`.trim()).to.equal(`Yes`); 217 | 218 | expect(wgsl` 219 | #if ${false} 220 | No 221 | #elif ${false} 222 | #if ${true} 223 | No 224 | #endif 225 | #endif`.trim()).to.equal(``); 226 | }); 227 | 228 | }); 229 | 230 | describe('#else', () => { 231 | 232 | it('should include the contents of an #else block if the #if expression is not truthy', () => { 233 | const x = 0; 234 | const f = () => 0; 235 | expect(wgsl`#if ${false} No #else Yes #endif`).to.equal(` Yes `); 236 | expect(wgsl`#if ${0} No #else Yes #endif`).to.equal(` Yes `); 237 | expect(wgsl`#if ${null} No #else Yes #endif`).to.equal(` Yes `); 238 | expect(wgsl`#if ${undefined} No #else Yes #endif`).to.equal(` Yes `); 239 | expect(wgsl`#if ${''} No #else Yes #endif`).to.equal(` Yes `); 240 | expect(wgsl`#if ${x} No #else Yes #endif`).to.equal(` Yes `); 241 | expect(wgsl`#if ${x > 1} No #else Yes #endif`).to.equal(` Yes `); 242 | expect(wgsl`#if ${x != 0} No #else Yes #endif`).to.equal(` Yes `); 243 | expect(wgsl`#if ${f()} No #else Yes #endif`).to.equal(` Yes `); 244 | expect(wgsl`#if ${f() > 1} No #else Yes #endif`).to.equal(` Yes `); 245 | expect(wgsl`#if ${f() != 0} No #else Yes #endif`).to.equal(` Yes `); 246 | }); 247 | 248 | it('should omit the contents of an #else block if the #if expression is truthy', () => { 249 | const x = 3; 250 | const f = () => 3; 251 | expect(wgsl`#if ${true} Yes #else No #endif`).to.equal(` Yes `); 252 | expect(wgsl`#if ${1} Yes #else No #endif`).to.equal(` Yes `); 253 | expect(wgsl`#if ${12} Yes #else No #endif`).to.equal(` Yes `); 254 | expect(wgsl`#if ${'string'} Yes #else No #endif`).to.equal(` Yes `); 255 | expect(wgsl`#if ${new Float32Array(1)} Yes #else No #endif`).to.equal(` Yes `); 256 | expect(wgsl`#if ${x} Yes #else No #endif`).to.equal(` Yes `); 257 | expect(wgsl`#if ${x > 1} Yes #else No #endif`).to.equal(` Yes `); 258 | expect(wgsl`#if ${x == 3} Yes #else No #endif`).to.equal(` Yes `); 259 | expect(wgsl`#if ${f()} Yes #else No #endif`).to.equal(` Yes `); 260 | expect(wgsl`#if ${f() > 1} Yes #else No #endif`).to.equal(` Yes `); 261 | expect(wgsl`#if ${f() == 3} Yes #else No #endif`).to.equal(` Yes `); 262 | }); 263 | 264 | it('should omit the contents of an #else block if any preceeding #elif expression is truthy', () => { 265 | expect(wgsl`#if ${true} Yes #elif ${false} No #else No #endif`).to.equal(` Yes `); 266 | expect(wgsl`#if ${false} No #elif ${true} Yes #else No #endif`).to.equal(` Yes `); 267 | expect(wgsl`#if ${true} Yes #elif ${true} No #else No #endif`).to.equal(` Yes `); 268 | expect(wgsl`#if ${false} No #elif ${false} No #else Yes #endif`).to.equal(` Yes `); 269 | 270 | expect(wgsl`#if ${true} Yes #elif ${false} No #elif ${false} No #else No #endif`).to.equal(` Yes `); 271 | expect(wgsl`#if ${false} No #elif ${true} Yes #elif ${false} No #else No #endif`).to.equal(` Yes `); 272 | expect(wgsl`#if ${false} No #elif ${false} No #elif ${true} Yes #else No #endif`).to.equal(` Yes `); 273 | expect(wgsl`#if ${false} No #elif ${false} No #elif ${false} No #else Yes #endif`).to.equal(` Yes `); 274 | }); 275 | 276 | }); 277 | 278 | describe('errors', () => { 279 | it('should not allow #if statments that are not immediately followed by an expression', () => { 280 | expect(() => wgsl`#if No #endif`).to.throw(); 281 | expect(() => wgsl`#if 1 No #endif`).to.throw(); 282 | expect(() => wgsl`#if true No #endif`).to.throw(); 283 | expect(() => wgsl`#if true ${true} No #endif`).to.throw(); 284 | }); 285 | 286 | it('should not allow #elif without a preceeding #if', () => { 287 | expect(() => wgsl`#elif ${true} No #endif`).to.throw(); 288 | expect(() => wgsl`#if ${false} No #endif #elif ${true} No #endif`).to.throw(); 289 | expect(() => wgsl`#elif ${true} No #elif ${true} No #endif`).to.throw(); 290 | }); 291 | 292 | it('should not allow #elif statments that are not immediately followed by an expression', () => { 293 | expect(() => wgsl`#if ${true} No #elif No #endif`).to.throw(); 294 | expect(() => wgsl`#if ${true} No #elif 1 No #endif`).to.throw(); 295 | expect(() => wgsl`#if ${true} No #elif true No #endif`).to.throw(); 296 | expect(() => wgsl`#if ${true} No #elif true ${true} No #endif`).to.throw(); 297 | 298 | expect(() => wgsl`#if ${false} No #elif No #endif`).to.throw(); 299 | expect(() => wgsl`#if ${false} No #elif 1 No #endif`).to.throw(); 300 | expect(() => wgsl`#if ${false} No #elif true No #endif`).to.throw(); 301 | expect(() => wgsl`#if ${false} No #elif true ${true} No #endif`).to.throw(); 302 | 303 | expect(() => wgsl`#if ${false} No #elif ${false} No #elif No #endif`).to.throw(); 304 | expect(() => wgsl`#if ${false} No #elif ${false} No #elif 1 No #endif`).to.throw(); 305 | expect(() => wgsl`#if ${false} No #elif ${false} No #elif true No #endif`).to.throw(); 306 | expect(() => wgsl`#if ${false} No #elif ${false} No #elif true ${true} No #endif`).to.throw(); 307 | }); 308 | 309 | it('should not allow #else without a preceeding #if', () => { 310 | expect(() => wgsl`#else ${true} No #endif`).to.throw(); 311 | expect(() => wgsl`#if ${false} No #endif #else ${true} No #endif`).to.throw(); 312 | expect(() => wgsl`#elif ${true} No #else No #endif`).to.throw(); 313 | }); 314 | 315 | it('should not allow #endif without a preceeding #if', () => { 316 | expect(() => wgsl`#endif No`).to.throw(); 317 | expect(() => wgsl`#if ${false} No #endif #endif No`).to.throw(); 318 | expect(() => wgsl`#if ${true} No #endif #endif No`).to.throw(); 319 | expect(() => wgsl`#elif ${false} No #endif`).to.throw(); 320 | expect(() => wgsl`#else No #endif`).to.throw(); 321 | }); 322 | 323 | it('should not allow #if without a matching #endif', () => { 324 | expect(() => wgsl`#if ${false} No`).to.throw(); 325 | expect(() => wgsl`#if ${true} No`).to.throw(); 326 | expect(() => wgsl`#if ${false} No #endif #if ${false} No`).to.throw(); 327 | expect(() => wgsl`#if ${false} No #if ${false} No #endif`).to.throw(); 328 | expect(() => wgsl`#if ${false} No #else No`).to.throw(); 329 | expect(() => wgsl`#if ${false} No #elif ${true} No`).to.throw(); 330 | expect(() => wgsl`#if ${false} No #elif ${true} No #else No`).to.throw(); 331 | }); 332 | }); 333 | }); 334 | -------------------------------------------------------------------------------- /wgsl-preprocessor.js: -------------------------------------------------------------------------------- 1 | /** WGSL Preprocessor v1.0.0 **/ 2 | const preprocessorSymbols = /#([^\s]*)(\s*)/gm 3 | 4 | class ConditionalState { 5 | elseIsValid = true; 6 | branches = []; 7 | 8 | constructor(initialExpression) { 9 | this.pushBranch('if', initialExpression); 10 | } 11 | 12 | pushBranch(token, expression) { 13 | if (!this.elseIsValid) { 14 | throw new Error(`#${token} not preceeded by an #if or #elif`); 15 | } 16 | this.elseIsValid = (token === 'if' || token === 'elif'); 17 | this.branches.push({ 18 | expression: !!expression, 19 | string: '' 20 | }); 21 | } 22 | 23 | appendStringToCurrentBranch(...strings) { 24 | for (const string of strings) { 25 | this.branches[this.branches.length-1].string += string; 26 | } 27 | } 28 | 29 | resolve() { 30 | for (const branch of this.branches) { 31 | if (branch.expression) { 32 | return branch.string; 33 | } 34 | } 35 | 36 | return ''; 37 | } 38 | } 39 | 40 | // Template literal tag that handles simple preprocessor symbols for WGSL 41 | // shaders. Supports #if/elif/else/endif statements. 42 | export function wgsl(strings, ...values) { 43 | const stateStack = []; 44 | let state = new ConditionalState(true); 45 | state.elseIsValid = false; 46 | let depth = 1; 47 | 48 | const assertTemplateFollows = (match, string) => { 49 | if (match.index + match[0].length != string.length) { 50 | throw new Error(`#${match[1]} must be immediately followed by a template expression (ie: \${value})`); 51 | } 52 | } 53 | 54 | for (let i = 0; i < strings.length; ++i) { 55 | const string = strings[i]; 56 | const matchedSymbols = string.matchAll(preprocessorSymbols); 57 | 58 | let lastIndex = 0; 59 | let valueConsumed = false; 60 | 61 | for (const match of matchedSymbols) { 62 | state.appendStringToCurrentBranch(string.substring(lastIndex, match.index)); 63 | 64 | switch (match[1]) { 65 | case 'if': 66 | assertTemplateFollows(match, string); 67 | 68 | valueConsumed = true; 69 | stateStack.push(state); 70 | state = new ConditionalState(values[i]); 71 | break; 72 | case 'elif': 73 | assertTemplateFollows(match, string); 74 | 75 | valueConsumed = true; 76 | state.pushBranch(match[1], values[i]); 77 | break; 78 | case 'else': 79 | state.pushBranch(match[1], true); 80 | state.appendStringToCurrentBranch(match[2]); 81 | break; 82 | case 'endif': 83 | if (!stateStack.length) { 84 | throw new Error(`#${match[1]} not preceeded by an #if`); 85 | } 86 | 87 | const result = state.resolve(); 88 | 89 | state = stateStack.pop(); 90 | state.appendStringToCurrentBranch(result, match[2]); 91 | break; 92 | default: 93 | // Unknown preprocessor symbol. Emit it back into the output string unchanged. 94 | state.appendStringToCurrentBranch(match[0]); 95 | break; 96 | } 97 | 98 | lastIndex = match.index + match[0].length; 99 | } 100 | 101 | // If the string didn't end on one of the preprocessor symbols append the rest of it here. 102 | if (lastIndex != string.length) { 103 | state.appendStringToCurrentBranch(string.substring(lastIndex, string.length)); 104 | } 105 | 106 | // If the next value wasn't consumed by the preprocessor symbol, append it here. 107 | if (!valueConsumed && values.length > i) { 108 | state.appendStringToCurrentBranch(values[i]); 109 | } 110 | } 111 | 112 | if (stateStack.length) { 113 | throw new Error('Mismatched #if/#endif count'); 114 | } 115 | 116 | return state.resolve(); 117 | } --------------------------------------------------------------------------------