Update TextDecoder's constructor to Handle Undefined (#19708)

Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com>
This commit is contained in:
Braden Everson
2025-05-19 18:44:57 -05:00
committed by GitHub
parent bfd12eeeba
commit 67b64c3334
3 changed files with 33 additions and 33 deletions

View File

@@ -280,46 +280,40 @@ fn decodeSlice(this: *TextDecoder, globalThis: *JSC.JSGlobalObject, buffer_slice
}
pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!*TextDecoder {
var args_ = callframe.arguments_old(2);
var arguments: []const JSC.JSValue = args_.ptr[0..args_.len];
const encoding_value, const options_value = callframe.argumentsAsArray(2);
var decoder = TextDecoder{};
if (arguments.len > 0) {
// encoding
if (arguments[0].isString()) {
var str = try arguments[0].toSlice(globalThis, bun.default_allocator);
defer if (str.isAllocated()) str.deinit();
if (encoding_value.isString()) {
var str = try encoding_value.toSlice(globalThis, bun.default_allocator);
defer str.deinit();
if (EncodingLabel.which(str.slice())) |label| {
decoder.encoding = label;
} else {
return globalThis.ERR(.ENCODING_NOT_SUPPORTED, "Unsupported encoding label \"{s}\"", .{str.slice()}).throw();
}
} else if (arguments[0].isUndefined()) {
// default to utf-8
decoder.encoding = EncodingLabel.@"UTF-8";
if (EncodingLabel.which(str.slice())) |label| {
decoder.encoding = label;
} else {
return globalThis.throwInvalidArguments("TextDecoder(encoding) label is invalid", .{});
return globalThis.ERR(.ENCODING_NOT_SUPPORTED, "Unsupported encoding label \"{s}\"", .{str.slice()}).throw();
}
} else if (encoding_value.isUndefined()) {
// default to utf-8
decoder.encoding = EncodingLabel.@"UTF-8";
} else {
return globalThis.throwInvalidArguments("TextDecoder(encoding) label is invalid", .{});
}
if (!options_value.isUndefined()) {
if (!options_value.isObject()) {
return globalThis.throwInvalidArguments("TextDecoder(options) is invalid", .{});
}
if (arguments.len >= 2) {
const options = arguments[1];
if (try options_value.get(globalThis, "fatal")) |fatal| {
decoder.fatal = fatal.toBoolean();
}
if (!options.isObject()) {
return globalThis.throwInvalidArguments("TextDecoder(options) is invalid", .{});
}
if (try options.get(globalThis, "fatal")) |fatal| {
decoder.fatal = fatal.toBoolean();
}
if (try options.get(globalThis, "ignoreBOM")) |ignoreBOM| {
if (ignoreBOM.isBoolean()) {
decoder.ignore_bom = ignoreBOM.asBoolean();
} else {
return globalThis.throwInvalidArguments("TextDecoder(options) ignoreBOM is invalid. Expected boolean value", .{});
}
if (try options_value.get(globalThis, "ignoreBOM")) |ignoreBOM| {
if (ignoreBOM.isBoolean()) {
decoder.ignore_bom = ignoreBOM.asBoolean();
} else {
return globalThis.throwInvalidArguments("TextDecoder(options) ignoreBOM is invalid. Expected boolean value", .{});
}
}
}

View File

@@ -41,7 +41,7 @@ const words: Record<string, { reason: string; limit?: number; regex?: boolean }>
"std.fs.File": { reason: "Prefer bun.sys + bun.FD instead of std.fs", limit: 64 },
".stdFile()": { reason: "Prefer bun.sys + bun.FD instead of std.fs.File. Zig hides 'errno' when Bun wants to match libuv", limit: 18 },
".stdDir()": { reason: "Prefer bun.sys + bun.FD instead of std.fs.File. Zig hides 'errno' when Bun wants to match libuv", limit: 48 },
".arguments_old(": { reason: "Please migrate to .argumentsAsArray() or another argument API", limit: 286 },
".arguments_old(": { reason: "Please migrate to .argumentsAsArray() or another argument API", limit: 285 },
"// autofix": { reason: "Evaluate if this variable should be deleted entirely or explicitly discarded.", limit: 176 },
};
const words_keys = [...Object.keys(words)];

View File

@@ -298,6 +298,12 @@ describe("TextDecoder", () => {
const decoder = new TextDecoder(undefined);
expect(decoder.encoding).toBe("utf-8");
});
it("should support undefined options", () => {
expect(() => {
const decoder = new TextDecoder("utf-8", undefined);
}).not.toThrow();
});
});
describe("TextDecoder ignoreBOM", () => {