├── .gitattributes ├── .github └── workflows │ ├── build.yaml │ └── deploy.yml ├── .gitignore ├── LICENSE ├── README.md ├── base64.md ├── package-lock.json ├── package.json ├── playground ├── index-raw.html ├── polyfill-core.mjs ├── polyfill-install.mjs ├── prism.css ├── style.css └── water-light.css ├── scripts └── static-highlight.js ├── spec.html ├── stream.mjs └── test-polyfill.mjs /.gitattributes: -------------------------------------------------------------------------------- 1 | index.html -diff merge=ours 2 | spec.js -diff merge=ours 3 | spec.css -diff merge=ours 4 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build spec 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | - uses: actions/setup-node@v3 16 | with: 17 | node-version: 20 18 | - run: npm ci 19 | - run: npm run build 20 | - run: npm run check-format 21 | - run: npm run test 22 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy gh-pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: actions/setup-node@v3 15 | with: 16 | node-version: 20 17 | - run: npm ci 18 | - run: npm run build 19 | - uses: JamesIves/github-pages-deploy-action@v4.4.1 20 | with: 21 | branch: gh-pages 22 | folder: dist 23 | clean: true 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 ECMA TC39 and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Uint8Array to/from base64 and hex 2 | 3 | base64 is a common way to represent arbitrary binary data as ASCII. JavaScript has Uint8Arrays to work with binary data, but no built-in mechanism to encode that data as base64, nor to take base64'd data and produce a corresponding Uint8Arrays. This is a proposal to fix that. It also adds methods for converting between hex strings and Uint8Arrays. 4 | 5 | It is currently at stage 3 of [the TC39 process](https://tc39.es/process-document/): it is ready for implementations. See [this issue](https://github.com/tc39/proposal-arraybuffer-base64/issues/51) for current status. 6 | 7 | Try it out on [the playground](https://tc39.github.io/proposal-arraybuffer-base64/). 8 | 9 | Spec text is available [here](https://tc39.github.io/proposal-arraybuffer-base64/spec/), and test262 tests in [this PR](https://github.com/tc39/test262/pull/3994). 10 | 11 | Implementers may be interested in [the open-source simdutf library](https://github.com/simdutf/simdutf/?tab=readme-ov-file#base64), which provides a fast implementation of a base64 decoder which matches `Uint8Array.fromBase64(string)` (including handling of whitespace) when it is called without specifying any options. As of this writing it only works on latin1 strings, but a utf16 version [may be coming](https://github.com/simdutf/simdutf/pull/375#issuecomment-2016979707). 12 | 13 | ## Basic API 14 | 15 | ```js 16 | let arr = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]); 17 | console.log(arr.toBase64()); 18 | // 'SGVsbG8gV29ybGQ=' 19 | console.log(arr.toHex()); 20 | // '48656c6c6f20576f726c64' 21 | ``` 22 | 23 | ```js 24 | let string = 'SGVsbG8gV29ybGQ='; 25 | console.log(Uint8Array.fromBase64(string)); 26 | // Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]) 27 | 28 | string = '48656c6c6f20576f726c64'; 29 | console.log(Uint8Array.fromHex(string)); 30 | // Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]) 31 | ``` 32 | 33 | This would add `Uint8Array.prototype.toBase64`/`Uint8Array.prototype.toHex` and `Uint8Array.fromBase64`/`Uint8Array.fromHex` methods. The latter pair would throw if given a string which is not properly encoded. 34 | 35 | ## Base64 options 36 | 37 | Additional options are supplied in an options bag argument: 38 | 39 | - `alphabet`: Allows specifying the alphabet as either `base64` or `base64url`. 40 | 41 | - `lastChunkHandling`: Recall that base64 decoding operates on chunks of 4 characters at a time, but the input may have some characters which don't fit evenly into such a chunk of 4 characters. This option determines how the final chunk of characters should be handled. The three options are `"loose"` (the default), which treats the chunk as if it had any necessary `=` padding (but throws if this is not possible, i.e. there is exactly one extra character); `"strict"`, which enforces that the chunk has exactly 4 characters (counting `=` padding) and that [overflow bits](https://datatracker.ietf.org/doc/html/rfc4648#section-3.5) are 0; and `"stop-before-partial"`, which stops decoding before the final chunk unless the final chunk has exactly 4 characters. 42 | 43 | - `omitPadding`: When encoding, whether to include `=` padding. Defaults to `false`, i.e., padding is included. 44 | 45 | The hex methods do not take any options. 46 | 47 | ## Writing to an existing Uint8Array 48 | 49 | The `Uint8Array.prototype.setFromBase64` method allows writing to an existing Uint8Array. Like the [TextEncoder `encodeInto` method](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder/encodeInto), it returns a `{ read, written }` pair. 50 | 51 | ```js 52 | let target = new Uint8Array(8); 53 | let { read, written } = target.setFromBase64('Zm9vYmFy'); 54 | assert.deepStrictEqual([...target], [102, 111, 111, 98, 97, 114, 0, 0]); 55 | assert.deepStrictEqual({ read, written }, { read: 8, written: 6 }); 56 | ``` 57 | 58 | This method takes an optional final options bag with the same options as above. 59 | 60 | As with `encodeInto`, there is not explicit support for writing to specified offset of the target, but you can accomplish that by creating a subarray. 61 | 62 | `Uint8Array.prototype.setFromHex` is the same except for hex. 63 | 64 | ## Streaming 65 | 66 | There is no explicit support for streaming. However, it is [relatively straightforward to do effeciently in userland](./stream.mjs) on top of this API, with support for all the same options as the underlying functions. 67 | 68 | ## FAQ 69 | 70 | ### What variation exists among base64 implementations in standards, in other languages, and in existing JavaScript libraries? 71 | 72 | I have a [whole page on that](./base64.md), with tables and footnotes and everything. There is relatively little room for variation, but languages and libraries manage to explore almost all of the room there is. 73 | 74 | To summarize, base64 encoders can vary in the following ways: 75 | 76 | - Standard or URL-safe alphabet 77 | - Whether `=` is included in output 78 | - Whether to add linebreaks after a certain number of characters 79 | 80 | and decoders can vary in the following ways: 81 | 82 | - Standard or URL-safe alphabet 83 | - Whether `=` is required in input, and how to handle malformed padding (e.g. extra `=`) 84 | - Whether to fail on non-zero padding bits 85 | - Whether lines must be of a limited length 86 | - How non-base64-alphabet characters are handled (sometimes with special handling for only a subset, like whitespace) 87 | 88 | ### What alphabets are supported? 89 | 90 | For base64, you can specify either base64 or base64url for both the encoder and the decoder. 91 | 92 | For hex, both lowercase and uppercase characters (including mixed within the same string) will decode successfully. Output is always lowercase. 93 | 94 | ### How are the extra padding bits handled? 95 | 96 | If the length of your input data isn't exactly a multiple of 3 bytes, then encoding it will use either 2 or 3 base64 characters to encode the final 1 or 2 bytes. Since each base64 character is 6 bits, this means you'll be using either 12 or 18 bits to represent 8 or 16 bits, which means you have an extra 4 or 2 bits which don't encode anything. 97 | 98 | Per [the RFC](https://datatracker.ietf.org/doc/html/rfc4648#section-3.5), decoders MAY reject input strings where the padding bits are non-zero. Here, non-zero padding bits are silently ignored unless `lastChunkHandling: "strict"` is specified. 99 | 100 | ### How is whitespace handled? 101 | 102 | The encoders do not output whitespace. The hex decoder does not allow it as input. The base64 decoder allows [ASCII whitespace](https://infra.spec.whatwg.org/#ascii-whitespace) anywhere in the string. 103 | 104 | ### How are other characters handled? 105 | 106 | The presence of any other characters causes an exception. 107 | 108 | ### Why are these synchronous? 109 | 110 | In practice most base64'd data I encounter is on the order of hundreds of bytes (e.g. SSH keys), which can be encoded and decoded extremely quickly. It would be a shame to require Promises to deal with such data, I think, especially given that the alternatives people currently use all appear to be synchronous. 111 | 112 | ### Why just these encodings? 113 | 114 | While other string encodings exist, none are nearly as commonly used as these two. 115 | 116 | See issues [#7](https://github.com/tc39/proposal-arraybuffer-base64/issues/7), [#8](https://github.com/tc39/proposal-arraybuffer-base64/issues/8), and [#11](https://github.com/tc39/proposal-arraybuffer-base64/issues/11). 117 | 118 | ### Why not just use `atob` and `btoa`? 119 | 120 | Those methods take and consume strings, rather than translating between a string and a Uint8Array. 121 | 122 | ### Why not TextEncoder? 123 | 124 | base64 is not a text encoding format; there's no [code points](https://unicode.org/glossary/#code_point) involved. So despite fitting with the type signature of TextEncoder/TextDecoder, base64 encoding and decoding is not a conceptually appropriate thing for those APIs to do. 125 | 126 | That's also been the consensus when it's come up [previously](https://discourse.wicg.io/t/base64-with-textencoder-textdecoder/1307/2). 127 | 128 | ### What if I just want to encode a portion of an ArrayBuffer? 129 | 130 | Uint8Arrays can be partial views of an underlying buffer, so you can create such a view and invoke `.toBase64` on it. 131 | -------------------------------------------------------------------------------- /base64.md: -------------------------------------------------------------------------------- 1 | # Notes on Base64 as it exists 2 | 3 | Towards an implementation in JavaScript. 4 | 5 | ## The RFCs 6 | 7 | There are two RFCs which are still generally relevant in modern times: [4648](https://datatracker.ietf.org/doc/html/rfc4648), which defines only the base64 and base64url encodings, and [2045](https://datatracker.ietf.org/doc/html/rfc2045#section-6.8), which defines [MIME](https://en.wikipedia.org/wiki/MIME) and includes a base64 encoding. 8 | 9 | RFC 4648 is "the base64 RFC". It obsoletes RFC [3548](https://datatracker.ietf.org/doc/html/rfc3548). 10 | 11 | - It defines both the standard (`+/`) and url-safe (`-_`) alphabets. 12 | - "Implementations MUST include appropriate pad characters at the end of encoded data unless the specification referring to this document explicitly states otherwise." Certain malformed padding MAY be ignored. 13 | - "Decoders MAY chose to reject an encoding if the pad bits have not been set to zero" 14 | - "Implementations MUST reject the encoded data if it contains characters outside the base alphabet when interpreting base-encoded data, unless the specification referring to this document explicitly states otherwise." 15 | 16 | RFC 2045 is not usually relevant, but it's worth summarizing its behavior anyway: 17 | 18 | - Only the standard (`+/`) alphabet is supported. 19 | - It defines only an encoding. The encoding is specified to include `=`. No direction is given for decoders which encounter data which is not padded with `=`, or which has non-zero padding bits. In practice, decoders seem to ignore both. 20 | - "Any characters outside of the base64 alphabet are to be ignored in base64-encoded data." 21 | - MIME requires lines of length at most 76 characters, seperated by CRLF. 22 | 23 | RFCs [1421](https://datatracker.ietf.org/doc/html/rfc1421) and [7468](https://datatracker.ietf.org/doc/html/rfc7468), which define "Privacy-Enhanced Mail" and related things (think `-----BEGIN PRIVATE KEY-----`), are basically identical to the above except that they mandate lines of exactly 64 characters, except that the last line may be shorter. 24 | 25 | RFC [4880](https://datatracker.ietf.org/doc/html/rfc4880#section-6) defines OpenPGP messages and is just the RFC 2045 format plus a checksum. In practice, only whitespace is ignored, not all non-base64 characters. 26 | 27 | No other variations are contemplated in any other RFC or implementation that I'm aware of. That is, we have the following ways that base64 encoders can vary: 28 | 29 | - Standard or URL-safe alphabet 30 | - Whether `=` is included in output 31 | - Whether to add linebreaks after a certain number of characters 32 | 33 | and the following ways that base64 decoders can vary: 34 | 35 | - Standard or URL-safe alphabet 36 | - Whether `=` is required in input, and how to handle malformed padding (e.g. extra `=`) 37 | - Whether to fail on non-zero padding bits 38 | - Whether lines must be of a limited length 39 | - How non-base64-alphabet characters are handled (sometimes with special handling for only a subset, like whitespace) 40 | 41 | ## Programming languages 42 | 43 | Note that neither C++ nor Rust have built-in base64 support. In C++ the Boost library is quite common in large projects and parts sometimes get pulled in to the standard library, and in Rust the [base64 crate](https://docs.rs/base64/latest/base64/) is the clear choice of everyone, so I'm mentioning those as well. 44 | 45 | "✅ / ⚙️" means the default is yes but it's configurable. A bare "⚙️" means it's configurable and there is no default. 46 | 47 | | | supports urlsafe | `=`s in output | whitespace in output | can omit `=`s in input | can have non-zero padding bits | can have arbitrary characters in input | can have whitespace in input | 48 | | ------------------- | ---------------- | -------------- | -------------------- | ---------------------- | ------------------------------ | -------------------------------------- | ---------------------------- | 49 | | C++ (Boost) | ❌ | ❌ | ❌ | ?[^cpp] | ? | ❌ | ❌ | 50 | | Ruby | ✅ | ✅ / ⚙️[^ruby] | ✅ / ⚙️[^ruby2] | ✅ / ⚙️ | ✅ / ⚙️ | ❌ | ✅ / ⚙️ | 51 | | Python | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ / ⚙️ | ✅ / ⚙️ | 52 | | Rust (base64 crate) | ✅ | ⚙️ | ❌ | ⚙️ | ⚙️ | ❌ | ❌ | 53 | | Java | ✅ | ✅ / ⚙️ | ❌ / ⚙️[^java] | ✅ | ✅ | ❌ | ❌ / ⚙️ | 54 | | Go | ✅ | ✅ | ❌ | ✅ / ⚙️ | ✅ / ⚙️ | ❌ | ✅[^go] | 55 | | C# | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | 56 | | PHP | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ / ⚙️ | ✅ / ⚙️ | 57 | | Swift | ❌ | ✅ | ❌ / ⚙️ | ❌ | ✅ | ❌ / ⚙️ | ❌ / ⚙️ | 58 | 59 | [^cpp]: Boost adds extra null bytes to the output when padding is present, and treats non-zero padding bits as meaningful (i.e. it produces more output when they are present) 60 | [^ruby]: Ruby only allows configuring padding with the urlsafe alphabet 61 | [^ruby2]: Ruby adds linebreaks every 60 characters 62 | [^java]: Java allows MIME-format output, with `\r\n` sequences after every 76 characters of output 63 | [^go]: Go only allows linebreaks specifically 64 | 65 | ## JS libraries 66 | 67 | Only including libraries with a least a million downloads per week and at least 100 distinct dependents. 68 | 69 | | | supports urlsafe | `=`s in output | whitespace in output | can omit `=`s in input | can have non-zero padding bits | can have arbitrary characters in input | can have whitespace in input | 70 | | --------------------------- | ----------------- | -------------- | -------------------- | ---------------------- | ------------------------------ | -------------------------------------- | ---------------------------- | 71 | | `atob`/`btoa` | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | 72 | | Node's Buffer | ✅[^node] | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | 73 | | base64-js (38m/wk) | ✅ (for decoding) | ✅ | ❌ | ❌ | ✅ | ❌[^base64-js] | ❌ | 74 | | @smithy/util-base64 (8m/wk) | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | 75 | | crypto-js (6m/wk) | ✅ | ✅ | ❌ | ✅ | ✅ | ❌[^crypto-js] | ❌ | 76 | | js-base64 (5m/wk) | ✅ | ✅ / ⚙️ | ❌ | ✅ | ✅ | ✅ | ✅ | 77 | | base64-arraybuffer (4m/wk) | ❌ | ✅ | ❌ | ✅ | ✅ | ❌[^base64-arraybuffer] | ❌ | 78 | | base64url (2m/wk) | ✅ | ❌ / ⚙️ | ❌ | ✅ | ✅ | ✅ | ✅ | 79 | | base-64 (2m/wk) | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | 80 | 81 | [^node]: Node allows mixing alphabets within the same string in input 82 | [^base64-js]: Illegal characters are interpreted as `A` 83 | [^crypto-js]: Illegal characters are interpreted as `A` 84 | [^base64-arraybuffer]: Illegal characters are interpreted as `A` 85 | 86 | ## "Whitespace" 87 | 88 | In all of the above, "whitespace" means only _ASCII_ whitespace. I don't think anyone has special handling for Unicode but non-ASCII whitespace. 89 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proposal-arraybuffer-base64", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "name": "proposal-arraybuffer-base64", 8 | "dependencies": { 9 | "@tc39/ecma262-biblio": "2.1.2672", 10 | "ecmarkup": "^18.0.0", 11 | "jsdom": "^21.1.1", 12 | "prismjs": "^1.29.0" 13 | } 14 | }, 15 | "node_modules/@babel/code-frame": { 16 | "version": "7.12.11", 17 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", 18 | "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", 19 | "dependencies": { 20 | "@babel/highlight": "^7.10.4" 21 | } 22 | }, 23 | "node_modules/@babel/helper-validator-identifier": { 24 | "version": "7.19.1", 25 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", 26 | "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", 27 | "engines": { 28 | "node": ">=6.9.0" 29 | } 30 | }, 31 | "node_modules/@babel/highlight": { 32 | "version": "7.18.6", 33 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", 34 | "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", 35 | "dependencies": { 36 | "@babel/helper-validator-identifier": "^7.18.6", 37 | "chalk": "^2.0.0", 38 | "js-tokens": "^4.0.0" 39 | }, 40 | "engines": { 41 | "node": ">=6.9.0" 42 | } 43 | }, 44 | "node_modules/@babel/highlight/node_modules/ansi-styles": { 45 | "version": "3.2.1", 46 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 47 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 48 | "dependencies": { 49 | "color-convert": "^1.9.0" 50 | }, 51 | "engines": { 52 | "node": ">=4" 53 | } 54 | }, 55 | "node_modules/@babel/highlight/node_modules/chalk": { 56 | "version": "2.4.2", 57 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 58 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 59 | "dependencies": { 60 | "ansi-styles": "^3.2.1", 61 | "escape-string-regexp": "^1.0.5", 62 | "supports-color": "^5.3.0" 63 | }, 64 | "engines": { 65 | "node": ">=4" 66 | } 67 | }, 68 | "node_modules/@babel/highlight/node_modules/color-convert": { 69 | "version": "1.9.3", 70 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 71 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 72 | "dependencies": { 73 | "color-name": "1.1.3" 74 | } 75 | }, 76 | "node_modules/@babel/highlight/node_modules/color-name": { 77 | "version": "1.1.3", 78 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 79 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 80 | }, 81 | "node_modules/@babel/highlight/node_modules/has-flag": { 82 | "version": "3.0.0", 83 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 84 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 85 | "engines": { 86 | "node": ">=4" 87 | } 88 | }, 89 | "node_modules/@babel/highlight/node_modules/supports-color": { 90 | "version": "5.5.0", 91 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 92 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 93 | "dependencies": { 94 | "has-flag": "^3.0.0" 95 | }, 96 | "engines": { 97 | "node": ">=4" 98 | } 99 | }, 100 | "node_modules/@esfx/async-canceltoken": { 101 | "version": "1.0.0", 102 | "resolved": "https://registry.npmjs.org/@esfx/async-canceltoken/-/async-canceltoken-1.0.0.tgz", 103 | "integrity": "sha512-3Ps/4NPd7qFltmHL+CYXCjZtNXcQGV9BZmpzu8Rt3/0SZMtbQve0gtX0uJDJGvAWa6w3IB4HrKVP12VPoFONmA==", 104 | "dependencies": { 105 | "@esfx/cancelable": "^1.0.0", 106 | "@esfx/canceltoken": "^1.0.0", 107 | "@esfx/disposable": "^1.0.0", 108 | "tslib": "^2.4.0" 109 | } 110 | }, 111 | "node_modules/@esfx/cancelable": { 112 | "version": "1.0.0", 113 | "resolved": "https://registry.npmjs.org/@esfx/cancelable/-/cancelable-1.0.0.tgz", 114 | "integrity": "sha512-2dry/TuOT9ydpw86f396v09cyi/gLeGPIZSH4Gx+V/qKQaS/OXCRurCY+Cn8zkBfTAgFsjk9NE15d+LPo2kt9A==", 115 | "dependencies": { 116 | "@esfx/disposable": "^1.0.0" 117 | } 118 | }, 119 | "node_modules/@esfx/canceltoken": { 120 | "version": "1.0.0", 121 | "resolved": "https://registry.npmjs.org/@esfx/canceltoken/-/canceltoken-1.0.0.tgz", 122 | "integrity": "sha512-/TgdzC5O89w5v0TgwE2wcdtampWNAFOxzurCtb4RxYVr3m72yk3Bg82vMdznx+H9nnf28zVDR0PtpZO9FxmOkw==", 123 | "dependencies": { 124 | "@esfx/cancelable": "^1.0.0", 125 | "@esfx/disposable": "^1.0.0", 126 | "tslib": "^2.4.0" 127 | } 128 | }, 129 | "node_modules/@esfx/disposable": { 130 | "version": "1.0.0", 131 | "resolved": "https://registry.npmjs.org/@esfx/disposable/-/disposable-1.0.0.tgz", 132 | "integrity": "sha512-hu7EI+YxlEWEKrb2himbS13HNaq5mlUePASf99KeQqkiNeqiAZbKqG4w59uDcLZs8JrV3qJqS/NYib5ZMhbfTQ==" 133 | }, 134 | "node_modules/@nodelib/fs.scandir": { 135 | "version": "2.1.5", 136 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 137 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 138 | "dependencies": { 139 | "@nodelib/fs.stat": "2.0.5", 140 | "run-parallel": "^1.1.9" 141 | }, 142 | "engines": { 143 | "node": ">= 8" 144 | } 145 | }, 146 | "node_modules/@nodelib/fs.stat": { 147 | "version": "2.0.5", 148 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 149 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 150 | "engines": { 151 | "node": ">= 8" 152 | } 153 | }, 154 | "node_modules/@nodelib/fs.walk": { 155 | "version": "1.2.8", 156 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 157 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 158 | "dependencies": { 159 | "@nodelib/fs.scandir": "2.1.5", 160 | "fastq": "^1.6.0" 161 | }, 162 | "engines": { 163 | "node": ">= 8" 164 | } 165 | }, 166 | "node_modules/@tc39/ecma262-biblio": { 167 | "version": "2.1.2672", 168 | "resolved": "https://registry.npmjs.org/@tc39/ecma262-biblio/-/ecma262-biblio-2.1.2672.tgz", 169 | "integrity": "sha512-S4AVovjzgm9cq1O2Odn7y+OqZ3LNKVGzhd5zVggueFogQyQPw8mpaIzdGxqrm7jmkRtnggO9i+NY5g23GCBXNg==" 170 | }, 171 | "node_modules/@tootallnate/once": { 172 | "version": "2.0.0", 173 | "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", 174 | "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", 175 | "engines": { 176 | "node": ">= 10" 177 | } 178 | }, 179 | "node_modules/abab": { 180 | "version": "2.0.6", 181 | "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", 182 | "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" 183 | }, 184 | "node_modules/acorn": { 185 | "version": "8.8.2", 186 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", 187 | "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", 188 | "bin": { 189 | "acorn": "bin/acorn" 190 | }, 191 | "engines": { 192 | "node": ">=0.4.0" 193 | } 194 | }, 195 | "node_modules/acorn-globals": { 196 | "version": "7.0.1", 197 | "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", 198 | "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", 199 | "dependencies": { 200 | "acorn": "^8.1.0", 201 | "acorn-walk": "^8.0.2" 202 | } 203 | }, 204 | "node_modules/acorn-walk": { 205 | "version": "8.2.0", 206 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 207 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 208 | "engines": { 209 | "node": ">=0.4.0" 210 | } 211 | }, 212 | "node_modules/agent-base": { 213 | "version": "6.0.2", 214 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", 215 | "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", 216 | "dependencies": { 217 | "debug": "4" 218 | }, 219 | "engines": { 220 | "node": ">= 6.0.0" 221 | } 222 | }, 223 | "node_modules/ansi-styles": { 224 | "version": "4.3.0", 225 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 226 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 227 | "dependencies": { 228 | "color-convert": "^2.0.1" 229 | }, 230 | "engines": { 231 | "node": ">=8" 232 | }, 233 | "funding": { 234 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 235 | } 236 | }, 237 | "node_modules/argparse": { 238 | "version": "1.0.10", 239 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 240 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 241 | "dependencies": { 242 | "sprintf-js": "~1.0.2" 243 | } 244 | }, 245 | "node_modules/array-back": { 246 | "version": "3.1.0", 247 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", 248 | "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", 249 | "engines": { 250 | "node": ">=6" 251 | } 252 | }, 253 | "node_modules/asynckit": { 254 | "version": "0.4.0", 255 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 256 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 257 | }, 258 | "node_modules/braces": { 259 | "version": "3.0.2", 260 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 261 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 262 | "dependencies": { 263 | "fill-range": "^7.0.1" 264 | }, 265 | "engines": { 266 | "node": ">=8" 267 | } 268 | }, 269 | "node_modules/browser-process-hrtime": { 270 | "version": "1.0.0", 271 | "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", 272 | "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" 273 | }, 274 | "node_modules/chalk": { 275 | "version": "4.1.2", 276 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 277 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 278 | "dependencies": { 279 | "ansi-styles": "^4.1.0", 280 | "supports-color": "^7.1.0" 281 | }, 282 | "engines": { 283 | "node": ">=10" 284 | }, 285 | "funding": { 286 | "url": "https://github.com/chalk/chalk?sponsor=1" 287 | } 288 | }, 289 | "node_modules/color-convert": { 290 | "version": "2.0.1", 291 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 292 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 293 | "dependencies": { 294 | "color-name": "~1.1.4" 295 | }, 296 | "engines": { 297 | "node": ">=7.0.0" 298 | } 299 | }, 300 | "node_modules/color-name": { 301 | "version": "1.1.4", 302 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 303 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 304 | }, 305 | "node_modules/combined-stream": { 306 | "version": "1.0.8", 307 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 308 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 309 | "dependencies": { 310 | "delayed-stream": "~1.0.0" 311 | }, 312 | "engines": { 313 | "node": ">= 0.8" 314 | } 315 | }, 316 | "node_modules/command-line-args": { 317 | "version": "5.2.1", 318 | "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", 319 | "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", 320 | "dependencies": { 321 | "array-back": "^3.1.0", 322 | "find-replace": "^3.0.0", 323 | "lodash.camelcase": "^4.3.0", 324 | "typical": "^4.0.0" 325 | }, 326 | "engines": { 327 | "node": ">=4.0.0" 328 | } 329 | }, 330 | "node_modules/command-line-usage": { 331 | "version": "6.1.3", 332 | "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", 333 | "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", 334 | "dependencies": { 335 | "array-back": "^4.0.2", 336 | "chalk": "^2.4.2", 337 | "table-layout": "^1.0.2", 338 | "typical": "^5.2.0" 339 | }, 340 | "engines": { 341 | "node": ">=8.0.0" 342 | } 343 | }, 344 | "node_modules/command-line-usage/node_modules/ansi-styles": { 345 | "version": "3.2.1", 346 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 347 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 348 | "dependencies": { 349 | "color-convert": "^1.9.0" 350 | }, 351 | "engines": { 352 | "node": ">=4" 353 | } 354 | }, 355 | "node_modules/command-line-usage/node_modules/array-back": { 356 | "version": "4.0.2", 357 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", 358 | "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", 359 | "engines": { 360 | "node": ">=8" 361 | } 362 | }, 363 | "node_modules/command-line-usage/node_modules/chalk": { 364 | "version": "2.4.2", 365 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 366 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 367 | "dependencies": { 368 | "ansi-styles": "^3.2.1", 369 | "escape-string-regexp": "^1.0.5", 370 | "supports-color": "^5.3.0" 371 | }, 372 | "engines": { 373 | "node": ">=4" 374 | } 375 | }, 376 | "node_modules/command-line-usage/node_modules/color-convert": { 377 | "version": "1.9.3", 378 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 379 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 380 | "dependencies": { 381 | "color-name": "1.1.3" 382 | } 383 | }, 384 | "node_modules/command-line-usage/node_modules/color-name": { 385 | "version": "1.1.3", 386 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 387 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 388 | }, 389 | "node_modules/command-line-usage/node_modules/has-flag": { 390 | "version": "3.0.0", 391 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 392 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 393 | "engines": { 394 | "node": ">=4" 395 | } 396 | }, 397 | "node_modules/command-line-usage/node_modules/supports-color": { 398 | "version": "5.5.0", 399 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 400 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 401 | "dependencies": { 402 | "has-flag": "^3.0.0" 403 | }, 404 | "engines": { 405 | "node": ">=4" 406 | } 407 | }, 408 | "node_modules/command-line-usage/node_modules/typical": { 409 | "version": "5.2.0", 410 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 411 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", 412 | "engines": { 413 | "node": ">=8" 414 | } 415 | }, 416 | "node_modules/cssom": { 417 | "version": "0.5.0", 418 | "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", 419 | "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==" 420 | }, 421 | "node_modules/cssstyle": { 422 | "version": "3.0.0", 423 | "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", 424 | "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", 425 | "dependencies": { 426 | "rrweb-cssom": "^0.6.0" 427 | }, 428 | "engines": { 429 | "node": ">=14" 430 | } 431 | }, 432 | "node_modules/data-urls": { 433 | "version": "4.0.0", 434 | "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", 435 | "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", 436 | "dependencies": { 437 | "abab": "^2.0.6", 438 | "whatwg-mimetype": "^3.0.0", 439 | "whatwg-url": "^12.0.0" 440 | }, 441 | "engines": { 442 | "node": ">=14" 443 | } 444 | }, 445 | "node_modules/debug": { 446 | "version": "4.3.1", 447 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", 448 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", 449 | "dependencies": { 450 | "ms": "2.1.2" 451 | }, 452 | "engines": { 453 | "node": ">=6.0" 454 | }, 455 | "peerDependenciesMeta": { 456 | "supports-color": { 457 | "optional": true 458 | } 459 | } 460 | }, 461 | "node_modules/decimal.js": { 462 | "version": "10.4.3", 463 | "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", 464 | "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" 465 | }, 466 | "node_modules/dedent-js": { 467 | "version": "1.0.1", 468 | "resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz", 469 | "integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==" 470 | }, 471 | "node_modules/deep-extend": { 472 | "version": "0.6.0", 473 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 474 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 475 | "engines": { 476 | "node": ">=4.0.0" 477 | } 478 | }, 479 | "node_modules/deep-is": { 480 | "version": "0.1.3", 481 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 482 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" 483 | }, 484 | "node_modules/delayed-stream": { 485 | "version": "1.0.0", 486 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 487 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 488 | "engines": { 489 | "node": ">=0.4.0" 490 | } 491 | }, 492 | "node_modules/domexception": { 493 | "version": "4.0.0", 494 | "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", 495 | "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", 496 | "dependencies": { 497 | "webidl-conversions": "^7.0.0" 498 | }, 499 | "engines": { 500 | "node": ">=12" 501 | } 502 | }, 503 | "node_modules/ecmarkdown": { 504 | "version": "8.1.0", 505 | "resolved": "https://registry.npmjs.org/ecmarkdown/-/ecmarkdown-8.1.0.tgz", 506 | "integrity": "sha512-dx6cM6RFjzAXkWr2KQRikED4gy70NFQ0vTI4XUQM/LWcjUYRJUbGdd7nd++trXi5az1JSe49TeeCIVMKDXOtcQ==", 507 | "dependencies": { 508 | "escape-html": "^1.0.1" 509 | } 510 | }, 511 | "node_modules/ecmarkup": { 512 | "version": "18.0.0", 513 | "resolved": "https://registry.npmjs.org/ecmarkup/-/ecmarkup-18.0.0.tgz", 514 | "integrity": "sha512-VSItKQ+39dv1FeR1YbGGlJ/rx17wsPSkS7morrOCwLGHh+7ehy89hao+rQ0/ptiBAN3nbytXzwUBUTC3XNmxaA==", 515 | "dependencies": { 516 | "chalk": "^4.1.2", 517 | "command-line-args": "^5.2.0", 518 | "command-line-usage": "^6.1.1", 519 | "dedent-js": "^1.0.1", 520 | "ecmarkdown": "^8.1.0", 521 | "eslint-formatter-codeframe": "^7.32.1", 522 | "fast-glob": "^3.2.7", 523 | "grammarkdown": "^3.2.0", 524 | "highlight.js": "11.0.1", 525 | "html-escape": "^1.0.2", 526 | "js-yaml": "^3.13.1", 527 | "jsdom": "^19.0.0", 528 | "nwsapi": "2.2.0", 529 | "parse5": "^6.0.1", 530 | "prex": "^0.4.7", 531 | "promise-debounce": "^1.0.1" 532 | }, 533 | "bin": { 534 | "ecmarkup": "bin/ecmarkup.js", 535 | "emu-format": "bin/emu-format.js" 536 | }, 537 | "engines": { 538 | "node": ">= 12 || ^11.10.1 || ^10.13 || ^8.10" 539 | } 540 | }, 541 | "node_modules/ecmarkup/node_modules/acorn-globals": { 542 | "version": "6.0.0", 543 | "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", 544 | "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", 545 | "dependencies": { 546 | "acorn": "^7.1.1", 547 | "acorn-walk": "^7.1.1" 548 | } 549 | }, 550 | "node_modules/ecmarkup/node_modules/acorn-globals/node_modules/acorn": { 551 | "version": "7.4.1", 552 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", 553 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", 554 | "bin": { 555 | "acorn": "bin/acorn" 556 | }, 557 | "engines": { 558 | "node": ">=0.4.0" 559 | } 560 | }, 561 | "node_modules/ecmarkup/node_modules/acorn-walk": { 562 | "version": "7.2.0", 563 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", 564 | "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", 565 | "engines": { 566 | "node": ">=0.4.0" 567 | } 568 | }, 569 | "node_modules/ecmarkup/node_modules/cssstyle": { 570 | "version": "2.3.0", 571 | "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", 572 | "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", 573 | "dependencies": { 574 | "cssom": "~0.3.6" 575 | }, 576 | "engines": { 577 | "node": ">=8" 578 | } 579 | }, 580 | "node_modules/ecmarkup/node_modules/cssstyle/node_modules/cssom": { 581 | "version": "0.3.8", 582 | "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", 583 | "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" 584 | }, 585 | "node_modules/ecmarkup/node_modules/data-urls": { 586 | "version": "3.0.2", 587 | "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", 588 | "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", 589 | "dependencies": { 590 | "abab": "^2.0.6", 591 | "whatwg-mimetype": "^3.0.0", 592 | "whatwg-url": "^11.0.0" 593 | }, 594 | "engines": { 595 | "node": ">=12" 596 | } 597 | }, 598 | "node_modules/ecmarkup/node_modules/data-urls/node_modules/whatwg-url": { 599 | "version": "11.0.0", 600 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", 601 | "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", 602 | "dependencies": { 603 | "tr46": "^3.0.0", 604 | "webidl-conversions": "^7.0.0" 605 | }, 606 | "engines": { 607 | "node": ">=12" 608 | } 609 | }, 610 | "node_modules/ecmarkup/node_modules/jsdom": { 611 | "version": "19.0.0", 612 | "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-19.0.0.tgz", 613 | "integrity": "sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==", 614 | "dependencies": { 615 | "abab": "^2.0.5", 616 | "acorn": "^8.5.0", 617 | "acorn-globals": "^6.0.0", 618 | "cssom": "^0.5.0", 619 | "cssstyle": "^2.3.0", 620 | "data-urls": "^3.0.1", 621 | "decimal.js": "^10.3.1", 622 | "domexception": "^4.0.0", 623 | "escodegen": "^2.0.0", 624 | "form-data": "^4.0.0", 625 | "html-encoding-sniffer": "^3.0.0", 626 | "http-proxy-agent": "^5.0.0", 627 | "https-proxy-agent": "^5.0.0", 628 | "is-potential-custom-element-name": "^1.0.1", 629 | "nwsapi": "^2.2.0", 630 | "parse5": "6.0.1", 631 | "saxes": "^5.0.1", 632 | "symbol-tree": "^3.2.4", 633 | "tough-cookie": "^4.0.0", 634 | "w3c-hr-time": "^1.0.2", 635 | "w3c-xmlserializer": "^3.0.0", 636 | "webidl-conversions": "^7.0.0", 637 | "whatwg-encoding": "^2.0.0", 638 | "whatwg-mimetype": "^3.0.0", 639 | "whatwg-url": "^10.0.0", 640 | "ws": "^8.2.3", 641 | "xml-name-validator": "^4.0.0" 642 | }, 643 | "engines": { 644 | "node": ">=12" 645 | }, 646 | "peerDependencies": { 647 | "canvas": "^2.5.0" 648 | }, 649 | "peerDependenciesMeta": { 650 | "canvas": { 651 | "optional": true 652 | } 653 | } 654 | }, 655 | "node_modules/ecmarkup/node_modules/nwsapi": { 656 | "version": "2.2.0", 657 | "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", 658 | "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" 659 | }, 660 | "node_modules/ecmarkup/node_modules/parse5": { 661 | "version": "6.0.1", 662 | "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", 663 | "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" 664 | }, 665 | "node_modules/ecmarkup/node_modules/saxes": { 666 | "version": "5.0.1", 667 | "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", 668 | "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", 669 | "dependencies": { 670 | "xmlchars": "^2.2.0" 671 | }, 672 | "engines": { 673 | "node": ">=10" 674 | } 675 | }, 676 | "node_modules/ecmarkup/node_modules/tr46": { 677 | "version": "3.0.0", 678 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", 679 | "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", 680 | "dependencies": { 681 | "punycode": "^2.1.1" 682 | }, 683 | "engines": { 684 | "node": ">=12" 685 | } 686 | }, 687 | "node_modules/ecmarkup/node_modules/w3c-xmlserializer": { 688 | "version": "3.0.0", 689 | "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", 690 | "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", 691 | "dependencies": { 692 | "xml-name-validator": "^4.0.0" 693 | }, 694 | "engines": { 695 | "node": ">=12" 696 | } 697 | }, 698 | "node_modules/ecmarkup/node_modules/whatwg-url": { 699 | "version": "10.0.0", 700 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-10.0.0.tgz", 701 | "integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==", 702 | "dependencies": { 703 | "tr46": "^3.0.0", 704 | "webidl-conversions": "^7.0.0" 705 | }, 706 | "engines": { 707 | "node": ">=12" 708 | } 709 | }, 710 | "node_modules/entities": { 711 | "version": "4.4.0", 712 | "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", 713 | "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", 714 | "engines": { 715 | "node": ">=0.12" 716 | }, 717 | "funding": { 718 | "url": "https://github.com/fb55/entities?sponsor=1" 719 | } 720 | }, 721 | "node_modules/escape-html": { 722 | "version": "1.0.3", 723 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 724 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 725 | }, 726 | "node_modules/escape-string-regexp": { 727 | "version": "1.0.5", 728 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 729 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 730 | "engines": { 731 | "node": ">=0.8.0" 732 | } 733 | }, 734 | "node_modules/escodegen": { 735 | "version": "2.0.0", 736 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", 737 | "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", 738 | "dependencies": { 739 | "esprima": "^4.0.1", 740 | "estraverse": "^5.2.0", 741 | "esutils": "^2.0.2", 742 | "optionator": "^0.8.1" 743 | }, 744 | "bin": { 745 | "escodegen": "bin/escodegen.js", 746 | "esgenerate": "bin/esgenerate.js" 747 | }, 748 | "engines": { 749 | "node": ">=6.0" 750 | }, 751 | "optionalDependencies": { 752 | "source-map": "~0.6.1" 753 | } 754 | }, 755 | "node_modules/escodegen/node_modules/estraverse": { 756 | "version": "5.3.0", 757 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 758 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 759 | "engines": { 760 | "node": ">=4.0" 761 | } 762 | }, 763 | "node_modules/escodegen/node_modules/levn": { 764 | "version": "0.3.0", 765 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 766 | "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", 767 | "dependencies": { 768 | "prelude-ls": "~1.1.2", 769 | "type-check": "~0.3.2" 770 | }, 771 | "engines": { 772 | "node": ">= 0.8.0" 773 | } 774 | }, 775 | "node_modules/escodegen/node_modules/optionator": { 776 | "version": "0.8.3", 777 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", 778 | "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", 779 | "dependencies": { 780 | "deep-is": "~0.1.3", 781 | "fast-levenshtein": "~2.0.6", 782 | "levn": "~0.3.0", 783 | "prelude-ls": "~1.1.2", 784 | "type-check": "~0.3.2", 785 | "word-wrap": "~1.2.3" 786 | }, 787 | "engines": { 788 | "node": ">= 0.8.0" 789 | } 790 | }, 791 | "node_modules/escodegen/node_modules/prelude-ls": { 792 | "version": "1.1.2", 793 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 794 | "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", 795 | "engines": { 796 | "node": ">= 0.8.0" 797 | } 798 | }, 799 | "node_modules/escodegen/node_modules/type-check": { 800 | "version": "0.3.2", 801 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 802 | "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", 803 | "dependencies": { 804 | "prelude-ls": "~1.1.2" 805 | }, 806 | "engines": { 807 | "node": ">= 0.8.0" 808 | } 809 | }, 810 | "node_modules/eslint-formatter-codeframe": { 811 | "version": "7.32.1", 812 | "resolved": "https://registry.npmjs.org/eslint-formatter-codeframe/-/eslint-formatter-codeframe-7.32.1.tgz", 813 | "integrity": "sha512-DK/3Q3+zVKq/7PdSYiCxPrsDF8H/TRMK5n8Hziwr4IMkMy+XiKSwbpj25AdajS63I/B61Snetq4uVvX9fOLyAg==", 814 | "dependencies": { 815 | "@babel/code-frame": "7.12.11", 816 | "chalk": "^4.0.0" 817 | }, 818 | "engines": { 819 | "node": "^10.12.0 || >=12.0.0" 820 | } 821 | }, 822 | "node_modules/esprima": { 823 | "version": "4.0.1", 824 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 825 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 826 | "bin": { 827 | "esparse": "bin/esparse.js", 828 | "esvalidate": "bin/esvalidate.js" 829 | }, 830 | "engines": { 831 | "node": ">=4" 832 | } 833 | }, 834 | "node_modules/esutils": { 835 | "version": "2.0.3", 836 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 837 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 838 | "engines": { 839 | "node": ">=0.10.0" 840 | } 841 | }, 842 | "node_modules/fast-glob": { 843 | "version": "3.2.12", 844 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", 845 | "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", 846 | "dependencies": { 847 | "@nodelib/fs.stat": "^2.0.2", 848 | "@nodelib/fs.walk": "^1.2.3", 849 | "glob-parent": "^5.1.2", 850 | "merge2": "^1.3.0", 851 | "micromatch": "^4.0.4" 852 | }, 853 | "engines": { 854 | "node": ">=8.6.0" 855 | } 856 | }, 857 | "node_modules/fast-levenshtein": { 858 | "version": "2.0.6", 859 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 860 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" 861 | }, 862 | "node_modules/fastq": { 863 | "version": "1.15.0", 864 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", 865 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", 866 | "dependencies": { 867 | "reusify": "^1.0.4" 868 | } 869 | }, 870 | "node_modules/fill-range": { 871 | "version": "7.0.1", 872 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 873 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 874 | "dependencies": { 875 | "to-regex-range": "^5.0.1" 876 | }, 877 | "engines": { 878 | "node": ">=8" 879 | } 880 | }, 881 | "node_modules/find-replace": { 882 | "version": "3.0.0", 883 | "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", 884 | "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", 885 | "dependencies": { 886 | "array-back": "^3.0.1" 887 | }, 888 | "engines": { 889 | "node": ">=4.0.0" 890 | } 891 | }, 892 | "node_modules/form-data": { 893 | "version": "4.0.0", 894 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 895 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 896 | "dependencies": { 897 | "asynckit": "^0.4.0", 898 | "combined-stream": "^1.0.8", 899 | "mime-types": "^2.1.12" 900 | }, 901 | "engines": { 902 | "node": ">= 6" 903 | } 904 | }, 905 | "node_modules/glob-parent": { 906 | "version": "5.1.2", 907 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 908 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 909 | "dependencies": { 910 | "is-glob": "^4.0.1" 911 | }, 912 | "engines": { 913 | "node": ">= 6" 914 | } 915 | }, 916 | "node_modules/grammarkdown": { 917 | "version": "3.2.0", 918 | "resolved": "https://registry.npmjs.org/grammarkdown/-/grammarkdown-3.2.0.tgz", 919 | "integrity": "sha512-pEVUvG2Kxv/PwM3Dm3kFEU1/GHRkNcFWmk/zkqN/y0uoQtPaZ+5VaBacMQAaFOIL9WGYjHXtqpkT5YRvySsISQ==", 920 | "dependencies": { 921 | "@esfx/async-canceltoken": "^1.0.0-pre.13", 922 | "@esfx/cancelable": "^1.0.0-pre.13" 923 | }, 924 | "bin": { 925 | "grammarkdown": "bin/grammarkdown" 926 | } 927 | }, 928 | "node_modules/has-flag": { 929 | "version": "4.0.0", 930 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 931 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 932 | "engines": { 933 | "node": ">=8" 934 | } 935 | }, 936 | "node_modules/highlight.js": { 937 | "version": "11.0.1", 938 | "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.0.1.tgz", 939 | "integrity": "sha512-EqYpWyTF2s8nMfttfBA2yLKPNoZCO33pLS4MnbXQ4hECf1TKujCt1Kq7QAdrio7roL4+CqsfjqwYj4tYgq0pJQ==", 940 | "engines": { 941 | "node": ">=12.0.0" 942 | } 943 | }, 944 | "node_modules/html-encoding-sniffer": { 945 | "version": "3.0.0", 946 | "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", 947 | "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", 948 | "dependencies": { 949 | "whatwg-encoding": "^2.0.0" 950 | }, 951 | "engines": { 952 | "node": ">=12" 953 | } 954 | }, 955 | "node_modules/html-escape": { 956 | "version": "1.0.2", 957 | "resolved": "https://registry.npmjs.org/html-escape/-/html-escape-1.0.2.tgz", 958 | "integrity": "sha512-r4cqVc7QAX1/jpPsW9OJNsTTtFhcf+ZBqoA3rWOddMg/y+n6ElKfz+IGKbvV2RTeECDzyrQXa2rpo3IFFrANWg==" 959 | }, 960 | "node_modules/http-proxy-agent": { 961 | "version": "5.0.0", 962 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", 963 | "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", 964 | "dependencies": { 965 | "@tootallnate/once": "2", 966 | "agent-base": "6", 967 | "debug": "4" 968 | }, 969 | "engines": { 970 | "node": ">= 6" 971 | } 972 | }, 973 | "node_modules/https-proxy-agent": { 974 | "version": "5.0.1", 975 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", 976 | "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", 977 | "dependencies": { 978 | "agent-base": "6", 979 | "debug": "4" 980 | }, 981 | "engines": { 982 | "node": ">= 6" 983 | } 984 | }, 985 | "node_modules/iconv-lite": { 986 | "version": "0.6.3", 987 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 988 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 989 | "dependencies": { 990 | "safer-buffer": ">= 2.1.2 < 3.0.0" 991 | }, 992 | "engines": { 993 | "node": ">=0.10.0" 994 | } 995 | }, 996 | "node_modules/is-extglob": { 997 | "version": "2.1.1", 998 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 999 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1000 | "engines": { 1001 | "node": ">=0.10.0" 1002 | } 1003 | }, 1004 | "node_modules/is-glob": { 1005 | "version": "4.0.3", 1006 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1007 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1008 | "dependencies": { 1009 | "is-extglob": "^2.1.1" 1010 | }, 1011 | "engines": { 1012 | "node": ">=0.10.0" 1013 | } 1014 | }, 1015 | "node_modules/is-number": { 1016 | "version": "7.0.0", 1017 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1018 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1019 | "engines": { 1020 | "node": ">=0.12.0" 1021 | } 1022 | }, 1023 | "node_modules/is-potential-custom-element-name": { 1024 | "version": "1.0.1", 1025 | "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", 1026 | "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" 1027 | }, 1028 | "node_modules/js-tokens": { 1029 | "version": "4.0.0", 1030 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1031 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 1032 | }, 1033 | "node_modules/js-yaml": { 1034 | "version": "3.14.1", 1035 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", 1036 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", 1037 | "dependencies": { 1038 | "argparse": "^1.0.7", 1039 | "esprima": "^4.0.0" 1040 | }, 1041 | "bin": { 1042 | "js-yaml": "bin/js-yaml.js" 1043 | } 1044 | }, 1045 | "node_modules/jsdom": { 1046 | "version": "21.1.1", 1047 | "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-21.1.1.tgz", 1048 | "integrity": "sha512-Jjgdmw48RKcdAIQyUD1UdBh2ecH7VqwaXPN3ehoZN6MqgVbMn+lRm1aAT1AsdJRAJpwfa4IpwgzySn61h2qu3w==", 1049 | "dependencies": { 1050 | "abab": "^2.0.6", 1051 | "acorn": "^8.8.2", 1052 | "acorn-globals": "^7.0.0", 1053 | "cssstyle": "^3.0.0", 1054 | "data-urls": "^4.0.0", 1055 | "decimal.js": "^10.4.3", 1056 | "domexception": "^4.0.0", 1057 | "escodegen": "^2.0.0", 1058 | "form-data": "^4.0.0", 1059 | "html-encoding-sniffer": "^3.0.0", 1060 | "http-proxy-agent": "^5.0.0", 1061 | "https-proxy-agent": "^5.0.1", 1062 | "is-potential-custom-element-name": "^1.0.1", 1063 | "nwsapi": "^2.2.2", 1064 | "parse5": "^7.1.2", 1065 | "rrweb-cssom": "^0.6.0", 1066 | "saxes": "^6.0.0", 1067 | "symbol-tree": "^3.2.4", 1068 | "tough-cookie": "^4.1.2", 1069 | "w3c-xmlserializer": "^4.0.0", 1070 | "webidl-conversions": "^7.0.0", 1071 | "whatwg-encoding": "^2.0.0", 1072 | "whatwg-mimetype": "^3.0.0", 1073 | "whatwg-url": "^12.0.1", 1074 | "ws": "^8.13.0", 1075 | "xml-name-validator": "^4.0.0" 1076 | }, 1077 | "engines": { 1078 | "node": ">=14" 1079 | }, 1080 | "peerDependencies": { 1081 | "canvas": "^2.5.0" 1082 | }, 1083 | "peerDependenciesMeta": { 1084 | "canvas": { 1085 | "optional": true 1086 | } 1087 | } 1088 | }, 1089 | "node_modules/lodash.camelcase": { 1090 | "version": "4.3.0", 1091 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", 1092 | "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" 1093 | }, 1094 | "node_modules/merge2": { 1095 | "version": "1.4.1", 1096 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 1097 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 1098 | "engines": { 1099 | "node": ">= 8" 1100 | } 1101 | }, 1102 | "node_modules/micromatch": { 1103 | "version": "4.0.5", 1104 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 1105 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 1106 | "dependencies": { 1107 | "braces": "^3.0.2", 1108 | "picomatch": "^2.3.1" 1109 | }, 1110 | "engines": { 1111 | "node": ">=8.6" 1112 | } 1113 | }, 1114 | "node_modules/mime-db": { 1115 | "version": "1.52.0", 1116 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1117 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 1118 | "engines": { 1119 | "node": ">= 0.6" 1120 | } 1121 | }, 1122 | "node_modules/mime-types": { 1123 | "version": "2.1.35", 1124 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1125 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1126 | "dependencies": { 1127 | "mime-db": "1.52.0" 1128 | }, 1129 | "engines": { 1130 | "node": ">= 0.6" 1131 | } 1132 | }, 1133 | "node_modules/ms": { 1134 | "version": "2.1.2", 1135 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1136 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 1137 | }, 1138 | "node_modules/nwsapi": { 1139 | "version": "2.2.2", 1140 | "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", 1141 | "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==" 1142 | }, 1143 | "node_modules/parse5": { 1144 | "version": "7.1.2", 1145 | "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", 1146 | "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", 1147 | "dependencies": { 1148 | "entities": "^4.4.0" 1149 | }, 1150 | "funding": { 1151 | "url": "https://github.com/inikulin/parse5?sponsor=1" 1152 | } 1153 | }, 1154 | "node_modules/picomatch": { 1155 | "version": "2.3.1", 1156 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1157 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1158 | "engines": { 1159 | "node": ">=8.6" 1160 | }, 1161 | "funding": { 1162 | "url": "https://github.com/sponsors/jonschlinkert" 1163 | } 1164 | }, 1165 | "node_modules/prex": { 1166 | "version": "0.4.9", 1167 | "resolved": "https://registry.npmjs.org/prex/-/prex-0.4.9.tgz", 1168 | "integrity": "sha512-pQCB9AH8MXQRBaelDkhnTkqY6GRiXt1xWlx2hBReZYZwVA0m7EQcnF/K55zr87cCADDHmdD+qq7G6a8Pu+BRFA==", 1169 | "deprecated": "This package has been deprecated in favor of several '@esfx/*' packages that replace it. Please see the README for more information", 1170 | "dependencies": { 1171 | "@esfx/cancelable": "^1.0.0 || >=1.0.0-pre.13", 1172 | "@esfx/disposable": "^1.0.0 || >=1.0.0-pre.13" 1173 | } 1174 | }, 1175 | "node_modules/prismjs": { 1176 | "version": "1.29.0", 1177 | "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", 1178 | "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", 1179 | "engines": { 1180 | "node": ">=6" 1181 | } 1182 | }, 1183 | "node_modules/promise-debounce": { 1184 | "version": "1.0.1", 1185 | "resolved": "https://registry.npmjs.org/promise-debounce/-/promise-debounce-1.0.1.tgz", 1186 | "integrity": "sha512-jq3Crngf1DaaOXQIOUkPr7LsW4UsWyn0KW1MJ+yMn5njTJ+F1AuHmjjwJhod9HuoNSSMspSLS9PS3V7BrexwjQ==" 1187 | }, 1188 | "node_modules/psl": { 1189 | "version": "1.9.0", 1190 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", 1191 | "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" 1192 | }, 1193 | "node_modules/punycode": { 1194 | "version": "2.3.0", 1195 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", 1196 | "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", 1197 | "engines": { 1198 | "node": ">=6" 1199 | } 1200 | }, 1201 | "node_modules/querystringify": { 1202 | "version": "2.2.0", 1203 | "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", 1204 | "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" 1205 | }, 1206 | "node_modules/queue-microtask": { 1207 | "version": "1.2.3", 1208 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1209 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1210 | "funding": [ 1211 | { 1212 | "type": "github", 1213 | "url": "https://github.com/sponsors/feross" 1214 | }, 1215 | { 1216 | "type": "patreon", 1217 | "url": "https://www.patreon.com/feross" 1218 | }, 1219 | { 1220 | "type": "consulting", 1221 | "url": "https://feross.org/support" 1222 | } 1223 | ] 1224 | }, 1225 | "node_modules/reduce-flatten": { 1226 | "version": "2.0.0", 1227 | "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", 1228 | "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", 1229 | "engines": { 1230 | "node": ">=6" 1231 | } 1232 | }, 1233 | "node_modules/requires-port": { 1234 | "version": "1.0.0", 1235 | "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", 1236 | "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" 1237 | }, 1238 | "node_modules/reusify": { 1239 | "version": "1.0.4", 1240 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1241 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1242 | "engines": { 1243 | "iojs": ">=1.0.0", 1244 | "node": ">=0.10.0" 1245 | } 1246 | }, 1247 | "node_modules/rrweb-cssom": { 1248 | "version": "0.6.0", 1249 | "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", 1250 | "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==" 1251 | }, 1252 | "node_modules/run-parallel": { 1253 | "version": "1.2.0", 1254 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1255 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1256 | "funding": [ 1257 | { 1258 | "type": "github", 1259 | "url": "https://github.com/sponsors/feross" 1260 | }, 1261 | { 1262 | "type": "patreon", 1263 | "url": "https://www.patreon.com/feross" 1264 | }, 1265 | { 1266 | "type": "consulting", 1267 | "url": "https://feross.org/support" 1268 | } 1269 | ], 1270 | "dependencies": { 1271 | "queue-microtask": "^1.2.2" 1272 | } 1273 | }, 1274 | "node_modules/safer-buffer": { 1275 | "version": "2.1.2", 1276 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1277 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1278 | }, 1279 | "node_modules/saxes": { 1280 | "version": "6.0.0", 1281 | "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", 1282 | "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", 1283 | "dependencies": { 1284 | "xmlchars": "^2.2.0" 1285 | }, 1286 | "engines": { 1287 | "node": ">=v12.22.7" 1288 | } 1289 | }, 1290 | "node_modules/source-map": { 1291 | "version": "0.6.1", 1292 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1293 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1294 | "optional": true, 1295 | "engines": { 1296 | "node": ">=0.10.0" 1297 | } 1298 | }, 1299 | "node_modules/sprintf-js": { 1300 | "version": "1.0.3", 1301 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1302 | "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" 1303 | }, 1304 | "node_modules/supports-color": { 1305 | "version": "7.2.0", 1306 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1307 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1308 | "dependencies": { 1309 | "has-flag": "^4.0.0" 1310 | }, 1311 | "engines": { 1312 | "node": ">=8" 1313 | } 1314 | }, 1315 | "node_modules/symbol-tree": { 1316 | "version": "3.2.4", 1317 | "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", 1318 | "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" 1319 | }, 1320 | "node_modules/table-layout": { 1321 | "version": "1.0.2", 1322 | "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", 1323 | "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", 1324 | "dependencies": { 1325 | "array-back": "^4.0.1", 1326 | "deep-extend": "~0.6.0", 1327 | "typical": "^5.2.0", 1328 | "wordwrapjs": "^4.0.0" 1329 | }, 1330 | "engines": { 1331 | "node": ">=8.0.0" 1332 | } 1333 | }, 1334 | "node_modules/table-layout/node_modules/array-back": { 1335 | "version": "4.0.2", 1336 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", 1337 | "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", 1338 | "engines": { 1339 | "node": ">=8" 1340 | } 1341 | }, 1342 | "node_modules/table-layout/node_modules/typical": { 1343 | "version": "5.2.0", 1344 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 1345 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", 1346 | "engines": { 1347 | "node": ">=8" 1348 | } 1349 | }, 1350 | "node_modules/to-regex-range": { 1351 | "version": "5.0.1", 1352 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1353 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1354 | "dependencies": { 1355 | "is-number": "^7.0.0" 1356 | }, 1357 | "engines": { 1358 | "node": ">=8.0" 1359 | } 1360 | }, 1361 | "node_modules/tough-cookie": { 1362 | "version": "4.1.2", 1363 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", 1364 | "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", 1365 | "dependencies": { 1366 | "psl": "^1.1.33", 1367 | "punycode": "^2.1.1", 1368 | "universalify": "^0.2.0", 1369 | "url-parse": "^1.5.3" 1370 | }, 1371 | "engines": { 1372 | "node": ">=6" 1373 | } 1374 | }, 1375 | "node_modules/tr46": { 1376 | "version": "4.1.1", 1377 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", 1378 | "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", 1379 | "dependencies": { 1380 | "punycode": "^2.3.0" 1381 | }, 1382 | "engines": { 1383 | "node": ">=14" 1384 | } 1385 | }, 1386 | "node_modules/tslib": { 1387 | "version": "2.5.0", 1388 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", 1389 | "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" 1390 | }, 1391 | "node_modules/typical": { 1392 | "version": "4.0.0", 1393 | "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", 1394 | "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", 1395 | "engines": { 1396 | "node": ">=8" 1397 | } 1398 | }, 1399 | "node_modules/universalify": { 1400 | "version": "0.2.0", 1401 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", 1402 | "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", 1403 | "engines": { 1404 | "node": ">= 4.0.0" 1405 | } 1406 | }, 1407 | "node_modules/url-parse": { 1408 | "version": "1.5.10", 1409 | "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", 1410 | "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", 1411 | "dependencies": { 1412 | "querystringify": "^2.1.1", 1413 | "requires-port": "^1.0.0" 1414 | } 1415 | }, 1416 | "node_modules/w3c-hr-time": { 1417 | "version": "1.0.2", 1418 | "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", 1419 | "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", 1420 | "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", 1421 | "dependencies": { 1422 | "browser-process-hrtime": "^1.0.0" 1423 | } 1424 | }, 1425 | "node_modules/w3c-xmlserializer": { 1426 | "version": "4.0.0", 1427 | "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", 1428 | "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", 1429 | "dependencies": { 1430 | "xml-name-validator": "^4.0.0" 1431 | }, 1432 | "engines": { 1433 | "node": ">=14" 1434 | } 1435 | }, 1436 | "node_modules/webidl-conversions": { 1437 | "version": "7.0.0", 1438 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", 1439 | "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", 1440 | "engines": { 1441 | "node": ">=12" 1442 | } 1443 | }, 1444 | "node_modules/whatwg-encoding": { 1445 | "version": "2.0.0", 1446 | "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", 1447 | "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", 1448 | "dependencies": { 1449 | "iconv-lite": "0.6.3" 1450 | }, 1451 | "engines": { 1452 | "node": ">=12" 1453 | } 1454 | }, 1455 | "node_modules/whatwg-mimetype": { 1456 | "version": "3.0.0", 1457 | "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", 1458 | "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", 1459 | "engines": { 1460 | "node": ">=12" 1461 | } 1462 | }, 1463 | "node_modules/whatwg-url": { 1464 | "version": "12.0.1", 1465 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", 1466 | "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", 1467 | "dependencies": { 1468 | "tr46": "^4.1.1", 1469 | "webidl-conversions": "^7.0.0" 1470 | }, 1471 | "engines": { 1472 | "node": ">=14" 1473 | } 1474 | }, 1475 | "node_modules/word-wrap": { 1476 | "version": "1.2.3", 1477 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", 1478 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 1479 | "engines": { 1480 | "node": ">=0.10.0" 1481 | } 1482 | }, 1483 | "node_modules/wordwrapjs": { 1484 | "version": "4.0.1", 1485 | "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", 1486 | "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", 1487 | "dependencies": { 1488 | "reduce-flatten": "^2.0.0", 1489 | "typical": "^5.2.0" 1490 | }, 1491 | "engines": { 1492 | "node": ">=8.0.0" 1493 | } 1494 | }, 1495 | "node_modules/wordwrapjs/node_modules/typical": { 1496 | "version": "5.2.0", 1497 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 1498 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", 1499 | "engines": { 1500 | "node": ">=8" 1501 | } 1502 | }, 1503 | "node_modules/ws": { 1504 | "version": "8.13.0", 1505 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", 1506 | "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", 1507 | "engines": { 1508 | "node": ">=10.0.0" 1509 | }, 1510 | "peerDependencies": { 1511 | "bufferutil": "^4.0.1", 1512 | "utf-8-validate": ">=5.0.2" 1513 | }, 1514 | "peerDependenciesMeta": { 1515 | "bufferutil": { 1516 | "optional": true 1517 | }, 1518 | "utf-8-validate": { 1519 | "optional": true 1520 | } 1521 | } 1522 | }, 1523 | "node_modules/xml-name-validator": { 1524 | "version": "4.0.0", 1525 | "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", 1526 | "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", 1527 | "engines": { 1528 | "node": ">=12" 1529 | } 1530 | }, 1531 | "node_modules/xmlchars": { 1532 | "version": "2.2.0", 1533 | "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", 1534 | "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" 1535 | } 1536 | } 1537 | } 1538 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "proposal-arraybuffer-base64", 4 | "scripts": { 5 | "build-playground": "mkdir -p dist && cp playground/* dist && node scripts/static-highlight.js playground/index-raw.html > dist/index.html && rm dist/index-raw.html", 6 | "build-spec": "mkdir -p dist/spec && ecmarkup --lint-spec --strict --load-biblio @tc39/ecma262-biblio --verbose --mark-effects spec.html --assets-dir dist/spec dist/spec/index.html", 7 | "build": "npm run build-playground && npm run build-spec", 8 | "format": "emu-format --write spec.html", 9 | "check-format": "emu-format --check spec.html", 10 | "test": "node --test" 11 | }, 12 | "dependencies": { 13 | "@tc39/ecma262-biblio": "2.1.2672", 14 | "ecmarkup": "^18.0.0", 15 | "jsdom": "^21.1.1", 16 | "prismjs": "^1.29.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /playground/index-raw.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |This page documents a stage 3 proposal for native base64 and hex encoding and decoding for binary data in JavaScript, and includes a non-production polyfill you can experiment with in the browser's console.
53 |The proposal would provide methods for encoding and decoding Uint8Arrays as base64 and hex strings.
54 |Feedback on the proposal's repository is appreciated.
55 |Specification text for the proposal is available here.
56 | 57 |Encoding a Uint8Array to a base64 string:
60 |
61 | let arr = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]);
62 | console.log(arr.toBase64());
63 | // 'SGVsbG8gV29ybGQ='
64 |
65 |
66 | Decoding a base64 string to a Uint8Array:
67 |
68 | let string = 'SGVsbG8gV29ybGQ=';
69 | console.log(Uint8Array.fromBase64(string));
70 | // Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100])
71 |
72 |
73 | Encoding a Uint8Array to a hex string:
74 |
75 | let arr = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]);
76 | console.log(arr.toHex());
77 | // '48656c6c6f20576f726c64'
78 |
79 |
80 | Decoding a hex string to a Uint8Array:
81 |
82 | let string = '48656c6c6f20576f726c64';
83 | console.log(Uint8Array.fromHex(string));
84 | // Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100])
85 |
86 |
87 | The base64 methods take an optional options bag which allows specifying the alphabet as either "base64"
(the default) or "base64url"
(the URL-safe variant).
The base64 decoder also allows specifying the behavior for the final chunk with lastChunkHandling
. Recall that base64 decoding operates on chunks of 4 characters at a time, but the input may have some characters which don't fit evenly into such a chunk of 4 characters. This option determines how the final chunk of characters should be handled. The three options are "loose"
(the default), which treats the chunk as if it had any necessary =
padding (but throws if this is not possible, i.e. there is exactly one extra character); "strict"
, which enforces that the chunk has exactly 4 characters (counting =
padding) and that overflow bits are 0; and "stop-before-partial"
, which stops decoding before the final chunk unless the final chunk has exactly 4 characters.
The base64 encoder allows omitting padding by specifying omitPadding: true
. The default is to include padding.
The hex methods do not have any options.
92 | 93 |
94 | let array = new Uint8Array([251, 255, 191]);
95 | console.log(array.toBase64({ alphabet: 'base64' }));
96 | // '+/+/'
97 | console.log(array.toBase64({ alphabet: 'base64url' }));
98 | // '-_-_'
99 |
100 | console.log(Uint8Array.fromBase64('SGVsbG8g\nV29ybG R'));
101 | // works, despite whitespace, missing padding, and non-zero overflow bits
102 |
103 | try {
104 | Uint8Array.fromBase64('SGVsbG8gV29ybGR=', { lastChunkHandling: 'strict' });
105 | } catch {
106 | console.log('with lastChunkHandling: "strict", overflow bits are rejected');
107 | }
108 | try {
109 | Uint8Array.fromBase64('SGVsbG8gV29ybGQ', { lastChunkHandling: 'strict' });
110 | } catch {
111 | console.log('with lastChunkHandling: "strict", overflow bits are rejected');
112 | }
113 |
114 | console.log((new Uint8Array([72])).toBase64()); // 'SA=='
115 | console.log((new Uint8Array([72])).toBase64({ omitPadding: true })); // 'SA'
116 |
117 |
118 | The Uint8Array.prototype.setFromBase64
method allows writing to an existing Uint8Array. Like the TextEncoder encodeInto
method, it returns a { read, written }
pair.
This method takes an optional final options bag with the same options as above.
122 | 123 |
124 | let target = new Uint8Array(7);
125 | let { read, written } = target.setFromBase64('Zm9vYmFy');
126 | console.log({ target, read, written });
127 | // { target: Uint8Array([102, 111, 111, 98, 97, 114, 0]), read: 8, written: 6 }
128 |
129 |
130 | Uint8Array.prototype.setFromHex
is the same except for hex.
133 | let target = new Uint8Array(6);
134 | let { read, written } = target.setFromHex('deadbeef');
135 | console.log({ target, read, written });
136 | // { target: Uint8Array([222, 173, 190, 239, 0, 0]), read: 8, written: 4 }
137 |
138 |
139 | There is no support for streaming. However, it can be implemented in userland.
141 | 142 | 145 | -------------------------------------------------------------------------------- /playground/polyfill-core.mjs: -------------------------------------------------------------------------------- 1 | let base64Characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 2 | let base64UrlCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; 3 | 4 | let tag = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Uint8Array.prototype), Symbol.toStringTag).get; 5 | export function checkUint8Array(arg) { 6 | let kind; 7 | try { 8 | kind = tag.call(arg); 9 | } catch { 10 | throw new TypeError('not a Uint8Array'); 11 | } 12 | if (kind !== 'Uint8Array') { 13 | throw new TypeError('not a Uint8Array'); 14 | } 15 | } 16 | 17 | function assert(condition, message) { 18 | if (!condition) { 19 | throw new Error(`Assert failed: ${message}`); 20 | } 21 | } 22 | 23 | function getOptions(options) { 24 | if (typeof options === 'undefined') { 25 | return Object.create(null); 26 | } 27 | if (options && typeof options === 'object') { 28 | return options; 29 | } 30 | throw new TypeError('options is not object'); 31 | } 32 | 33 | export function uint8ArrayToBase64(arr, options) { 34 | checkUint8Array(arr); 35 | let opts = getOptions(options); 36 | let alphabet = opts.alphabet; 37 | if (typeof alphabet === 'undefined') { 38 | alphabet = 'base64'; 39 | } 40 | if (alphabet !== 'base64' && alphabet !== 'base64url') { 41 | throw new TypeError('expected alphabet to be either "base64" or "base64url"'); 42 | } 43 | let omitPadding = !!opts.omitPadding; 44 | 45 | if ('detached' in arr.buffer && arr.buffer.detached) { 46 | throw new TypeError('toBase64 called on array backed by detached buffer'); 47 | } 48 | 49 | let lookup = alphabet === 'base64' ? base64Characters : base64UrlCharacters; 50 | let result = ''; 51 | 52 | let i = 0; 53 | for (; i + 2 < arr.length; i += 3) { 54 | let triplet = (arr[i] << 16) + (arr[i + 1] << 8) + arr[i + 2]; 55 | result += 56 | lookup[(triplet >> 18) & 63] + 57 | lookup[(triplet >> 12) & 63] + 58 | lookup[(triplet >> 6) & 63] + 59 | lookup[triplet & 63]; 60 | } 61 | if (i + 2 === arr.length) { 62 | let triplet = (arr[i] << 16) + (arr[i + 1] << 8); 63 | result += 64 | lookup[(triplet >> 18) & 63] + 65 | lookup[(triplet >> 12) & 63] + 66 | lookup[(triplet >> 6) & 63] + 67 | (omitPadding ? '' : '='); 68 | } else if (i + 1 === arr.length) { 69 | let triplet = arr[i] << 16; 70 | result += 71 | lookup[(triplet >> 18) & 63] + 72 | lookup[(triplet >> 12) & 63] + 73 | (omitPadding ? '' : '=='); 74 | } 75 | return result; 76 | } 77 | 78 | function decodeBase64Chunk(chunk, throwOnExtraBits) { 79 | let actualChunkLength = chunk.length; 80 | if (actualChunkLength < 4) { 81 | chunk += actualChunkLength === 2 ? 'AA' : 'A'; 82 | } 83 | 84 | let map = new Map(base64Characters.split('').map((c, i) => [c, i])); 85 | 86 | let c1 = chunk[0]; 87 | let c2 = chunk[1]; 88 | let c3 = chunk[2]; 89 | let c4 = chunk[3]; 90 | 91 | let triplet = 92 | (map.get(c1) << 18) + 93 | (map.get(c2) << 12) + 94 | (map.get(c3) << 6) + 95 | map.get(c4); 96 | 97 | let chunkBytes = [ 98 | (triplet >> 16) & 255, 99 | (triplet >> 8) & 255, 100 | triplet & 255 101 | ]; 102 | 103 | if (actualChunkLength === 2) { 104 | if (throwOnExtraBits && chunkBytes[1] !== 0) { 105 | throw new SyntaxError('extra bits'); 106 | } 107 | return [chunkBytes[0]]; 108 | } else if (actualChunkLength === 3) { 109 | if (throwOnExtraBits && chunkBytes[2] !== 0) { 110 | throw new SyntaxError('extra bits'); 111 | } 112 | return [chunkBytes[0], chunkBytes[1]]; 113 | } 114 | return chunkBytes; 115 | } 116 | 117 | function skipAsciiWhitespace(string, index) { 118 | for (; index < string.length; ++index) { 119 | if (!/[\u0009\u000A\u000C\u000D\u0020]/.test(string[index])) { 120 | break; 121 | } 122 | } 123 | return index; 124 | } 125 | 126 | function fromBase64(string, alphabet, lastChunkHandling, maxLength) { 127 | if (maxLength === 0) { 128 | return { read: 0, bytes: [], error: null }; 129 | } 130 | 131 | let read = 0; 132 | let bytes = []; 133 | let chunk = ''; 134 | 135 | let index = 0 136 | while (true) { 137 | index = skipAsciiWhitespace(string, index); 138 | if (index === string.length) { 139 | if (chunk.length > 0) { 140 | if (lastChunkHandling === 'stop-before-partial') { 141 | return { bytes, read, error: null }; 142 | } else if (lastChunkHandling === 'loose') { 143 | if (chunk.length === 1) { 144 | let error = new SyntaxError('malformed padding: exactly one additional character'); 145 | return { bytes, read, error }; 146 | } 147 | bytes.push(...decodeBase64Chunk(chunk, false)); 148 | } else { 149 | assert(lastChunkHandling === 'strict'); 150 | let error = new SyntaxError('missing padding'); 151 | return { bytes, read, error }; 152 | } 153 | } 154 | return { bytes, read: string.length, error: null }; 155 | } 156 | let char = string[index]; 157 | ++index; 158 | if (char === '=') { 159 | if (chunk.length < 2) { 160 | let error = new SyntaxError('padding is too early'); 161 | return { bytes, read, error }; 162 | } 163 | index = skipAsciiWhitespace(string, index); 164 | if (chunk.length === 2) { 165 | if (index === string.length) { 166 | if (lastChunkHandling === 'stop-before-partial') { 167 | // two characters then `=` then EOS: this is, technically, a partial chunk 168 | return { bytes, read, error: null }; 169 | } 170 | let error = new SyntaxError('malformed padding - only one ='); 171 | return { bytes, read, error }; 172 | } 173 | if (string[index] === '=') { 174 | ++index; 175 | index = skipAsciiWhitespace(string, index); 176 | } 177 | } 178 | if (index < string.length) { 179 | let error = new SyntaxError('unexpected character after padding'); 180 | return { bytes, read, error }; 181 | } 182 | bytes.push(...decodeBase64Chunk(chunk, lastChunkHandling === 'strict')); 183 | assert(bytes.length <= maxLength); 184 | return { bytes, read: string.length, error: null }; 185 | } 186 | if (alphabet === 'base64url') { 187 | if (char === '+' || char === '/') { 188 | let error = new SyntaxError(`unexpected character ${JSON.stringify(char)}`); 189 | return { bytes, read, error }; 190 | } else if (char === '-') { 191 | char = '+'; 192 | } else if (char === '_') { 193 | char = '/'; 194 | } 195 | } 196 | if (!base64Characters.includes(char)) { 197 | let error = new SyntaxError(`unexpected character ${JSON.stringify(char)}`); 198 | return { bytes, read, error }; 199 | } 200 | let remainingBytes = maxLength - bytes.length; 201 | if (remainingBytes === 1 && chunk.length === 2 || remainingBytes === 2 && chunk.length === 3) { 202 | // special case: we can fit exactly the number of bytes currently represented by chunk, so we were just checking for `=` 203 | return { bytes, read, error: null }; 204 | } 205 | 206 | chunk += char; 207 | if (chunk.length === 4) { 208 | bytes.push(...decodeBase64Chunk(chunk, false)); 209 | chunk = ''; 210 | read = index; 211 | assert(bytes.length <= maxLength); 212 | if (bytes.length === maxLength) { 213 | return { bytes, read, error: null }; 214 | } 215 | } 216 | } 217 | } 218 | 219 | export function base64ToUint8Array(string, options, into) { 220 | let opts = getOptions(options); 221 | let alphabet = opts.alphabet; 222 | if (typeof alphabet === 'undefined') { 223 | alphabet = 'base64'; 224 | } 225 | if (alphabet !== 'base64' && alphabet !== 'base64url') { 226 | throw new TypeError('expected alphabet to be either "base64" or "base64url"'); 227 | } 228 | let lastChunkHandling = opts.lastChunkHandling; 229 | if (typeof lastChunkHandling === 'undefined') { 230 | lastChunkHandling = 'loose'; 231 | } 232 | if (!['loose', 'strict', 'stop-before-partial'].includes(lastChunkHandling)) { 233 | throw new TypeError('expected lastChunkHandling to be either "loose", "strict", or "stop-before-partial"'); 234 | } 235 | if (into && 'detached' in into.buffer && into.buffer.detached) { 236 | throw new TypeError('toBase64Into called on array backed by detached buffer'); 237 | } 238 | 239 | let maxLength = into ? into.length : 2 ** 53 - 1; 240 | 241 | let { bytes, read, error } = fromBase64(string, alphabet, lastChunkHandling, maxLength); 242 | if (error && !into) { 243 | throw error; 244 | } 245 | 246 | bytes = new Uint8Array(bytes); 247 | if (into && bytes.length > 0) { 248 | assert(bytes.length <= into.length); 249 | into.set(bytes); 250 | } 251 | 252 | if (error) { 253 | throw error; 254 | } 255 | 256 | return { read, bytes }; 257 | } 258 | 259 | export function uint8ArrayToHex(arr) { 260 | checkUint8Array(arr); 261 | if ('detached' in arr.buffer && arr.buffer.detached) { 262 | throw new TypeError('toHex called on array backed by detached buffer'); 263 | } 264 | let out = ''; 265 | for (let i = 0; i < arr.length; ++i) { 266 | out += arr[i].toString(16).padStart(2, '0'); 267 | } 268 | return out; 269 | } 270 | 271 | function fromHex(string, maxLength) { 272 | let bytes = []; 273 | let read = 0; 274 | if (maxLength > 0) { 275 | while (read < string.length) { 276 | let hexits = string.slice(read, read + 2); 277 | if (/[^0-9a-fA-F]/.test(hexits)) { 278 | let error = new SyntaxError('string should only contain hex characters'); 279 | return { read, bytes, error } 280 | } 281 | bytes.push(parseInt(hexits, 16)); 282 | read += 2; 283 | if (bytes.length === maxLength) { 284 | break; 285 | } 286 | } 287 | } 288 | return { read, bytes, error: null } 289 | } 290 | 291 | export function hexToUint8Array(string, into) { 292 | if (typeof string !== 'string') { 293 | throw new TypeError('expected string to be a string'); 294 | } 295 | if (into && 'detached' in into.buffer && into.buffer.detached) { 296 | throw new TypeError('fromHexInto called on array backed by detached buffer'); 297 | } 298 | if (string.length % 2 !== 0) { 299 | throw new SyntaxError('string should be an even number of characters'); 300 | } 301 | 302 | let maxLength = into ? into.length : 2 ** 53 - 1; 303 | let { read, bytes, error } = fromHex(string, maxLength); 304 | if (error && !into) { 305 | throw error; 306 | } 307 | 308 | bytes = new Uint8Array(bytes); 309 | if (into && bytes.length > 0) { 310 | assert(bytes.length <= into.length); 311 | into.set(bytes); 312 | } 313 | 314 | if (error) { 315 | throw error; 316 | } 317 | 318 | return { read, bytes }; 319 | } 320 | -------------------------------------------------------------------------------- /playground/polyfill-install.mjs: -------------------------------------------------------------------------------- 1 | import { uint8ArrayToBase64, base64ToUint8Array, uint8ArrayToHex, hexToUint8Array, checkUint8Array } from './polyfill-core.mjs'; 2 | 3 | // method shenanigans to make a non-constructor which can refer to "this" 4 | Uint8Array.prototype.toBase64 = { 5 | toBase64(options) { 6 | return uint8ArrayToBase64(this, options); 7 | } 8 | }.toBase64; 9 | Object.defineProperty(Uint8Array.prototype, 'toBase64', { enumerable: false }); 10 | Object.defineProperty(Uint8Array.prototype.toBase64, 'length', { value: 0 }); 11 | 12 | Uint8Array.fromBase64 = (string, options) => { 13 | if (typeof string !== 'string') { 14 | throw new TypeError('expected input to be a string'); 15 | } 16 | return base64ToUint8Array(string, options).bytes; 17 | }; 18 | Object.defineProperty(Uint8Array, 'fromBase64', { enumerable: false }); 19 | Object.defineProperty(Uint8Array.fromBase64, 'length', { value: 1 }); 20 | Object.defineProperty(Uint8Array.fromBase64, 'name', { value: 'fromBase64' }); 21 | 22 | // method shenanigans to make a non-constructor which can refer to "this" 23 | Uint8Array.prototype.setFromBase64 = { 24 | setFromBase64(string, options) { 25 | checkUint8Array(this); 26 | if (typeof string !== 'string') { 27 | throw new TypeError('expected input to be a string'); 28 | } 29 | let { read, bytes } = base64ToUint8Array(string, options, this); 30 | return { read, written: bytes.length }; 31 | } 32 | }.setFromBase64; 33 | Object.defineProperty(Uint8Array.prototype, 'setFromBase64', { enumerable: false }); 34 | Object.defineProperty(Uint8Array.prototype.setFromBase64, 'length', { value: 1 }); 35 | 36 | Uint8Array.prototype.toHex = { 37 | toHex() { 38 | return uint8ArrayToHex(this); 39 | } 40 | }.toHex; 41 | Object.defineProperty(Uint8Array.prototype, 'toHex', { enumerable: false }); 42 | 43 | Uint8Array.fromHex = (string) => { 44 | if (typeof string !== 'string') { 45 | throw new TypeError('expected input to be a string'); 46 | } 47 | return hexToUint8Array(string).bytes; 48 | }; 49 | Object.defineProperty(Uint8Array, 'fromHex', { enumerable: false }); 50 | Object.defineProperty(Uint8Array.fromHex, 'name', { value: 'fromHex' }); 51 | 52 | Uint8Array.prototype.setFromHex = { 53 | setFromHex(string) { 54 | checkUint8Array(this); 55 | if (typeof string !== 'string') { 56 | throw new TypeError('expected input to be a string'); 57 | } 58 | let { read, bytes } = hexToUint8Array(string, this); 59 | return { read, written: bytes.length }; 60 | } 61 | }.setFromHex; 62 | Object.defineProperty(Uint8Array.prototype, 'setFromHex', { enumerable: false }); 63 | -------------------------------------------------------------------------------- /playground/prism.css: -------------------------------------------------------------------------------- 1 | /* 2 | Prism.js stylesheet - https://prismjs.com/ 3 | 4 | Used under the MIT license 5 | 6 | Copyright (c) 2012 Lea Verou 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | */ 26 | 27 | /** 28 | * prism.js default theme for JavaScript, CSS and HTML 29 | * Based on dabblet (http://dabblet.com) 30 | * @author Lea Verou 31 | */ 32 | 33 | code[class*="language-"], 34 | pre[class*="language-"] { 35 | color: black; 36 | background: none; 37 | text-shadow: 0 1px white; 38 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 39 | font-size: 1em; 40 | text-align: left; 41 | white-space: pre; 42 | word-spacing: normal; 43 | word-break: normal; 44 | word-wrap: normal; 45 | line-height: 1.5; 46 | 47 | -moz-tab-size: 4; 48 | -o-tab-size: 4; 49 | tab-size: 4; 50 | 51 | -webkit-hyphens: none; 52 | -moz-hyphens: none; 53 | -ms-hyphens: none; 54 | hyphens: none; 55 | } 56 | 57 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, 58 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { 59 | text-shadow: none; 60 | background: #b3d4fc; 61 | } 62 | 63 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection, 64 | code[class*="language-"]::selection, code[class*="language-"] ::selection { 65 | text-shadow: none; 66 | background: #b3d4fc; 67 | } 68 | 69 | @media print { 70 | code[class*="language-"], 71 | pre[class*="language-"] { 72 | text-shadow: none; 73 | } 74 | } 75 | 76 | /* Code blocks */ 77 | pre[class*="language-"] { 78 | padding: 1em; 79 | margin: .5em 0; 80 | overflow: auto; 81 | } 82 | 83 | :not(pre) > code[class*="language-"], 84 | pre[class*="language-"] { 85 | background: #f5f2f0; 86 | } 87 | 88 | /* Inline code */ 89 | :not(pre) > code[class*="language-"] { 90 | padding: .1em; 91 | border-radius: .3em; 92 | white-space: normal; 93 | } 94 | 95 | .token.comment, 96 | .token.prolog, 97 | .token.doctype, 98 | .token.cdata { 99 | color: slategray; 100 | } 101 | 102 | .token.punctuation { 103 | color: #999; 104 | } 105 | 106 | .token.namespace { 107 | opacity: .7; 108 | } 109 | 110 | .token.property, 111 | .token.tag, 112 | .token.boolean, 113 | .token.number, 114 | .token.constant, 115 | .token.symbol, 116 | .token.deleted { 117 | color: #905; 118 | } 119 | 120 | .token.selector, 121 | .token.attr-name, 122 | .token.string, 123 | .token.char, 124 | .token.builtin, 125 | .token.inserted { 126 | color: #690; 127 | } 128 | 129 | .token.operator, 130 | .token.entity, 131 | .token.url, 132 | .language-css .token.string, 133 | .style .token.string { 134 | color: #9a6e3a; 135 | /* This background color was intended by the author of this theme. */ 136 | background: hsla(0, 0%, 100%, .5); 137 | } 138 | 139 | .token.atrule, 140 | .token.attr-value, 141 | .token.keyword { 142 | color: #07a; 143 | } 144 | 145 | .token.function, 146 | .token.class-name { 147 | color: #DD4A68; 148 | } 149 | 150 | .token.regex, 151 | .token.important, 152 | .token.variable { 153 | color: #e90; 154 | } 155 | 156 | .token.important, 157 | .token.bold { 158 | font-weight: bold; 159 | } 160 | .token.italic { 161 | font-style: italic; 162 | } 163 | 164 | .token.entity { 165 | cursor: help; 166 | } 167 | -------------------------------------------------------------------------------- /playground/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 18px; 3 | line-height: 1.5; 4 | } 5 | h2 { 6 | border-bottom: 2px solid #999; 7 | margin-top: 2em; 8 | } 9 | pre { border-left: 4px solid #39a33c; } 10 | code { 11 | padding: 1px 5px 2px 5px; 12 | line-height: 1.1; 13 | display: inline-block; 14 | } 15 | a code { color: inherit; } 16 | a code:hover { text-decoration: underline; } 17 | pre code { line-height: 1.4; } 18 | pre code[class*="language-"] { font-size: 0.85em; } 19 | pre[class*="language-"] { 20 | position: relative; 21 | padding: 0.5em; 22 | } 23 | pre[class*="language-"] button { 24 | display: none; 25 | position: absolute; 26 | top: 5px; 27 | right: 5px; 28 | 29 | width: 1.7em; 30 | height: 1.7em; 31 | 32 | font-size: 1em; 33 | padding: 0.15rem; 34 | background-color: transparent; 35 | 36 | border: ridge 1px #7b7b7c; 37 | border-radius: 5px; 38 | } 39 | pre[class*="language-"]:hover button { 40 | display: initial; 41 | } 42 | pre[class*="language-"] button:hover { 43 | cursor: pointer; 44 | } 45 | footer { 46 | border-top: 1px solid var(--background); 47 | color: var(--text-muted); 48 | font-size: 0.8em; 49 | margin-top: 2em; 50 | padding-top: 10px; 51 | } -------------------------------------------------------------------------------- /playground/water-light.css: -------------------------------------------------------------------------------- 1 | /* 2 | Water.css - https://watercss.kognise.dev/ 3 | 4 | Used under the MIT license: 5 | 6 | Copyright © 2019 Kognise 7 | 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: 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 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. 10 | */ 11 | 12 | :root { 13 | --background-body: #fff; 14 | --background: #efefef; 15 | --background-alt: #f7f7f7; 16 | --selection: #9e9e9e; 17 | --text-main: #363636; 18 | --text-bright: #000; 19 | --text-muted: #70777f; 20 | --links: #0076d1; 21 | --focus: #0096bfab; 22 | --border: #dbdbdb; 23 | --code: #000; 24 | --animation-duration: 0.1s; 25 | --button-base: #d0cfcf; 26 | --button-hover: #9b9b9b; 27 | --scrollbar-thumb: rgb(170, 170, 170); 28 | --scrollbar-thumb-hover: var(--button-hover); 29 | --form-placeholder: #949494; 30 | --form-text: #1d1d1d; 31 | --variable: #39a33c; 32 | --highlight: #ff0; 33 | --select-arrow: url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23161f27'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E"); 34 | } 35 | 36 | html { 37 | scrollbar-color: rgb(170, 170, 170) #fff; 38 | scrollbar-color: var(--scrollbar-thumb) var(--background-body); 39 | scrollbar-width: thin; 40 | } 41 | 42 | body { 43 | font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif; 44 | line-height: 1.4; 45 | max-width: 800px; 46 | margin: 20px auto; 47 | padding: 0 10px; 48 | word-wrap: break-word; 49 | color: #363636; 50 | color: var(--text-main); 51 | background: #fff; 52 | background: var(--background-body); 53 | text-rendering: optimizeLegibility; 54 | } 55 | 56 | button { 57 | transition: 58 | background-color 0.1s linear, 59 | border-color 0.1s linear, 60 | color 0.1s linear, 61 | box-shadow 0.1s linear, 62 | transform 0.1s ease; 63 | transition: 64 | background-color var(--animation-duration) linear, 65 | border-color var(--animation-duration) linear, 66 | color var(--animation-duration) linear, 67 | box-shadow var(--animation-duration) linear, 68 | transform var(--animation-duration) ease; 69 | } 70 | 71 | input { 72 | transition: 73 | background-color 0.1s linear, 74 | border-color 0.1s linear, 75 | color 0.1s linear, 76 | box-shadow 0.1s linear, 77 | transform 0.1s ease; 78 | transition: 79 | background-color var(--animation-duration) linear, 80 | border-color var(--animation-duration) linear, 81 | color var(--animation-duration) linear, 82 | box-shadow var(--animation-duration) linear, 83 | transform var(--animation-duration) ease; 84 | } 85 | 86 | textarea { 87 | transition: 88 | background-color 0.1s linear, 89 | border-color 0.1s linear, 90 | color 0.1s linear, 91 | box-shadow 0.1s linear, 92 | transform 0.1s ease; 93 | transition: 94 | background-color var(--animation-duration) linear, 95 | border-color var(--animation-duration) linear, 96 | color var(--animation-duration) linear, 97 | box-shadow var(--animation-duration) linear, 98 | transform var(--animation-duration) ease; 99 | } 100 | 101 | h1 { 102 | font-size: 2.2em; 103 | margin-top: 0; 104 | } 105 | 106 | h1, 107 | h2, 108 | h3, 109 | h4, 110 | h5, 111 | h6 { 112 | margin-bottom: 12px; 113 | margin-top: 24px; 114 | } 115 | 116 | h1 { 117 | color: #000; 118 | color: var(--text-bright); 119 | } 120 | 121 | h2 { 122 | color: #000; 123 | color: var(--text-bright); 124 | } 125 | 126 | h3 { 127 | color: #000; 128 | color: var(--text-bright); 129 | } 130 | 131 | h4 { 132 | color: #000; 133 | color: var(--text-bright); 134 | } 135 | 136 | h5 { 137 | color: #000; 138 | color: var(--text-bright); 139 | } 140 | 141 | h6 { 142 | color: #000; 143 | color: var(--text-bright); 144 | } 145 | 146 | strong { 147 | color: #000; 148 | color: var(--text-bright); 149 | } 150 | 151 | h1, 152 | h2, 153 | h3, 154 | h4, 155 | h5, 156 | h6, 157 | b, 158 | strong, 159 | th { 160 | font-weight: 600; 161 | } 162 | 163 | q::before { 164 | content: none; 165 | } 166 | 167 | q::after { 168 | content: none; 169 | } 170 | 171 | blockquote { 172 | border-left: 4px solid #0096bfab; 173 | border-left: 4px solid var(--focus); 174 | margin: 1.5em 0; 175 | padding: 0.5em 1em; 176 | font-style: italic; 177 | } 178 | 179 | q { 180 | border-left: 4px solid #0096bfab; 181 | border-left: 4px solid var(--focus); 182 | margin: 1.5em 0; 183 | padding: 0.5em 1em; 184 | font-style: italic; 185 | } 186 | 187 | blockquote > footer { 188 | font-style: normal; 189 | border: 0; 190 | } 191 | 192 | blockquote cite { 193 | font-style: normal; 194 | } 195 | 196 | address { 197 | font-style: normal; 198 | } 199 | 200 | a[href^='mailto\:']::before { 201 | content: '📧 '; 202 | } 203 | 204 | a[href^='tel\:']::before { 205 | content: '📞 '; 206 | } 207 | 208 | a[href^='sms\:']::before { 209 | content: '💬 '; 210 | } 211 | 212 | mark { 213 | background-color: #ff0; 214 | background-color: var(--highlight); 215 | border-radius: 2px; 216 | padding: 0 2px 0 2px; 217 | color: #000; 218 | } 219 | 220 | a > code, 221 | a > strong { 222 | color: inherit; 223 | } 224 | 225 | button, 226 | select, 227 | input[type='submit'], 228 | input[type='reset'], 229 | input[type='button'], 230 | input[type='checkbox'], 231 | input[type='range'], 232 | input[type='radio'] { 233 | cursor: pointer; 234 | } 235 | 236 | input, 237 | select { 238 | display: block; 239 | } 240 | 241 | [type='checkbox'], 242 | [type='radio'] { 243 | display: initial; 244 | } 245 | 246 | input { 247 | color: #1d1d1d; 248 | color: var(--form-text); 249 | background-color: #efefef; 250 | background-color: var(--background); 251 | font-family: inherit; 252 | font-size: inherit; 253 | margin-right: 6px; 254 | margin-bottom: 6px; 255 | padding: 10px; 256 | border: none; 257 | border-radius: 6px; 258 | outline: none; 259 | } 260 | 261 | button { 262 | color: #1d1d1d; 263 | color: var(--form-text); 264 | background-color: #efefef; 265 | background-color: var(--background); 266 | font-family: inherit; 267 | font-size: inherit; 268 | margin-right: 6px; 269 | margin-bottom: 6px; 270 | padding: 10px; 271 | border: none; 272 | border-radius: 6px; 273 | outline: none; 274 | } 275 | 276 | textarea { 277 | color: #1d1d1d; 278 | color: var(--form-text); 279 | background-color: #efefef; 280 | background-color: var(--background); 281 | font-family: inherit; 282 | font-size: inherit; 283 | margin-right: 6px; 284 | margin-bottom: 6px; 285 | padding: 10px; 286 | border: none; 287 | border-radius: 6px; 288 | outline: none; 289 | } 290 | 291 | select { 292 | color: #1d1d1d; 293 | color: var(--form-text); 294 | background-color: #efefef; 295 | background-color: var(--background); 296 | font-family: inherit; 297 | font-size: inherit; 298 | margin-right: 6px; 299 | margin-bottom: 6px; 300 | padding: 10px; 301 | border: none; 302 | border-radius: 6px; 303 | outline: none; 304 | } 305 | 306 | button { 307 | background-color: #d0cfcf; 308 | background-color: var(--button-base); 309 | padding-right: 30px; 310 | padding-left: 30px; 311 | } 312 | 313 | input[type='submit'] { 314 | background-color: #d0cfcf; 315 | background-color: var(--button-base); 316 | padding-right: 30px; 317 | padding-left: 30px; 318 | } 319 | 320 | input[type='reset'] { 321 | background-color: #d0cfcf; 322 | background-color: var(--button-base); 323 | padding-right: 30px; 324 | padding-left: 30px; 325 | } 326 | 327 | input[type='button'] { 328 | background-color: #d0cfcf; 329 | background-color: var(--button-base); 330 | padding-right: 30px; 331 | padding-left: 30px; 332 | } 333 | 334 | button:hover { 335 | background: #9b9b9b; 336 | background: var(--button-hover); 337 | } 338 | 339 | input[type='submit']:hover { 340 | background: #9b9b9b; 341 | background: var(--button-hover); 342 | } 343 | 344 | input[type='reset']:hover { 345 | background: #9b9b9b; 346 | background: var(--button-hover); 347 | } 348 | 349 | input[type='button']:hover { 350 | background: #9b9b9b; 351 | background: var(--button-hover); 352 | } 353 | 354 | input[type='color'] { 355 | min-height: 2rem; 356 | padding: 8px; 357 | cursor: pointer; 358 | } 359 | 360 | input[type='checkbox'], 361 | input[type='radio'] { 362 | height: 1em; 363 | width: 1em; 364 | } 365 | 366 | input[type='radio'] { 367 | border-radius: 100%; 368 | } 369 | 370 | input { 371 | vertical-align: top; 372 | } 373 | 374 | label { 375 | vertical-align: middle; 376 | margin-bottom: 4px; 377 | display: inline-block; 378 | } 379 | 380 | input:not([type='checkbox']):not([type='radio']), 381 | input[type='range'], 382 | select, 383 | button, 384 | textarea { 385 | -webkit-appearance: none; 386 | } 387 | 388 | textarea { 389 | display: block; 390 | margin-right: 0; 391 | box-sizing: border-box; 392 | resize: vertical; 393 | } 394 | 395 | textarea:not([cols]) { 396 | width: 100%; 397 | } 398 | 399 | textarea:not([rows]) { 400 | min-height: 40px; 401 | height: 140px; 402 | } 403 | 404 | select { 405 | background: #efefef url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23161f27'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E") calc(100% - 12px) 50% / 12px no-repeat; 406 | background: var(--background) var(--select-arrow) calc(100% - 12px) 50% / 12px no-repeat; 407 | padding-right: 35px; 408 | } 409 | 410 | select::-ms-expand { 411 | display: none; 412 | } 413 | 414 | select[multiple] { 415 | padding-right: 10px; 416 | background-image: none; 417 | overflow-y: auto; 418 | } 419 | 420 | input:focus { 421 | box-shadow: 0 0 0 2px #0096bfab; 422 | box-shadow: 0 0 0 2px var(--focus); 423 | } 424 | 425 | select:focus { 426 | box-shadow: 0 0 0 2px #0096bfab; 427 | box-shadow: 0 0 0 2px var(--focus); 428 | } 429 | 430 | button:focus { 431 | box-shadow: 0 0 0 2px #0096bfab; 432 | box-shadow: 0 0 0 2px var(--focus); 433 | } 434 | 435 | textarea:focus { 436 | box-shadow: 0 0 0 2px #0096bfab; 437 | box-shadow: 0 0 0 2px var(--focus); 438 | } 439 | 440 | input[type='checkbox']:active, 441 | input[type='radio']:active, 442 | input[type='submit']:active, 443 | input[type='reset']:active, 444 | input[type='button']:active, 445 | input[type='range']:active, 446 | button:active { 447 | transform: translateY(2px); 448 | } 449 | 450 | input:disabled, 451 | select:disabled, 452 | button:disabled, 453 | textarea:disabled { 454 | cursor: not-allowed; 455 | opacity: 0.5; 456 | } 457 | 458 | ::-moz-placeholder { 459 | color: #949494; 460 | color: var(--form-placeholder); 461 | } 462 | 463 | :-ms-input-placeholder { 464 | color: #949494; 465 | color: var(--form-placeholder); 466 | } 467 | 468 | ::-ms-input-placeholder { 469 | color: #949494; 470 | color: var(--form-placeholder); 471 | } 472 | 473 | ::placeholder { 474 | color: #949494; 475 | color: var(--form-placeholder); 476 | } 477 | 478 | fieldset { 479 | border: 1px #0096bfab solid; 480 | border: 1px var(--focus) solid; 481 | border-radius: 6px; 482 | margin: 0; 483 | margin-bottom: 12px; 484 | padding: 10px; 485 | } 486 | 487 | legend { 488 | font-size: 0.9em; 489 | font-weight: 600; 490 | } 491 | 492 | input[type='range'] { 493 | margin: 10px 0; 494 | padding: 10px 0; 495 | background: transparent; 496 | } 497 | 498 | input[type='range']:focus { 499 | outline: none; 500 | } 501 | 502 | input[type='range']::-webkit-slider-runnable-track { 503 | width: 100%; 504 | height: 9.5px; 505 | -webkit-transition: 0.2s; 506 | transition: 0.2s; 507 | background: #efefef; 508 | background: var(--background); 509 | border-radius: 3px; 510 | } 511 | 512 | input[type='range']::-webkit-slider-thumb { 513 | box-shadow: 0 1px 1px #000, 0 0 1px #0d0d0d; 514 | height: 20px; 515 | width: 20px; 516 | border-radius: 50%; 517 | background: #dbdbdb; 518 | background: var(--border); 519 | -webkit-appearance: none; 520 | margin-top: -7px; 521 | } 522 | 523 | input[type='range']:focus::-webkit-slider-runnable-track { 524 | background: #efefef; 525 | background: var(--background); 526 | } 527 | 528 | input[type='range']::-moz-range-track { 529 | width: 100%; 530 | height: 9.5px; 531 | -moz-transition: 0.2s; 532 | transition: 0.2s; 533 | background: #efefef; 534 | background: var(--background); 535 | border-radius: 3px; 536 | } 537 | 538 | input[type='range']::-moz-range-thumb { 539 | box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; 540 | height: 20px; 541 | width: 20px; 542 | border-radius: 50%; 543 | background: #dbdbdb; 544 | background: var(--border); 545 | } 546 | 547 | input[type='range']::-ms-track { 548 | width: 100%; 549 | height: 9.5px; 550 | background: transparent; 551 | border-color: transparent; 552 | border-width: 16px 0; 553 | color: transparent; 554 | } 555 | 556 | input[type='range']::-ms-fill-lower { 557 | background: #efefef; 558 | background: var(--background); 559 | border: 0.2px solid #010101; 560 | border-radius: 3px; 561 | box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; 562 | } 563 | 564 | input[type='range']::-ms-fill-upper { 565 | background: #efefef; 566 | background: var(--background); 567 | border: 0.2px solid #010101; 568 | border-radius: 3px; 569 | box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; 570 | } 571 | 572 | input[type='range']::-ms-thumb { 573 | box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; 574 | border: 1px solid #000; 575 | height: 20px; 576 | width: 20px; 577 | border-radius: 50%; 578 | background: #dbdbdb; 579 | background: var(--border); 580 | } 581 | 582 | input[type='range']:focus::-ms-fill-lower { 583 | background: #efefef; 584 | background: var(--background); 585 | } 586 | 587 | input[type='range']:focus::-ms-fill-upper { 588 | background: #efefef; 589 | background: var(--background); 590 | } 591 | 592 | a { 593 | text-decoration: none; 594 | color: #0076d1; 595 | color: var(--links); 596 | } 597 | 598 | a:hover { 599 | text-decoration: underline; 600 | } 601 | 602 | code { 603 | background: #efefef; 604 | background: var(--background); 605 | color: #000; 606 | color: var(--code); 607 | padding: 2.5px 5px; 608 | border-radius: 6px; 609 | font-size: 1em; 610 | } 611 | 612 | samp { 613 | background: #efefef; 614 | background: var(--background); 615 | color: #000; 616 | color: var(--code); 617 | padding: 2.5px 5px; 618 | border-radius: 6px; 619 | font-size: 1em; 620 | } 621 | 622 | time { 623 | background: #efefef; 624 | background: var(--background); 625 | color: #000; 626 | color: var(--code); 627 | padding: 2.5px 5px; 628 | border-radius: 6px; 629 | font-size: 1em; 630 | } 631 | 632 | pre > code { 633 | padding: 10px; 634 | display: block; 635 | overflow-x: auto; 636 | } 637 | 638 | var { 639 | color: #39a33c; 640 | color: var(--variable); 641 | font-style: normal; 642 | font-family: monospace; 643 | } 644 | 645 | kbd { 646 | background: #efefef; 647 | background: var(--background); 648 | border: 1px solid #dbdbdb; 649 | border: 1px solid var(--border); 650 | border-radius: 2px; 651 | color: #363636; 652 | color: var(--text-main); 653 | padding: 2px 4px 2px 4px; 654 | } 655 | 656 | img, 657 | video { 658 | max-width: 100%; 659 | height: auto; 660 | } 661 | 662 | hr { 663 | border: none; 664 | border-top: 1px solid #dbdbdb; 665 | border-top: 1px solid var(--border); 666 | } 667 | 668 | table { 669 | border-collapse: collapse; 670 | margin-bottom: 10px; 671 | width: 100%; 672 | table-layout: fixed; 673 | } 674 | 675 | table caption { 676 | text-align: left; 677 | } 678 | 679 | td, 680 | th { 681 | padding: 6px; 682 | text-align: left; 683 | vertical-align: top; 684 | word-wrap: break-word; 685 | } 686 | 687 | thead { 688 | border-bottom: 1px solid #dbdbdb; 689 | border-bottom: 1px solid var(--border); 690 | } 691 | 692 | tfoot { 693 | border-top: 1px solid #dbdbdb; 694 | border-top: 1px solid var(--border); 695 | } 696 | 697 | tbody tr:nth-child(even) { 698 | background-color: #efefef; 699 | background-color: var(--background); 700 | } 701 | 702 | tbody tr:nth-child(even) button { 703 | background-color: #f7f7f7; 704 | background-color: var(--background-alt); 705 | } 706 | 707 | tbody tr:nth-child(even) button:hover { 708 | background-color: #fff; 709 | background-color: var(--background-body); 710 | } 711 | 712 | ::-webkit-scrollbar { 713 | height: 10px; 714 | width: 10px; 715 | } 716 | 717 | ::-webkit-scrollbar-track { 718 | background: #efefef; 719 | background: var(--background); 720 | border-radius: 6px; 721 | } 722 | 723 | ::-webkit-scrollbar-thumb { 724 | background: rgb(170, 170, 170); 725 | background: var(--scrollbar-thumb); 726 | border-radius: 6px; 727 | } 728 | 729 | ::-webkit-scrollbar-thumb:hover { 730 | background: #9b9b9b; 731 | background: var(--scrollbar-thumb-hover); 732 | } 733 | 734 | ::-moz-selection { 735 | background-color: #9e9e9e; 736 | background-color: var(--selection); 737 | color: #000; 738 | color: var(--text-bright); 739 | } 740 | 741 | ::selection { 742 | background-color: #9e9e9e; 743 | background-color: var(--selection); 744 | color: #000; 745 | color: var(--text-bright); 746 | } 747 | 748 | details { 749 | display: flex; 750 | flex-direction: column; 751 | align-items: flex-start; 752 | background-color: #f7f7f7; 753 | background-color: var(--background-alt); 754 | padding: 10px 10px 0; 755 | margin: 1em 0; 756 | border-radius: 6px; 757 | overflow: hidden; 758 | } 759 | 760 | details[open] { 761 | padding: 10px; 762 | } 763 | 764 | details > :last-child { 765 | margin-bottom: 0; 766 | } 767 | 768 | details[open] summary { 769 | margin-bottom: 10px; 770 | } 771 | 772 | summary { 773 | display: list-item; 774 | background-color: #efefef; 775 | background-color: var(--background); 776 | padding: 10px; 777 | margin: -10px -10px 0; 778 | cursor: pointer; 779 | outline: none; 780 | } 781 | 782 | summary:hover, 783 | summary:focus { 784 | text-decoration: underline; 785 | } 786 | 787 | details > :not(summary) { 788 | margin-top: 0; 789 | } 790 | 791 | summary::-webkit-details-marker { 792 | color: #363636; 793 | color: var(--text-main); 794 | } 795 | 796 | dialog { 797 | background-color: #f7f7f7; 798 | background-color: var(--background-alt); 799 | color: #363636; 800 | color: var(--text-main); 801 | border: none; 802 | border-radius: 6px; 803 | border-color: #dbdbdb; 804 | border-color: var(--border); 805 | padding: 10px 30px; 806 | } 807 | 808 | dialog > header:first-child { 809 | background-color: #efefef; 810 | background-color: var(--background); 811 | border-radius: 6px 6px 0 0; 812 | margin: -10px -30px 10px; 813 | padding: 10px; 814 | text-align: center; 815 | } 816 | 817 | dialog::-webkit-backdrop { 818 | background: #0000009c; 819 | -webkit-backdrop-filter: blur(4px); 820 | backdrop-filter: blur(4px); 821 | } 822 | 823 | dialog::backdrop { 824 | background: #0000009c; 825 | -webkit-backdrop-filter: blur(4px); 826 | backdrop-filter: blur(4px); 827 | } 828 | 829 | footer { 830 | border-top: 1px solid #dbdbdb; 831 | border-top: 1px solid var(--border); 832 | padding-top: 10px; 833 | color: #70777f; 834 | color: var(--text-muted); 835 | } 836 | 837 | body > footer { 838 | margin-top: 40px; 839 | } 840 | 841 | @media print { 842 | body, 843 | pre, 844 | code, 845 | summary, 846 | details, 847 | button, 848 | input, 849 | textarea { 850 | background-color: #fff; 851 | } 852 | 853 | button, 854 | input, 855 | textarea { 856 | border: 1px solid #000; 857 | } 858 | 859 | body, 860 | h1, 861 | h2, 862 | h3, 863 | h4, 864 | h5, 865 | h6, 866 | pre, 867 | code, 868 | button, 869 | input, 870 | textarea, 871 | footer, 872 | summary, 873 | strong { 874 | color: #000; 875 | } 876 | 877 | summary::marker { 878 | color: #000; 879 | } 880 | 881 | summary::-webkit-details-marker { 882 | color: #000; 883 | } 884 | 885 | tbody tr:nth-child(even) { 886 | background-color: #f2f2f2; 887 | } 888 | 889 | a { 890 | color: #00f; 891 | text-decoration: underline; 892 | } 893 | } 894 | -------------------------------------------------------------------------------- /scripts/static-highlight.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let fs = require('fs'); 4 | let path = require('path'); 5 | 6 | let jsdom = require('jsdom'); 7 | let Prism = require('prismjs'); 8 | 9 | // jsdom is the laziest possible way of doing this 10 | // but whatever it works fine and only takes ~1s 11 | function highlightCodeblocks(html) { 12 | let dom = new jsdom.JSDOM(html, { includeNodeLocations: true }); 13 | let nodes = dom.window.document.querySelectorAll('code[class="lang-js"],code[class="language-js"],code[class="lang-javascript"],code[class="language-javascript"]'); 14 | if (nodes.length === 0) { 15 | console.error('warning: no code blocks found'); 16 | return html; 17 | } 18 | // last-first 19 | let sorted = [...nodes].map(n => ({ node: n, loc: dom.nodeLocation(n) })).sort((a, b) => b.loc.startOffset - a.loc.startOffset); 20 | for (let { node, loc } of sorted) { 21 | let prefix = html.slice(0, loc.startTag.endOffset); 22 | let code = html.slice(loc.startTag.endOffset, loc.endTag.startOffset).trimStart(); // for the leading newline 23 | let suffix = html.slice(loc.endTag.startOffset); 24 | 25 | let formatted = Prism.highlight(code, Prism.languages.javascript, 'javascript'); 26 | html = `${prefix}${formatted}${suffix}`; 27 | } 28 | return html; 29 | } 30 | 31 | if (process.argv.length < 3) { 32 | console.log('Usage: node static-highlight.js path-to-input.html > path-to-output.html'); 33 | } 34 | let source = fs.readFileSync(process.argv[2], 'utf8'); 35 | console.log(highlightCodeblocks(source)); 36 | -------------------------------------------------------------------------------- /spec.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |4 | title: Uint8Array to/from base64 5 | status: proposal 6 | stage: 3 7 | location: https://github.com/tc39/proposal-arraybuffer-base64 8 | copyright: false 9 | contributors: Kevin Gibbons 10 |11 | 12 |
This proposal is developed on GitHub. A playground is available with examples and a non-production polyfill to allow direct experimentation.
15 |The standard base64 alphabet is the String whose elements are the code units corresponding to every letter and number in the Unicode Basic Latin block along with *"+"* and *"/"*; that is, it is *"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"*.
233 |NOTE: We need to add RFC 4648 to the bibliography as part of landing this upstream.
397 |