UNPKG

@nberlette/utf8

Version:

Blazing fast universal ponyfills for TextEncoder and TextDecoder.

242 lines 11.6 kB
"use strict"; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _TextDecoder_encoding, _TextDecoder_fatal, _TextDecoder_ignoreBOM, _TextDecoder_buffer; Object.defineProperty(exports, "__esModule", { value: true }); exports.TextDecoder = void 0; /** * This module provides a high performance dependency-free ponyfill for the * `TextDecoder` Web API, allowing you to decode UTF-8 encoded `BufferSource` * buffers into strings in any ES2015+ environment. * * Currently only UTF-8 encoding is supported, but additional encodings will be * added in the near future. Encodings that are currently being implemented are * UTF-16, ISO-8859-1, Windows-1252, and ASCII. * * @module text-decoder */ const _internal_js_1 = require("./_internal.js"); /** * Decodes an encoded sequence of bytes into a string, using the specified * encoding standard. Currently, only UTF-8 encoding is supported. * * @see https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder * @category Encoding * @tags utf-8, decoder */ class TextDecoder { /** * Creates a new TextDecoder instance. * @param label The encoding to use. Currently, only "utf-8" is supported. * @param options Configuration options. */ constructor(label = "utf-8", options = {}) { _TextDecoder_encoding.set(this, void 0); _TextDecoder_fatal.set(this, void 0); _TextDecoder_ignoreBOM.set(this, void 0); _TextDecoder_buffer.set(this, new _internal_js_1.Uint8Array(0)); __classPrivateFieldSet(this, _TextDecoder_encoding, (0, _internal_js_1.normalizeEncoding)(label), "f"); __classPrivateFieldSet(this, _TextDecoder_fatal, !!options.fatal, "f"); __classPrivateFieldSet(this, _TextDecoder_ignoreBOM, !!options.ignoreBOM, "f"); if (__classPrivateFieldGet(this, _TextDecoder_encoding, "f") !== "utf-8") { throw new _internal_js_1.TypeError(`The encoding "${label}" is not supported.`); } } /** The encoding standard to use. */ get encoding() { return __classPrivateFieldGet(this, _TextDecoder_encoding, "f"); } /** If true, invalid bytes will throw a TypeError. */ get fatal() { return __classPrivateFieldGet(this, _TextDecoder_fatal, "f"); } /** If true, the BOM (Byte Order Mark) will be ignored. */ get ignoreBOM() { return __classPrivateFieldGet(this, _TextDecoder_ignoreBOM, "f"); } /** * Decodes a BufferSource into a string using UTF-8 decoding. * * @param input The bytes to decode. Defaults to an empty Uint8Array. * @param [options] Decoding options. * @returns The decoded string. * @throws if the input is not a BufferSource. * @throws if fatal is true and an invalid byte sequence is encountered. */ decode(input, options) { const stream = options?.stream ?? false; let bytes = (0, _internal_js_1.toUint8Array)(input); // Concatenate any leftover bytes from the previous decode call if (__classPrivateFieldGet(this, _TextDecoder_buffer, "f").length > 0) { const combined = new _internal_js_1.Uint8Array(__classPrivateFieldGet(this, _TextDecoder_buffer, "f").length + bytes.length); combined.set(__classPrivateFieldGet(this, _TextDecoder_buffer, "f"), 0); combined.set(bytes, __classPrivateFieldGet(this, _TextDecoder_buffer, "f").length); bytes = combined; __classPrivateFieldSet(this, _TextDecoder_buffer, new _internal_js_1.Uint8Array(), "f"); } let string = "", i = 0; // Handle BOM if (!this.ignoreBOM && bytes.length >= 3 && bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf) i += 3; while (i < bytes.length) { const startIndex = i; const byte1 = bytes[i++]; if (byte1 <= 0x7f) { string += (0, _internal_js_1.StringFromCharCode)(byte1); } else if (byte1 >= 0xc0 && byte1 <= 0xdf) { // 2-byte sequence const byte2 = bytes[i++]; if (byte2 === _internal_js_1.undefined) { // Incomplete sequence if (stream) { __classPrivateFieldSet(this, _TextDecoder_buffer, (0, _internal_js_1.Uint8ArrayPrototypeSubarray)(bytes, startIndex), "f"); break; } else { if (this.fatal) throw new _internal_js_1.TypeError("Incomplete byte sequence"); string += "\uFFFD"; break; } } if ((byte2 & 0xc0) !== 0x80) { if (this.fatal) throw new _internal_js_1.TypeError("Invalid continuation byte"); string += "\uFFFD"; i = startIndex + 1; continue; } const codePoint = ((byte1 & 0x1f) << 6) | (byte2 & 0x3f); string += (0, _internal_js_1.StringFromCharCode)(codePoint); } else if (byte1 >= 0xe0 && byte1 <= 0xef) { // 3-byte sequence const byte2 = bytes[i++]; if (byte2 === _internal_js_1.undefined) { // Incomplete sequence if (stream) { __classPrivateFieldSet(this, _TextDecoder_buffer, (0, _internal_js_1.Uint8ArrayPrototypeSubarray)(bytes, startIndex), "f"); break; } else { if (this.fatal) throw new _internal_js_1.TypeError("Incomplete byte sequence"); string += "\uFFFD"; break; } } const byte3 = bytes[i++]; if (byte3 === _internal_js_1.undefined) { // Incomplete sequence if (stream) { __classPrivateFieldSet(this, _TextDecoder_buffer, (0, _internal_js_1.Uint8ArrayPrototypeSubarray)(bytes, startIndex), "f"); break; } else { if (this.fatal) throw new _internal_js_1.TypeError("Incomplete byte sequence"); string += "\uFFFD"; break; } } if ((byte2 & 0xc0) !== 0x80 || (byte3 & 0xc0) !== 0x80) { if (this.fatal) throw new _internal_js_1.TypeError("Invalid continuation bytes"); string += "\uFFFD"; i = startIndex + 1; continue; } const codePoint = ((byte1 & 0x0f) << 12) | ((byte2 & 0x3f) << 6) | (byte3 & 0x3f); string += (0, _internal_js_1.StringFromCharCode)(codePoint); } else if (byte1 >= 0xf0 && byte1 <= 0xf7) { // 4-byte sequence const byte2 = bytes[i++]; if (byte2 === _internal_js_1.undefined) { // Incomplete sequence if (stream) { __classPrivateFieldSet(this, _TextDecoder_buffer, (0, _internal_js_1.Uint8ArrayPrototypeSubarray)(bytes, startIndex), "f"); break; } else { if (this.fatal) throw new _internal_js_1.TypeError("Incomplete byte sequence"); string += "\uFFFD"; break; } } const byte3 = bytes[i++]; if (byte3 === _internal_js_1.undefined) { // Incomplete sequence if (stream) { __classPrivateFieldSet(this, _TextDecoder_buffer, (0, _internal_js_1.Uint8ArrayPrototypeSubarray)(bytes, startIndex), "f"); break; } else { if (this.fatal) throw new _internal_js_1.TypeError("Incomplete byte sequence"); string += "\uFFFD"; break; } } const byte4 = bytes[i++]; if (byte4 === _internal_js_1.undefined) { // Incomplete sequence if (stream) { __classPrivateFieldSet(this, _TextDecoder_buffer, (0, _internal_js_1.Uint8ArrayPrototypeSubarray)(bytes, startIndex), "f"); break; } else { if (this.fatal) throw new _internal_js_1.TypeError("Incomplete byte sequence"); string += "\uFFFD"; break; } } if ((byte2 & 0xc0) !== 0x80 || (byte3 & 0xc0) !== 0x80 || (byte4 & 0xc0) !== 0x80) { if (this.fatal) throw new _internal_js_1.TypeError("Invalid continuation bytes"); string += "\uFFFD"; i = startIndex + 1; continue; } let codePoint = ((byte1 & 0x07) << 18) | ((byte2 & 0x3f) << 12) | ((byte3 & 0x3f) << 6) | (byte4 & 0x3f); codePoint -= 0x10000; string += (0, _internal_js_1.StringFromCharCode)(0xd800 + ((codePoint >> 10) & 0x3ff), 0xdc00 + (codePoint & 0x3ff)); } else { if (this.fatal) throw new _internal_js_1.TypeError("Invalid byte"); string += "\uFFFD"; } } // If not streaming, reset the buffer if (!stream) __classPrivateFieldSet(this, _TextDecoder_buffer, new _internal_js_1.Uint8Array(), "f"); return string; } } exports.TextDecoder = TextDecoder; _TextDecoder_encoding = new WeakMap(), _TextDecoder_fatal = new WeakMap(), _TextDecoder_ignoreBOM = new WeakMap(), _TextDecoder_buffer = new WeakMap(); //# sourceMappingURL=text_decoder.js.map