Houjie
2025-07-24 52a3ff1bce1417b39f6872d8e8cb378e9c2ccc6f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { DEFAULT_ENCODING } from "../encoding/defaultEncoding";
import { encoders } from "../encoding/encoding-factory";
import { getEncoding } from "../encoding/encodings";
import { finished } from "../encoding/finished";
import { end_of_stream } from "../encoding/terminology";
import { stringToCodePoints, ToDictionary } from "../encoding/utilities";
import { getGlobalScope } from "../helper/getGlobalScope";
import { Stream } from "./Stream";
/**
 * @constructor
 * @param {string=} label The label of the encoding. NONSTANDARD.
 * @param {Object=} options NONSTANDARD.
 */
export class TextEncoder {
    constructor(label, options) {
        const optionsMap = ToDictionary(options);
        // A TextEncoder object has an associated encoding and encoder.
        /** @private */
        this._encoding = null;
        /** @private @type {?Encoder} */
        this._encoder = null;
        // Non-standard
        /** @private @type {boolean} */
        this._do_not_flush = false;
        /** @private @type {string} */
        this._fatal = Boolean(optionsMap['fatal']) ? 'fatal' : 'replacement';
        // 1. Let enc be a new TextEncoder object.
        // const enc = this;
        // no need to do this as this is a proper class 
        // now and TSC will handle transpilation to older platforms
        // 2. Set enc's encoding to UTF-8's encoder.
        if (Boolean(optionsMap['NONSTANDARD_allowLegacyEncoding'])) {
            // NONSTANDARD behavior.
            label = !!label ? String(label) : DEFAULT_ENCODING;
            const encoding = getEncoding(label);
            if (encoding === null || encoding.name === 'replacement')
                throw RangeError('Unknown encoding: ' + label);
            if (!encoders[encoding.name]) {
                throw Error('Encoder not present.' +
                    ' Did you forget to include encoding-indexes.js first?');
            }
            this._encoding = encoding;
            // EXPERIMENTAL_CODE
            // } else if (["iso-8859-1", "ISO-8859-1", "latin-1", "latin1", "LATIN-1", "LATIN1"].indexOf(label) !== -1) {
            //   this._encoding = getEncoding('iso-8859-1');
        }
        else {
            // Standard behavior.
            this._encoding = getEncoding('utf-8');
            const glo = getGlobalScope() || {};
            if (label !== undefined && 'console' in glo) {
                console.warn('TextEncoder constructor called with encoding label, '
                    + 'which is ignored.');
            }
        }
        // For pre-ES5 runtimes:
        // if (!Object.defineProperty)
        // this.encoding = enc._encoding.name.toLowerCase();
        // 3. Return enc.
        // return enc;
    }
    // if(Object.defineProperty) {
    //  // The encoding attribute's getter must return encoding's name.
    //   Object.defineProperty(TextEncoder.prototype, 'encoding', {
    //     /** @this {TextEncoder} */
    //     get: function () { return this._encoding.name.toLowerCase(); }
    //   });
    // }
    get encoding() {
        return this._encoding.name.toLowerCase();
    }
    /**
     * @param {string=} opt_string The string to encode.
     * @param {Object=} options
     * @return {!Uint8Array} Encoded bytes, as a Uint8Array.
     */
    encode(opt_string, options) {
        opt_string = opt_string === undefined ? '' : String(opt_string);
        const optionsMap = ToDictionary(options);
        // NOTE: This option is nonstandard. None of the encodings
        // permitted for encoding (i.e. UTF-8, UTF-16) are stateful when
        // the input is a USVString so streaming is not necessary.
        if (!this._do_not_flush)
            this._encoder = encoders[this._encoding.name]({
                fatal: this._fatal === 'fatal'
            });
        this._do_not_flush = Boolean(optionsMap['stream']);
        // 1. Convert input to a stream.
        const input = new Stream(stringToCodePoints(opt_string));
        // 2. Let output be a new stream
        const output = [];
        /** @type {?(number|!Array.<number>)} */
        let result;
        // 3. While true, run these substeps:
        while (true) {
            // 1. Let token be the result of reading from input.
            const token = input.read();
            if (token === end_of_stream)
                break;
            // 2. Let result be the result of processing token for encoder,
            // input, output.
            result = this._encoder.handler(input, token);
            if (result === finished)
                break;
            if (Array.isArray(result))
                output.push.apply(output, /**@type {!Array.<number>}*/ (result));
            else
                output.push(result);
        }
        // TODO: Align with spec algorithm.
        if (!this._do_not_flush) {
            while (true) {
                result = this._encoder.handler(input, input.read());
                if (result === finished)
                    break;
                if (Array.isArray(result))
                    output.push.apply(output, /**@type {!Array.<number>}*/ (result));
                else
                    output.push(result);
            }
            this._encoder = null;
        }
        // 3. If result is finished, convert output into a byte sequence,
        // and then return a Uint8Array object wrapping an ArrayBuffer
        // containing output.
        return new Uint8Array(output);
    }
}
//# sourceMappingURL=TextEncoder.js.map