UNPKG

@exodus/test-bundler

Version:

Test bundler for @exodus/test for barebone and browser engines

91 lines (73 loc) 3.63 kB
// Adapted from https://github.com/ExodusMovement/text-encoding-utf8 /* eslint-disable unicorn/prefer-set-has, unicorn/text-encoding-identifier-case */ const UTF8 = 'utf-8' const UTF16LE = 'utf-16le' // https://encoding.spec.whatwg.org/#names-and-labels const UTF8alias = ['utf8', 'unicode-1-1-utf-8', 'unicode11utf8', 'unicode20utf8', 'x-unicode20utf8'] const UTF16LEalias = ['utf-16', 'ucs-2', 'unicode', 'unicodefeff', 'iso-10646-ucs-2', 'csunicode'] // but not utf16 const normalizeEncoding = (encoding) => { const lower = encoding.toLowerCase() if (UTF8 === lower || UTF16LE === lower) return lower // fast path if (UTF8alias.includes(lower)) return UTF8 if (UTF16LEalias.includes(lower)) return UTF16LE return lower } const defineFinal = (obj, key, value) => Object.defineProperty(obj, key, { value, writable: false }) const assertUTF8 = (encoding) => { if (encoding !== UTF8) throw new Error('only utf-8 is supported') } const assertUTF8orUTF16LE = (enc) => { // We don't include ascii because it's an alias to windows-1252 in TextDecoder and differs from Buffer ascii // We don't include utf-16be because it's not supported by buffer package if (enc !== UTF8 && enc !== UTF16LE) throw new Error('only utf-8 and utf-16le are supported') } const assertBufferSource = (buf) => { if (buf instanceof ArrayBuffer || ArrayBuffer.isView(buf)) return if (globalThis.SharedArrayBuffer && buf instanceof globalThis.SharedArrayBuffer) return throw new Error('argument must be a SharedArrayBuffer, ArrayBuffer or ArrayBufferView') } // encoding argument is non-standard but catches usage of 'text-encoding' npm package API // Standard TextEncoder constructor doesn't have any arguments at all and is always utf-8 function TextEncoder(encoding = UTF8) { encoding = normalizeEncoding(encoding) assertUTF8(encoding) defineFinal(this, 'encoding', encoding) } TextEncoder.prototype.encode = function (str) { const buf = Buffer.from(str) return new Uint8Array(buf.buffer, buf.byteOffset, buf.length) } TextEncoder.prototype.encodeInto = function () { throw new Error('not supported') } function TextDecoder(encoding = UTF8, options = {}) { encoding = normalizeEncoding(encoding) assertUTF8orUTF16LE(encoding) const { fatal = false, ignoreBOM = false, stream = false } = options if (ignoreBOM !== false) throw new Error('option "ignoreBOM" is not supported') if (stream !== false) throw new Error('option "stream" is not supported') // see: https://github.com/inexorabletash/text-encoding/blob/master/lib/encoding.js#L1049 defineFinal(this, 'encoding', encoding) defineFinal(this, 'fatal', fatal) defineFinal(this, 'ignoreBOM', ignoreBOM) } // Note: https://npmjs.com/package/buffer has a bug // Buffer.from([0xf0, 0x90, 0x80]).toString().length should be 1, but it is 3 in https://npmjs.com/package/buffer // Buffer.from([0xf0, 0x80, 0x80]).toString().length should be 3, see https://github.com/nodejs/node/issues/16894 TextDecoder.prototype.decode = function (buf) { if (buf === undefined) return '' assertBufferSource(buf) if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf) const res = buf.toString(this.encoding) if (this.fatal && res.includes('\uFFFD')) { // We have a replacement symbol, recheck if output matches input const reconstructed = Buffer.from(res, this.encoding) if (Buffer.compare(buf, reconstructed) !== 0) { const err = new TypeError('The encoded data was not valid for encoding utf-8') err.code = 'ERR_ENCODING_INVALID_ENCODED_DATA' throw err } } return res } module.exports = { TextEncoder, TextDecoder }