@nberlette/utf8
Version:
Blazing fast universal ponyfills for TextEncoder and TextDecoder.
242 lines • 11.6 kB
JavaScript
"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