├── .editorconfig ├── .eslintrc.json ├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── lib └── html-encoding-sniffer.js ├── package-lock.json ├── package.json └── test ├── fixtures ├── bom │ ├── UTF-16BE.html │ ├── UTF-16LE.html │ └── UTF-8.html ├── no-result │ ├── http-equiv-refresh_windows-1252.html │ └── no-indicators_windows-1252.html ├── normal │ ├── charset-bracket_UTF-8.html │ ├── charset-short-comment_ISO-8859-2.html │ ├── charset-x-user-defined_windows-1252.html │ ├── charset_KOI8-R.html │ ├── http-equiv-no-quotes_ISO-8859-5.html │ ├── http-equiv-second-charset_ISO-8859-2.html │ ├── http-equiv-trailing-space_ISO-8859-2.html │ └── http-equiv_windows-874.html └── utf │ ├── charset-utf-16.html │ ├── charset-utf-16be.html │ └── charset-utf-16le.html └── tests.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 2 10 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": "@domenic", 4 | "env": { 5 | "node": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | pull_request: 4 | branches: [main] 5 | push: 6 | branches: [main] 7 | jobs: 8 | build: 9 | name: Lint and tests 10 | runs-on: ubuntu-latest 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | node-version: 15 | - 18 16 | - 20 17 | - latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: actions/setup-node@v4 21 | with: 22 | node-version: ${{ matrix.node-version }} 23 | - run: npm ci 24 | - run: npm run lint 25 | - run: npm test 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright © Domenic Denicola 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Determine the Encoding of a HTML Byte Stream 2 | 3 | This package implements the HTML Standard's [encoding sniffing algorithm](https://html.spec.whatwg.org/multipage/syntax.html#encoding-sniffing-algorithm) in all its glory. The most interesting part of this is how it pre-scans the first 1024 bytes in order to search for certain ``-related patterns. 4 | 5 | ```js 6 | const htmlEncodingSniffer = require("html-encoding-sniffer"); 7 | const fs = require("fs"); 8 | 9 | const htmlBytes = fs.readFileSync("./html-page.html"); 10 | const sniffedEncoding = htmlEncodingSniffer(htmlBytes); 11 | ``` 12 | 13 | The passed bytes are given as a `Uint8Array`; the Node.js `Buffer` subclass of `Uint8Array` will also work, as shown above. 14 | 15 | The returned value will be a canonical [encoding name](https://encoding.spec.whatwg.org/#names-and-labels) (not a label). You might then combine this with the [whatwg-encoding](https://github.com/jsdom/whatwg-encoding) package to decode the result: 16 | 17 | ```js 18 | const whatwgEncoding = require("whatwg-encoding"); 19 | const htmlString = whatwgEncoding.decode(htmlBytes, sniffedEncoding); 20 | ``` 21 | 22 | ## Options 23 | 24 | You can pass two potential options to `htmlEncodingSniffer`: 25 | 26 | ```js 27 | const sniffedEncoding = htmlEncodingSniffer(htmlBytes, { 28 | transportLayerEncodingLabel, 29 | defaultEncoding 30 | }); 31 | ``` 32 | 33 | These represent two possible inputs into the [encoding sniffing algorithm](https://html.spec.whatwg.org/multipage/syntax.html#encoding-sniffing-algorithm): 34 | 35 | - `transportLayerEncodingLabel` is an encoding label that is obtained from the "transport layer" (probably a HTTP `Content-Type` header), which overrides everything but a BOM. 36 | - `defaultEncoding` is the ultimate fallback encoding used if no valid encoding is supplied by the transport layer, and no encoding is sniffed from the bytes. It defaults to `"windows-1252"`, as recommended by the algorithm's table of suggested defaults for "All other locales" (including the `en` locale). 37 | 38 | ## Credits 39 | 40 | This package was originally based on the excellent work of [@nicolashenry](https://github.com/nicolashenry), [in jsdom](https://github.com/tmpvar/jsdom/blob/16fd85618f2705d181232f6552125872a37164bc/lib/jsdom/living/helpers/encoding.js). It has since been pulled out into this separate package. 41 | -------------------------------------------------------------------------------- /lib/html-encoding-sniffer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const whatwgEncoding = require("whatwg-encoding"); 3 | 4 | // https://html.spec.whatwg.org/#encoding-sniffing-algorithm 5 | module.exports = (uint8Array, { transportLayerEncodingLabel, defaultEncoding = "windows-1252" } = {}) => { 6 | let encoding = whatwgEncoding.getBOMEncoding(uint8Array); 7 | 8 | if (encoding === null && transportLayerEncodingLabel !== undefined) { 9 | encoding = whatwgEncoding.labelToName(transportLayerEncodingLabel); 10 | } 11 | 12 | if (encoding === null) { 13 | encoding = prescanMetaCharset(uint8Array); 14 | } 15 | 16 | if (encoding === null) { 17 | encoding = defaultEncoding; 18 | } 19 | 20 | return encoding; 21 | }; 22 | 23 | // https://html.spec.whatwg.org/multipage/syntax.html#prescan-a-byte-stream-to-determine-its-encoding 24 | function prescanMetaCharset(uint8Array) { 25 | const l = Math.min(uint8Array.byteLength, 1024); 26 | for (let i = 0; i < l; i++) { 27 | let c = uint8Array[i]; 28 | if (c === 0x3C) { 29 | // "<" 30 | const c1 = uint8Array[i + 1]; 31 | const c2 = uint8Array[i + 2]; 32 | const c3 = uint8Array[i + 3]; 33 | const c4 = uint8Array[i + 4]; 34 | const c5 = uint8Array[i + 5]; 35 | // !-- (comment start) 36 | if (c1 === 0x21 && c2 === 0x2D && c3 === 0x2D) { 37 | i += 4; 38 | for (; i < l; i++) { 39 | c = uint8Array[i]; 40 | const cMinus1 = uint8Array[i - 1]; 41 | const cMinus2 = uint8Array[i - 2]; 42 | // --> (comment end) 43 | if (c === 0x3E && cMinus1 === 0x2D && cMinus2 === 0x2D) { 44 | break; 45 | } 46 | } 47 | } else if ((c1 === 0x4D || c1 === 0x6D) && 48 | (c2 === 0x45 || c2 === 0x65) && 49 | (c3 === 0x54 || c3 === 0x74) && 50 | (c4 === 0x41 || c4 === 0x61) && 51 | (isSpaceCharacter(c5) || c5 === 0x2F)) { 52 | // "meta" + space or / 53 | i += 6; 54 | const attributeList = new Set(); 55 | let gotPragma = false; 56 | let needPragma = null; 57 | let charset = null; 58 | 59 | let attrRes; 60 | do { 61 | attrRes = getAttribute(uint8Array, i, l); 62 | if (attrRes.attr && !attributeList.has(attrRes.attr.name)) { 63 | attributeList.add(attrRes.attr.name); 64 | if (attrRes.attr.name === "http-equiv") { 65 | gotPragma = attrRes.attr.value === "content-type"; 66 | } else if (attrRes.attr.name === "content" && !charset) { 67 | charset = extractCharacterEncodingFromMeta(attrRes.attr.value); 68 | if (charset !== null) { 69 | needPragma = true; 70 | } 71 | } else if (attrRes.attr.name === "charset") { 72 | charset = whatwgEncoding.labelToName(attrRes.attr.value); 73 | needPragma = false; 74 | } 75 | } 76 | i = attrRes.i; 77 | } while (attrRes.attr); 78 | 79 | if (needPragma === null) { 80 | continue; 81 | } 82 | if (needPragma === true && gotPragma === false) { 83 | continue; 84 | } 85 | if (charset === null) { 86 | continue; 87 | } 88 | 89 | if (charset === "UTF-16LE" || charset === "UTF-16BE") { 90 | charset = "UTF-8"; 91 | } 92 | if (charset === "x-user-defined") { 93 | charset = "windows-1252"; 94 | } 95 | 96 | return charset; 97 | } else if ((c1 >= 0x41 && c1 <= 0x5A) || (c1 >= 0x61 && c1 <= 0x7A)) { 98 | // a-z or A-Z 99 | for (i += 2; i < l; i++) { 100 | c = uint8Array[i]; 101 | // space or > 102 | if (isSpaceCharacter(c) || c === 0x3E) { 103 | break; 104 | } 105 | } 106 | let attrRes; 107 | do { 108 | attrRes = getAttribute(uint8Array, i, l); 109 | i = attrRes.i; 110 | } while (attrRes.attr); 111 | } else if (c1 === 0x21 || c1 === 0x2F || c1 === 0x3F) { 112 | // ! or / or ? 113 | for (i += 2; i < l; i++) { 114 | c = uint8Array[i]; 115 | // > 116 | if (c === 0x3E) { 117 | break; 118 | } 119 | } 120 | } 121 | } 122 | } 123 | return null; 124 | } 125 | 126 | // https://html.spec.whatwg.org/multipage/syntax.html#concept-get-attributes-when-sniffing 127 | function getAttribute(uint8Array, i, l) { 128 | for (; i < l; i++) { 129 | let c = uint8Array[i]; 130 | // space or / 131 | if (isSpaceCharacter(c) || c === 0x2F) { 132 | continue; 133 | } 134 | // ">" 135 | if (c === 0x3E) { 136 | break; 137 | } 138 | let name = ""; 139 | let value = ""; 140 | nameLoop:for (; i < l; i++) { 141 | c = uint8Array[i]; 142 | // "=" 143 | if (c === 0x3D && name !== "") { 144 | i++; 145 | break; 146 | } 147 | // space 148 | if (isSpaceCharacter(c)) { 149 | for (i++; i < l; i++) { 150 | c = uint8Array[i]; 151 | // space 152 | if (isSpaceCharacter(c)) { 153 | continue; 154 | } 155 | // not "=" 156 | if (c !== 0x3D) { 157 | return { attr: { name, value }, i }; 158 | } 159 | 160 | i++; 161 | break nameLoop; 162 | } 163 | break; 164 | } 165 | // / or > 166 | if (c === 0x2F || c === 0x3E) { 167 | return { attr: { name, value }, i }; 168 | } 169 | // A-Z 170 | if (c >= 0x41 && c <= 0x5A) { 171 | name += String.fromCharCode(c + 0x20); // lowercase 172 | } else { 173 | name += String.fromCharCode(c); 174 | } 175 | } 176 | c = uint8Array[i]; 177 | // space 178 | if (isSpaceCharacter(c)) { 179 | for (i++; i < l; i++) { 180 | c = uint8Array[i]; 181 | // space 182 | if (isSpaceCharacter(c)) { 183 | continue; 184 | } else { 185 | break; 186 | } 187 | } 188 | } 189 | // " or ' 190 | if (c === 0x22 || c === 0x27) { 191 | const quote = c; 192 | for (i++; i < l; i++) { 193 | c = uint8Array[i]; 194 | 195 | if (c === quote) { 196 | i++; 197 | return { attr: { name, value }, i }; 198 | } 199 | 200 | // A-Z 201 | if (c >= 0x41 && c <= 0x5A) { 202 | value += String.fromCharCode(c + 0x20); // lowercase 203 | } else { 204 | value += String.fromCharCode(c); 205 | } 206 | } 207 | } 208 | 209 | // > 210 | if (c === 0x3E) { 211 | return { attr: { name, value }, i }; 212 | } 213 | 214 | // A-Z 215 | if (c >= 0x41 && c <= 0x5A) { 216 | value += String.fromCharCode(c + 0x20); // lowercase 217 | } else { 218 | value += String.fromCharCode(c); 219 | } 220 | 221 | for (i++; i < l; i++) { 222 | c = uint8Array[i]; 223 | 224 | // space or > 225 | if (isSpaceCharacter(c) || c === 0x3E) { 226 | return { attr: { name, value }, i }; 227 | } 228 | 229 | // A-Z 230 | if (c >= 0x41 && c <= 0x5A) { 231 | value += String.fromCharCode(c + 0x20); // lowercase 232 | } else { 233 | value += String.fromCharCode(c); 234 | } 235 | } 236 | } 237 | return { i }; 238 | } 239 | 240 | function extractCharacterEncodingFromMeta(string) { 241 | let position = 0; 242 | 243 | while (true) { 244 | const indexOfCharset = string.substring(position).search(/charset/ui); 245 | 246 | if (indexOfCharset === -1) { 247 | return null; 248 | } 249 | let subPosition = position + indexOfCharset + "charset".length; 250 | 251 | while (isSpaceCharacter(string[subPosition].charCodeAt(0))) { 252 | ++subPosition; 253 | } 254 | 255 | if (string[subPosition] !== "=") { 256 | position = subPosition - 1; 257 | continue; 258 | } 259 | 260 | ++subPosition; 261 | 262 | while (isSpaceCharacter(string[subPosition].charCodeAt(0))) { 263 | ++subPosition; 264 | } 265 | 266 | position = subPosition; 267 | break; 268 | } 269 | 270 | if (string[position] === "\"" || string[position] === "'") { 271 | const nextIndex = string.indexOf(string[position], position + 1); 272 | 273 | if (nextIndex !== -1) { 274 | return whatwgEncoding.labelToName(string.substring(position + 1, nextIndex)); 275 | } 276 | 277 | // It is an unmatched quotation mark 278 | return null; 279 | } 280 | 281 | if (string.length === position + 1) { 282 | return null; 283 | } 284 | 285 | const indexOfASCIIWhitespaceOrSemicolon = string.substring(position + 1).search(/\x09|\x0A|\x0C|\x0D|\x20|;/u); 286 | const end = indexOfASCIIWhitespaceOrSemicolon === -1 ? 287 | string.length : 288 | position + indexOfASCIIWhitespaceOrSemicolon + 1; 289 | 290 | return whatwgEncoding.labelToName(string.substring(position, end)); 291 | } 292 | 293 | function isSpaceCharacter(c) { 294 | return c === 0x09 || c === 0x0A || c === 0x0C || c === 0x0D || c === 0x20; 295 | } 296 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "html-encoding-sniffer", 3 | "version": "4.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "html-encoding-sniffer", 9 | "version": "4.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "whatwg-encoding": "^3.1.1" 13 | }, 14 | "devDependencies": { 15 | "@domenic/eslint-config": "^3.0.0", 16 | "eslint": "^8.53.0" 17 | }, 18 | "engines": { 19 | "node": ">=18" 20 | } 21 | }, 22 | "node_modules/@aashutoshrathi/word-wrap": { 23 | "version": "1.2.6", 24 | "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", 25 | "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", 26 | "dev": true, 27 | "engines": { 28 | "node": ">=0.10.0" 29 | } 30 | }, 31 | "node_modules/@domenic/eslint-config": { 32 | "version": "3.0.0", 33 | "resolved": "https://registry.npmjs.org/@domenic/eslint-config/-/eslint-config-3.0.0.tgz", 34 | "integrity": "sha512-XhG03wcob9LIzTfucyl0jhoIueVynfyk/i1HmrZqf7x2iKrLh9TN/+5pbWFuHB3cvyS5Pn3OVyUJ8NHSsOIejQ==", 35 | "dev": true, 36 | "peerDependencies": { 37 | "eslint": "^8.28.0" 38 | } 39 | }, 40 | "node_modules/@eslint-community/eslint-utils": { 41 | "version": "4.4.0", 42 | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", 43 | "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", 44 | "dev": true, 45 | "dependencies": { 46 | "eslint-visitor-keys": "^3.3.0" 47 | }, 48 | "engines": { 49 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 50 | }, 51 | "peerDependencies": { 52 | "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" 53 | } 54 | }, 55 | "node_modules/@eslint-community/regexpp": { 56 | "version": "4.10.0", 57 | "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", 58 | "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", 59 | "dev": true, 60 | "engines": { 61 | "node": "^12.0.0 || ^14.0.0 || >=16.0.0" 62 | } 63 | }, 64 | "node_modules/@eslint/eslintrc": { 65 | "version": "2.1.3", 66 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", 67 | "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", 68 | "dev": true, 69 | "dependencies": { 70 | "ajv": "^6.12.4", 71 | "debug": "^4.3.2", 72 | "espree": "^9.6.0", 73 | "globals": "^13.19.0", 74 | "ignore": "^5.2.0", 75 | "import-fresh": "^3.2.1", 76 | "js-yaml": "^4.1.0", 77 | "minimatch": "^3.1.2", 78 | "strip-json-comments": "^3.1.1" 79 | }, 80 | "engines": { 81 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 82 | }, 83 | "funding": { 84 | "url": "https://opencollective.com/eslint" 85 | } 86 | }, 87 | "node_modules/@eslint/js": { 88 | "version": "8.53.0", 89 | "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz", 90 | "integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==", 91 | "dev": true, 92 | "engines": { 93 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 94 | } 95 | }, 96 | "node_modules/@humanwhocodes/config-array": { 97 | "version": "0.11.13", 98 | "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", 99 | "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", 100 | "dev": true, 101 | "dependencies": { 102 | "@humanwhocodes/object-schema": "^2.0.1", 103 | "debug": "^4.1.1", 104 | "minimatch": "^3.0.5" 105 | }, 106 | "engines": { 107 | "node": ">=10.10.0" 108 | } 109 | }, 110 | "node_modules/@humanwhocodes/module-importer": { 111 | "version": "1.0.1", 112 | "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", 113 | "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", 114 | "dev": true, 115 | "engines": { 116 | "node": ">=12.22" 117 | }, 118 | "funding": { 119 | "type": "github", 120 | "url": "https://github.com/sponsors/nzakas" 121 | } 122 | }, 123 | "node_modules/@humanwhocodes/object-schema": { 124 | "version": "2.0.1", 125 | "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", 126 | "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", 127 | "dev": true 128 | }, 129 | "node_modules/@nodelib/fs.scandir": { 130 | "version": "2.1.5", 131 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 132 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 133 | "dev": true, 134 | "dependencies": { 135 | "@nodelib/fs.stat": "2.0.5", 136 | "run-parallel": "^1.1.9" 137 | }, 138 | "engines": { 139 | "node": ">= 8" 140 | } 141 | }, 142 | "node_modules/@nodelib/fs.stat": { 143 | "version": "2.0.5", 144 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 145 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 146 | "dev": true, 147 | "engines": { 148 | "node": ">= 8" 149 | } 150 | }, 151 | "node_modules/@nodelib/fs.walk": { 152 | "version": "1.2.8", 153 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 154 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 155 | "dev": true, 156 | "dependencies": { 157 | "@nodelib/fs.scandir": "2.1.5", 158 | "fastq": "^1.6.0" 159 | }, 160 | "engines": { 161 | "node": ">= 8" 162 | } 163 | }, 164 | "node_modules/@ungap/structured-clone": { 165 | "version": "1.2.0", 166 | "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", 167 | "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", 168 | "dev": true 169 | }, 170 | "node_modules/acorn": { 171 | "version": "8.11.2", 172 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", 173 | "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", 174 | "dev": true, 175 | "bin": { 176 | "acorn": "bin/acorn" 177 | }, 178 | "engines": { 179 | "node": ">=0.4.0" 180 | } 181 | }, 182 | "node_modules/acorn-jsx": { 183 | "version": "5.3.2", 184 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 185 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 186 | "dev": true, 187 | "peerDependencies": { 188 | "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 189 | } 190 | }, 191 | "node_modules/ajv": { 192 | "version": "6.12.6", 193 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 194 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 195 | "dev": true, 196 | "dependencies": { 197 | "fast-deep-equal": "^3.1.1", 198 | "fast-json-stable-stringify": "^2.0.0", 199 | "json-schema-traverse": "^0.4.1", 200 | "uri-js": "^4.2.2" 201 | }, 202 | "funding": { 203 | "type": "github", 204 | "url": "https://github.com/sponsors/epoberezkin" 205 | } 206 | }, 207 | "node_modules/ansi-regex": { 208 | "version": "5.0.1", 209 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 210 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 211 | "dev": true, 212 | "engines": { 213 | "node": ">=8" 214 | } 215 | }, 216 | "node_modules/ansi-styles": { 217 | "version": "4.3.0", 218 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 219 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 220 | "dev": true, 221 | "dependencies": { 222 | "color-convert": "^2.0.1" 223 | }, 224 | "engines": { 225 | "node": ">=8" 226 | }, 227 | "funding": { 228 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 229 | } 230 | }, 231 | "node_modules/argparse": { 232 | "version": "2.0.1", 233 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 234 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 235 | "dev": true 236 | }, 237 | "node_modules/balanced-match": { 238 | "version": "1.0.2", 239 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 240 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 241 | "dev": true 242 | }, 243 | "node_modules/brace-expansion": { 244 | "version": "1.1.11", 245 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 246 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 247 | "dev": true, 248 | "dependencies": { 249 | "balanced-match": "^1.0.0", 250 | "concat-map": "0.0.1" 251 | } 252 | }, 253 | "node_modules/callsites": { 254 | "version": "3.1.0", 255 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 256 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 257 | "dev": true, 258 | "engines": { 259 | "node": ">=6" 260 | } 261 | }, 262 | "node_modules/chalk": { 263 | "version": "4.1.2", 264 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 265 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 266 | "dev": true, 267 | "dependencies": { 268 | "ansi-styles": "^4.1.0", 269 | "supports-color": "^7.1.0" 270 | }, 271 | "engines": { 272 | "node": ">=10" 273 | }, 274 | "funding": { 275 | "url": "https://github.com/chalk/chalk?sponsor=1" 276 | } 277 | }, 278 | "node_modules/color-convert": { 279 | "version": "2.0.1", 280 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 281 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 282 | "dev": true, 283 | "dependencies": { 284 | "color-name": "~1.1.4" 285 | }, 286 | "engines": { 287 | "node": ">=7.0.0" 288 | } 289 | }, 290 | "node_modules/color-name": { 291 | "version": "1.1.4", 292 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 293 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 294 | "dev": true 295 | }, 296 | "node_modules/concat-map": { 297 | "version": "0.0.1", 298 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 299 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 300 | "dev": true 301 | }, 302 | "node_modules/cross-spawn": { 303 | "version": "7.0.3", 304 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 305 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 306 | "dev": true, 307 | "dependencies": { 308 | "path-key": "^3.1.0", 309 | "shebang-command": "^2.0.0", 310 | "which": "^2.0.1" 311 | }, 312 | "engines": { 313 | "node": ">= 8" 314 | } 315 | }, 316 | "node_modules/debug": { 317 | "version": "4.3.4", 318 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 319 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 320 | "dev": true, 321 | "dependencies": { 322 | "ms": "2.1.2" 323 | }, 324 | "engines": { 325 | "node": ">=6.0" 326 | }, 327 | "peerDependenciesMeta": { 328 | "supports-color": { 329 | "optional": true 330 | } 331 | } 332 | }, 333 | "node_modules/deep-is": { 334 | "version": "0.1.4", 335 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 336 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", 337 | "dev": true 338 | }, 339 | "node_modules/doctrine": { 340 | "version": "3.0.0", 341 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 342 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 343 | "dev": true, 344 | "dependencies": { 345 | "esutils": "^2.0.2" 346 | }, 347 | "engines": { 348 | "node": ">=6.0.0" 349 | } 350 | }, 351 | "node_modules/escape-string-regexp": { 352 | "version": "4.0.0", 353 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 354 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 355 | "dev": true, 356 | "engines": { 357 | "node": ">=10" 358 | }, 359 | "funding": { 360 | "url": "https://github.com/sponsors/sindresorhus" 361 | } 362 | }, 363 | "node_modules/eslint": { 364 | "version": "8.53.0", 365 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz", 366 | "integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==", 367 | "dev": true, 368 | "dependencies": { 369 | "@eslint-community/eslint-utils": "^4.2.0", 370 | "@eslint-community/regexpp": "^4.6.1", 371 | "@eslint/eslintrc": "^2.1.3", 372 | "@eslint/js": "8.53.0", 373 | "@humanwhocodes/config-array": "^0.11.13", 374 | "@humanwhocodes/module-importer": "^1.0.1", 375 | "@nodelib/fs.walk": "^1.2.8", 376 | "@ungap/structured-clone": "^1.2.0", 377 | "ajv": "^6.12.4", 378 | "chalk": "^4.0.0", 379 | "cross-spawn": "^7.0.2", 380 | "debug": "^4.3.2", 381 | "doctrine": "^3.0.0", 382 | "escape-string-regexp": "^4.0.0", 383 | "eslint-scope": "^7.2.2", 384 | "eslint-visitor-keys": "^3.4.3", 385 | "espree": "^9.6.1", 386 | "esquery": "^1.4.2", 387 | "esutils": "^2.0.2", 388 | "fast-deep-equal": "^3.1.3", 389 | "file-entry-cache": "^6.0.1", 390 | "find-up": "^5.0.0", 391 | "glob-parent": "^6.0.2", 392 | "globals": "^13.19.0", 393 | "graphemer": "^1.4.0", 394 | "ignore": "^5.2.0", 395 | "imurmurhash": "^0.1.4", 396 | "is-glob": "^4.0.0", 397 | "is-path-inside": "^3.0.3", 398 | "js-yaml": "^4.1.0", 399 | "json-stable-stringify-without-jsonify": "^1.0.1", 400 | "levn": "^0.4.1", 401 | "lodash.merge": "^4.6.2", 402 | "minimatch": "^3.1.2", 403 | "natural-compare": "^1.4.0", 404 | "optionator": "^0.9.3", 405 | "strip-ansi": "^6.0.1", 406 | "text-table": "^0.2.0" 407 | }, 408 | "bin": { 409 | "eslint": "bin/eslint.js" 410 | }, 411 | "engines": { 412 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 413 | }, 414 | "funding": { 415 | "url": "https://opencollective.com/eslint" 416 | } 417 | }, 418 | "node_modules/eslint-scope": { 419 | "version": "7.2.2", 420 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", 421 | "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", 422 | "dev": true, 423 | "dependencies": { 424 | "esrecurse": "^4.3.0", 425 | "estraverse": "^5.2.0" 426 | }, 427 | "engines": { 428 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 429 | }, 430 | "funding": { 431 | "url": "https://opencollective.com/eslint" 432 | } 433 | }, 434 | "node_modules/eslint-visitor-keys": { 435 | "version": "3.4.3", 436 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", 437 | "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", 438 | "dev": true, 439 | "engines": { 440 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 441 | }, 442 | "funding": { 443 | "url": "https://opencollective.com/eslint" 444 | } 445 | }, 446 | "node_modules/espree": { 447 | "version": "9.6.1", 448 | "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", 449 | "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", 450 | "dev": true, 451 | "dependencies": { 452 | "acorn": "^8.9.0", 453 | "acorn-jsx": "^5.3.2", 454 | "eslint-visitor-keys": "^3.4.1" 455 | }, 456 | "engines": { 457 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 458 | }, 459 | "funding": { 460 | "url": "https://opencollective.com/eslint" 461 | } 462 | }, 463 | "node_modules/esquery": { 464 | "version": "1.5.0", 465 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", 466 | "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", 467 | "dev": true, 468 | "dependencies": { 469 | "estraverse": "^5.1.0" 470 | }, 471 | "engines": { 472 | "node": ">=0.10" 473 | } 474 | }, 475 | "node_modules/esrecurse": { 476 | "version": "4.3.0", 477 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 478 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 479 | "dev": true, 480 | "dependencies": { 481 | "estraverse": "^5.2.0" 482 | }, 483 | "engines": { 484 | "node": ">=4.0" 485 | } 486 | }, 487 | "node_modules/estraverse": { 488 | "version": "5.3.0", 489 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 490 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 491 | "dev": true, 492 | "engines": { 493 | "node": ">=4.0" 494 | } 495 | }, 496 | "node_modules/esutils": { 497 | "version": "2.0.3", 498 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 499 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 500 | "dev": true, 501 | "engines": { 502 | "node": ">=0.10.0" 503 | } 504 | }, 505 | "node_modules/fast-deep-equal": { 506 | "version": "3.1.3", 507 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 508 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 509 | "dev": true 510 | }, 511 | "node_modules/fast-json-stable-stringify": { 512 | "version": "2.1.0", 513 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 514 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 515 | "dev": true 516 | }, 517 | "node_modules/fast-levenshtein": { 518 | "version": "2.0.6", 519 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 520 | "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", 521 | "dev": true 522 | }, 523 | "node_modules/fastq": { 524 | "version": "1.15.0", 525 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", 526 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", 527 | "dev": true, 528 | "dependencies": { 529 | "reusify": "^1.0.4" 530 | } 531 | }, 532 | "node_modules/file-entry-cache": { 533 | "version": "6.0.1", 534 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", 535 | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", 536 | "dev": true, 537 | "dependencies": { 538 | "flat-cache": "^3.0.4" 539 | }, 540 | "engines": { 541 | "node": "^10.12.0 || >=12.0.0" 542 | } 543 | }, 544 | "node_modules/find-up": { 545 | "version": "5.0.0", 546 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 547 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 548 | "dev": true, 549 | "dependencies": { 550 | "locate-path": "^6.0.0", 551 | "path-exists": "^4.0.0" 552 | }, 553 | "engines": { 554 | "node": ">=10" 555 | }, 556 | "funding": { 557 | "url": "https://github.com/sponsors/sindresorhus" 558 | } 559 | }, 560 | "node_modules/flat-cache": { 561 | "version": "3.1.1", 562 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", 563 | "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", 564 | "dev": true, 565 | "dependencies": { 566 | "flatted": "^3.2.9", 567 | "keyv": "^4.5.3", 568 | "rimraf": "^3.0.2" 569 | }, 570 | "engines": { 571 | "node": ">=12.0.0" 572 | } 573 | }, 574 | "node_modules/flatted": { 575 | "version": "3.2.9", 576 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", 577 | "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", 578 | "dev": true 579 | }, 580 | "node_modules/fs.realpath": { 581 | "version": "1.0.0", 582 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 583 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 584 | "dev": true 585 | }, 586 | "node_modules/glob": { 587 | "version": "7.2.3", 588 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 589 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 590 | "dev": true, 591 | "dependencies": { 592 | "fs.realpath": "^1.0.0", 593 | "inflight": "^1.0.4", 594 | "inherits": "2", 595 | "minimatch": "^3.1.1", 596 | "once": "^1.3.0", 597 | "path-is-absolute": "^1.0.0" 598 | }, 599 | "engines": { 600 | "node": "*" 601 | }, 602 | "funding": { 603 | "url": "https://github.com/sponsors/isaacs" 604 | } 605 | }, 606 | "node_modules/glob-parent": { 607 | "version": "6.0.2", 608 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 609 | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 610 | "dev": true, 611 | "dependencies": { 612 | "is-glob": "^4.0.3" 613 | }, 614 | "engines": { 615 | "node": ">=10.13.0" 616 | } 617 | }, 618 | "node_modules/globals": { 619 | "version": "13.23.0", 620 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", 621 | "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", 622 | "dev": true, 623 | "dependencies": { 624 | "type-fest": "^0.20.2" 625 | }, 626 | "engines": { 627 | "node": ">=8" 628 | }, 629 | "funding": { 630 | "url": "https://github.com/sponsors/sindresorhus" 631 | } 632 | }, 633 | "node_modules/graphemer": { 634 | "version": "1.4.0", 635 | "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", 636 | "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", 637 | "dev": true 638 | }, 639 | "node_modules/has-flag": { 640 | "version": "4.0.0", 641 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 642 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 643 | "dev": true, 644 | "engines": { 645 | "node": ">=8" 646 | } 647 | }, 648 | "node_modules/iconv-lite": { 649 | "version": "0.6.3", 650 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 651 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 652 | "dependencies": { 653 | "safer-buffer": ">= 2.1.2 < 3.0.0" 654 | }, 655 | "engines": { 656 | "node": ">=0.10.0" 657 | } 658 | }, 659 | "node_modules/ignore": { 660 | "version": "5.2.4", 661 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", 662 | "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", 663 | "dev": true, 664 | "engines": { 665 | "node": ">= 4" 666 | } 667 | }, 668 | "node_modules/import-fresh": { 669 | "version": "3.3.0", 670 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 671 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 672 | "dev": true, 673 | "dependencies": { 674 | "parent-module": "^1.0.0", 675 | "resolve-from": "^4.0.0" 676 | }, 677 | "engines": { 678 | "node": ">=6" 679 | }, 680 | "funding": { 681 | "url": "https://github.com/sponsors/sindresorhus" 682 | } 683 | }, 684 | "node_modules/imurmurhash": { 685 | "version": "0.1.4", 686 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 687 | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", 688 | "dev": true, 689 | "engines": { 690 | "node": ">=0.8.19" 691 | } 692 | }, 693 | "node_modules/inflight": { 694 | "version": "1.0.6", 695 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 696 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 697 | "dev": true, 698 | "dependencies": { 699 | "once": "^1.3.0", 700 | "wrappy": "1" 701 | } 702 | }, 703 | "node_modules/inherits": { 704 | "version": "2.0.4", 705 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 706 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 707 | "dev": true 708 | }, 709 | "node_modules/is-extglob": { 710 | "version": "2.1.1", 711 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 712 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 713 | "dev": true, 714 | "engines": { 715 | "node": ">=0.10.0" 716 | } 717 | }, 718 | "node_modules/is-glob": { 719 | "version": "4.0.3", 720 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 721 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 722 | "dev": true, 723 | "dependencies": { 724 | "is-extglob": "^2.1.1" 725 | }, 726 | "engines": { 727 | "node": ">=0.10.0" 728 | } 729 | }, 730 | "node_modules/is-path-inside": { 731 | "version": "3.0.3", 732 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", 733 | "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", 734 | "dev": true, 735 | "engines": { 736 | "node": ">=8" 737 | } 738 | }, 739 | "node_modules/isexe": { 740 | "version": "2.0.0", 741 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 742 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 743 | "dev": true 744 | }, 745 | "node_modules/js-yaml": { 746 | "version": "4.1.0", 747 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 748 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 749 | "dev": true, 750 | "dependencies": { 751 | "argparse": "^2.0.1" 752 | }, 753 | "bin": { 754 | "js-yaml": "bin/js-yaml.js" 755 | } 756 | }, 757 | "node_modules/json-buffer": { 758 | "version": "3.0.1", 759 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", 760 | "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", 761 | "dev": true 762 | }, 763 | "node_modules/json-schema-traverse": { 764 | "version": "0.4.1", 765 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 766 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 767 | "dev": true 768 | }, 769 | "node_modules/json-stable-stringify-without-jsonify": { 770 | "version": "1.0.1", 771 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 772 | "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", 773 | "dev": true 774 | }, 775 | "node_modules/keyv": { 776 | "version": "4.5.4", 777 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", 778 | "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", 779 | "dev": true, 780 | "dependencies": { 781 | "json-buffer": "3.0.1" 782 | } 783 | }, 784 | "node_modules/levn": { 785 | "version": "0.4.1", 786 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 787 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 788 | "dev": true, 789 | "dependencies": { 790 | "prelude-ls": "^1.2.1", 791 | "type-check": "~0.4.0" 792 | }, 793 | "engines": { 794 | "node": ">= 0.8.0" 795 | } 796 | }, 797 | "node_modules/locate-path": { 798 | "version": "6.0.0", 799 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 800 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 801 | "dev": true, 802 | "dependencies": { 803 | "p-locate": "^5.0.0" 804 | }, 805 | "engines": { 806 | "node": ">=10" 807 | }, 808 | "funding": { 809 | "url": "https://github.com/sponsors/sindresorhus" 810 | } 811 | }, 812 | "node_modules/lodash.merge": { 813 | "version": "4.6.2", 814 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 815 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 816 | "dev": true 817 | }, 818 | "node_modules/minimatch": { 819 | "version": "3.1.2", 820 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 821 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 822 | "dev": true, 823 | "dependencies": { 824 | "brace-expansion": "^1.1.7" 825 | }, 826 | "engines": { 827 | "node": "*" 828 | } 829 | }, 830 | "node_modules/ms": { 831 | "version": "2.1.2", 832 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 833 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 834 | "dev": true 835 | }, 836 | "node_modules/natural-compare": { 837 | "version": "1.4.0", 838 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 839 | "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", 840 | "dev": true 841 | }, 842 | "node_modules/once": { 843 | "version": "1.4.0", 844 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 845 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 846 | "dev": true, 847 | "dependencies": { 848 | "wrappy": "1" 849 | } 850 | }, 851 | "node_modules/optionator": { 852 | "version": "0.9.3", 853 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", 854 | "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", 855 | "dev": true, 856 | "dependencies": { 857 | "@aashutoshrathi/word-wrap": "^1.2.3", 858 | "deep-is": "^0.1.3", 859 | "fast-levenshtein": "^2.0.6", 860 | "levn": "^0.4.1", 861 | "prelude-ls": "^1.2.1", 862 | "type-check": "^0.4.0" 863 | }, 864 | "engines": { 865 | "node": ">= 0.8.0" 866 | } 867 | }, 868 | "node_modules/p-limit": { 869 | "version": "3.1.0", 870 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 871 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 872 | "dev": true, 873 | "dependencies": { 874 | "yocto-queue": "^0.1.0" 875 | }, 876 | "engines": { 877 | "node": ">=10" 878 | }, 879 | "funding": { 880 | "url": "https://github.com/sponsors/sindresorhus" 881 | } 882 | }, 883 | "node_modules/p-locate": { 884 | "version": "5.0.0", 885 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 886 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 887 | "dev": true, 888 | "dependencies": { 889 | "p-limit": "^3.0.2" 890 | }, 891 | "engines": { 892 | "node": ">=10" 893 | }, 894 | "funding": { 895 | "url": "https://github.com/sponsors/sindresorhus" 896 | } 897 | }, 898 | "node_modules/parent-module": { 899 | "version": "1.0.1", 900 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 901 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 902 | "dev": true, 903 | "dependencies": { 904 | "callsites": "^3.0.0" 905 | }, 906 | "engines": { 907 | "node": ">=6" 908 | } 909 | }, 910 | "node_modules/path-exists": { 911 | "version": "4.0.0", 912 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 913 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 914 | "dev": true, 915 | "engines": { 916 | "node": ">=8" 917 | } 918 | }, 919 | "node_modules/path-is-absolute": { 920 | "version": "1.0.1", 921 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 922 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 923 | "dev": true, 924 | "engines": { 925 | "node": ">=0.10.0" 926 | } 927 | }, 928 | "node_modules/path-key": { 929 | "version": "3.1.1", 930 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 931 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 932 | "dev": true, 933 | "engines": { 934 | "node": ">=8" 935 | } 936 | }, 937 | "node_modules/prelude-ls": { 938 | "version": "1.2.1", 939 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 940 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 941 | "dev": true, 942 | "engines": { 943 | "node": ">= 0.8.0" 944 | } 945 | }, 946 | "node_modules/punycode": { 947 | "version": "2.3.1", 948 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", 949 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", 950 | "dev": true, 951 | "engines": { 952 | "node": ">=6" 953 | } 954 | }, 955 | "node_modules/queue-microtask": { 956 | "version": "1.2.3", 957 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 958 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 959 | "dev": true, 960 | "funding": [ 961 | { 962 | "type": "github", 963 | "url": "https://github.com/sponsors/feross" 964 | }, 965 | { 966 | "type": "patreon", 967 | "url": "https://www.patreon.com/feross" 968 | }, 969 | { 970 | "type": "consulting", 971 | "url": "https://feross.org/support" 972 | } 973 | ] 974 | }, 975 | "node_modules/resolve-from": { 976 | "version": "4.0.0", 977 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 978 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 979 | "dev": true, 980 | "engines": { 981 | "node": ">=4" 982 | } 983 | }, 984 | "node_modules/reusify": { 985 | "version": "1.0.4", 986 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 987 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 988 | "dev": true, 989 | "engines": { 990 | "iojs": ">=1.0.0", 991 | "node": ">=0.10.0" 992 | } 993 | }, 994 | "node_modules/rimraf": { 995 | "version": "3.0.2", 996 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 997 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 998 | "dev": true, 999 | "dependencies": { 1000 | "glob": "^7.1.3" 1001 | }, 1002 | "bin": { 1003 | "rimraf": "bin.js" 1004 | }, 1005 | "funding": { 1006 | "url": "https://github.com/sponsors/isaacs" 1007 | } 1008 | }, 1009 | "node_modules/run-parallel": { 1010 | "version": "1.2.0", 1011 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1012 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1013 | "dev": true, 1014 | "funding": [ 1015 | { 1016 | "type": "github", 1017 | "url": "https://github.com/sponsors/feross" 1018 | }, 1019 | { 1020 | "type": "patreon", 1021 | "url": "https://www.patreon.com/feross" 1022 | }, 1023 | { 1024 | "type": "consulting", 1025 | "url": "https://feross.org/support" 1026 | } 1027 | ], 1028 | "dependencies": { 1029 | "queue-microtask": "^1.2.2" 1030 | } 1031 | }, 1032 | "node_modules/safer-buffer": { 1033 | "version": "2.1.2", 1034 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1035 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1036 | }, 1037 | "node_modules/shebang-command": { 1038 | "version": "2.0.0", 1039 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1040 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1041 | "dev": true, 1042 | "dependencies": { 1043 | "shebang-regex": "^3.0.0" 1044 | }, 1045 | "engines": { 1046 | "node": ">=8" 1047 | } 1048 | }, 1049 | "node_modules/shebang-regex": { 1050 | "version": "3.0.0", 1051 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 1052 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 1053 | "dev": true, 1054 | "engines": { 1055 | "node": ">=8" 1056 | } 1057 | }, 1058 | "node_modules/strip-ansi": { 1059 | "version": "6.0.1", 1060 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1061 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1062 | "dev": true, 1063 | "dependencies": { 1064 | "ansi-regex": "^5.0.1" 1065 | }, 1066 | "engines": { 1067 | "node": ">=8" 1068 | } 1069 | }, 1070 | "node_modules/strip-json-comments": { 1071 | "version": "3.1.1", 1072 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1073 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1074 | "dev": true, 1075 | "engines": { 1076 | "node": ">=8" 1077 | }, 1078 | "funding": { 1079 | "url": "https://github.com/sponsors/sindresorhus" 1080 | } 1081 | }, 1082 | "node_modules/supports-color": { 1083 | "version": "7.2.0", 1084 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1085 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1086 | "dev": true, 1087 | "dependencies": { 1088 | "has-flag": "^4.0.0" 1089 | }, 1090 | "engines": { 1091 | "node": ">=8" 1092 | } 1093 | }, 1094 | "node_modules/text-table": { 1095 | "version": "0.2.0", 1096 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1097 | "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", 1098 | "dev": true 1099 | }, 1100 | "node_modules/type-check": { 1101 | "version": "0.4.0", 1102 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 1103 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 1104 | "dev": true, 1105 | "dependencies": { 1106 | "prelude-ls": "^1.2.1" 1107 | }, 1108 | "engines": { 1109 | "node": ">= 0.8.0" 1110 | } 1111 | }, 1112 | "node_modules/type-fest": { 1113 | "version": "0.20.2", 1114 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", 1115 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", 1116 | "dev": true, 1117 | "engines": { 1118 | "node": ">=10" 1119 | }, 1120 | "funding": { 1121 | "url": "https://github.com/sponsors/sindresorhus" 1122 | } 1123 | }, 1124 | "node_modules/uri-js": { 1125 | "version": "4.4.1", 1126 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 1127 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 1128 | "dev": true, 1129 | "dependencies": { 1130 | "punycode": "^2.1.0" 1131 | } 1132 | }, 1133 | "node_modules/whatwg-encoding": { 1134 | "version": "3.1.1", 1135 | "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", 1136 | "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", 1137 | "dependencies": { 1138 | "iconv-lite": "0.6.3" 1139 | }, 1140 | "engines": { 1141 | "node": ">=18" 1142 | } 1143 | }, 1144 | "node_modules/which": { 1145 | "version": "2.0.2", 1146 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1147 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1148 | "dev": true, 1149 | "dependencies": { 1150 | "isexe": "^2.0.0" 1151 | }, 1152 | "bin": { 1153 | "node-which": "bin/node-which" 1154 | }, 1155 | "engines": { 1156 | "node": ">= 8" 1157 | } 1158 | }, 1159 | "node_modules/wrappy": { 1160 | "version": "1.0.2", 1161 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1162 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1163 | "dev": true 1164 | }, 1165 | "node_modules/yocto-queue": { 1166 | "version": "0.1.0", 1167 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1168 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1169 | "dev": true, 1170 | "engines": { 1171 | "node": ">=10" 1172 | }, 1173 | "funding": { 1174 | "url": "https://github.com/sponsors/sindresorhus" 1175 | } 1176 | } 1177 | } 1178 | } 1179 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "html-encoding-sniffer", 3 | "description": "Sniff the encoding from a HTML byte stream", 4 | "keywords": [ 5 | "encoding", 6 | "html" 7 | ], 8 | "version": "4.0.0", 9 | "author": "Domenic Denicola (https://domenic.me/)", 10 | "license": "MIT", 11 | "repository": "jsdom/html-encoding-sniffer", 12 | "main": "lib/html-encoding-sniffer.js", 13 | "files": [ 14 | "lib/" 15 | ], 16 | "scripts": { 17 | "test": "node --test", 18 | "lint": "eslint ." 19 | }, 20 | "dependencies": { 21 | "whatwg-encoding": "^3.1.1" 22 | }, 23 | "devDependencies": { 24 | "@domenic/eslint-config": "^3.0.0", 25 | "eslint": "^8.53.0" 26 | }, 27 | "engines": { 28 | "node": ">=18" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/fixtures/bom/UTF-16BE.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdom/html-encoding-sniffer/d655e5adef00678d24d228c1cd8e34f1299c2e1f/test/fixtures/bom/UTF-16BE.html -------------------------------------------------------------------------------- /test/fixtures/bom/UTF-16LE.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdom/html-encoding-sniffer/d655e5adef00678d24d228c1cd8e34f1299c2e1f/test/fixtures/bom/UTF-16LE.html -------------------------------------------------------------------------------- /test/fixtures/bom/UTF-8.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | © 9 | -------------------------------------------------------------------------------- /test/fixtures/no-result/http-equiv-refresh_windows-1252.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/no-result/no-indicators_windows-1252.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdom/html-encoding-sniffer/d655e5adef00678d24d228c1cd8e34f1299c2e1f/test/fixtures/no-result/no-indicators_windows-1252.html -------------------------------------------------------------------------------- /test/fixtures/normal/charset-bracket_UTF-8.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/normal/charset-short-comment_ISO-8859-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/normal/charset-x-user-defined_windows-1252.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/fixtures/normal/charset_KOI8-R.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | This is not really koi8 (KOI8-R), of course 9 | 10 | -------------------------------------------------------------------------------- /test/fixtures/normal/http-equiv-no-quotes_ISO-8859-5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/fixtures/normal/http-equiv-second-charset_ISO-8859-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/normal/http-equiv-trailing-space_ISO-8859-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/normal/http-equiv_windows-874.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | This is not really tis-620 (windows-874), of course 9 | 10 | -------------------------------------------------------------------------------- /test/fixtures/utf/charset-utf-16.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/fixtures/utf/charset-utf-16be.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/fixtures/utf/charset-utf-16le.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/tests.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const { describe, it } = require("node:test"); 3 | const assert = require("node:assert"); 4 | const fs = require("node:fs"); 5 | const path = require("node:path"); 6 | const htmlEncodingSniffer = require(".."); 7 | 8 | function read(relative) { 9 | // Test that the module works with Uint8Arrays, not just Buffers: 10 | const buffer = fs.readFileSync(path.resolve(__dirname, relative)); 11 | return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength); 12 | } 13 | 14 | for (const file of fs.readdirSync(path.resolve(__dirname, "fixtures/bom"))) { 15 | describe(file, () => { 16 | const buffer = read(`fixtures/bom/${file}`); 17 | const desiredEncoding = path.basename(file, ".html"); 18 | 19 | it(`should sniff as ${desiredEncoding}, given no options`, () => { 20 | const sniffedEncoding = htmlEncodingSniffer(buffer); 21 | 22 | assert.strictEqual(sniffedEncoding, desiredEncoding); 23 | }); 24 | 25 | it(`should sniff as ${desiredEncoding}, given overriding options`, () => { 26 | const sniffedEncoding = htmlEncodingSniffer(buffer, { 27 | transportLayerEncodingLabel: "windows-1252", 28 | defaultEncoding: "UTF-16LE" 29 | }); 30 | 31 | assert.strictEqual(sniffedEncoding, desiredEncoding); 32 | }); 33 | }); 34 | } 35 | 36 | for (const file of fs.readdirSync(path.resolve(__dirname, "fixtures/normal"))) { 37 | describe(file, () => { 38 | const buffer = read(`fixtures/normal/${file}`); 39 | const desiredEncoding = path.basename(file, ".html").split("_")[1]; 40 | 41 | it(`should sniff as ${desiredEncoding}, given no options`, () => { 42 | const sniffedEncoding = htmlEncodingSniffer(buffer); 43 | 44 | assert.strictEqual(sniffedEncoding, desiredEncoding); 45 | }); 46 | 47 | it("should sniff as the transport layer encoding, given that", () => { 48 | const sniffedEncoding = htmlEncodingSniffer(buffer, { 49 | transportLayerEncodingLabel: "windows-1251", 50 | defaultEncoding: "ISO-8859-16" 51 | }); 52 | 53 | assert.strictEqual(sniffedEncoding, "windows-1251"); 54 | }); 55 | 56 | 57 | it(`should sniff as ${desiredEncoding}, given only a default encoding`, () => { 58 | const sniffedEncoding = htmlEncodingSniffer(buffer, { 59 | defaultEncoding: "ISO-8859-16" 60 | }); 61 | 62 | assert.strictEqual(sniffedEncoding, desiredEncoding); 63 | }); 64 | }); 65 | } 66 | 67 | for (const file of fs.readdirSync(path.resolve(__dirname, "fixtures/no-result"))) { 68 | describe(file, () => { 69 | const buffer = read(`fixtures/no-result/${file}`); 70 | const desiredEncoding = path.basename(file, ".html").split("_")[1]; 71 | 72 | it(`should sniff as ${desiredEncoding}, given no options`, () => { 73 | const sniffedEncoding = htmlEncodingSniffer(buffer); 74 | 75 | assert.strictEqual(sniffedEncoding, desiredEncoding); 76 | }); 77 | 78 | it("should sniff as the transport layer encoding, given that", () => { 79 | const sniffedEncoding = htmlEncodingSniffer(buffer, { 80 | transportLayerEncodingLabel: "windows-1251", 81 | defaultEncoding: "ISO-8859-16" 82 | }); 83 | 84 | assert.strictEqual(sniffedEncoding, "windows-1251"); 85 | }); 86 | 87 | 88 | it("should sniff as the default encoding, given that", () => { 89 | const sniffedEncoding = htmlEncodingSniffer(buffer, { 90 | defaultEncoding: "ISO-8859-16" 91 | }); 92 | 93 | assert.strictEqual(sniffedEncoding, "ISO-8859-16"); 94 | }); 95 | }); 96 | } 97 | 98 | for (const file of fs.readdirSync(path.resolve(__dirname, "fixtures/utf"))) { 99 | describe(file, () => { 100 | const buffer = read(`fixtures/utf/${file}`); 101 | 102 | it("should sniff as UTF-8, given no options", () => { 103 | const sniffedEncoding = htmlEncodingSniffer(buffer); 104 | 105 | assert.strictEqual(sniffedEncoding, "UTF-8"); 106 | }); 107 | 108 | it("should sniff as the transport layer encoding, given that", () => { 109 | const sniffedEncoding = htmlEncodingSniffer(buffer, { 110 | transportLayerEncodingLabel: "windows-1251", 111 | defaultEncoding: "ISO-8859-16" 112 | }); 113 | 114 | assert.strictEqual(sniffedEncoding, "windows-1251"); 115 | }); 116 | 117 | 118 | it("should sniff as UTF-8, given only a default encoding", () => { 119 | const sniffedEncoding = htmlEncodingSniffer(buffer, { 120 | defaultEncoding: "ISO-8859-16" 121 | }); 122 | 123 | assert.strictEqual(sniffedEncoding, "UTF-8"); 124 | }); 125 | }); 126 | } 127 | --------------------------------------------------------------------------------