import { Buffer, isAscii, isUtf8, transcode } from "node:buffer"; import { TextEncoder, TextDecoder } from "node:util"; export { transcode }; const encoder = new TextEncoder(); export function encodeInto(source, destination) { return encoder.encodeInto(source, destination); } export function reportEncoding() { for (const source of ["", "ASCII", "café", "€", "😀", "A😀é€Z", "\ud800x\udc00", "\0a"]) { for (let capacity = 0; capacity <= 16; capacity++) { const backing = new Uint8Array(capacity + 4).fill(0x55); const result = encoder.encodeInto(source, backing.subarray(2, capacity + 2)); console.log(JSON.stringify(source), capacity, JSON.stringify(result), Buffer.from(backing).toString("hex")); } } const decoder = new TextDecoder("utf8", { fatal: true, ignoreBOM: true }); console.log(encoder.encoding, decoder.encoding, decoder.fatal, decoder.ignoreBOM); const samples = [[], [0x41, 0x7f], [0x80], [0xc2, 0xa0], [0xed, 0xa0, 0x80], [0xf4, 0x8f, 0xbf, 0xbf], [0xf0, 0x9f], [0xef, 0xbb, 0xbf], [0], [0, 0xd8], [0xff, 0xfe, 0x61, 0], [0x61, 0, 0xff]]; for (const values of samples) { const input = Buffer.from(values); console.log(input.toString("hex"), isAscii(input), isUtf8(input)); for (const from of ["ascii", "latin1", "utf8", "utf16le"]) { for (const to of ["ascii", "latin1", "utf8", "utf16le"]) { try { const output = transcode(input, from, to); console.log(from, to, output.toString("hex"), Buffer.isBuffer(output), output === input); } catch (error) { console.log(from, to, error.name, error.code, error.errno, error.message); } } } } for (const input of [new Uint16Array([0x80]), new Int8Array([0x41]), new Uint8ClampedArray([0x7f]), new Float32Array([0]), new ArrayBuffer(3), new Uint8Array([0xff, 0x41, 0xff]).subarray(1, 2)]) { console.log(input.constructor.name, isAscii(input), isUtf8(input)); } for (const input of [undefined, null, 1, true, "x", {}, [], Symbol("input"), 1n, new DataView(new ArrayBuffer(2))]) { for (const validate of [isAscii, isUtf8]) { try { console.log(validate(input)); } catch (error) { console.log(error.name, error.code, error.message); } } try { transcode(input, "utf8", "ascii"); } catch (error) { console.log(error.name, error.code, error.message); } try { encoder.encodeInto(input, new Uint8Array(4)); } catch (error) { console.log(error.name, error.code, error.message); } } for (const destination of [undefined, null, 1, {}, new Uint16Array(2), new Uint8ClampedArray(4), new DataView(new ArrayBuffer(4))]) { try { encoder.encodeInto("x", destination); } catch (error) { console.log(error.name, error.code, error.message); } } for (const encoding of [undefined, null, "", "bad", "hex", "base64", 1, {}]) { for (const direction of [true, false]) { try { console.log(transcode(Buffer.from("abc"), direction ? encoding : "utf8", direction ? "utf8" : encoding).toString("hex")); } catch (error) { console.log(error.name, error.code, error.errno, error.message); } } } for (const receiver of [{}, Object.create(TextEncoder.prototype)]) { try { TextEncoder.prototype.encodeInto.call(receiver, "x", new Uint8Array(1)); } catch (error) { console.log(error.name, error.code, error.message); } } const input = new Uint8Array([0xff, 0xc3, 0xa9, 0xff]).subarray(1, 3); console.log(transcode(input, "UTF-8", "UCS-2").toString("hex")); console.log(transcode(Buffer.alloc(0), "bad", "hex").length); }