From ef0b9c2be3ab107f79cab0edc915e376a6c9b933 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Tue, 21 Oct 2025 10:24:35 -0400 Subject: [PATCH] util: reduce TextEncoder.encodeInto function size --- lib/internal/encoding.js | 41 +++++++++---------- .../test-whatwg-encoding-custom-interop.js | 10 +++-- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/lib/internal/encoding.js b/lib/internal/encoding.js index b2ca3c612bf6ef..e054ca4dd5202d 100644 --- a/lib/internal/encoding.js +++ b/lib/internal/encoding.js @@ -26,7 +26,6 @@ const kHandle = Symbol('handle'); const kFlags = Symbol('flags'); const kEncoding = Symbol('encoding'); const kDecoder = Symbol('decoder'); -const kEncoder = Symbol('encoder'); const kFatal = Symbol('kFatal'); const kUTF8FastPath = Symbol('kUTF8FastPath'); const kLatin1FastPath = Symbol('kLatin1FastPath'); @@ -61,11 +60,6 @@ const { const { Buffer } = require('buffer'); -function validateEncoder(obj) { - if (obj == null || obj[kEncoder] !== true) - throw new ERR_INVALID_THIS('TextEncoder'); -} - function validateDecoder(obj) { if (obj == null || obj[kDecoder] !== true) throw new ERR_INVALID_THIS('TextDecoder'); @@ -338,45 +332,50 @@ function getEncodingFromLabel(label) { return encodings.get(trimAsciiWhitespace(label.toLowerCase())); } +let lazyInspect; + class TextEncoder { - constructor() { - this[kEncoder] = true; + #encoding = 'utf-8'; + + #encode(input) { + return encodeUtf8String(`${input}`); + } + + #encodeInto(input, dest) { + encodeInto(input, dest); + // We need to read from the binding here since the buffer gets refreshed + // from the snapshot. + const { 0: read, 1: written } = encodeIntoResults; + return { read, written }; } get encoding() { - validateEncoder(this); - return 'utf-8'; + return this.#encoding; } encode(input = '') { - validateEncoder(this); - return encodeUtf8String(`${input}`); + return this.#encode(input); } encodeInto(src, dest) { - validateEncoder(this); validateString(src, 'src'); if (!dest || !isUint8Array(dest)) throw new ERR_INVALID_ARG_TYPE('dest', 'Uint8Array', dest); - encodeInto(src, dest); - // We need to read from the binding here since the buffer gets refreshed - // from the snapshot. - const { 0: read, 1: written } = encodeIntoResults; - return { read, written }; + return this.#encodeInto(src, dest); } [inspect](depth, opts) { - validateEncoder(this); if (typeof depth === 'number' && depth < 0) return this; const ctor = getConstructorOf(this); const obj = { __proto__: { constructor: ctor === null ? TextEncoder : ctor, } }; - obj.encoding = this.encoding; + obj.encoding = this.#encoding; // Lazy to avoid circular dependency - return require('internal/util/inspect').inspect(obj, opts); + lazyInspect ??= require('internal/util/inspect').inspect; + return lazyInspect(obj, opts); } } diff --git a/test/parallel/test-whatwg-encoding-custom-interop.js b/test/parallel/test-whatwg-encoding-custom-interop.js index 80d088f6ce3741..65d47d0c4c2cbd 100644 --- a/test/parallel/test-whatwg-encoding-custom-interop.js +++ b/test/parallel/test-whatwg-encoding-custom-interop.js @@ -46,9 +46,8 @@ assert(TextEncoder); const instance = new TextEncoder(); const expectedError = { - code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Value of "this" must be of type TextEncoder' + message: /from an object whose class did not declare it/, }; inspectFn.call(instance, Infinity, {}); @@ -58,7 +57,12 @@ assert(TextEncoder); const invalidThisArgs = [{}, [], true, 1, '', new TextDecoder()]; for (const i of invalidThisArgs) { assert.throws(() => inspectFn.call(i, Infinity, {}), expectedError); - assert.throws(() => encodeFn.call(i), expectedError); assert.throws(() => encodingGetter.call(i), expectedError); } + for (const i of invalidThisArgs) { + assert.throws(() => encodeFn.call(i), { + name: 'TypeError', + message: 'Receiver must be an instance of class TextEncoder', + }); + } }