diff --git a/src/bun.js/api/BunObject.zig b/src/bun.js/api/BunObject.zig index bef890cb65d280..381bac382778ad 100644 --- a/src/bun.js/api/BunObject.zig +++ b/src/bun.js/api/BunObject.zig @@ -938,28 +938,27 @@ pub fn shrink(globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) JSC.JSValue fn doResolve( globalThis: *JSC.JSGlobalObject, arguments: []const JSValue, - exception: js.ExceptionRef, -) ?JSC.JSValue { +) bun.JSError!JSC.JSValue { var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); defer args.deinit(); const specifier = args.protectEatNext() orelse { - JSC.throwInvalidArguments("Expected a specifier and a from path", .{}, globalThis, exception); - return null; + globalThis.throwInvalidArguments("Expected a specifier and a from path", .{}); + return error.JSError; }; if (specifier.isUndefinedOrNull()) { - JSC.throwInvalidArguments("specifier must be a string", .{}, globalThis, exception); - return null; + globalThis.throwInvalidArguments("specifier must be a string", .{}); + return error.JSError; } const from = args.protectEatNext() orelse { - JSC.throwInvalidArguments("Expected a from path", .{}, globalThis, exception); - return null; + globalThis.throwInvalidArguments("Expected a from path", .{}); + return error.JSError; }; if (from.isUndefinedOrNull()) { - JSC.throwInvalidArguments("from must be a string", .{}, globalThis, exception); - return null; + globalThis.throwInvalidArguments("from must be a string", .{}); + return error.JSError; } var is_esm = true; @@ -967,8 +966,8 @@ fn doResolve( if (next.isBoolean()) { is_esm = next.toBoolean(); } else { - JSC.throwInvalidArguments("esm must be a boolean", .{}, globalThis, exception); - return null; + globalThis.throwInvalidArguments("esm must be a boolean", .{}); + return error.JSError; } } @@ -980,7 +979,6 @@ fn doResolve( globalThis, specifier_str, from_str, - exception, is_esm, false, ); @@ -990,10 +988,9 @@ fn doResolveWithArgs( ctx: js.JSContextRef, specifier: bun.String, from: bun.String, - exception: js.ExceptionRef, is_esm: bool, comptime is_file_path: bool, -) ?JSC.JSValue { +) bun.JSError!JSC.JSValue { var errorable: ErrorableString = undefined; var query_string = ZigString.Empty; @@ -1024,8 +1021,8 @@ fn doResolveWithArgs( } if (!errorable.success) { - exception.* = bun.cast(JSC.JSValueRef, errorable.result.err.ptr.?); - return null; + ctx.throwValue(bun.cast(JSC.JSValueRef, errorable.result.err.ptr.?).?.value()); + return error.JSError; } if (query_string.len > 0) { @@ -1037,9 +1034,8 @@ fn doResolveWithArgs( errorable.result.value, query_string, }) catch { - // TODO: binding for createOutOfMemoryError - exception.* = JSC.createError(ctx, "Out of memory", .{}).asObjectRef(); - return null; + ctx.throwOutOfMemory(); + return error.JSError; }; return ZigString.initUTF8(arraylist.items).toJS(ctx); @@ -1049,24 +1045,16 @@ fn doResolveWithArgs( } pub fn resolveSync(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { - var exception_ = [1]JSC.JSValueRef{null}; - const exception = &exception_; const arguments = callframe.arguments(3); - const result = doResolve(globalObject, arguments.slice(), exception); - - if (exception_[0] != null) { - globalObject.throwValue(exception_[0].?.value()); - } - - return result orelse .zero; + const result = doResolve(globalObject, arguments.slice()); + return result catch .zero; } pub fn resolve(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { - var exception_ = [1]JSC.JSValueRef{null}; - const exception = &exception_; const arguments = callframe.arguments(3); - const value = doResolve(globalObject, arguments.slice(), exception) orelse { - return JSC.JSPromise.rejectedPromiseValue(globalObject, exception_[0].?.value()); + const value = doResolve(globalObject, arguments.slice()) catch { + const err = globalObject.tryTakeException().?; + return JSC.JSPromise.rejectedPromiseValue(globalObject, err); }; return JSC.JSPromise.resolvedPromiseValue(globalObject, value); } @@ -1077,16 +1065,15 @@ export fn Bun__resolve( source: JSValue, is_esm: bool, ) JSC.JSValue { - var exception_ = [1]JSC.JSValueRef{null}; - const exception = &exception_; const specifier_str = specifier.toBunString(global); defer specifier_str.deref(); const source_str = source.toBunString(global); defer source_str.deref(); - const value = doResolveWithArgs(global, specifier_str, source_str, exception, is_esm, true) orelse { - return JSC.JSPromise.rejectedPromiseValue(global, exception_[0].?.value()); + const value = doResolveWithArgs(global, specifier_str, source_str, is_esm, true) catch { + const err = global.tryTakeException().?; + return JSC.JSPromise.rejectedPromiseValue(global, err); }; return JSC.JSPromise.resolvedPromiseValue(global, value); @@ -1098,18 +1085,13 @@ export fn Bun__resolveSync( source: JSValue, is_esm: bool, ) JSC.JSValue { - var exception_ = [1]JSC.JSValueRef{null}; - const exception = &exception_; - const specifier_str = specifier.toBunString(global); defer specifier_str.deref(); const source_str = source.toBunString(global); defer source_str.deref(); - return doResolveWithArgs(global, specifier_str, source_str, exception, is_esm, true) orelse { - return JSC.JSValue.fromRef(exception[0]); - }; + return doResolveWithArgs(global, specifier_str, source_str, is_esm, true) catch return .zero; } export fn Bun__resolveSyncWithStrings( @@ -1119,10 +1101,7 @@ export fn Bun__resolveSyncWithStrings( is_esm: bool, ) JSC.JSValue { Output.scoped(.importMetaResolve, false)("source: {s}, specifier: {s}", .{ source.*, specifier.* }); - var exception = [1]JSC.JSValueRef{null}; - return doResolveWithArgs(global, specifier.*, source.*, &exception, is_esm, true) orelse { - return JSC.JSValue.fromRef(exception[0]); - }; + return doResolveWithArgs(global, specifier.*, source.*, is_esm, true) catch return .zero; } export fn Bun__resolveSyncWithSource( @@ -1131,14 +1110,9 @@ export fn Bun__resolveSyncWithSource( source: *bun.String, is_esm: bool, ) JSC.JSValue { - var exception_ = [1]JSC.JSValueRef{null}; const specifier_str = specifier.toBunString(global); defer specifier_str.deref(); - - const exception = &exception_; - return doResolveWithArgs(global, specifier_str, source.*, exception, is_esm, true) orelse { - return JSC.JSValue.fromRef(exception[0]); - }; + return doResolveWithArgs(global, specifier_str, source.*, is_esm, true) catch return .zero; } extern fn dump_zone_malloc_stats() void; @@ -3326,22 +3300,12 @@ pub fn serve( ) JSC.JSValue { const arguments = callframe.arguments(2).slice(); var config: JSC.API.ServerConfig = brk: { - var exception_ = [1]JSC.JSValueRef{null}; - const exception = &exception_; - var args = JSC.Node.ArgumentsSlice.init(globalObject.bunVM(), arguments); var config: JSC.API.ServerConfig = .{}; - JSC.API.ServerConfig.fromJS(globalObject, &config, &args, exception); - if (exception[0] != null) { - config.deinit(); - - globalObject.throwValue(exception_[0].?.value()); - return .zero; - } + JSC.API.ServerConfig.fromJS(globalObject, &config, &args) catch return .zero; if (globalObject.hasException()) { config.deinit(); - return .zero; } diff --git a/src/bun.js/api/JSTranspiler.zig b/src/bun.js/api/JSTranspiler.zig index 7015d20093e3ae..67b3dd63af2090 100644 --- a/src/bun.js/api/JSTranspiler.zig +++ b/src/bun.js/api/JSTranspiler.zig @@ -310,7 +310,7 @@ fn exportReplacementValue(value: JSValue, globalThis: *JSGlobalObject) ?JSAst.Ex return null; } -fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std.mem.Allocator, args: *JSC.Node.ArgumentsSlice, exception: JSC.C.ExceptionRef) !TranspilerOptions { +fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std.mem.Allocator, args: *JSC.Node.ArgumentsSlice) (bun.JSError || bun.OOM)!TranspilerOptions { const globalThis = globalObject; const object = args.next() orelse return TranspilerOptions{ .log = logger.Log.init(temp_allocator) }; if (object.isUndefinedOrNull()) return TranspilerOptions{ .log = logger.Log.init(temp_allocator) }; @@ -325,8 +325,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std }; if (!object.isObject()) { - JSC.throwInvalidArguments("Expected an object", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("Expected an object", .{}); + return error.JSError; } if (object.getTruthy(globalObject, "define")) |define| { @@ -336,8 +336,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std } if (!define.isObject()) { - JSC.throwInvalidArguments("define must be an object", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("define must be an object", .{}); + return error.JSError; } var define_iter = JSC.JSPropertyIterator(.{ @@ -358,8 +358,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std const value_type = property_value.jsType(); if (!value_type.isStringLike()) { - JSC.throwInvalidArguments("define \"{s}\" must be a JSON string", .{prop}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("define \"{s}\" must be a JSON string", .{prop}); + return error.JSError; } names[define_iter.i] = prop.toOwnedSlice(allocator) catch unreachable; @@ -399,8 +399,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std var i: usize = 0; while (iter.next()) |entry| { if (!entry.jsType().isStringLike()) { - JSC.throwInvalidArguments("external must be a string or string[]", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("external must be a string or string[]", .{}); + return error.JSError; } var zig_str = JSC.ZigString.init(""); @@ -412,35 +412,27 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std transpiler.transform.external = externals[0..i]; } else { - JSC.throwInvalidArguments("external must be a string or string[]", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("external must be a string or string[]", .{}); + return error.JSError; } } } if (object.get(globalThis, "loader")) |loader| { - if (Loader.fromJS(globalThis, loader, exception)) |resolved| { + if (try Loader.fromJS(globalThis, loader)) |resolved| { if (!resolved.isJavaScriptLike()) { - JSC.throwInvalidArguments("only JavaScript-like loaders supported for now", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("only JavaScript-like loaders supported for now", .{}); + return error.JSError; } transpiler.default_loader = resolved; } - - if (exception.* != null) { - return transpiler; - } } if (object.get(globalThis, "target")) |target| { - if (Target.fromJS(globalThis, target, exception)) |resolved| { + if (try Target.fromJS(globalThis, target)) |resolved| { transpiler.transform.target = resolved.toAPI(); } - - if (exception.* != null) { - return transpiler; - } } if (object.get(globalThis, "tsconfig")) |tsconfig| { @@ -451,8 +443,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std defer out.deref(); if (kind.isArray()) { - JSC.throwInvalidArguments("tsconfig must be a string or object", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("tsconfig must be a string or object", .{}); + return error.JSError; } if (!kind.isStringLike()) { @@ -492,8 +484,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std const kind = macros.jsType(); const is_object = kind.isObject(); if (!(kind.isStringLike() or is_object)) { - JSC.throwInvalidArguments("macro must be an object", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("macro must be an object", .{}); + return error.JSError; } var out = bun.String.empty; @@ -517,23 +509,23 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std } } - if (object.getOptional(globalThis, "autoImportJSX", bool) catch return transpiler) |flag| { + if (try object.getOptional(globalThis, "autoImportJSX", bool)) |flag| { transpiler.runtime.auto_import_jsx = flag; } - if (object.getOptional(globalThis, "allowBunRuntime", bool) catch return transpiler) |flag| { + if (try object.getOptional(globalThis, "allowBunRuntime", bool)) |flag| { transpiler.runtime.allow_runtime = flag; } - if (object.getOptional(globalThis, "inline", bool) catch return transpiler) |flag| { + if (try object.getOptional(globalThis, "inline", bool)) |flag| { transpiler.runtime.inlining = flag; } - if (object.getOptional(globalThis, "minifyWhitespace", bool) catch return transpiler) |flag| { + if (try object.getOptional(globalThis, "minifyWhitespace", bool)) |flag| { transpiler.minify_whitespace = flag; } - if (object.getOptional(globalThis, "deadCodeElimination", bool) catch return transpiler) |flag| { + if (try object.getOptional(globalThis, "deadCodeElimination", bool)) |flag| { transpiler.dead_code_elimination = flag; } @@ -553,8 +545,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std transpiler.minify_identifiers = syntax; } } else { - JSC.throwInvalidArguments("Expected minify to be a boolean or an object", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("Expected minify to be a boolean or an object", .{}); + return error.JSError; } } @@ -569,8 +561,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std if (options.SourceMapOption.Map.fromJS(globalObject, flag)) |source| { transpiler.transform.source_map = source.toAPI(); } else { - JSC.throwInvalidArguments("sourcemap must be one of \"inline\", \"linked\", \"external\", or \"none\"", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("sourcemap must be one of \"inline\", \"linked\", \"external\", or \"none\"", .{}); + return error.JSError; } } } @@ -580,19 +572,19 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std } var tree_shaking: ?bool = null; - if (object.getOptional(globalThis, "treeShaking", bool) catch return transpiler) |treeShaking| { + if (try object.getOptional(globalThis, "treeShaking", bool)) |treeShaking| { tree_shaking = treeShaking; } var trim_unused_imports: ?bool = null; - if (object.getOptional(globalThis, "trimUnusedImports", bool) catch return transpiler) |trimUnusedImports| { + if (try object.getOptional(globalThis, "trimUnusedImports", bool)) |trimUnusedImports| { trim_unused_imports = trimUnusedImports; } if (object.getTruthy(globalThis, "exports")) |exports| { if (!exports.isObject()) { - JSC.throwInvalidArguments("exports must be an object", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("exports must be an object", .{}); + return error.JSError; } var replacements = Runtime.Features.ReplaceableExport.Map{}; @@ -600,8 +592,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std if (exports.getTruthy(globalThis, "eliminate")) |eliminate| { if (!eliminate.jsType().isArray()) { - JSC.throwInvalidArguments("exports.eliminate must be an array", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("exports.eliminate must be an array", .{}); + return error.JSError; } var total_name_buf_len: u32 = 0; @@ -628,8 +620,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std const str = value.getZigString(globalThis); if (str.len == 0) continue; const name = std.fmt.bufPrint(buf.items.ptr[buf.items.len..buf.capacity], "{}", .{str}) catch { - JSC.throwInvalidArguments("Error reading exports.eliminate. TODO: utf-16", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("Error reading exports.eliminate. TODO: utf-16", .{}); + return error.JSError; }; buf.items.len += name.len; if (name.len > 0) { @@ -642,8 +634,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std if (exports.getTruthy(globalThis, "replace")) |replace| { if (!replace.isObject()) { - JSC.throwInvalidArguments("replace must be an object", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("replace must be an object", .{}); + return error.JSError; } var iter = JSC.JSPropertyIterator(.{ @@ -657,7 +649,7 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std // We cannot set the exception before `try` because it could be // a double free with the `errdefer`. - defer if (exception.* != null) { + defer if (globalThis.hasException()) { iter.deinit(); for (replacements.keys()) |key| { bun.default_allocator.free(@constCast(key)); @@ -672,9 +664,9 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std const key = try key_.toOwnedSlice(bun.default_allocator); if (!JSLexer.isIdentifier(key)) { - JSC.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{key}, globalObject, exception); + globalObject.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{key}); bun.default_allocator.free(key); - return transpiler; + return error.JSError; } const entry = replacements.getOrPutAssumeCapacity(key); @@ -692,9 +684,9 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std const replacement_name = slice.slice(); if (!JSLexer.isIdentifier(replacement_name)) { - JSC.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{replacement_name}, globalObject, exception); + globalObject.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{replacement_name}); slice.deinit(); - return transpiler; + return error.JSError; } entry.value_ptr.* = .{ @@ -707,8 +699,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std } } - JSC.throwInvalidArguments("exports.replace values can only be string, null, undefined, number or boolean", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("exports.replace values can only be string, null, undefined, number or boolean", .{}); + return error.JSError; } } } @@ -721,8 +713,8 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std if (logger.Log.Level.Map.fromJS(globalObject, logLevel)) |level| { transpiler.log.level = level; } else { - JSC.throwInvalidArguments("logLevel must be one of \"verbose\", \"debug\", \"info\", \"warn\", or \"error\"", .{}, globalObject, exception); - return transpiler; + globalObject.throwInvalidArguments("logLevel must be one of \"verbose\", \"debug\", \"info\", \"warn\", or \"error\"", .{}); + return error.JSError; } } @@ -744,18 +736,18 @@ pub fn constructor( ); defer temp.deinit(); - var exception_ref = [_]JSC.C.JSValueRef{null}; - const exception = &exception_ref[0]; const transpiler_options: TranspilerOptions = if (arguments.len > 0) - transformOptionsFromJSC(globalThis, temp.allocator(), &args, exception) catch { - JSC.throwInvalidArguments("Failed to create transpiler", .{}, globalThis, exception); - return null; + transformOptionsFromJSC(globalThis, temp.allocator(), &args) catch |err| switch (err) { + error.JSError => return null, + error.OutOfMemory => { + globalThis.throwOutOfMemory(); + return null; + }, } else TranspilerOptions{ .log = logger.Log.init(getAllocator(globalThis)) }; - if (exception.* != null) { - globalThis.throwValue(JSC.JSValue.c(exception.*)); + if (globalThis.hasException()) { return null; } @@ -903,20 +895,17 @@ pub fn scan( defer code_holder.deinit(); const code = code_holder.slice(); args.eat(); - var exception_ref = [_]JSC.C.JSValueRef{null}; - const exception: JSC.C.ExceptionRef = &exception_ref; const loader: ?Loader = brk: { if (args.next()) |arg| { args.eat(); - break :brk Loader.fromJS(globalThis, arg, exception); + break :brk Loader.fromJS(globalThis, arg) catch return .zero; } break :brk null; }; - if (exception.* != null) { - globalThis.throwValue(JSC.JSValue.c(exception.*)); + if (globalThis.hasException()) { return .zero; } @@ -957,12 +946,7 @@ pub fn scan( const named_imports_value = namedImportsToJS( globalThis, parse_result.ast.import_records.slice(), - exception, ); - if (exception.* != null) { - globalThis.throwValue(JSC.JSValue.c(exception.*)); - return .zero; - } const named_exports_value = namedExportsToJS( globalThis, @@ -971,23 +955,12 @@ pub fn scan( return JSC.JSValue.createObject2(globalThis, imports_label, exports_label, named_imports_value, named_exports_value); } -// pub fn build( -// this: *Transpiler, -// ctx: js.JSContextRef, -// _: js.JSObjectRef, -// _: js.JSObjectRef, -// arguments: []const js.JSValueRef, -// exception: js.ExceptionRef, -// ) JSC.C.JSObjectRef {} - pub fn transform( this: *Transpiler, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame, ) JSC.JSValue { JSC.markBinding(@src()); - var exception_ref = [_]JSC.C.JSValueRef{null}; - const exception: JSC.C.ExceptionRef = &exception_ref; const arguments = callframe.arguments(3); var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.slice()); defer args.arena.deinit(); @@ -1000,23 +973,18 @@ pub fn transform( globalThis.throwInvalidArgumentType("transform", "code", "string or Uint8Array"); return .zero; }; + errdefer code.deinit(); args.eat(); const loader: ?Loader = brk: { if (args.next()) |arg| { args.eat(); - break :brk Loader.fromJS(globalThis, arg, exception); + break :brk Loader.fromJS(globalThis, arg) catch return .zero; } break :brk null; }; - if (exception.* != null) { - code.deinit(); - globalThis.throwValue(JSC.JSValue.c(exception.*)); - return .zero; - } - if (code == .buffer) { code_arg.protect(); } @@ -1042,8 +1010,6 @@ pub fn transformSync( callframe: *JSC.CallFrame, ) JSC.JSValue { JSC.markBinding(@src()); - var exception_value = [_]JSC.C.JSValueRef{null}; - const exception: JSC.C.ExceptionRef = &exception_value; const arguments = callframe.arguments(3); var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.slice()); @@ -1070,7 +1036,7 @@ pub fn transformSync( if (args.next()) |arg| { args.eat(); if (arg.isNumber() or arg.isString()) { - break :brk Loader.fromJS(globalThis, arg, exception); + break :brk Loader.fromJS(globalThis, arg) catch return .zero; } if (arg.isObject()) { @@ -1100,11 +1066,6 @@ pub fn transformSync( } } - if (exception.* != null) { - globalThis.throwValue(JSC.JSValue.c(exception.*)); - return .zero; - } - JSAst.Stmt.Data.Store.reset(); JSAst.Expr.Data.Store.reset(); defer { @@ -1201,7 +1162,6 @@ const ImportRecord = @import("../../import_record.zig").ImportRecord; fn namedImportsToJS( global: *JSGlobalObject, import_records: []const ImportRecord, - _: JSC.C.ExceptionRef, ) JSC.JSValue { const path_label = JSC.ZigString.static("path"); const kind_label = JSC.ZigString.static("kind"); @@ -1227,8 +1187,6 @@ pub fn scanImports( callframe: *JSC.CallFrame, ) JSC.JSValue { const arguments = callframe.arguments(2); - var exception_val = [_]JSC.C.JSValueRef{null}; - const exception: JSC.C.ExceptionRef = &exception_val; var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.slice()); defer args.deinit(); @@ -1238,12 +1196,9 @@ pub fn scanImports( }; const code_holder = JSC.Node.StringOrBuffer.fromJS(globalThis, args.arena.allocator(), code_arg) orelse { - if (exception.* == null) { + if (!globalThis.hasException()) { globalThis.throwInvalidArgumentType("scanImports", "code", "string or Uint8Array"); - } else { - globalThis.throwValue(JSC.JSValue.c(exception.*)); } - return .zero; }; args.eat(); @@ -1252,7 +1207,7 @@ pub fn scanImports( var loader: Loader = this.transpiler_options.default_loader; if (args.next()) |arg| { - if (Loader.fromJS(globalThis, arg, exception)) |_loader| { + if (Loader.fromJS(globalThis, arg) catch return .zero) |_loader| { loader = _loader; } args.eat(); @@ -1263,11 +1218,6 @@ pub fn scanImports( return .zero; } - if (exception.* != null) { - globalThis.throwValue(JSC.JSValue.c(exception.*)); - return .zero; - } - var arena = Mimalloc.Arena.init() catch unreachable; const prev_allocator = this.bundler.allocator; this.bundler.setAllocator(arena.allocator()); @@ -1329,11 +1279,6 @@ pub fn scanImports( const named_imports_value = namedImportsToJS( globalThis, this.scan_pass_result.import_records.items, - exception, ); - if (exception.* != null) { - globalThis.throwValue(JSC.JSValue.c(exception.*)); - return .zero; - } return named_imports_value; } diff --git a/src/bun.js/api/bun/h2_frame_parser.zig b/src/bun.js/api/bun/h2_frame_parser.zig index 535db8e26fa934..4fe99cc86d558c 100644 --- a/src/bun.js/api/bun/h2_frame_parser.zig +++ b/src/bun.js/api/bun/h2_frame_parser.zig @@ -586,15 +586,15 @@ const Handlers = struct { return this.vm.eventLoop().runCallbackWithResult(callback, this.globalObject, thisValue, data); } - pub fn fromJS(globalObject: *JSC.JSGlobalObject, opts: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Handlers { + pub fn fromJS(globalObject: *JSC.JSGlobalObject, opts: JSC.JSValue) bun.JSError!Handlers { var handlers = Handlers{ .vm = globalObject.bunVM(), .globalObject = globalObject, }; if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) { - exception.* = JSC.toInvalidArguments("Expected \"handlers\" to be an object", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"handlers\" to be an object", .{}); + return error.JSError; } const pairs = .{ @@ -617,8 +617,8 @@ const Handlers = struct { inline for (pairs) |pair| { if (opts.getTruthy(globalObject, pair.@"1")) |callback_value| { if (!callback_value.isCell() or !callback_value.isCallable(globalObject.vm())) { - exception.* = JSC.toInvalidArguments(comptime std.fmt.comptimePrint("Expected \"{s}\" callback to be a function", .{pair.@"1"}), .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"{s}\" callback to be a function", .{pair[1]}); + return error.JSError; } @field(handlers, pair.@"0") = callback_value; @@ -627,8 +627,8 @@ const Handlers = struct { if (opts.fastGet(globalObject, .@"error")) |callback_value| { if (!callback_value.isCell() or !callback_value.isCallable(globalObject.vm())) { - exception.* = JSC.toInvalidArguments("Expected \"error\" callback to be a function", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"error\" callback to be a function", .{}); + return error.JSError; } handlers.onError = callback_value; @@ -636,19 +636,19 @@ const Handlers = struct { // onWrite is required for duplex support or if more than 1 parser is attached to the same socket (unliked) if (handlers.onWrite == .zero) { - exception.* = JSC.toInvalidArguments("Expected at least \"write\" callback", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected at least \"write\" callback", .{}); + return error.JSError; } if (opts.getTruthy(globalObject, "binaryType")) |binary_type_value| { if (!binary_type_value.isString()) { - exception.* = JSC.toInvalidArguments("Expected \"binaryType\" to be a string", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"binaryType\" to be a string", .{}); + return error.JSError; } handlers.binary_type = BinaryType.fromJSValue(globalObject, binary_type_value) orelse { - exception.* = JSC.toInvalidArguments("Expected 'binaryType' to be 'arraybuffer', 'uint8array', 'buffer'", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected 'binaryType' to be 'ArrayBuffer', 'Uint8Array', or 'Buffer'", .{}); + return error.JSError; }; } @@ -3765,7 +3765,6 @@ pub const H2FrameParser = struct { return null; } - var exception: JSC.C.JSValueRef = null; const context_obj = options.get(globalObject, "context") orelse { globalObject.throw("Expected \"context\" option", .{}); return null; @@ -3774,10 +3773,7 @@ pub const H2FrameParser = struct { if (options.get(globalObject, "handlers")) |handlers_| { handler_js = handlers_; } - var handlers = Handlers.fromJS(globalObject, handler_js, &exception) orelse { - globalObject.throwValue(exception.?.value()); - return null; - }; + var handlers = Handlers.fromJS(globalObject, handler_js) catch return null; var this = brk: { if (ENABLE_ALLOCATOR_POOL) { diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig index ee52bcb260c271..7b59bf0f47bcdf 100644 --- a/src/bun.js/api/bun/socket.zig +++ b/src/bun.js/api/bun/socket.zig @@ -218,15 +218,15 @@ const Handlers = struct { return true; } - pub fn fromJS(globalObject: *JSC.JSGlobalObject, opts: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Handlers { + pub fn fromJS(globalObject: *JSC.JSGlobalObject, opts: JSC.JSValue) bun.JSError!Handlers { var handlers = Handlers{ .vm = globalObject.bunVM(), .globalObject = globalObject, }; if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) { - exception.* = JSC.toInvalidArguments("Expected \"socket\" to be an object", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"socket\" to be an object", .{}); + return error.JSError; } const pairs = .{ @@ -243,8 +243,8 @@ const Handlers = struct { inline for (pairs) |pair| { if (opts.getTruthyComptime(globalObject, pair.@"1")) |callback_value| { if (!callback_value.isCell() or !callback_value.isCallable(globalObject.vm())) { - exception.* = JSC.toInvalidArguments(comptime std.fmt.comptimePrint("Expected \"{s}\" callback to be a function", .{pair.@"1"}), .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"{s}\" callback to be a function", .{pair[1]}); + return error.JSError; } @field(handlers, pair.@"0") = callback_value; @@ -252,19 +252,19 @@ const Handlers = struct { } if (handlers.onData == .zero and handlers.onWritable == .zero) { - exception.* = JSC.toInvalidArguments("Expected at least \"data\" or \"drain\" callback", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected at least \"data\" or \"drain\" callback", .{}); + return error.JSError; } if (opts.getTruthy(globalObject, "binaryType")) |binary_type_value| { if (!binary_type_value.isString()) { - exception.* = JSC.toInvalidArguments("Expected \"binaryType\" to be a string", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"binaryType\" to be a string", .{}); + return error.JSError; } handlers.binary_type = BinaryType.fromJSValue(globalObject, binary_type_value) orelse { - exception.* = JSC.toInvalidArguments("Expected 'binaryType' to be 'arraybuffer', 'uint8array', 'buffer'", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected 'binaryType' to be 'ArrayBuffer', 'Uint8Array', or 'Buffer'", .{}); + return error.JSError; }; } @@ -320,8 +320,7 @@ pub const SocketConfig = struct { vm: *JSC.VirtualMachine, opts: JSC.JSValue, globalObject: *JSC.JSGlobalObject, - exception: JSC.C.ExceptionRef, - ) ?SocketConfig { + ) bun.JSError!SocketConfig { var hostname_or_unix: JSC.ZigString.Slice = JSC.ZigString.Slice.empty; var port: ?u16 = null; var exclusive = false; @@ -336,10 +335,8 @@ pub const SocketConfig = struct { ssl = JSC.API.ServerConfig.SSLConfig.zero; } } else { - if (JSC.API.ServerConfig.SSLConfig.inJS(vm, globalObject, tls, exception)) |ssl_config| { + if (try JSC.API.ServerConfig.SSLConfig.fromJS(vm, globalObject, tls)) |ssl_config| { ssl = ssl_config; - } else if (exception.* != null) { - return null; } } } @@ -353,8 +350,8 @@ pub const SocketConfig = struct { if (opts.getTruthy(globalObject, "unix")) |unix_socket| { if (!unix_socket.isString()) { - exception.* = JSC.toInvalidArguments("Expected \"unix\" to be a string", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"unix\" to be a string", .{}); + return error.JSError; } hostname_or_unix = unix_socket.getZigString(globalObject).toSlice(bun.default_allocator); @@ -378,8 +375,8 @@ pub const SocketConfig = struct { if (opts.getTruthy(globalObject, "hostname") orelse opts.getTruthy(globalObject, "host")) |hostname| { if (!hostname.isString()) { - exception.* = JSC.toInvalidArguments("Expected \"hostname\" to be a string", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"hostname\" to be a string", .{}); + return error.JSError; } var port_value = opts.get(globalObject, "port") orelse JSValue.zero; @@ -395,25 +392,25 @@ pub const SocketConfig = struct { } if (port_value.isEmptyOrUndefinedOrNull()) { - exception.* = JSC.toInvalidArguments("Expected \"port\" to be a number between 0 and 65535", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"port\" to be a number between 0 and 65535", .{}); + return error.JSError; } const porti32 = port_value.coerceToInt32(globalObject); if (globalObject.hasException()) { - return null; + return error.JSError; } if (porti32 < 0 or porti32 > 65535) { - exception.* = JSC.toInvalidArguments("Expected \"port\" to be a number between 0 and 65535", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"port\" to be a number between 0 and 65535", .{}); + return error.JSError; } port = @intCast(porti32); if (hostname_or_unix.len == 0) { - exception.* = JSC.toInvalidArguments("Expected \"hostname\" to be a non-empty string", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"hostname\" to be a non-empty string", .{}); + return error.JSError; } if (hostname_or_unix.len > 0) { @@ -422,18 +419,16 @@ pub const SocketConfig = struct { } if (hostname_or_unix.len == 0) { - exception.* = JSC.toInvalidArguments("Expected \"unix\" or \"hostname\" to be a non-empty string", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected \"unix\" or \"hostname\" to be a non-empty string", .{}); + return error.JSError; } - exception.* = JSC.toInvalidArguments("Expected either \"hostname\" or \"unix\"", .{}, globalObject).asObjectRef(); - return null; + globalObject.throwInvalidArguments("Expected either \"hostname\" or \"unix\"", .{}); + return error.JSError; } + errdefer hostname_or_unix.deinit(); - var handlers = Handlers.fromJS(globalObject, opts.get(globalObject, "socket") orelse JSValue.zero, exception) orelse { - hostname_or_unix.deinit(); - return null; - }; + var handlers = try Handlers.fromJS(globalObject, opts.get(globalObject, "socket") orelse JSValue.zero); if (opts.fastGet(globalObject, .data)) |default_data_value| { default_data = default_data_value; @@ -580,17 +575,12 @@ pub const Listener = struct { return .zero; } - var exception: JSC.C.JSValueRef = null; - const socket_obj = opts.get(globalObject, "socket") orelse { globalObject.throw("Expected \"socket\" object", .{}); return .zero; }; - const handlers = Handlers.fromJS(globalObject, socket_obj, &exception) orelse { - globalObject.throwValue(exception.?.value()); - return .zero; - }; + const handlers = Handlers.fromJS(globalObject, socket_obj) catch return .zero; var prev_handlers = &this.handlers; prev_handlers.unprotect(); @@ -602,23 +592,14 @@ pub const Listener = struct { pub fn listen(globalObject: *JSC.JSGlobalObject, opts: JSValue) JSValue { log("listen", .{}); - var exception_ = [1]JSC.JSValueRef{null}; - const exception: JSC.C.ExceptionRef = &exception_; - defer { - if (exception_[0] != null) { - globalObject.throwValue(exception_[0].?.value()); - } - } if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) { - exception.* = JSC.toInvalidArguments("Expected object", .{}, globalObject).asObjectRef(); + globalObject.throwInvalidArguments("Expected object", .{}); return .zero; } const vm = JSC.VirtualMachine.get(); - var socket_config = SocketConfig.fromJS(vm, opts, globalObject, exception) orelse { - return .zero; - }; + var socket_config = SocketConfig.fromJS(vm, opts, globalObject) catch return .zero; var hostname_or_unix = socket_config.hostname_or_unix; const port = socket_config.port; @@ -672,7 +653,7 @@ pub const Listener = struct { this.listener = .{ // we need to add support for the backlog parameter on listen here we use the default value of nodejs .namedPipe = WindowsNamedPipeListeningContext.listen(globalObject, pipe_name, 511, ssl, this) catch { - exception.* = JSC.toInvalidArguments("Failed to listen at {s}", .{pipe_name}, globalObject).asObjectRef(); + globalObject.throwInvalidArguments("Failed to listen at {s}", .{pipe_name}); this.deinit(); return .zero; }, @@ -715,7 +696,7 @@ pub const Listener = struct { } } - exception.* = err.asObjectRef(); + globalObject.throwValue(err); return .zero; }; @@ -791,10 +772,7 @@ pub const Listener = struct { defer bun.default_allocator.free(host); break :brk uws.us_socket_context_listen_unix(@intFromBool(ssl_enabled), socket_context, host, host.len, socket_flags, 8, &errno); }, - .fd => { - // don't call listen() on an fd - return .zero; - }, + .fd => unreachable, } } orelse { defer { @@ -815,8 +793,7 @@ pub const Listener = struct { err.put(globalObject, ZigString.static("code"), ZigString.init(@tagName(str)).toJS(globalObject)); } } - exception.* = err.asObjectRef(); - + globalObject.throwValue(err); return .zero; }; @@ -940,19 +917,13 @@ pub const Listener = struct { global.throwInvalidArguments("hostname pattern cannot be empty", .{}); return .zero; } - var exception_ref = [_]JSC.C.JSValueRef{null}; - const exception: JSC.C.ExceptionRef = &exception_ref; - if (JSC.API.ServerConfig.SSLConfig.inJS(JSC.VirtualMachine.get(), global, tls, exception)) |ssl_config| { + if (JSC.API.ServerConfig.SSLConfig.fromJS(JSC.VirtualMachine.get(), global, tls) catch return .zero) |ssl_config| { // to keep nodejs compatibility, we allow to replace the server name uws.us_socket_context_remove_server_name(1, this.socket_context, server_name); uws.us_bun_socket_context_add_server_name(1, this.socket_context, server_name, ssl_config.asUSockets(), null); } - if (exception.* != null) { - global.throwValue(exception_ref[0].?.value()); - return .zero; - } return JSValue.jsUndefined(); } @@ -1088,22 +1059,13 @@ pub const Listener = struct { globalObject: *JSC.JSGlobalObject, opts: JSValue, ) JSValue { - var exception_ = [1]JSC.JSValueRef{null}; - const exception: JSC.C.ExceptionRef = &exception_; - defer { - if (exception_[0] != null) { - globalObject.throwValue(exception_[0].?.value()); - } - } if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) { - exception.* = JSC.toInvalidArguments("Expected options object", .{}, globalObject).asObjectRef(); + globalObject.throwInvalidArguments("Expected options object", .{}); return .zero; } const vm = globalObject.bunVM(); - const socket_config = SocketConfig.fromJS(vm, opts, globalObject, exception) orelse { - return .zero; - }; + const socket_config = SocketConfig.fromJS(vm, opts, globalObject) catch return .zero; var hostname_or_unix = socket_config.hostname_or_unix; const port = socket_config.port; @@ -1239,7 +1201,7 @@ pub const Listener = struct { .syscall = bun.String.static("connect"), .code = if (port == null) bun.String.static("ENOENT") else bun.String.static("ECONNREFUSED"), }; - exception.* = err.toErrorInstance(globalObject).asObjectRef(); + globalObject.throwValue(err.toErrorInstance(globalObject)); handlers.unprotect(); connection.deinit(); return .zero; @@ -2644,17 +2606,12 @@ fn NewSocket(comptime ssl: bool) type { return .zero; } - var exception: JSC.C.JSValueRef = null; - const socket_obj = opts.get(globalObject, "socket") orelse { globalObject.throw("Expected \"socket\" option", .{}); return .zero; }; - const handlers = Handlers.fromJS(globalObject, socket_obj, &exception) orelse { - globalObject.throwValue(exception.?.value()); - return .zero; - }; + const handlers = Handlers.fromJS(globalObject, socket_obj) catch return .zero; var prev_handlers = this.handlers; prev_handlers.unprotect(); @@ -2782,8 +2739,6 @@ fn NewSocket(comptime ssl: bool) type { var arena: bun.ArenaAllocator = bun.ArenaAllocator.init(bun.default_allocator); defer arena.deinit(); - var exception_ref = [_]JSC.C.JSValueRef{null}; - const exception: JSC.C.ExceptionRef = &exception_ref; if (JSC.Node.StringOrBuffer.fromJS(globalObject, arena.allocator(), session_arg)) |sb| { defer sb.deinit(); const session_slice = sb.slice(); @@ -2795,9 +2750,6 @@ fn NewSocket(comptime ssl: bool) type { return .zero; } return JSValue.jsUndefined(); - } else if (exception.* != null) { - globalObject.throwValue(JSC.JSValue.c(exception.*)); - return .zero; } else { globalObject.throw("Expected session to be a string, Buffer or TypedArray", .{}); return .zero; @@ -2913,8 +2865,6 @@ fn NewSocket(comptime ssl: bool) type { var arena: bun.ArenaAllocator = bun.ArenaAllocator.init(bun.default_allocator); defer arena.deinit(); - var exception_ref = [_]JSC.C.JSValueRef{null}; - const exception: JSC.C.ExceptionRef = &exception_ref; if (JSC.Node.StringOrBuffer.fromJS(globalObject, arena.allocator(), context_arg)) |sb| { defer sb.deinit(); const context_slice = sb.slice(); @@ -2929,9 +2879,6 @@ fn NewSocket(comptime ssl: bool) type { return .zero; } return buffer; - } else if (exception.* != null) { - globalObject.throwValue(JSC.JSValue.c(exception.*)); - return .zero; } else { globalObject.throw("Expected context to be a string, Buffer or TypedArray", .{}); return .zero; @@ -3417,7 +3364,6 @@ fn NewSocket(comptime ssl: bool) type { return .zero; } - var exception: JSC.C.JSValueRef = null; var success = false; const opts = args.ptr[0]; @@ -3434,17 +3380,7 @@ fn NewSocket(comptime ssl: bool) type { return .zero; } - const handlers = Handlers.fromJS(globalObject, socket_obj, &exception) orelse { - if (!globalObject.hasException() and exception != null) { - globalObject.throwValue(exception.?.value()); - } - - return .zero; - }; - - if (!globalObject.hasException() and exception != null) { - globalObject.throwValue(exception.?.value()); - } + const handlers = Handlers.fromJS(globalObject, socket_obj) catch return .zero; if (globalObject.hasException()) { return .zero; @@ -3465,18 +3401,12 @@ fn NewSocket(comptime ssl: bool) type { ssl_opts = JSC.API.ServerConfig.SSLConfig.zero; } } else { - if (JSC.API.ServerConfig.SSLConfig.inJS(JSC.VirtualMachine.get(), globalObject, tls, &exception)) |ssl_config| { + if (JSC.API.ServerConfig.SSLConfig.fromJS(JSC.VirtualMachine.get(), globalObject, tls) catch return .zero) |ssl_config| { ssl_opts = ssl_config; } } } - if (exception != null) { - if (!globalObject.hasException()) { - globalObject.throwValue(exception.?.value()); - } - } - if (globalObject.hasException()) { return .zero; } @@ -4344,8 +4274,6 @@ pub fn jsUpgradeDuplexToTLS(globalObject: *JSC.JSGlobalObject, callframe: *JSC.C return .zero; } - var exception: JSC.C.JSValueRef = null; - const opts = args.ptr[1]; if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) { globalObject.throw("Expected options object", .{}); @@ -4357,10 +4285,7 @@ pub fn jsUpgradeDuplexToTLS(globalObject: *JSC.JSGlobalObject, callframe: *JSC.C return .zero; }; - var handlers = Handlers.fromJS(globalObject, socket_obj, &exception) orelse { - globalObject.throwValue(exception.?.value()); - return .zero; - }; + var handlers = Handlers.fromJS(globalObject, socket_obj) catch return .zero; var ssl_opts: ?JSC.API.ServerConfig.SSLConfig = null; if (opts.getTruthy(globalObject, "tls")) |tls| { @@ -4369,10 +4294,8 @@ pub fn jsUpgradeDuplexToTLS(globalObject: *JSC.JSGlobalObject, callframe: *JSC.C ssl_opts = JSC.API.ServerConfig.SSLConfig.zero; } } else { - if (JSC.API.ServerConfig.SSLConfig.inJS(JSC.VirtualMachine.get(), globalObject, tls, &exception)) |ssl_config| { + if (JSC.API.ServerConfig.SSLConfig.fromJS(JSC.VirtualMachine.get(), globalObject, tls) catch return .zero) |ssl_config| { ssl_opts = ssl_config; - } else if (exception != null) { - return .zero; } } } diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index b3a19337344da6..e6c33aa52acc0b 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -92,7 +92,8 @@ const httplog = Output.scoped(.Server, false); const ctxLog = Output.scoped(.RequestContext, false); const BlobFileContentResult = struct { data: [:0]const u8, - fn init(comptime fieldname: []const u8, js_obj: JSC.JSValue, global: *JSC.JSGlobalObject, exception: JSC.C.ExceptionRef) ?BlobFileContentResult { + + fn init(comptime fieldname: []const u8, js_obj: JSC.JSValue, global: *JSC.JSGlobalObject) bun.JSError!?BlobFileContentResult { if (JSC.WebCore.Body.Value.fromJS(global, js_obj)) |body| { if (body == .Blob and body.Blob.store != null and body.Blob.store.?.data == .file) { var fs: JSC.Node.NodeFS = .{}; @@ -100,15 +101,15 @@ const BlobFileContentResult = struct { switch (read) { .err => { global.throwValue(read.err.toJSC(global)); - return .{ .data = "" }; + return error.JSError; }, else => { const str = read.result.null_terminated; if (str.len > 0) { return .{ .data = str }; } - JSC.throwInvalidArguments(std.fmt.comptimePrint("Invalid {s} file", .{fieldname}), .{}, global, exception); - return .{ .data = str }; + global.throwInvalidArguments(std.fmt.comptimePrint("Invalid {s} file", .{fieldname}), .{}); + return error.JSError; }, } } @@ -747,15 +748,16 @@ pub const ServerConfig = struct { pub const zero = SSLConfig{}; - pub fn inJS(vm: *JSC.VirtualMachine, global: *JSC.JSGlobalObject, obj: JSC.JSValue, exception: JSC.C.ExceptionRef) ?SSLConfig { + pub fn fromJS(vm: *JSC.VirtualMachine, global: *JSC.JSGlobalObject, obj: JSC.JSValue) bun.JSError!?SSLConfig { var result = zero; + errdefer result.deinit(); var arena: bun.ArenaAllocator = bun.ArenaAllocator.init(bun.default_allocator); defer arena.deinit(); if (!obj.isObject()) { - JSC.throwInvalidArguments("tls option expects an object", .{}, global, exception); - return null; + global.throwInvalidArguments("tls option expects an object", .{}); + return error.JSError; } var any = false; @@ -769,10 +771,8 @@ pub const ServerConfig = struct { if (sliced.len > 0) { result.key_file_name = bun.default_allocator.dupeZ(u8, sliced.slice()) catch unreachable; if (std.posix.system.access(result.key_file_name, std.posix.F_OK) != 0) { - JSC.throwInvalidArguments("Unable to access keyFile path", .{}, global, exception); - result.deinit(); - - return null; + global.throwInvalidArguments("Unable to access keyFile path", .{}); + return error.JSError; } any = true; result.requires_custom_request_ctx = true; @@ -797,7 +797,7 @@ pub const ServerConfig = struct { any = true; result.requires_custom_request_ctx = true; } - } else if (BlobFileContentResult.init("key", item, global, exception)) |content| { + } else if (try BlobFileContentResult.init("key", item, global)) |content| { if (content.data.len > 0) { native_array[valid_count] = content.data.ptr; valid_count += 1; @@ -813,8 +813,7 @@ pub const ServerConfig = struct { global.throwInvalidArguments("key argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{}); // mark and free all keys result.key = native_array; - result.deinit(); - return null; + return error.JSError; } } @@ -826,7 +825,7 @@ pub const ServerConfig = struct { result.key_count = valid_count; } - } else if (BlobFileContentResult.init("key", js_obj, global, exception)) |content| { + } else if (try BlobFileContentResult.init("key", js_obj, global)) |content| { if (content.data.len > 0) { const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable; native_array[0] = content.data.ptr; @@ -856,8 +855,7 @@ pub const ServerConfig = struct { global.throwInvalidArguments("key argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{}); // mark and free all certs result.key = native_array; - result.deinit(); - return null; + return error.JSError; } } } @@ -868,9 +866,8 @@ pub const ServerConfig = struct { if (sliced.len > 0) { result.cert_file_name = bun.default_allocator.dupeZ(u8, sliced.slice()) catch unreachable; if (std.posix.system.access(result.cert_file_name, std.posix.F_OK) != 0) { - JSC.throwInvalidArguments("Unable to access certFile path", .{}, global, exception); - result.deinit(); - return null; + global.throwInvalidArguments("Unable to access certFile path", .{}); + return error.JSError; } any = true; result.requires_custom_request_ctx = true; @@ -890,8 +887,7 @@ pub const ServerConfig = struct { result.requires_custom_request_ctx = true; } else { global.throwInvalidArguments("ALPNProtocols argument must be an string, Buffer or TypedArray", .{}); - result.deinit(); - return null; + return error.JSError; } } @@ -913,7 +909,7 @@ pub const ServerConfig = struct { any = true; result.requires_custom_request_ctx = true; } - } else if (BlobFileContentResult.init("cert", item, global, exception)) |content| { + } else if (try BlobFileContentResult.init("cert", item, global)) |content| { if (content.data.len > 0) { native_array[valid_count] = content.data.ptr; valid_count += 1; @@ -929,8 +925,7 @@ pub const ServerConfig = struct { global.throwInvalidArguments("cert argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{}); // mark and free all certs result.cert = native_array; - result.deinit(); - return null; + return error.JSError; } } @@ -942,7 +937,7 @@ pub const ServerConfig = struct { result.cert_count = valid_count; } - } else if (BlobFileContentResult.init("cert", js_obj, global, exception)) |content| { + } else if (try BlobFileContentResult.init("cert", js_obj, global)) |content| { if (content.data.len > 0) { const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable; native_array[0] = content.data.ptr; @@ -972,8 +967,7 @@ pub const ServerConfig = struct { global.throwInvalidArguments("cert argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{}); // mark and free all certs result.cert = native_array; - result.deinit(); - return null; + return error.JSError; } } } @@ -984,8 +978,7 @@ pub const ServerConfig = struct { any = true; } else { global.throw("Expected requestCert to be a boolean", .{}); - result.deinit(); - return null; + return error.JSError; } } @@ -995,8 +988,7 @@ pub const ServerConfig = struct { any = true; } else { global.throw("Expected rejectUnauthorized to be a boolean", .{}); - result.deinit(); - return null; + return error.JSError; } } @@ -1038,7 +1030,7 @@ pub const ServerConfig = struct { any = true; result.requires_custom_request_ctx = true; } - } else if (BlobFileContentResult.init("ca", item, global, exception)) |content| { + } else if (try BlobFileContentResult.init("ca", item, global)) |content| { if (content.data.len > 0) { native_array[valid_count] = content.data.ptr; valid_count += 1; @@ -1054,8 +1046,7 @@ pub const ServerConfig = struct { global.throwInvalidArguments("ca argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{}); // mark and free all CA's result.cert = native_array; - result.deinit(); - return null; + return error.JSError; } } @@ -1067,7 +1058,7 @@ pub const ServerConfig = struct { result.ca_count = valid_count; } - } else if (BlobFileContentResult.init("ca", js_obj, global, exception)) |content| { + } else if (try BlobFileContentResult.init("ca", js_obj, global)) |content| { if (content.data.len > 0) { const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable; native_array[0] = content.data.ptr; @@ -1094,11 +1085,10 @@ pub const ServerConfig = struct { bun.default_allocator.free(native_array); } } else { - JSC.throwInvalidArguments("ca argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{}, global, exception); + global.throwInvalidArguments("ca argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{}); // mark and free all certs result.ca = native_array; - result.deinit(); - return null; + return error.JSError; } } } @@ -1109,9 +1099,8 @@ pub const ServerConfig = struct { if (sliced.len > 0) { result.ca_file_name = bun.default_allocator.dupeZ(u8, sliced.slice()) catch unreachable; if (std.posix.system.access(result.ca_file_name, std.posix.F_OK) != 0) { - JSC.throwInvalidArguments("Invalid caFile path", .{}, global, exception); - result.deinit(); - return null; + global.throwInvalidArguments("Invalid caFile path", .{}); + return error.JSError; } } } @@ -1141,9 +1130,8 @@ pub const ServerConfig = struct { if (sliced.len > 0) { result.dh_params_file_name = bun.default_allocator.dupeZ(u8, sliced.slice()) catch unreachable; if (std.posix.system.access(result.dh_params_file_name, std.posix.F_OK) != 0) { - JSC.throwInvalidArguments("Invalid dhParamsFile path", .{}, global, exception); - result.deinit(); - return null; + global.throwInvalidArguments("Invalid dhParamsFile path", .{}); + return error.JSError; } } } @@ -1162,8 +1150,7 @@ pub const ServerConfig = struct { any = true; } else { global.throw("Expected lowMemoryMode to be a boolean", .{}); - result.deinit(); - return null; + return error.JSError; } } } @@ -1178,8 +1165,7 @@ pub const ServerConfig = struct { global: *JSC.JSGlobalObject, args: *ServerConfig, arguments: *JSC.Node.ArgumentsSlice, - exception: JSC.C.ExceptionRef, - ) void { + ) bun.JSError!void { const vm = arguments.vm; const env = vm.bundler.env; @@ -1230,7 +1216,7 @@ pub const ServerConfig = struct { } defer { - if (global.hasException() or exception.* != null) { + if (global.hasException()) { if (args.ssl_config) |*conf| { conf.deinit(); args.ssl_config = null; @@ -1240,14 +1226,14 @@ pub const ServerConfig = struct { if (arguments.next()) |arg| { if (!arg.isObject()) { - JSC.throwInvalidArguments("Bun.serve expects an object", .{}, global, exception); - return; + global.throwInvalidArguments("Bun.serve expects an object", .{}); + return error.JSError; } if (arg.get(global, "static")) |static| { if (!static.isObject()) { - JSC.throwInvalidArguments("Bun.serve expects 'static' to be an object shaped like { [pathname: string]: Response }", .{}, global, exception); - return; + global.throwInvalidArguments("Bun.serve expects 'static' to be an object shaped like { [pathname: string]: Response }", .{}); + return error.JSError; } var iter = JSC.JSPropertyIterator(.{ @@ -1263,14 +1249,14 @@ pub const ServerConfig = struct { if (path.len == 0 or path[0] != '/') { bun.default_allocator.free(path); - JSC.throwInvalidArguments("Invalid static route \"{s}\". path must start with '/'", .{path}, global, exception); - return; + global.throwInvalidArguments("Invalid static route \"{s}\". path must start with '/'", .{path}); + return error.JSError; } if (!is_ascii) { bun.default_allocator.free(path); - JSC.throwInvalidArguments("Invalid static route \"{s}\". Please encode all non-ASCII characters in the path.", .{path}, global, exception); - return; + global.throwInvalidArguments("Invalid static route \"{s}\". Please encode all non-ASCII characters in the path.", .{path}); + return error.JSError; } if (StaticRoute.fromJS(global, value)) |route| { @@ -1280,28 +1266,27 @@ pub const ServerConfig = struct { }) catch bun.outOfMemory(); } else if (global.hasException()) { bun.default_allocator.free(path); - return; + return error.JSError; } else { Output.panic("Internal error: expected exception or static route", .{}); } } } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; if (arg.get(global, "idleTimeout")) |value| { if (!value.isUndefinedOrNull()) { if (!value.isAnyInt()) { - JSC.throwInvalidArguments("Bun.serve expects idleTimeout to be an integer", .{}, global, exception); - - return; + global.throwInvalidArguments("Bun.serve expects idleTimeout to be an integer", .{}); + return error.JSError; } args.has_idleTimeout = true; const idleTimeout: u64 = @intCast(@max(value.toInt64(), 0)); if (idleTimeout > 255) { - JSC.throwInvalidArguments("Bun.serve expects idleTimeout to be 255 or less", .{}, global, exception); - return; + global.throwInvalidArguments("Bun.serve expects idleTimeout to be 255 or less", .{}); + return error.JSError; } args.idleTimeout = @truncate(idleTimeout); @@ -1310,11 +1295,11 @@ pub const ServerConfig = struct { if (arg.getTruthy(global, "webSocket") orelse arg.getTruthy(global, "websocket")) |websocket_object| { if (!websocket_object.isObject()) { - JSC.throwInvalidArguments("Expected websocket to be an object", .{}, global, exception); + global.throwInvalidArguments("Expected websocket to be an object", .{}); if (args.ssl_config) |*conf| { conf.deinit(); } - return; + return error.JSError; } if (WebSocketServer.onCreate(global, websocket_object)) |wss| { @@ -1326,7 +1311,7 @@ pub const ServerConfig = struct { return; } } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; if (arg.getTruthy(global, "port")) |port_| { args.address.tcp.port = @as( @@ -1338,7 +1323,7 @@ pub const ServerConfig = struct { ); port = args.address.tcp.port; } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; if (arg.getTruthy(global, "baseURI")) |baseURI| { var sliced = baseURI.toSlice(global, bun.default_allocator); @@ -1348,7 +1333,7 @@ pub const ServerConfig = struct { args.base_uri = bun.default_allocator.dupe(u8, sliced.slice()) catch unreachable; } } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; if (arg.getTruthy(global, "hostname") orelse arg.getTruthy(global, "host")) |host| { const host_str = host.toSlice( @@ -1362,7 +1347,7 @@ pub const ServerConfig = struct { has_hostname = true; } } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; if (arg.getTruthy(global, "unix")) |unix| { const unix_str = unix.toSlice( @@ -1372,14 +1357,14 @@ pub const ServerConfig = struct { defer unix_str.deinit(); if (unix_str.len > 0) { if (has_hostname) { - JSC.throwInvalidArguments("Cannot specify both hostname and unix", .{}, global, exception); - return; + global.throwInvalidArguments("Cannot specify both hostname and unix", .{}); + return error.JSError; } args.address = .{ .unix = bun.default_allocator.dupeZ(u8, unix_str.slice()) catch unreachable }; } } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; if (arg.get(global, "id")) |id| { if (id.isUndefinedOrNull()) { @@ -1397,59 +1382,59 @@ pub const ServerConfig = struct { } } } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; if (arg.get(global, "development")) |dev| { args.development = dev.coerce(bool, global); args.reuse_port = !args.development; } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; if (arg.get(global, "reusePort")) |dev| { args.reuse_port = dev.coerce(bool, global); } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; if (arg.get(global, "inspector")) |inspector| { args.inspector = inspector.coerce(bool, global); if (args.inspector and !args.development) { - JSC.throwInvalidArguments("Cannot enable inspector in production. Please set development: true in Bun.serve()", .{}, global, exception); - return; + global.throwInvalidArguments("Cannot enable inspector in production. Please set development: true in Bun.serve()", .{}); + return error.JSError; } } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; if (arg.getTruthy(global, "maxRequestBodySize")) |max_request_body_size| { if (max_request_body_size.isNumber()) { args.max_request_body_size = @as(u64, @intCast(@max(0, max_request_body_size.toInt64()))); } } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; if (arg.getTruthyComptime(global, "error")) |onError| { if (!onError.isCallable(global.vm())) { - JSC.throwInvalidArguments("Expected error to be a function", .{}, global, exception); - return; + global.throwInvalidArguments("Expected error to be a function", .{}); + return error.JSError; } const onErrorSnapshot = onError.withAsyncContextIfNeeded(global); args.onError = onErrorSnapshot; onErrorSnapshot.protect(); } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; if (arg.getTruthy(global, "fetch")) |onRequest_| { if (!onRequest_.isCallable(global.vm())) { - JSC.throwInvalidArguments("Expected fetch() to be a function", .{}, global, exception); - return; + global.throwInvalidArguments("Expected fetch() to be a function", .{}); + return error.JSError; } const onRequest = onRequest_.withAsyncContextIfNeeded(global); JSC.C.JSValueProtect(global, onRequest.asObjectRef()); args.onRequest = onRequest; } else { - if (global.hasException()) return; - JSC.throwInvalidArguments("Expected fetch() to be a function", .{}, global, exception); - return; + if (global.hasException()) return error.JSError; + global.throwInvalidArguments("Expected fetch() to be a function", .{}); + return error.JSError; } if (arg.getTruthy(global, "tls")) |tls| { @@ -1458,17 +1443,13 @@ pub const ServerConfig = struct { } else if (tls.jsType().isArray()) { var value_iter = tls.arrayIterator(global); if (value_iter.len == 1) { - JSC.throwInvalidArguments("tls option expects at least 1 tls object", .{}, global, exception); - return; + global.throwInvalidArguments("tls option expects at least 1 tls object", .{}); + return error.JSError; } while (value_iter.next()) |item| { - var ssl_config = SSLConfig.inJS(vm, global, item, exception) orelse { - if (exception.* != null) { - return; - } - + var ssl_config = try SSLConfig.fromJS(vm, global, item) orelse { if (global.hasException()) { - return; + return error.JSError; } // Backwards-compatibility; we ignored empty tls objects. @@ -1480,8 +1461,8 @@ pub const ServerConfig = struct { } else { if (ssl_config.server_name == null or std.mem.span(ssl_config.server_name).len == 0) { defer ssl_config.deinit(); - JSC.throwInvalidArguments("SNI tls object must have a serverName", .{}, global, exception); - return; + global.throwInvalidArguments("SNI tls object must have a serverName", .{}); + return error.JSError; } if (args.sni == null) { args.sni = bun.BabyList(SSLConfig).initCapacity(bun.default_allocator, value_iter.len - 1) catch bun.outOfMemory(); @@ -1491,55 +1472,45 @@ pub const ServerConfig = struct { } } } else { - if (SSLConfig.inJS(vm, global, tls, exception)) |ssl_config| { + if (try SSLConfig.fromJS(vm, global, tls)) |ssl_config| { args.ssl_config = ssl_config; } - - if (exception.* != null) { - return; - } - if (global.hasException()) { - return; + return error.JSError; } } } - if (global.hasException()) return; + if (global.hasException()) return error.JSError; // @compatibility Bun v0.x - v0.2.1 // this used to be top-level, now it's "tls" object if (args.ssl_config == null) { - if (SSLConfig.inJS(vm, global, arg, exception)) |ssl_config| { + if (try SSLConfig.fromJS(vm, global, arg)) |ssl_config| { args.ssl_config = ssl_config; } - - if (exception.* != null) { - return; - } - if (global.hasException()) { - return; + return error.JSError; } } } else { - JSC.throwInvalidArguments("Bun.serve expects an object", .{}, global, exception); - return; + global.throwInvalidArguments("Bun.serve expects an object", .{}); + return error.JSError; } if (args.base_uri.len > 0) { args.base_url = URL.parse(args.base_uri); if (args.base_url.hostname.len == 0) { - JSC.throwInvalidArguments("baseURI must have a hostname", .{}, global, exception); + global.throwInvalidArguments("baseURI must have a hostname", .{}); bun.default_allocator.free(@constCast(args.base_uri)); args.base_uri = ""; - return; + return error.JSError; } if (!strings.isAllASCII(args.base_uri)) { - JSC.throwInvalidArguments("Unicode baseURI must already be encoded for now.\nnew URL(baseuRI).toString() should do the trick.", .{}, global, exception); + global.throwInvalidArguments("Unicode baseURI must already be encoded for now.\nnew URL(baseuRI).toString() should do the trick.", .{}); bun.default_allocator.free(@constCast(args.base_uri)); args.base_uri = ""; - return; + return error.JSError; } if (args.base_url.protocol.len == 0) { @@ -1604,10 +1575,10 @@ pub const ServerConfig = struct { } if (!strings.isAllASCII(hostname)) { - JSC.throwInvalidArguments("Unicode hostnames must already be encoded for now.\nnew URL(input).hostname should do the trick.", .{}, global, exception); + global.throwInvalidArguments("Unicode hostnames must already be encoded for now.\nnew URL(input).hostname should do the trick.", .{}); bun.default_allocator.free(@constCast(args.base_uri)); args.base_uri = ""; - return; + return error.JSError; } args.base_url = URL.parse(args.base_uri); @@ -1616,17 +1587,17 @@ pub const ServerConfig = struct { // I don't think there's a case where this can happen // but let's check anyway, just in case if (args.base_url.hostname.len == 0) { - JSC.throwInvalidArguments("baseURI must have a hostname", .{}, global, exception); + global.throwInvalidArguments("baseURI must have a hostname", .{}); bun.default_allocator.free(@constCast(args.base_uri)); args.base_uri = ""; - return; + return error.JSError; } if (args.base_url.username.len > 0 or args.base_url.password.len > 0) { - JSC.throwInvalidArguments("baseURI can't have a username or password", .{}, global, exception); + global.throwInvalidArguments("baseURI can't have a username or password", .{}); bun.default_allocator.free(@constCast(args.base_uri)); args.base_uri = ""; - return; + return error.JSError; } return; @@ -5900,7 +5871,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp this.config.idleTimeout = @truncate(@min(seconds, 255)); } - pub fn publish(this: *ThisServer, globalThis: *JSC.JSGlobalObject, topic: ZigString, message_value: JSValue, compress_value: ?JSValue, exception: JSC.C.ExceptionRef) JSValue { + pub fn publish(this: *ThisServer, globalThis: *JSC.JSGlobalObject, topic: ZigString, message_value: JSValue, compress_value: ?JSValue) JSValue { if (this.config.websocket == null) return JSValue.jsNumber(0); @@ -5908,14 +5879,14 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp if (topic.len == 0) { httplog("publish() topic invalid", .{}); - exception.* = JSC.createError(globalThis, "publish requires a topic string", .{}).asObjectRef(); + globalThis.throw("publish requires a topic string", .{}); return .zero; } var topic_slice = topic.toSlice(bun.default_allocator); defer topic_slice.deinit(); if (topic_slice.len == 0) { - exception.* = JSC.createError(globalThis, "publish requires a non-empty topic", .{}).asObjectRef(); + globalThis.throw("publish requires a non-empty topic", .{}); return .zero; } @@ -5949,11 +5920,10 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp globalThis: *JSC.JSGlobalObject, object: JSC.JSValue, optional: ?JSValue, - exception: js.ExceptionRef, - ) JSValue { + ) bun.JSError!JSValue { if (this.config.websocket == null) { - JSC.throwInvalidArguments("To enable websocket support, set the \"websocket\" object in Bun.serve({})", .{}, globalThis, exception); - return JSValue.jsUndefined(); + globalThis.throwInvalidArguments("To enable websocket support, set the \"websocket\" object in Bun.serve({})", .{}); + return error.JSError; } if (this.flags.terminated) { @@ -5961,8 +5931,8 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp } var request = object.as(Request) orelse { - JSC.throwInvalidArguments("upgrade requires a Request object", .{}, globalThis, exception); - return JSValue.jsUndefined(); + globalThis.throwInvalidArguments("upgrade requires a Request object", .{}); + return error.JSError; }; var upgrader = request.request_context.get(RequestContext) orelse return JSC.jsBoolean(false); @@ -6033,8 +6003,8 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp } if (!opts.isObject()) { - JSC.throwInvalidArguments("upgrade options must be an object", .{}, globalThis, exception); - return JSValue.jsUndefined(); + globalThis.throwInvalidArguments("upgrade options must be an object", .{}); + return error.JSError; } if (opts.fastGet(globalThis, .data)) |headers_value| { @@ -6042,7 +6012,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp } if (globalThis.hasException()) { - return JSValue.jsUndefined(); + return error.JSError; } if (opts.fastGet(globalThis, .headers)) |headers_value| { @@ -6060,13 +6030,13 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp break :brk null; } orelse { if (!globalThis.hasException()) { - JSC.throwInvalidArguments("upgrade options.headers must be a Headers or an object", .{}, globalThis, exception); + globalThis.throwInvalidArguments("upgrade options.headers must be a Headers or an object", .{}); } - return JSValue.jsUndefined(); + return error.JSError; }; if (globalThis.hasException()) { - return JSValue.jsUndefined(); + return error.JSError; } if (fetch_headers_to_use.fastGet(.SecWebSocketProtocol)) |protocol| { @@ -6084,7 +6054,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp } if (globalThis.hasException()) { - return JSValue.jsUndefined(); + return error.JSError; } } } @@ -6174,16 +6144,9 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp var args_slice = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); defer args_slice.deinit(); - var exception_ref = [_]JSC.C.JSValueRef{null}; - const exception: JSC.C.ExceptionRef = &exception_ref; var new_config: ServerConfig = .{}; - ServerConfig.fromJS(globalThis, &new_config, &args_slice, exception); - if (exception.* != null) { - new_config.deinit(); - globalThis.throwValue(exception_ref[0].?.value()); - return .zero; - } + ServerConfig.fromJS(globalThis, &new_config, &args_slice) catch return .zero; if (globalThis.hasException()) { new_config.deinit(); return .zero; diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig index 461d6f0112a706..acf7aecd21ae9a 100644 --- a/src/bun.js/base.zig +++ b/src/bun.js/base.zig @@ -413,7 +413,8 @@ pub const ArrayBuffer = extern struct { pub fn fromTypedArray(ctx: JSC.C.JSContextRef, value: JSC.JSValue) ArrayBuffer { var out = std.mem.zeroes(ArrayBuffer); - bun.assert(value.asArrayBuffer_(ctx.ptr(), &out)); + const was = value.asArrayBuffer_(ctx.ptr(), &out); + bun.assert(was); out.value = value; return out; } @@ -605,7 +606,7 @@ pub const MarkedArrayBuffer = struct { return MarkedArrayBuffer.fromBytes(buf, allocator, JSC.JSValue.JSType.Uint8Array); } - pub fn fromJS(global: *JSC.JSGlobalObject, value: JSC.JSValue, _: JSC.C.ExceptionRef) ?MarkedArrayBuffer { + pub fn fromJS(global: *JSC.JSGlobalObject, value: JSC.JSValue) ?MarkedArrayBuffer { const array_buffer = value.asArrayBuffer(global) orelse return null; return MarkedArrayBuffer{ .buffer = array_buffer, .allocator = null }; } @@ -1160,7 +1161,10 @@ pub fn wrapInstanceMethod( } } - return @call(.always_inline, @field(Container, name), args); + const result = @call(.always_inline, @field(Container, name), args); + if (@TypeOf(result) == JSValue) return result; + if (@TypeOf(result) == bun.JSError!JSValue) return result catch .zero; + comptime unreachable; } }.method; } diff --git a/src/bun.js/bindings/ImportMetaObject.cpp b/src/bun.js/bindings/ImportMetaObject.cpp index c3525feb04dfaf..61b64f0229da44 100644 --- a/src/bun.js/bindings/ImportMetaObject.cpp +++ b/src/bun.js/bindings/ImportMetaObject.cpp @@ -80,6 +80,7 @@ static JSC::EncodedJSValue functionRequireResolve(JSC::JSGlobalObject* globalObj BunString from = Bun::toString(fromStr); auto result = Bun__resolveSyncWithSource(globalObject, JSC::JSValue::encode(moduleName), &from, false); + RETURN_IF_EXCEPTION(scope, {}); if (!JSC::JSValue::decode(result).isString()) { JSC::throwException(globalObject, scope, JSC::JSValue::decode(result)); @@ -260,6 +261,7 @@ extern "C" JSC::EncodedJSValue functionImportMeta__resolveSync(JSC::JSGlobalObje } auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), from, isESM); + RETURN_IF_EXCEPTION(scope, {}); if (!JSC::JSValue::decode(result).isString()) { JSC::throwException(globalObject, scope, JSC::JSValue::decode(result)); @@ -330,6 +332,7 @@ extern "C" JSC::EncodedJSValue functionImportMeta__resolveSyncPrivate(JSC::JSGlo } auto result = Bun__resolveSync(lexicalGlobalObject, JSC::JSValue::encode(moduleName), JSValue::encode(from), isESM); + RETURN_IF_EXCEPTION(scope, {}); if (!JSC::JSValue::decode(result).isString()) { JSC::throwException(lexicalGlobalObject, scope, JSC::JSValue::decode(result)); @@ -426,6 +429,8 @@ JSC_DEFINE_HOST_FUNCTION(functionImportMeta__resolve, auto a = Bun::toString(specifier); auto b = Bun::toString(fromWTFString); auto result = JSValue::decode(Bun__resolveSyncWithStrings(globalObject, &a, &b, true)); + RETURN_IF_EXCEPTION(scope, {}); + if (!result.isString()) { JSC::throwException(globalObject, scope, result); return {}; diff --git a/src/bun.js/modules/NodeModuleModule.cpp b/src/bun.js/modules/NodeModuleModule.cpp index f412eb67859a81..e913e937b97608 100644 --- a/src/bun.js/modules/NodeModuleModule.cpp +++ b/src/bun.js/modules/NodeModuleModule.cpp @@ -354,9 +354,9 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionResolveFileName, } } - auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), - JSValue::encode(fromValue), false); auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), JSValue::encode(fromValue), false); + RETURN_IF_EXCEPTION(scope, {}); if (!JSC::JSValue::decode(result).isString()) { JSC::throwException(globalObject, scope, JSC::JSValue::decode(result)); diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig index 8d644c66d89a55..94003ef968bd25 100644 --- a/src/bun.js/node/node_fs.zig +++ b/src/bun.js/node/node_fs.zig @@ -1281,29 +1281,15 @@ pub const Arguments = struct { this.new_path.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Rename { - const old_path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "oldPath must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Rename { + const old_path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("oldPath must be a string or TypedArray", .{}); + return error.JSError; }; - const new_path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "newPath must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + const new_path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("newPath must be a string or TypedArray", .{}); + return error.JSError; }; return Rename{ .old_path = old_path, .new_path = new_path }; @@ -1328,17 +1314,10 @@ pub const Arguments = struct { this.path.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Truncate { - const path = PathOrFileDescriptor.fromJS(ctx, arguments, bun.default_allocator, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Truncate { + const path = try PathOrFileDescriptor.fromJS(ctx, arguments, bun.default_allocator) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; const len: JSC.WebCore.Blob.SizeType = brk: { @@ -1378,50 +1357,25 @@ pub const Arguments = struct { this.buffers.buffers.allocator = bun.default_allocator; } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Writev { + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Writev { const fd_value = arguments.nextEat() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "file descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("file descriptor is required", .{}); + return error.JSError; }; - const fd = JSC.Node.fileDescriptorFromJS(ctx, fd_value, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "file descriptor must be a number", - .{}, - ctx, - exception, - ); - } - return null; + const fd = try JSC.Node.fileDescriptorFromJS(ctx, fd_value) orelse { + ctx.throwInvalidArguments("file descriptor must be a number", .{}); + return error.JSError; }; - const buffers = JSC.Node.VectorArrayBuffer.fromJS( + const buffers = try JSC.Node.VectorArrayBuffer.fromJS( ctx, arguments.protectEatNext() orelse { - JSC.throwInvalidArguments("Expected an ArrayBufferView[]", .{}, ctx, exception); - return null; + ctx.throwInvalidArguments("Expected an ArrayBufferView[]", .{}); + return error.JSError; }, - exception, arguments.arena.allocator(), - ) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "buffers must be an array of TypedArray", - .{}, - ctx, - exception, - ); - } - return null; - }; + ); var position: ?u52 = null; @@ -1430,13 +1384,8 @@ pub const Arguments = struct { if (pos_value.isNumber()) { position = pos_value.to(u52); } else { - JSC.throwInvalidArguments( - "position must be a number", - .{}, - ctx, - exception, - ); - return null; + ctx.throwInvalidArguments("position must be a number", .{}); + return error.JSError; } } } @@ -1469,50 +1418,25 @@ pub const Arguments = struct { this.buffers.buffers.allocator = bun.default_allocator; } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Readv { + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Readv { const fd_value = arguments.nextEat() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "file descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("file descriptor is required", .{}); + return error.JSError; }; - const fd = JSC.Node.fileDescriptorFromJS(ctx, fd_value, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "file descriptor must be a number", - .{}, - ctx, - exception, - ); - } - return null; + const fd = try JSC.Node.fileDescriptorFromJS(ctx, fd_value) orelse { + ctx.throwInvalidArguments("file descriptor must be a number", .{}); + return error.JSError; }; - const buffers = JSC.Node.VectorArrayBuffer.fromJS( + const buffers = try JSC.Node.VectorArrayBuffer.fromJS( ctx, arguments.protectEatNext() orelse { - JSC.throwInvalidArguments("Expected an ArrayBufferView[]", .{}, ctx, exception); - return null; + ctx.throwInvalidArguments("Expected an ArrayBufferView[]", .{}); + return error.JSError; }, - exception, arguments.arena.allocator(), - ) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "buffers must be an array of TypedArray", - .{}, - ctx, - exception, - ); - } - return null; - }; + ); var position: ?u52 = null; @@ -1521,13 +1445,8 @@ pub const Arguments = struct { if (pos_value.isNumber()) { position = pos_value.to(u52); } else { - JSC.throwInvalidArguments( - "position must be a number", - .{}, - ctx, - exception, - ); - return null; + ctx.throwInvalidArguments("position must be a number", .{}); + return error.JSError; } } } @@ -1552,33 +1471,17 @@ pub const Arguments = struct { _ = this; } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?FTruncate { - const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "file descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "file descriptor must be a number", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!FTruncate { + const fd = try JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { + ctx.throwInvalidArguments("file descriptor is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("file descriptor must be a number", .{}); + return error.JSError; }; arguments.eat(); - if (exception.* != null) return null; - const len: JSC.WebCore.Blob.SizeType = brk: { const len_value = arguments.next() orelse break :brk 0; if (len_value.isNumber()) { @@ -1610,57 +1513,37 @@ pub const Arguments = struct { this.path.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Chown { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Chown { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; + errdefer path.deinit(); const uid: uid_t = brk: { const uid_value = arguments.next() orelse break :brk { - if (exception.* == null) { - JSC.throwInvalidArguments( - "uid is required", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("uid is required", .{}); + return error.JSError; }; arguments.eat(); if (!uid_value.isNumber()) { _ = ctx.throwInvalidArgumentTypeValue("uid", "number", uid_value); - return null; + return error.JSError; } break :brk @as(uid_t, @intCast(uid_value.toInt32())); }; const gid: gid_t = brk: { const gid_value = arguments.next() orelse break :brk { - if (exception.* == null) { - JSC.throwInvalidArguments( - "gid is required", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("gid is required", .{}); + return error.JSError; }; arguments.eat(); if (!gid_value.isNumber()) { _ = ctx.throwInvalidArgumentTypeValue("gid", "number", gid_value); - return null; + return error.JSError; } break :brk @as(gid_t, @intCast(gid_value.toInt32())); }; @@ -1678,42 +1561,19 @@ pub const Arguments = struct { pub fn toThreadSafe(_: *const @This()) void {} - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Fchown { - const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "file descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "file descriptor must be a number", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Fchown { + const fd = try JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { + ctx.throwInvalidArguments("file descriptor is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("file descriptor must be a number", .{}); + return error.JSError; }; - if (exception.* != null) return null; - const uid: uid_t = brk: { const uid_value = arguments.next() orelse break :brk { - if (exception.* == null) { - JSC.throwInvalidArguments( - "uid is required", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("uid is required", .{}); + return error.JSError; }; arguments.eat(); @@ -1722,15 +1582,8 @@ pub const Arguments = struct { const gid: gid_t = brk: { const gid_value = arguments.next() orelse break :brk { - if (exception.* == null) { - JSC.throwInvalidArguments( - "gid is required", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("gid is required", .{}); + return error.JSError; }; arguments.eat(); @@ -1760,65 +1613,29 @@ pub const Arguments = struct { this.path.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Lutimes { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Lutimes { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; + errdefer path.deinit(); const atime = JSC.Node.timeLikeFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "atime is required", - .{}, - ctx, - exception, - ); - } - - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "atime must be a number or a Date", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("atime is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("atime must be a number or a Date", .{}); + return error.JSError; }; arguments.eat(); const mtime = JSC.Node.timeLikeFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "mtime is required", - .{}, - ctx, - exception, - ); - } - - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "mtime must be a number or a Date", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("mtime is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("mtime must be a number or a Date", .{}); + return error.JSError; }; arguments.eat(); @@ -1843,39 +1660,19 @@ pub const Arguments = struct { this.path.deinitAndUnprotect(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Chmod { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Chmod { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; + errdefer path.deinit(); - const mode: Mode = JSC.Node.modeFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "mode is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "mode must be a string or integer", - .{}, - ctx, - exception, - ); - } - return null; + const mode: Mode = try JSC.Node.modeFromJS(ctx, arguments.next() orelse { + ctx.throwInvalidArguments("mode is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("mode must be a string or integer", .{}); + return error.JSError; }; arguments.eat(); @@ -1892,52 +1689,23 @@ pub const Arguments = struct { pub fn toThreadSafe(_: *const @This()) void {} - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?FChmod { - const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "file descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "file descriptor must be a number", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!FChmod { + const fd = try JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { + ctx.throwInvalidArguments("file descriptor is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("file descriptor must be a number", .{}); + return error.JSError; }; - if (exception.* != null) return null; arguments.eat(); - const mode: Mode = JSC.Node.modeFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "mode is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "mode must be a string or integer", - .{}, - ctx, - exception, - ); - } - return null; + const mode: Mode = try JSC.Node.modeFromJS(ctx, arguments.next() orelse { + ctx.throwInvalidArguments("mode is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("mode must be a string or integer", .{}); + return error.JSError; }; arguments.eat(); @@ -1965,20 +1733,12 @@ pub const Arguments = struct { this.path.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Stat { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Stat { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer path.deinit(); var throw_if_no_entry = true; @@ -1988,17 +1748,11 @@ pub const Arguments = struct { if (next_val.isCallable(ctx.vm())) break :brk false; arguments.eat(); - if (next_val.getOptional(ctx, "throwIfNoEntry", bool) catch { - path.deinit(); - return null; - }) |throw_if_no_entry_val| { + if (try next_val.getOptional(ctx, "throwIfNoEntry", bool)) |throw_if_no_entry_val| { throw_if_no_entry = throw_if_no_entry_val; } - if (next_val.getOptional(ctx, "bigint", bool) catch { - path.deinit(); - return null; - }) |big_int| { + if (try next_val.getOptional(ctx, "bigint", bool)) |big_int| { break :brk big_int; } } @@ -2006,8 +1760,6 @@ pub const Arguments = struct { break :brk false; }; - if (exception.* != null) return null; - return Stat{ .path = path, .big_int = big_int, .throw_if_no_entry = throw_if_no_entry }; } }; @@ -2020,38 +1772,22 @@ pub const Arguments = struct { pub fn toThreadSafe(_: *@This()) void {} - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Fstat { - const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "file descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "file descriptor must be a number", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Fstat { + const fd = try JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { + ctx.throwInvalidArguments("file descriptor is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("file descriptor must be a number", .{}); + return error.JSError; }; - if (exception.* != null) return null; - const big_int = brk: { if (arguments.next()) |next_val| { if (next_val.isObject()) { if (next_val.isCallable(ctx.vm())) break :brk false; arguments.eat(); - if (next_val.getOptional(ctx, "bigint", bool) catch false) |big_int| { + if (try next_val.getOptional(ctx, "bigint", bool)) |big_int| { break :brk big_int; } } @@ -2059,8 +1795,6 @@ pub const Arguments = struct { break :brk false; }; - if (exception.* != null) return null; - return Fstat{ .fd = fd, .big_int = big_int }; } }; @@ -2086,35 +1820,17 @@ pub const Arguments = struct { this.new_path.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Link { - const old_path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "oldPath must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Link { + const old_path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("oldPath must be a string or TypedArray", .{}); + return error.JSError; }; - if (exception.* != null) return null; - - const new_path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "newPath must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + const new_path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("newPath must be a string or TypedArray", .{}); + return error.JSError; }; - if (exception.* != null) return null; - return Link{ .old_path = old_path, .new_path = new_path }; } }; @@ -2150,35 +1866,17 @@ pub const Arguments = struct { this.new_path.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Symlink { - const old_path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "target must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Symlink { + const old_path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("oldPath must be a string or TypedArray", .{}); + return error.JSError; }; - if (exception.* != null) return null; - - const new_path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + const new_path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("newPath must be a string or TypedArray", .{}); + return error.JSError; }; - if (exception.* != null) return null; - const link_type: LinkType = if (!Environment.isWindows) 0 else link_type: { @@ -2198,15 +1896,8 @@ pub const Arguments = struct { if (str.eqlComptime("dir")) break :link_type .dir; if (str.eqlComptime("file")) break :link_type .file; if (str.eqlComptime("junction")) break :link_type .junction; - if (exception.* == null) { - JSC.throwInvalidArguments( - "Symlink type must be one of \"dir\", \"file\", or \"junction\". Received \"{}\"", - .{str}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("Symlink type must be one of \"dir\", \"file\", or \"junction\". Received \"{}\"", .{str}); + return error.JSError; } // not a string. fallthrough to auto detect. @@ -2243,43 +1934,29 @@ pub const Arguments = struct { this.path.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Readlink { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Readlink { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; + errdefer path.deinit(); - if (exception.* != null) return null; var encoding = Encoding.utf8; if (arguments.next()) |val| { arguments.eat(); switch (val.jsType()) { JSC.JSValue.JSType.String, JSC.JSValue.JSType.StringObject, JSC.JSValue.JSType.DerivedStringObject => { - // Exception handled below. - encoding = Encoding.assert(val, ctx, encoding) catch encoding; + encoding = try Encoding.assert(val, ctx, encoding); }, else => { if (val.isObject()) { - // Exception handled below. - encoding = getEncoding(val, ctx, encoding) catch encoding; + encoding = try getEncoding(val, ctx, encoding); } }, } } - if (ctx.hasException()) { - path.deinit(); - return null; - } - return Readlink{ .path = path, .encoding = encoding }; } }; @@ -2300,48 +1977,34 @@ pub const Arguments = struct { this.path.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Realpath { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Realpath { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; + errdefer path.deinit(); - if (exception.* != null) return null; var encoding = Encoding.utf8; if (arguments.next()) |val| { arguments.eat(); switch (val.jsType()) { JSC.JSValue.JSType.String, JSC.JSValue.JSType.StringObject, JSC.JSValue.JSType.DerivedStringObject => { - // Exception handled below. - encoding = Encoding.assert(val, ctx, encoding) catch encoding; + encoding = try Encoding.assert(val, ctx, encoding); }, else => { if (val.isObject()) { - // Exception handled below. - encoding = getEncoding(val, ctx, encoding) catch encoding; + encoding = try getEncoding(val, ctx, encoding); } }, } } - if (ctx.hasException()) { - path.deinit(); - return null; - } - return Realpath{ .path = path, .encoding = encoding }; } }; - fn getEncoding(object: JSC.JSValue, globalObject: *JSC.JSGlobalObject, default: Encoding) !Encoding { + fn getEncoding(object: JSC.JSValue, globalObject: *JSC.JSGlobalObject, default: Encoding) bun.JSError!Encoding { if (object.fastGet(globalObject, .encoding)) |value| { return Encoding.assert(value, globalObject, default); } @@ -2364,20 +2027,12 @@ pub const Arguments = struct { this.path.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Unlink { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Unlink { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer path.deinit(); return Unlink{ .path = path, @@ -2408,20 +2063,12 @@ pub const Arguments = struct { this.path.deinit(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?RmDir { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!RmDir { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer path.deinit(); var recursive = false; var force = false; @@ -2429,17 +2076,11 @@ pub const Arguments = struct { arguments.eat(); if (val.isObject()) { - if (val.getOptional(ctx, "recursive", bool) catch { - path.deinit(); - return null; - }) |boolean| { + if (try val.getOptional(ctx, "recursive", bool)) |boolean| { recursive = boolean; } - if (val.getOptional(ctx, "force", bool) catch { - path.deinit(); - return null; - }) |boolean| { + if (try val.getOptional(ctx, "force", bool)) |boolean| { force = boolean; } } @@ -2479,20 +2120,12 @@ pub const Arguments = struct { this.path.toThreadSafe(); } - pub fn fromJS(ctx: *JSC.JSGlobalObject, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Mkdir { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: *JSC.JSGlobalObject, arguments: *ArgumentsSlice) bun.JSError!Mkdir { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer path.deinit(); var recursive = false; var mode: Mode = 0o777; @@ -2501,16 +2134,12 @@ pub const Arguments = struct { arguments.eat(); if (val.isObject()) { - if (val.getOptional(ctx, "recursive", bool) catch { - path.deinit(); - return null; - }) |boolean| { + if (try val.getOptional(ctx, "recursive", bool)) |boolean| { recursive = boolean; } if (val.get(ctx, "mode")) |mode_| { - mode = JSC.Node.modeFromJS(ctx, mode_, exception) orelse mode; - if (exception.* != null) return null; + mode = try JSC.Node.modeFromJS(ctx, mode_) orelse mode; } } } @@ -2539,22 +2168,14 @@ pub const Arguments = struct { this.prefix.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?MkdirTemp { + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!MkdirTemp { const prefix_value = arguments.next() orelse return MkdirTemp{}; const prefix = StringOrBuffer.fromJS(ctx, bun.default_allocator, prefix_value) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "prefix must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("prefix must be a string or TypedArray", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer prefix.deinit(); arguments.eat(); @@ -2565,22 +2186,16 @@ pub const Arguments = struct { switch (val.jsType()) { JSC.JSValue.JSType.String, JSC.JSValue.JSType.StringObject, JSC.JSValue.JSType.DerivedStringObject => { - // exception handled below. - encoding = Encoding.assert(val, ctx, encoding) catch encoding; + encoding = try Encoding.assert(val, ctx, encoding); }, else => { if (val.isObject()) { - encoding = getEncoding(val, ctx, encoding) catch encoding; + encoding = try getEncoding(val, ctx, encoding); } }, } } - if (ctx.hasException()) { - prefix.deinit(); - return null; - } - return MkdirTemp{ .prefix = prefix, .encoding = encoding, @@ -2616,20 +2231,12 @@ pub const Arguments = struct { }; } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Readdir { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Readdir { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer path.deinit(); var encoding = Encoding.utf8; var with_file_types = false; @@ -2639,32 +2246,21 @@ pub const Arguments = struct { arguments.eat(); switch (val.jsType()) { - JSC.JSValue.JSType.String, JSC.JSValue.JSType.StringObject, JSC.JSValue.JSType.DerivedStringObject => { - encoding = Encoding.assert(val, ctx, encoding) catch { - path.deinit(); - return null; - }; + .String, + .StringObject, + .DerivedStringObject, + => { + encoding = try Encoding.assert(val, ctx, encoding); }, else => { if (val.isObject()) { - encoding = getEncoding(val, ctx, encoding) catch encoding; - - if (ctx.hasException()) { - path.deinit(); - return null; - } + encoding = try getEncoding(val, ctx, encoding); - if (val.getOptional(ctx, "recursive", bool) catch { - path.deinit(); - return null; - }) |recursive_| { + if (try val.getOptional(ctx, "recursive", bool)) |recursive_| { recursive = recursive_; } - if (val.getOptional(ctx, "withFileTypes", bool) catch { - path.deinit(); - return null; - }) |with_file_types_| { + if (try val.getOptional(ctx, "withFileTypes", bool)) |with_file_types_| { with_file_types = with_file_types_; } } @@ -2687,31 +2283,15 @@ pub const Arguments = struct { pub fn deinit(_: Close) void {} pub fn toThreadSafe(_: Close) void {} - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Close { - const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "File descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "fd must be a number", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Close { + const fd = try JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { + ctx.throwInvalidArguments("file descriptor is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("file descriptor must be a number", .{}); + return error.JSError; }; - if (exception.* != null) return null; - return Close{ .fd = fd }; } }; @@ -2733,20 +2313,12 @@ pub const Arguments = struct { this.path.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Open { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Open { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer path.deinit(); var flags = FileSystemFlags.r; var mode: Mode = default_permission; @@ -2756,30 +2328,24 @@ pub const Arguments = struct { if (val.isObject()) { if (val.getTruthy(ctx, "flags")) |flags_| { - flags = FileSystemFlags.fromJS(ctx, flags_, exception) orelse flags; - if (exception.* != null) return null; + flags = try FileSystemFlags.fromJS(ctx, flags_) orelse flags; } if (val.getTruthy(ctx, "mode")) |mode_| { - mode = JSC.Node.modeFromJS(ctx, mode_, exception) orelse mode; - if (exception.* != null) return null; + mode = try JSC.Node.modeFromJS(ctx, mode_) orelse mode; } } else if (!val.isEmpty()) { if (!val.isUndefinedOrNull()) { // error is handled below - flags = FileSystemFlags.fromJS(ctx, val, exception) orelse flags; - if (exception.* != null) return null; + flags = try FileSystemFlags.fromJS(ctx, val) orelse flags; } if (arguments.nextEat()) |next| { - mode = JSC.Node.modeFromJS(ctx, next, exception) orelse mode; - if (exception.* != null) return null; + mode = try JSC.Node.modeFromJS(ctx, next) orelse mode; } } } - if (exception.* != null) return null; - return Open{ .path = path, .flags = flags, @@ -2808,78 +2374,33 @@ pub const Arguments = struct { _ = self; } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Futimes { - const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "File descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "fd must be a number", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Futimes { + const fd = try JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { + ctx.throwInvalidArguments("file descriptor is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("file descriptor must be a number", .{}); + return error.JSError; }; arguments.eat(); - if (exception.* != null) return null; const atime = JSC.Node.timeLikeFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "atime is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "atime must be a number, Date or string", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("atime is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("atime must be a number or a Date", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + arguments.eat(); const mtime = JSC.Node.timeLikeFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "mtime is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "mtime must be a number, Date or string", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("mtime is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("mtime must be a number or a Date", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + arguments.eat(); return Futimes{ .fd = fd, @@ -2934,54 +2455,27 @@ pub const Arguments = struct { self.buffer.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Write { - const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "File descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "fd must be a number", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Write { + const fd = try JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { + ctx.throwInvalidArguments("file descriptor is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("file descriptor must be a number", .{}); + return error.JSError; }; - arguments.eat(); - if (exception.* != null) return null; - const buffer_value = arguments.next(); const buffer = StringOrBuffer.fromJS(ctx, bun.default_allocator, buffer_value orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "data is required", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("data is required", .{}); + return error.JSError; }) orelse { - if (exception.* == null) { - _ = ctx.throwInvalidArgumentTypeValue("buffer", "string or TypedArray", buffer_value.?); - } - return null; + _ = ctx.throwInvalidArgumentTypeValue("buffer", "string or TypedArray", buffer_value.?); + return error.JSError; }; - if (exception.* != null) return null; if (buffer_value.?.isString() and !buffer_value.?.isStringLiteral()) { _ = ctx.throwInvalidArgumentTypeValue("buffer", "string or TypedArray", buffer_value.?); - return null; + return error.JSError; } var args = Write{ @@ -2992,6 +2486,7 @@ pub const Arguments = struct { inline else => Encoding.utf8, }, }; + errdefer args.deinit(); arguments.eat(); @@ -3009,10 +2504,7 @@ pub const Arguments = struct { } if (current.isString()) { - args.encoding = Encoding.assert(current, ctx, args.encoding) catch { - args.deinit(); - return null; - }; + args.encoding = try Encoding.assert(current, ctx, args.encoding); arguments.eat(); } }, @@ -3061,58 +2553,24 @@ pub const Arguments = struct { this.buffer.buffer.value.unprotect(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Read { - const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "File descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "fd must be a number", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Read { + const fd = try JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { + ctx.throwInvalidArguments("file descriptor is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("file descriptor must be a number", .{}); + return error.JSError; }; - arguments.eat(); - if (exception.* != null) return null; - const buffer_value = arguments.next(); - const buffer: Buffer = Buffer.fromJS(ctx, buffer_value orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "buffer is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "buffer must be a TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + const buffer = Buffer.fromJS(ctx, buffer_value orelse { + ctx.throwInvalidArguments("buffer is required", .{}); + return error.JSError; + }) orelse { + _ = ctx.throwInvalidArgumentTypeValue("buffer", "TypedArray", buffer_value.?); + return error.JSError; }; - - if (exception.* != null) return null; - arguments.eat(); var args = Read{ @@ -3127,8 +2585,8 @@ pub const Arguments = struct { args.offset = current.to(u52); if (arguments.remaining.len < 1) { - JSC.throwInvalidArguments("length is required", .{}, ctx, exception); - return null; + ctx.throwInvalidArguments("length is required", .{}); + return error.JSError; } const arg_length = arguments.next().?; @@ -3170,7 +2628,7 @@ pub const Arguments = struct { if (defined_length and args.length > 0 and buffer.slice().len == 0) { var formatter = bun.JSC.ConsoleObject.Formatter{ .globalThis = ctx }; ctx.ERR_INVALID_ARG_VALUE("The argument 'buffer' is empty and cannot be written. Received {}", .{buffer_value.?.toFmt(&formatter)}).throw(); - return null; + return error.JSError; } return args; @@ -3204,20 +2662,12 @@ pub const Arguments = struct { self.path.toThreadSafe(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?ReadFile { - const path = PathOrFileDescriptor.fromJS(ctx, arguments, bun.default_allocator, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or a file descriptor", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!ReadFile { + const path = try PathOrFileDescriptor.fromJS(ctx, arguments, bun.default_allocator) orelse { + ctx.throwInvalidArguments("path must be a string or a file descriptor", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer path.deinit(); var encoding = Encoding.buffer; var flag = FileSystemFlags.r; @@ -3225,36 +2675,16 @@ pub const Arguments = struct { if (arguments.next()) |arg| { arguments.eat(); if (arg.isString()) { - encoding = Encoding.assert(arg, ctx, encoding) catch { - path.deinit(); - return null; - }; + encoding = try Encoding.assert(arg, ctx, encoding); } else if (arg.isObject()) { - encoding = getEncoding(arg, ctx, encoding) catch encoding; - - if (ctx.hasException()) { - path.deinit(); - return null; - } + encoding = try getEncoding(arg, ctx, encoding); if (arg.getTruthy(ctx, "flag")) |flag_| { - flag = FileSystemFlags.fromJS(ctx, flag_, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "Invalid flag", - .{}, - ctx, - exception, - ); - } - return null; + flag = try FileSystemFlags.fromJS(ctx, flag_) orelse { + ctx.throwInvalidArguments("Invalid flag", .{}); + return error.JSError; }; } - - if (ctx.hasException()) { - path.deinit(); - return null; - } } } @@ -3295,32 +2725,16 @@ pub const Arguments = struct { self.data.deinitAndUnprotect(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?WriteFile { - const file = PathOrFileDescriptor.fromJS(ctx, arguments, bun.default_allocator, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or a file descriptor", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!WriteFile { + const path = try PathOrFileDescriptor.fromJS(ctx, arguments, bun.default_allocator) orelse { + ctx.throwInvalidArguments("path must be a string or a file descriptor", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer path.deinit(); const data_value = arguments.nextEat() orelse { - defer file.deinit(); - if (exception.* == null) { - JSC.throwInvalidArguments( - "data is required", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("data is required", .{}); + return error.JSError; }; var encoding = Encoding.buffer; @@ -3334,68 +2748,34 @@ pub const Arguments = struct { if (arguments.next()) |arg| { arguments.eat(); if (arg.isString()) { - encoding = Encoding.assert(arg, ctx, encoding) catch encoding; + encoding = try Encoding.assert(arg, ctx, encoding); } else if (arg.isObject()) { - encoding = getEncoding(arg, ctx, encoding) catch encoding; - - if (ctx.hasException()) { - file.deinit(); - return null; - } + encoding = try getEncoding(arg, ctx, encoding); if (arg.getTruthy(ctx, "flag")) |flag_| { - flag = FileSystemFlags.fromJS(ctx, flag_, exception) orelse { - defer file.deinit(); - if (exception.* == null) { - JSC.throwInvalidArguments( - "Invalid flag", - .{}, - ctx, - exception, - ); - } - return null; + flag = try FileSystemFlags.fromJS(ctx, flag_) orelse { + ctx.throwInvalidArguments("Invalid flag", .{}); + return error.JSError; }; } if (arg.getTruthy(ctx, "mode")) |mode_| { - mode = JSC.Node.modeFromJS(ctx, mode_, exception) orelse { - defer file.deinit(); - if (exception.* == null) { - JSC.throwInvalidArguments( - "Invalid flag", - .{}, - ctx, - exception, - ); - } - return null; + mode = try JSC.Node.modeFromJS(ctx, mode_) orelse { + ctx.throwInvalidArguments("Invalid mode", .{}); + return error.JSError; }; } } } - if (ctx.hasException()) { - file.deinit(); - return null; - } - const data = StringOrBuffer.fromJSWithEncodingMaybeAsync(ctx, bun.default_allocator, data_value, encoding, arguments.will_be_async) orelse { - defer file.deinit(); - if (exception.* == null) { - JSC.throwInvalidArguments( - "data must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("data must be a string or TypedArray", .{}); + return error.JSError; }; // Note: Signal is not implemented return WriteFile{ - .file = file, + .file = path, .encoding = encoding, .flag = flag, .mode = mode, @@ -3418,20 +2798,12 @@ pub const Arguments = struct { self.path.deinit(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?OpenDir { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or a file descriptor", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!OpenDir { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer path.deinit(); var encoding = Encoding.buffer; var buffer_size: c_int = 32; @@ -3445,33 +2817,16 @@ pub const Arguments = struct { encoding = encoding_; } - if (ctx.hasException()) { - path.deinit(); - return null; - } - if (arg.get(ctx, "bufferSize")) |buffer_size_| { buffer_size = buffer_size_.toInt32(); if (buffer_size < 0) { - if (exception.* == null) { - JSC.throwInvalidArguments( - "bufferSize must be > 0", - .{}, - ctx, - exception, - ); - } - return null; + ctx.throwInvalidArguments("bufferSize must be > 0", .{}); + return error.JSError; } } } } - if (ctx.hasException()) { - path.deinit(); - return null; - } - return OpenDir{ .path = path, .encoding = encoding, @@ -3501,9 +2856,9 @@ pub const Arguments = struct { } } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Exists { + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Exists { return Exists{ - .path = PathLike.fromJS(ctx, arguments, exception), + .path = try PathLike.fromJS(ctx, arguments), }; } }; @@ -3524,36 +2879,21 @@ pub const Arguments = struct { this.path.deinitAndUnprotect(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Access { - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "path must be a string or buffer", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Access { + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("path must be a string or TypedArray", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer path.deinit(); var mode = FileSystemFlags.r; if (arguments.next()) |arg| { arguments.eat(); if (arg.isString()) { - mode = FileSystemFlags.fromJS(ctx, arg, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "Invalid mode", - .{}, - ctx, - exception, - ); - } - return null; + mode = try FileSystemFlags.fromJS(ctx, arg) orelse { + ctx.throwInvalidArguments("Invalid mode", .{}); + return error.JSError; }; } } @@ -3573,30 +2913,15 @@ pub const Arguments = struct { _ = self; } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?FdataSync { - const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "File descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "fd must be a number", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!FdataSync { + const fd = try JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { + ctx.throwInvalidArguments("file descriptor is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("file descriptor must be a number", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + arguments.eat(); return FdataSync{ .fd = fd }; } @@ -3622,36 +2947,18 @@ pub const Arguments = struct { this.dest.deinitAndUnprotect(); } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?CopyFile { - const src = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "src must be a string or buffer", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!CopyFile { + const src = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("src must be a string or TypedArray", .{}); + return error.JSError; }; + errdefer src.deinit(); - if (exception.* != null) return null; - - const dest = PathLike.fromJS(ctx, arguments, exception) orelse { - src.deinit(); - - if (exception.* == null) { - JSC.throwInvalidArguments( - "dest must be a string or buffer", - .{}, - ctx, - exception, - ); - } - return null; + const dest = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("dest must be a string or TypedArray", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer dest.deinit(); var mode: i32 = 0; if (arguments.next()) |arg| { @@ -3689,35 +2996,18 @@ pub const Arguments = struct { } } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Cp { - const src = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "src must be a string or buffer", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Cp { + const src = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("src must be a string or TypedArray", .{}); + return error.JSError; }; + errdefer src.deinit(); - if (exception.* != null) return null; - - const dest = PathLike.fromJS(ctx, arguments, exception) orelse { - defer src.deinit(); - if (exception.* == null) { - JSC.throwInvalidArguments( - "dest must be a string or buffer", - .{}, - ctx, - exception, - ); - } - return null; + const dest = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("dest must be a string or TypedArray", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + errdefer dest.deinit(); var recursive: bool = false; var errorOnExist: bool = false; @@ -3783,30 +3073,15 @@ pub const Arguments = struct { pub fn deinit(_: Fsync) void {} pub fn toThreadSafe(_: *const @This()) void {} - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Fsync { - const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "File descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "fd must be a number", - .{}, - ctx, - exception, - ); - } - return null; + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Fsync { + const fd = try JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { + ctx.throwInvalidArguments("file descriptor is required", .{}); + return error.JSError; + }) orelse { + ctx.throwInvalidArguments("file descriptor must be a number", .{}); + return error.JSError; }; - - if (exception.* != null) return null; + arguments.eat(); return Fsync{ .fd = fd }; } diff --git a/src/bun.js/node/node_fs_binding.zig b/src/bun.js/node/node_fs_binding.zig index 927e40c43abb05..202ab5bf1f902d 100644 --- a/src/bun.js/node/node_fs_binding.zig +++ b/src/bun.js/node/node_fs_binding.zig @@ -35,32 +35,20 @@ fn callSync(comptime FunctionEnum: NodeFSFunctionEnum) NodeFSFunction { globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame, ) JSC.JSValue { - var exceptionref: JSC.C.JSValueRef = null; - var arguments = callframe.arguments(8); var slice = ArgumentsSlice.init(globalObject.bunVM(), arguments.slice()); defer slice.deinit(); const args = if (comptime Arguments != void) - (Arguments.fromJS(globalObject, &slice, &exceptionref) orelse { - // we might've already thrown - if (exceptionref != null) - globalObject.throwValue(JSC.JSValue.c(exceptionref)); - return .zero; - }) + (Arguments.fromJS(globalObject, &slice) catch return .zero) else Arguments{}; defer { if (comptime Arguments != void and @hasDecl(Arguments, "deinit")) args.deinit(); } - const exception1 = JSC.JSValue.c(exceptionref); - - if (exception1 != .zero) { - globalObject.throwValue(exception1); - return .zero; - } else if (globalObject.hasException()) { + if (globalObject.hasException()) { return .zero; } var result = Function( @@ -96,25 +84,15 @@ fn call(comptime FunctionEnum: NodeFSFunctionEnum) NodeFSFunction { var slice = ArgumentsSlice.init(globalObject.bunVM(), arguments.slice()); slice.will_be_async = true; - var exceptionref: JSC.C.JSValueRef = null; const args = if (comptime Arguments != void) - (Arguments.fromJS(globalObject, &slice, &exceptionref) orelse { - // we might've already thrown - if (exceptionref != null) - globalObject.throwValue(JSC.JSValue.c(exceptionref)); + (Arguments.fromJS(globalObject, &slice) catch { slice.deinit(); return .zero; }) else Arguments{}; - const exception1 = JSC.JSValue.c(exceptionref); - - if (exception1 != .zero) { - globalObject.throwValue(exception1); - slice.deinit(); - return .zero; - } else if (globalObject.hasException()) { + if (globalObject.hasException()) { slice.deinit(); return .zero; } diff --git a/src/bun.js/node/node_fs_stat_watcher.zig b/src/bun.js/node/node_fs_stat_watcher.zig index 5f197a0c1b0223..5c34738bc315cc 100644 --- a/src/bun.js/node/node_fs_stat_watcher.zig +++ b/src/bun.js/node/node_fs_stat_watcher.zig @@ -234,22 +234,13 @@ pub const StatWatcher = struct { global_this: JSC.C.JSContextRef, - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Arguments { + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Arguments { const vm = ctx.vm(); - const path = PathLike.fromJSWithAllocator(ctx, arguments, bun.default_allocator, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "filename must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + const path = try PathLike.fromJSWithAllocator(ctx, arguments, bun.default_allocator) orelse { + ctx.throwInvalidArguments("filename must be a string or TypedArray", .{}); + return error.JSError; }; - if (exception.* != null) return null; - var listener: JSC.JSValue = .zero; var persistent: bool = true; var bigint: bool = false; @@ -259,20 +250,15 @@ pub const StatWatcher = struct { // options if (options_or_callable.isObject()) { // default true - persistent = (options_or_callable.getOptional(ctx, "persistent", bool) catch return null) orelse true; + persistent = (try options_or_callable.getOptional(ctx, "persistent", bool)) orelse true; // default false - bigint = (options_or_callable.getOptional(ctx, "bigint", bool) catch return null) orelse false; + bigint = (try options_or_callable.getOptional(ctx, "bigint", bool)) orelse false; if (options_or_callable.get(ctx, "interval")) |interval_| { if (!interval_.isNumber() and !interval_.isAnyInt()) { - JSC.throwInvalidArguments( - "interval must be a number.", - .{}, - ctx, - exception, - ); - return null; + ctx.throwInvalidArguments("interval must be a number", .{}); + return error.JSError; } interval = interval_.coerce(i32, ctx); } @@ -286,8 +272,8 @@ pub const StatWatcher = struct { } if (listener == .zero) { - exception.* = JSC.toInvalidArguments("Expected \"listener\" callback", .{}, ctx).asObjectRef(); - return null; + ctx.throwInvalidArguments("Expected \"listener\" callback", .{}); + return error.JSError; } return Arguments{ diff --git a/src/bun.js/node/node_fs_watcher.zig b/src/bun.js/node/node_fs_watcher.zig index 8eeb4acd95737a..3a6c92690c683b 100644 --- a/src/bun.js/node/node_fs_watcher.zig +++ b/src/bun.js/node/node_fs_watcher.zig @@ -340,23 +340,16 @@ pub const FSWatcher = struct { recursive: bool, encoding: JSC.Node.Encoding, verbose: bool, - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Arguments { + + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Arguments { const vm = ctx.vm(); - const path = PathLike.fromJS(ctx, arguments, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "filename must be a string or TypedArray", - .{}, - ctx, - exception, - ); - } - return null; + const path = try PathLike.fromJS(ctx, arguments) orelse { + ctx.throwInvalidArguments("filename must be a string or TypedArray", .{}); + return error.JSError; }; var should_deinit_path = true; defer if (should_deinit_path) path.deinit(); - if (exception.* != null) return null; var listener: JSC.JSValue = .zero; var signal: ?*JSC.AbortSignal = null; var persistent: bool = true; @@ -369,43 +362,28 @@ pub const FSWatcher = struct { if (options_or_callable.isObject()) { if (options_or_callable.getTruthy(ctx, "persistent")) |persistent_| { if (!persistent_.isBoolean()) { - JSC.throwInvalidArguments( - "persistent must be a boolean.", - .{}, - ctx, - exception, - ); - return null; + ctx.throwInvalidArguments("persistent must be a boolean", .{}); + return error.JSError; } persistent = persistent_.toBoolean(); } if (options_or_callable.getTruthy(ctx, "verbose")) |verbose_| { if (!verbose_.isBoolean()) { - JSC.throwInvalidArguments( - "verbose must be a boolean.", - .{}, - ctx, - exception, - ); - return null; + ctx.throwInvalidArguments("verbose must be a boolean", .{}); + return error.JSError; } verbose = verbose_.toBoolean(); } if (options_or_callable.fastGet(ctx, .encoding)) |encoding_| { - encoding = JSC.Node.Encoding.assert(encoding_, ctx, encoding) catch return null; + encoding = try JSC.Node.Encoding.assert(encoding_, ctx, encoding); } if (options_or_callable.getTruthy(ctx, "recursive")) |recursive_| { if (!recursive_.isBoolean()) { - JSC.throwInvalidArguments( - "recursive must be a boolean.", - .{}, - ctx, - exception, - ); - return null; + ctx.throwInvalidArguments("recursive must be a boolean", .{}); + return error.JSError; } recursive = recursive_.toBoolean(); } @@ -417,36 +395,30 @@ pub const FSWatcher = struct { signal_.ensureStillAlive(); signal = signal_obj; } else { - JSC.throwInvalidArguments( - "signal is not of type AbortSignal.", - .{}, - ctx, - exception, - ); - - return null; + ctx.throwInvalidArguments("signal is not of type AbortSignal", .{}); + return error.JSError; } } // listener if (arguments.nextEat()) |callable| { if (!callable.isCell() or !callable.isCallable(vm)) { - exception.* = JSC.toInvalidArguments("Expected \"listener\" callback to be a function", .{}, ctx).asObjectRef(); - return null; + ctx.throwInvalidArguments("Expected \"listener\" callback to be a function", .{}); + return error.JSError; } listener = callable; } } else { if (!options_or_callable.isCell() or !options_or_callable.isCallable(vm)) { - exception.* = JSC.toInvalidArguments("Expected \"listener\" callback to be a function", .{}, ctx).asObjectRef(); - return null; + ctx.throwInvalidArguments("Expected \"listener\" callback to be a function", .{}); + return error.JSError; } listener = options_or_callable; } } if (listener == .zero) { - exception.* = JSC.toInvalidArguments("Expected \"listener\" callback", .{}, ctx).asObjectRef(); - return null; + ctx.throwInvalidArguments("Expected \"listener\" callback", .{}); + return error.JSError; } should_deinit_path = false; diff --git a/src/bun.js/node/node_zlib_binding.zig b/src/bun.js/node/node_zlib_binding.zig index 02aca9890f107c..210cc4d9c0fb0e 100644 --- a/src/bun.js/node/node_zlib_binding.zig +++ b/src/bun.js/node/node_zlib_binding.zig @@ -12,7 +12,6 @@ pub fn crc32(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callcon const data: ZigString.Slice = blk: { const data: JSC.JSValue = arguments[0]; - var exceptionref: JSC.C.JSValueRef = null; if (data == .zero) { return globalThis.throwInvalidArgumentTypeValue("data", "string or an instance of Buffer, TypedArray, or DataView", .undefined); @@ -20,16 +19,12 @@ pub fn crc32(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callcon if (data.isString()) { break :blk data.asString().toSlice(globalThis, bun.default_allocator); } - const buffer: JSC.Buffer = JSC.Buffer.fromJS(globalThis, data, &exceptionref) orelse { + const buffer: JSC.Buffer = JSC.Buffer.fromJS(globalThis, data) orelse { const ty_str = data.jsTypeString(globalThis).toSlice(globalThis, bun.default_allocator); defer ty_str.deinit(); globalThis.ERR_INVALID_ARG_TYPE("The \"data\" property must be an instance of Buffer, TypedArray, DataView, or ArrayBuffer. Received {s}", .{ty_str.slice()}).throw(); return .zero; }; - if (exceptionref) |ptr| { - globalThis.throwValue(JSC.JSValue.c(ptr)); - return .zero; - } break :blk ZigString.Slice.fromUTF8NeverFree(buffer.slice()); }; defer data.deinit(); diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig index 4f9af557d77e08..098ac92c958535 100644 --- a/src/bun.js/node/types.zig +++ b/src/bun.js/node/types.zig @@ -532,8 +532,11 @@ pub const StringOrBuffer = union(enum) { pub fn fromJSMaybeAsync(global: *JSC.JSGlobalObject, allocator: std.mem.Allocator, value: JSC.JSValue, is_async: bool) ?StringOrBuffer { return switch (value.jsType()) { - JSC.JSValue.JSType.String, JSC.JSValue.JSType.StringObject, JSC.JSValue.JSType.DerivedStringObject, JSC.JSValue.JSType.Object => { - const str = bun.String.tryFromJS(value, global) orelse return null; + .String, + .StringObject, + .DerivedStringObject, + => { + const str = bun.String.fromJS(value, global); if (is_async) { defer str.deref(); @@ -676,24 +679,20 @@ pub const Encoding = enum(u8) { return strings.inMapCaseInsensitive(slice, map); } - pub fn assert(value: JSC.JSValue, globalObject: *JSC.JSGlobalObject, default: Encoding) !Encoding { + pub fn assert(value: JSC.JSValue, globalObject: *JSC.JSGlobalObject, default: Encoding) bun.JSError!Encoding { if (value.isFalsey()) { return default; } if (!value.isString()) { - throwEncodingError(globalObject, value); - return error.JSError; + return throwEncodingError(globalObject, value); } - return fromJSWithDefaultOnEmpty(value, globalObject, default) orelse { - throwEncodingError(globalObject, value); - return error.JSError; - }; + return try fromJSWithDefaultOnEmpty(value, globalObject, default) orelse throwEncodingError(globalObject, value); } - pub fn fromJSWithDefaultOnEmpty(value: JSC.JSValue, globalObject: *JSC.JSGlobalObject, default: Encoding) ?Encoding { - const str = bun.String.tryFromJS(value, globalObject) orelse return null; + pub fn fromJSWithDefaultOnEmpty(value: JSC.JSValue, globalObject: *JSC.JSGlobalObject, default: Encoding) bun.JSError!?Encoding { + const str = bun.String.tryFromJS(value, globalObject) orelse return error.JSError; defer str.deref(); if (str.isEmpty()) { return default; @@ -701,13 +700,14 @@ pub const Encoding = enum(u8) { return str.inMapCaseInsensitive(Encoding.map); } - pub fn throwEncodingError(globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void { + pub fn throwEncodingError(globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) bun.JSError { globalObject.ERR_INVALID_ARG_VALUE( "encoding '{}' is an invalid encoding", .{ value.fmtString(globalObject), }, ).throw(); + return error.JSError; } pub fn encodeWithSize(encoding: Encoding, globalObject: *JSC.JSGlobalObject, comptime size: usize, input: *const [size]u8) JSC.JSValue { @@ -926,18 +926,18 @@ pub const PathLike = union(enum) { }; } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?PathLike { - return fromJSWithAllocator(ctx, arguments, bun.default_allocator, exception); + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!?PathLike { + return fromJSWithAllocator(ctx, arguments, bun.default_allocator); } - pub fn fromJSWithAllocator(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, allocator: std.mem.Allocator, exception: JSC.C.ExceptionRef) ?PathLike { + + pub fn fromJSWithAllocator(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, allocator: std.mem.Allocator) bun.JSError!?PathLike { const arg = arguments.next() orelse return null; switch (arg.jsType()) { JSC.JSValue.JSType.Uint8Array, JSC.JSValue.JSType.DataView, => { const buffer = Buffer.fromTypedArray(ctx, arg); - if (exception.* != null) return null; - if (!Valid.pathBuffer(buffer, ctx, exception)) return null; + try Valid.pathBuffer(buffer, ctx); arguments.protectEat(); return PathLike{ .buffer = buffer }; @@ -945,8 +945,7 @@ pub const PathLike = union(enum) { JSC.JSValue.JSType.ArrayBuffer => { const buffer = Buffer.fromArrayBuffer(ctx, arg); - if (exception.* != null) return null; - if (!Valid.pathBuffer(buffer, ctx, exception)) return null; + try Valid.pathBuffer(buffer, ctx); arguments.protectEat(); @@ -962,9 +961,7 @@ pub const PathLike = union(enum) { arguments.eat(); - if (!Valid.pathStringLength(str.length(), ctx, exception)) { - return null; - } + try Valid.pathStringLength(str.length(), ctx); if (arguments.will_be_async) { var sliced = str.toThreadSafeSlice(allocator); @@ -995,14 +992,12 @@ pub const PathLike = union(enum) { var str: bun.String = domurl.fileSystemPath(); defer str.deref(); if (str.isEmpty()) { - JSC.throwInvalidArguments("URL must be a non-empty \"file:\" path", .{}, ctx, exception); - return null; + ctx.throwInvalidArguments("URL must be a non-empty \"file:\" path", .{}); + return error.JSError; } arguments.eat(); - if (!Valid.pathStringLength(str.length(), ctx, exception)) { - return null; - } + try Valid.pathStringLength(str.length(), ctx); if (arguments.will_be_async) { var sliced = str.toThreadSafeSlice(allocator); @@ -1036,73 +1031,67 @@ pub const PathLike = union(enum) { }; pub const Valid = struct { - pub fn fileDescriptor(fd: i64, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) bool { + pub fn fileDescriptor(fd: i64, ctx: JSC.C.JSContextRef) bun.JSError!void { if (fd < 0) { - JSC.throwInvalidArguments("Invalid file descriptor, must not be negative number", .{}, ctx, exception); - return false; + ctx.throwInvalidArguments("Invalid file descriptor, must not be negative number", .{}); + return error.JSError; } const fd_t = if (Environment.isWindows) bun.windows.libuv.uv_file else bun.FileDescriptorInt; if (fd > std.math.maxInt(fd_t)) { - JSC.throwInvalidArguments("Invalid file descriptor, must not be greater than {d}", .{std.math.maxInt(fd_t)}, ctx, exception); - return false; + ctx.throwInvalidArguments("Invalid file descriptor, must not be greater than {d}", .{std.math.maxInt(fd_t)}); + return error.JSError; } - - return true; } - pub fn pathSlice(zig_str: JSC.ZigString.Slice, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) bool { + pub fn pathSlice(zig_str: JSC.ZigString.Slice, ctx: JSC.C.JSContextRef) bun.JSError!void { switch (zig_str.len) { - 0...bun.MAX_PATH_BYTES => return true, + 0...bun.MAX_PATH_BYTES => return, else => { // TODO: should this be an EINVAL? var system_error = bun.sys.Error.fromCode(.NAMETOOLONG, .open).withPath(zig_str.slice()).toSystemError(); system_error.syscall = bun.String.dead; - exception.* = system_error.toErrorInstance(ctx).asObjectRef(); - return false; + ctx.throwValue(system_error.toErrorInstance(ctx)); + return error.JSError; }, } - unreachable; } - pub fn pathStringLength(len: usize, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) bool { + pub fn pathStringLength(len: usize, ctx: JSC.C.JSContextRef) bun.JSError!void { switch (len) { - 0...bun.MAX_PATH_BYTES => return true, + 0...bun.MAX_PATH_BYTES => return, else => { // TODO: should this be an EINVAL? var system_error = bun.sys.Error.fromCode(.NAMETOOLONG, .open).toSystemError(); system_error.syscall = bun.String.dead; - exception.* = system_error.toErrorInstance(ctx).asObjectRef(); - return false; + ctx.throwValue(system_error.toErrorInstance(ctx)); + return error.JSError; }, } - unreachable; } - pub fn pathString(zig_str: JSC.ZigString, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) bool { - return pathStringLength(zig_str.len, ctx, exception); + pub fn pathString(zig_str: JSC.ZigString, ctx: JSC.C.JSContextRef) bun.JSError!void { + return pathStringLength(zig_str.len, ctx); } - pub fn pathBuffer(buffer: Buffer, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) bool { + pub fn pathBuffer(buffer: Buffer, ctx: JSC.C.JSContextRef) bun.JSError!void { const slice = buffer.slice(); switch (slice.len) { 0 => { - JSC.throwInvalidArguments("Invalid path buffer: can't be empty", .{}, ctx, exception); - return false; + ctx.throwInvalidArguments("Invalid path buffer: can't be empty", .{}); + return error.JSError; }, - else => { var system_error = bun.sys.Error.fromCode(.NAMETOOLONG, .open).toSystemError(); system_error.syscall = bun.String.dead; - exception.* = system_error.toErrorInstance(ctx).asObjectRef(); - return false; + ctx.throwValue(system_error.toErrorInstance(ctx)); + return error.JSError; }, - 1...bun.MAX_PATH_BYTES => return true, + 1...bun.MAX_PATH_BYTES => return, } - unreachable; } }; @@ -1115,10 +1104,10 @@ pub const VectorArrayBuffer = struct { return this.value; } - pub fn fromJS(globalObject: *JSC.JSGlobalObject, val: JSC.JSValue, exception: JSC.C.ExceptionRef, allocator: std.mem.Allocator) ?VectorArrayBuffer { + pub fn fromJS(globalObject: *JSC.JSGlobalObject, val: JSC.JSValue, allocator: std.mem.Allocator) bun.JSError!VectorArrayBuffer { if (!val.jsType().isArrayLike()) { - JSC.throwInvalidArguments("Expected ArrayBufferView[]", .{}, globalObject, exception); - return null; + globalObject.throwInvalidArguments("Expected ArrayBufferView[]", .{}); + return error.JSError; } var bufferlist = std.ArrayList(bun.PlatformIOVec).init(allocator); @@ -1130,13 +1119,13 @@ pub const VectorArrayBuffer = struct { const element = val.getIndex(globalObject, @as(u32, @truncate(i))); if (!element.isCell()) { - JSC.throwInvalidArguments("Expected ArrayBufferView[]", .{}, globalObject, exception); - return null; + globalObject.throwInvalidArguments("Expected ArrayBufferView[]", .{}); + return error.JSError; } const array_buffer = element.asArrayBuffer(globalObject) orelse { - JSC.throwInvalidArguments("Expected ArrayBufferView[]", .{}, globalObject, exception); - return null; + globalObject.throwInvalidArguments("Expected ArrayBufferView[]", .{}); + return error.JSError; }; const buf = array_buffer.byteSlice(); @@ -1233,8 +1222,8 @@ pub const ArgumentsSlice = struct { } }; -pub fn fileDescriptorFromJS(ctx: JSC.C.JSContextRef, value: JSC.JSValue, exception: JSC.C.ExceptionRef) ?bun.FileDescriptor { - return if (bun.FDImpl.fromJSValidated(value, ctx, exception) catch null) |fd| +pub fn fileDescriptorFromJS(ctx: JSC.C.JSContextRef, value: JSC.JSValue) bun.JSError!?bun.FileDescriptor { + return if (try bun.FDImpl.fromJSValidated(value, ctx)) |fd| fd.encode() else null; @@ -1243,7 +1232,7 @@ pub fn fileDescriptorFromJS(ctx: JSC.C.JSContextRef, value: JSC.JSValue, excepti // Node.js docs: // > Values can be either numbers representing Unix epoch time in seconds, Dates, or a numeric string like '123456789.0'. // > If the value can not be converted to a number, or is NaN, Infinity, or -Infinity, an Error will be thrown. -pub fn timeLikeFromJS(globalObject: *JSC.JSGlobalObject, value: JSC.JSValue, _: JSC.C.ExceptionRef) ?TimeLike { +pub fn timeLikeFromJS(globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) ?TimeLike { if (value.jsType() == .JSDate) { const milliseconds = value.getUnixTimestamp(); if (!std.math.isFinite(milliseconds)) { @@ -1279,16 +1268,16 @@ pub fn timeLikeFromJS(globalObject: *JSC.JSGlobalObject, value: JSC.JSValue, _: }; } -pub fn modeFromJS(ctx: JSC.C.JSContextRef, value: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Mode { +pub fn modeFromJS(ctx: JSC.C.JSContextRef, value: JSC.JSValue) bun.JSError!?Mode { const mode_int = if (value.isNumber()) brk: { - const m = validators.validateUint32(ctx, value, "mode", .{}, false) catch return null; + const m = try validators.validateUint32(ctx, value, "mode", .{}, false); break :brk @as(Mode, @as(u24, @truncate(m))); } else brk: { if (value.isUndefinedOrNull()) return null; if (!value.isString()) { _ = ctx.throwInvalidArgumentTypeValue("mode", "number", value); - return null; + return error.JSError; } // An easier method of constructing the mode is to use a sequence of @@ -1306,8 +1295,8 @@ pub fn modeFromJS(ctx: JSC.C.JSContextRef, value: JSC.JSValue, exception: JSC.C. break :brk std.fmt.parseInt(Mode, slice, 8) catch { var formatter = bun.JSC.ConsoleObject.Formatter{ .globalThis = ctx }; - exception.* = ctx.ERR_INVALID_ARG_VALUE("The argument 'mode' must be a 32-bit unsigned integer or an octal string. Received {}", .{value.toFmt(&formatter)}).toJS().asObjectRef(); - return null; + ctx.throwValue(ctx.ERR_INVALID_ARG_VALUE("The argument 'mode' must be a 32-bit unsigned integer or an octal string. Received {}", .{value.toFmt(&formatter)}).toJS()); + return error.JSError; }; }; @@ -1365,23 +1354,16 @@ pub const PathOrFileDescriptor = union(Tag) { } } - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, allocator: std.mem.Allocator, exception: JSC.C.ExceptionRef) ?JSC.Node.PathOrFileDescriptor { + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, allocator: std.mem.Allocator) bun.JSError!?JSC.Node.PathOrFileDescriptor { const first = arguments.next() orelse return null; - if (bun.FDImpl.fromJSValidated(first, ctx, exception) catch return null) |fd| { + if (try bun.FDImpl.fromJSValidated(first, ctx)) |fd| { arguments.eat(); return JSC.Node.PathOrFileDescriptor{ .fd = fd.encode() }; } return JSC.Node.PathOrFileDescriptor{ - .path = PathLike.fromJSWithAllocator(ctx, arguments, allocator, exception) orelse return null, - }; - } - - pub fn toJS(this: JSC.Node.PathOrFileDescriptor, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.C.JSValueRef { - return switch (this) { - .path => |path| path.toJS(ctx, exception), - .fd => |fd| bun.FDImpl.decode(fd).toJS(), + .path = try PathLike.fromJSWithAllocator(ctx, arguments, allocator) orelse return null, }; } }; @@ -1483,11 +1465,11 @@ pub const FileSystemFlags = enum(Mode) { .{ "SA+", O_APPEND | O_CREAT | O_RDWR | O_SYNC }, }); - pub fn fromJS(ctx: JSC.C.JSContextRef, val: JSC.JSValue, exception: JSC.C.ExceptionRef) ?FileSystemFlags { + pub fn fromJS(ctx: JSC.C.JSContextRef, val: JSC.JSValue) bun.JSError!?FileSystemFlags { if (val.isNumber()) { if (!val.isInt32()) { - exception.* = ctx.ERR_OUT_OF_RANGE("The value of \"flags\" is out of range. It must be an integer. Received {d}", .{val.asNumber()}).toJS().asObjectRef(); - return null; + ctx.throwValue(ctx.ERR_OUT_OF_RANGE("The value of \"flags\" is out of range. It must be an integer. Received {d}", .{val.asNumber()}).toJS()); + return error.JSError; } const number = val.coerce(i32, ctx); return @as(FileSystemFlags, @enumFromInt(@as(Mode, @intCast(@max(number, 0))))); @@ -1497,23 +1479,13 @@ pub const FileSystemFlags = enum(Mode) { if (jsType.isStringLike()) { const str = val.getZigString(ctx); if (str.isEmpty()) { - JSC.throwInvalidArguments( - "Expected flags to be a non-empty string. Learn more at https://nodejs.org/api/fs.html#fs_file_system_flags", - .{}, - ctx, - exception, - ); - return null; + ctx.throwInvalidArguments("Expected flags to be a non-empty string. Learn more at https://nodejs.org/api/fs.html#fs_file_system_flags", .{}); + return error.JSError; } // it's definitely wrong when the string is super long else if (str.len > 12) { - JSC.throwInvalidArguments( - "Invalid flag '{any}'. Learn more at https://nodejs.org/api/fs.html#fs_file_system_flags", - .{str}, - ctx, - exception, - ); - return null; + ctx.throwInvalidArguments("Invalid flag '{any}'. Learn more at https://nodejs.org/api/fs.html#fs_file_system_flags", .{str}); + return error.JSError; } const flags = brk: { @@ -1537,13 +1509,8 @@ pub const FileSystemFlags = enum(Mode) { break :brk map.getWithEql(str, JSC.ZigString.eqlComptime); } orelse { - JSC.throwInvalidArguments( - "Invalid flag '{any}'. Learn more at https://nodejs.org/api/fs.html#fs_file_system_flags", - .{str}, - ctx, - exception, - ); - return null; + ctx.throwInvalidArguments("Invalid flag '{any}'. Learn more at https://nodejs.org/api/fs.html#fs_file_system_flags", .{str}); + return error.JSError; }; return @as(FileSystemFlags, @enumFromInt(@as(Mode, @intCast(flags)))); diff --git a/src/bun.js/node/util/parse_args.zig b/src/bun.js/node/util/parse_args.zig index c047fddd258dc9..6fc4b2a8d61da5 100644 --- a/src/bun.js/node/util/parse_args.zig +++ b/src/bun.js/node/util/parse_args.zig @@ -26,8 +26,6 @@ const isOptionLikeValue = utils.isOptionLikeValue; const log = bun.Output.scoped(.parseArgs, true); -const ParseArgsError = error{ParseError}; - /// Represents a slice of a JSValue array const ArgsSlice = struct { array: JSValue, @@ -185,7 +183,7 @@ fn getDefaultArgs(globalThis: *JSGlobalObject) !ArgsSlice { } /// In strict mode, throw for possible usage errors like "--foo --bar" where foo was defined as a string-valued arg -fn checkOptionLikeValue(globalThis: *JSGlobalObject, token: OptionToken) ParseArgsError!void { +fn checkOptionLikeValue(globalThis: *JSGlobalObject, token: OptionToken) bun.JSError!void { if (!token.inline_value and isOptionLikeValue(token.value.asBunString(globalThis))) { const raw_name = OptionToken.RawNameFormatter{ .token = token, .globalThis = globalThis }; @@ -208,12 +206,12 @@ fn checkOptionLikeValue(globalThis: *JSGlobalObject, token: OptionToken) ParseAr ); } globalThis.vm().throwError(globalThis, err); - return error.ParseError; + return error.JSError; } } /// In strict mode, throw for usage errors. -fn checkOptionUsage(globalThis: *JSGlobalObject, options: []const OptionDefinition, allow_positionals: bool, token: OptionToken) ParseArgsError!void { +fn checkOptionUsage(globalThis: *JSGlobalObject, options: []const OptionDefinition, allow_positionals: bool, token: OptionToken) bun.JSError!void { if (token.option_idx) |option_idx| { const option = options[option_idx]; switch (option.type) { @@ -230,7 +228,7 @@ fn checkOptionUsage(globalThis: *JSGlobalObject, options: []const OptionDefiniti globalThis, ); globalThis.vm().throwError(globalThis, err); - return error.ParseError; + return error.JSError; }, .boolean => if (token.value != .jsvalue or !token.value.jsvalue.isUndefined()) { const err = JSC.toTypeError( @@ -245,7 +243,7 @@ fn checkOptionUsage(globalThis: *JSGlobalObject, options: []const OptionDefiniti globalThis, ); globalThis.vm().throwError(globalThis, err); - return error.ParseError; + return error.JSError; }, } } else { @@ -263,7 +261,7 @@ fn checkOptionUsage(globalThis: *JSGlobalObject, options: []const OptionDefiniti globalThis, )); globalThis.vm().throwError(globalThis, err); - return error.ParseError; + return error.JSError; } } @@ -303,7 +301,7 @@ fn storeOption(globalThis: *JSGlobalObject, option_name: ValueRef, option_value: } } -fn parseOptionDefinitions(globalThis: *JSGlobalObject, options_obj: JSValue, option_definitions: *std.ArrayList(OptionDefinition)) !void { +fn parseOptionDefinitions(globalThis: *JSGlobalObject, options_obj: JSValue, option_definitions: *std.ArrayList(OptionDefinition)) bun.JSError!void { try validateObject(globalThis, options_obj, "options", .{}, .{}); var iter = JSC.JSPropertyIterator(.{ @@ -330,7 +328,7 @@ fn parseOptionDefinitions(globalThis: *JSGlobalObject, options_obj: JSValue, opt if (short_option_str.length() != 1) { const err = JSC.toTypeError(.ERR_INVALID_ARG_VALUE, "options.{s}.short must be a single character", .{option.long_name}, globalThis); globalThis.vm().throwError(globalThis, err); - return error.ParseError; + return error.JSError; } option.short_name = short_option_str; } @@ -371,7 +369,10 @@ fn parseOptionDefinitions(globalThis: *JSGlobalObject, options_obj: JSValue, opt option.default_value, }); - try option_definitions.append(option); + option_definitions.append(option) catch { + globalThis.throwOutOfMemory(); + return error.JSError; + }; } } @@ -385,8 +386,8 @@ fn tokenizeArgs( args: ArgsSlice, options: []const OptionDefinition, ctx: *T, - emitToken: fn (ctx: *T, token: Token) ParseArgsError!void, -) !void { + emitToken: fn (ctx: *T, token: Token) bun.JSError!void, +) bun.JSError!void { const num_args: u32 = args.end - args.start; var index: u32 = 0; while (index < num_args) : (index += 1) { @@ -578,7 +579,7 @@ const ParseArgsState = struct { /// To reuse JSValue for the "kind" field in the output tokens array ("positional", "option", "option-terminator") kinds_jsvalues: [TokenKind.COUNT]?JSValue = [_]?JSValue{null} ** TokenKind.COUNT, - pub fn handleToken(this: *ParseArgsState, token_generic: Token) ParseArgsError!void { + pub fn handleToken(this: *ParseArgsState, token_generic: Token) bun.JSError!void { var globalThis = this.globalThis; switch (token_generic) { @@ -598,7 +599,7 @@ const ParseArgsState = struct { globalThis, ); globalThis.vm().throwError(globalThis, err); - return error.ParseError; + return error.JSError; } const value = token.value.asJSValue(globalThis); this.positionals.push(globalThis, value); @@ -656,13 +657,7 @@ pub fn parseArgs( JSC.markBinding(@src()); const arguments = callframe.arguments(1).slice(); const config = if (arguments.len > 0) arguments[0] else JSValue.undefined; - return parseArgsImpl(globalThis, config) catch |err| { - // these two types of error will already throw their own js exception - if (err != error.ParseError and err != error.InvalidArgument) { - globalThis.throwOutOfMemory(); - } - return JSValue.undefined; - }; + return parseArgsImpl(globalThis, config) catch return .zero; } comptime { @@ -670,7 +665,7 @@ comptime { @export(parseArgsFn, .{ .name = "Bun__NodeUtil__jsParseArgs" }); } -pub fn parseArgsImpl(globalThis: *JSGlobalObject, config_obj: JSValue) !JSValue { +pub fn parseArgsImpl(globalThis: *JSGlobalObject, config_obj: JSValue) bun.JSError!JSValue { // // Phase 0: parse the config object // diff --git a/src/bun.js/node/util/validators.zig b/src/bun.js/node/util/validators.zig index 554f62ddbffc8f..27280124161f4f 100644 --- a/src/bun.js/node/util/validators.zig +++ b/src/bun.js/node/util/validators.zig @@ -18,20 +18,20 @@ pub fn throwErrInvalidArgValue( globalThis: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype, -) !void { +) bun.JSError { @setCold(true); globalThis.ERR_INVALID_ARG_VALUE(fmt, args).throw(); - return error.InvalidArgument; + return error.JSError; } pub fn throwErrInvalidArgTypeWithMessage( globalThis: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype, -) !void { +) bun.JSError { @setCold(true); globalThis.ERR_INVALID_ARG_TYPE(fmt, args).throw(); - return error.InvalidArgument; + return error.JSError; } pub fn throwErrInvalidArgType( @@ -40,84 +40,84 @@ pub fn throwErrInvalidArgType( name_args: anytype, comptime expected_type: []const u8, value: JSValue, -) !void { +) bun.JSError { @setCold(true); const actual_type = getTypeName(globalThis, value); - try throwErrInvalidArgTypeWithMessage(globalThis, "\"" ++ name_fmt ++ "\" property must be of type {s}, got {s}", name_args ++ .{ expected_type, actual_type }); + return throwErrInvalidArgTypeWithMessage(globalThis, "\"" ++ name_fmt ++ "\" property must be of type {s}, got {s}", name_args ++ .{ expected_type, actual_type }); } pub fn throwRangeError( globalThis: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype, -) !void { +) bun.JSError { @setCold(true); globalThis.ERR_OUT_OF_RANGE(fmt, args).throw(); - return error.InvalidArgument; + return error.JSError; } -pub fn validateInteger(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, min_value: ?i64, max_value: ?i64) !i64 { +pub fn validateInteger(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, min_value: ?i64, max_value: ?i64) bun.JSError!i64 { const min = min_value orelse JSC.MIN_SAFE_INTEGER; const max = max_value orelse JSC.MAX_SAFE_INTEGER; if (!value.isNumber()) - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value); if (!value.isAnyInt()) { - try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be an integer. Received {s}", name_args ++ .{value}); + return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be an integer. Received {s}", name_args ++ .{value}); } const num = value.asInt52(); if (num < min or num > max) { - try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {s}", name_args ++ .{ min, max, value }); + return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {s}", name_args ++ .{ min, max, value }); } return num; } -pub fn validateInt32(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, min_value: ?i32, max_value: ?i32) !i32 { +pub fn validateInt32(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, min_value: ?i32, max_value: ?i32) bun.JSError!i32 { const min = min_value orelse std.math.minInt(i32); const max = max_value orelse std.math.maxInt(i32); // The defaults for min and max correspond to the limits of 32-bit integers. if (!value.isNumber()) { - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value); } if (!value.isInt32()) { var formatter = JSC.ConsoleObject.Formatter{ .globalThis = globalThis }; - try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be an integer. Received {}", name_args ++ .{value.toFmt(&formatter)}); + return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be an integer. Received {}", name_args ++ .{value.toFmt(&formatter)}); } const num = value.asInt32(); if (num < min or num > max) { var formatter = JSC.ConsoleObject.Formatter{ .globalThis = globalThis }; - try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {}", name_args ++ .{ min, max, value.toFmt(&formatter) }); + return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {}", name_args ++ .{ min, max, value.toFmt(&formatter) }); } return num; } -pub fn validateUint32(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, greater_than_zero: bool) !u32 { +pub fn validateUint32(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, greater_than_zero: bool) bun.JSError!u32 { if (!value.isNumber()) { - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value); } if (!value.isAnyInt()) { var formatter = JSC.ConsoleObject.Formatter{ .globalThis = globalThis }; - try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be an integer. Received {}", name_args ++ .{value.toFmt(&formatter)}); + return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be an integer. Received {}", name_args ++ .{value.toFmt(&formatter)}); } const num: i64 = value.asInt52(); const min: i64 = if (greater_than_zero) 1 else 0; const max: i64 = @intCast(std.math.maxInt(u32)); if (num < min or num > max) { var formatter = JSC.ConsoleObject.Formatter{ .globalThis = globalThis }; - try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {}", name_args ++ .{ min, max, value.toFmt(&formatter) }); + return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {}", name_args ++ .{ min, max, value.toFmt(&formatter) }); } return @truncate(@as(u63, @intCast(num))); } -pub fn validateString(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !void { +pub fn validateString(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) bun.JSError!void { if (!value.isString()) - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "string", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "string", value); } -pub fn validateNumber(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, min: ?f64, max: ?f64) !f64 { +pub fn validateNumber(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, min: ?f64, max: ?f64) bun.JSError!f64 { if (!value.isNumber()) - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value); const num: f64 = value.asNumber(); var valid = true; @@ -132,19 +132,19 @@ pub fn validateNumber(globalThis: *JSGlobalObject, value: JSValue, comptime name } if (!valid) { if (min != null and max != null) { - try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {s}", name_args ++ .{ min, max, value }); + return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {s}", name_args ++ .{ min, max, value }); } else if (min != null) { - try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d}. Received {s}", name_args ++ .{ max, value }); + return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d}. Received {s}", name_args ++ .{ max, value }); } else { - try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must and <= {d}. Received {s}", name_args ++ .{ max, value }); + return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must and <= {d}. Received {s}", name_args ++ .{ max, value }); } } return num; } -pub fn validateBoolean(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !bool { +pub fn validateBoolean(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) bun.JSError!bool { if (!value.isBoolean()) - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "boolean", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "boolean", value); return value.asBoolean(); } @@ -154,80 +154,80 @@ pub const ValidateObjectOptions = packed struct { allow_function: bool = false, }; -pub fn validateObject(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, comptime options: ValidateObjectOptions) !void { +pub fn validateObject(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, comptime options: ValidateObjectOptions) bun.JSError!void { if (comptime !options.allow_nullable and !options.allow_array and !options.allow_function) { if (value.isNull() or value.jsType().isArray()) { - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value); } if (!value.isObject()) { - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value); } } else { if (!options.allow_nullable and value.isNull()) { - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value); } if (!options.allow_array and value.jsType().isArray()) { - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value); } if (!value.isObject() and (!options.allow_function or !value.jsType().isFunction())) { - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value); } } } -pub fn validateArray(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, comptime min_length: ?i32) !void { +pub fn validateArray(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, comptime min_length: ?i32) bun.JSError!void { if (!value.jsType().isArray()) { const actual_type = getTypeName(globalThis, value); - try throwErrInvalidArgTypeWithMessage(globalThis, "\"" ++ name_fmt ++ "\" property must be an instance of Array, got {s}", name_args ++ .{actual_type}); + return throwErrInvalidArgTypeWithMessage(globalThis, "\"" ++ name_fmt ++ "\" property must be an instance of Array, got {s}", name_args ++ .{actual_type}); } if (comptime min_length != null) { if (value.getLength(globalThis) < min_length) { - try throwErrInvalidArgValue(globalThis, name_fmt ++ " must be longer than {d}", name_args ++ .{min_length}); + return throwErrInvalidArgValue(globalThis, name_fmt ++ " must be longer than {d}", name_args ++ .{min_length}); } } } -pub fn validateStringArray(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !usize { +pub fn validateStringArray(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) bun.JSError!usize { try validateArray(globalThis, value, name_fmt, name_args, null); var i: usize = 0; var iter = value.arrayIterator(globalThis); while (iter.next()) |item| { if (!item.isString()) { - try throwErrInvalidArgType(globalThis, name_fmt ++ "[{d}]", name_args ++ .{i}, "string", value); + return throwErrInvalidArgType(globalThis, name_fmt ++ "[{d}]", name_args ++ .{i}, "string", value); } i += 1; } return i; } -pub fn validateBooleanArray(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !usize { +pub fn validateBooleanArray(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) bun.JSError!usize { try validateArray(globalThis, value, name_fmt, name_args, null); var i: usize = 0; var iter = value.arrayIterator(globalThis); while (iter.next()) |item| { if (!item.isBoolean()) { - try throwErrInvalidArgType(globalThis, name_fmt ++ "[{d}]", name_args ++ .{i}, "boolean", value); + return throwErrInvalidArgType(globalThis, name_fmt ++ "[{d}]", name_args ++ .{i}, "boolean", value); } i += 1; } return i; } -pub fn validateFunction(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !JSValue { +pub fn validateFunction(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) bun.JSError!JSValue { if (!value.jsType().isFunction()) - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "function", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "function", value); return value; } -pub fn validateUndefined(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !void { +pub fn validateUndefined(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) bun.JSError!void { if (!value.isUndefined()) - try throwErrInvalidArgType(globalThis, name_fmt, name_args, "undefined", value); + return throwErrInvalidArgType(globalThis, name_fmt, name_args, "undefined", value); } -pub fn validateStringEnum(comptime T: type, globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !T { +pub fn validateStringEnum(comptime T: type, globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) bun.JSError!T { const str = value.toBunString(globalThis); defer str.deref(); inline for (@typeInfo(T).Enum.fields) |enum_field| { @@ -242,6 +242,5 @@ pub fn validateStringEnum(comptime T: type, globalThis: *JSGlobalObject, value: } break :blk out; }; - try throwErrInvalidArgTypeWithMessage(globalThis, name_fmt ++ " must be one of: {s}", name_args ++ .{values_info}); - return error.InvalidArgument; + return throwErrInvalidArgTypeWithMessage(globalThis, name_fmt ++ " must be one of: {s}", name_args ++ .{values_info}); } diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 950c339c5e4599..5dff0ed4e39e55 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -1228,22 +1228,6 @@ pub const DescribeScope = struct { } const ScopeStack = ObjectPool(std.ArrayListUnmanaged(*DescribeScope), null, true, 16); - - // pub fn runBeforeAll(this: *DescribeScope, ctx: js.JSContextRef, exception: js.ExceptionRef) bool { - // var scopes = ScopeStack.get(default_allocator); - // defer scopes.release(); - // scopes.data.clearRetainingCapacity(); - // var cur: ?*DescribeScope = this; - // while (cur) |scope| { - // scopes.data.append(default_allocator, this) catch unreachable; - // cur = scope.parent; - // } - - // // while (scopes.data.popOrNull()) |scope| { - // // scope. - // // } - // } - }; pub fn wrapTestFunction(comptime name: []const u8, comptime func: anytype) DescribeScope.CallbackFn { diff --git a/src/bun.js/webcore/blob.zig b/src/bun.js/webcore/blob.zig index 3b5322436cef32..14f14f0a5f27c5 100644 --- a/src/bun.js/webcore/blob.zig +++ b/src/bun.js/webcore/blob.zig @@ -48,8 +48,8 @@ const PathOrBlob = union(enum) { path: JSC.Node.PathOrFileDescriptor, blob: Blob, - pub fn fromJSNoCopy(ctx: js.JSContextRef, args: *JSC.Node.ArgumentsSlice, exception: js.ExceptionRef) ?PathOrBlob { - if (JSC.Node.PathOrFileDescriptor.fromJS(ctx, args, bun.default_allocator, exception)) |path| { + pub fn fromJSNoCopy(ctx: js.JSContextRef, args: *JSC.Node.ArgumentsSlice) bun.JSError!?PathOrBlob { + if (try JSC.Node.PathOrFileDescriptor.fromJS(ctx, args, bun.default_allocator)) |path| { return PathOrBlob{ .path = path, }; @@ -965,16 +965,10 @@ pub const Blob = struct { const arguments = callframe.arguments(3).slice(); var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); defer args.deinit(); - var exception_ = [1]JSC.JSValueRef{null}; - var exception = &exception_; // accept a path or a blob - var path_or_blob = PathOrBlob.fromJSNoCopy(globalThis, &args, exception) orelse { - if (exception[0] != null) { - globalThis.throwValue(exception[0].?.value()); - } else { - globalThis.throwInvalidArguments("Bun.write expects a path, file descriptor or a blob", .{}); - } + var path_or_blob = (PathOrBlob.fromJSNoCopy(globalThis, &args) catch return .zero) orelse { + globalThis.throwInvalidArguments("Bun.write expects a path, file descriptor or a blob", .{}); return .zero; }; defer { @@ -1563,17 +1557,10 @@ pub const Blob = struct { const arguments = callframe.arguments(2).slice(); var args = JSC.Node.ArgumentsSlice.init(vm, arguments); defer args.deinit(); - var exception_ = [1]JSC.JSValueRef{null}; - const exception = &exception_; - - var path = JSC.Node.PathOrFileDescriptor.fromJS(globalObject, &args, bun.default_allocator, exception) orelse { - if (exception_[0] == null) { - globalObject.throwInvalidArguments("Expected file path string or file descriptor", .{}); - } else { - globalObject.throwValue(exception_[0].?.value()); - } - return .undefined; + var path = (JSC.Node.PathOrFileDescriptor.fromJS(globalObject, &args, bun.default_allocator) catch return .zero) orelse { + globalObject.throwInvalidArguments("Expected file path string or file descriptor", .{}); + return .zero; }; defer path.deinitAndUnprotect(); diff --git a/src/bun.js/webcore/encoding.zig b/src/bun.js/webcore/encoding.zig index 8b8e8af0175971..d4b51840c985fd 100644 --- a/src/bun.js/webcore/encoding.zig +++ b/src/bun.js/webcore/encoding.zig @@ -640,25 +640,7 @@ pub const TextDecoder = struct { ) JSC.JSValue { return JSC.JSValue.jsBoolean(this.ignore_bom); } - // pub fn setIgnoreBOM( - // this: *TextDecoder, - // _: *JSC.JSGlobalObject, - // ) JSC.JSValue { - // this.ignore_bom = JSValue.fromRef(this.ignore_bom).toBoolean(); - // return true; - // } - // pub fn setFatal( - // this: *TextDecoder, - // _: js.JSContextRef, - // _: js.JSValueRef, - // _: js.JSStringRef, - // value: JSC.C.JSValueRef, - // _: js.ExceptionRef, - // ) bool { - // this.fatal = JSValue.fromRef(value).toBoolean(); - // return true; - // } pub fn getFatal( this: *TextDecoder, _: *JSC.JSGlobalObject, diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index ede288b541e618..371ed5ebdd7b1e 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -2001,18 +2001,11 @@ pub const Fetch = struct { bun.Analytics.Features.fetch += 1; const vm = JSC.VirtualMachine.get(); - var exception_val = [_]JSC.C.JSValueRef{null}; - const exception: JSC.C.ExceptionRef = &exception_val; var memory_reporter = bun.default_allocator.create(JSC.MemoryReportingAllocator) catch bun.outOfMemory(); // used to clean up dynamically allocated memory on error (a poor man's errdefer) var is_error = false; var allocator = memory_reporter.wrap(bun.default_allocator); defer { - if (exception.* != null) { - is_error = true; - ctx.throwValue(JSC.JSValue.c(exception.*)); - } - memory_reporter.report(globalThis.vm()); if (is_error) bun.default_allocator.destroy(memory_reporter); @@ -2317,21 +2310,14 @@ pub const Fetch = struct { return .zero; } - if (SSLConfig.inJS(vm, globalThis, tls, exception)) |config| { - if (exception.* != null) { - is_error = true; - return .zero; - } - + if (SSLConfig.fromJS(vm, globalThis, tls) catch { + is_error = true; + return .zero; + }) |config| { const ssl_config_object = bun.default_allocator.create(SSLConfig) catch bun.outOfMemory(); ssl_config_object.* = config; break :extract_ssl_config ssl_config_object; } - - if (exception.* != null) { - is_error = true; - return .zero; - } } } } diff --git a/src/comptime_string_map.zig b/src/comptime_string_map.zig index 754c1a5d547476..f5cecafc37eed0 100644 --- a/src/comptime_string_map.zig +++ b/src/comptime_string_map.zig @@ -173,7 +173,8 @@ pub fn ComptimeStringMapWithKeyType(comptime KeyType: type, comptime V: type, co } } - const str = bun.String.tryFromJS(input, globalThis) orelse return null; + const str = bun.String.fromJS(input, globalThis); + bun.assert(str.tag != .Dead); defer str.deref(); return getWithEql(str, bun.String.eqlComptime); } @@ -186,7 +187,8 @@ pub fn ComptimeStringMapWithKeyType(comptime KeyType: type, comptime V: type, co } } - const str = bun.String.tryFromJS(input, globalThis) orelse return null; + const str = bun.String.fromJS(input, globalThis); + bun.assert(str.tag != .Dead); defer str.deref(); return str.inMapCaseInsensitive(@This()); } diff --git a/src/fd.zig b/src/fd.zig index 59b743293aa47e..b1d466b0019e1c 100644 --- a/src/fd.zig +++ b/src/fd.zig @@ -320,12 +320,10 @@ pub const FDImpl = packed struct { // If a non-number is given, returns null. // If the given number is not an fd (negative), an error is thrown and error.JSException is returned. - pub fn fromJSValidated(value: JSValue, global: *JSC.JSGlobalObject, exception_ref: JSC.C.ExceptionRef) !?FDImpl { + pub fn fromJSValidated(value: JSValue, global: *JSC.JSGlobalObject) bun.JSError!?FDImpl { if (!value.isAnyInt()) return null; const fd64 = value.toInt64(); - if (!JSC.Node.Valid.fileDescriptor(fd64, global, exception_ref)) { - return error.JSException; - } + try JSC.Node.Valid.fileDescriptor(fd64, global); const fd: i32 = @intCast(fd64); if (comptime env.isWindows) { diff --git a/src/js_ast.zig b/src/js_ast.zig index e1840a32ddf980..df0b6d95dd4e0f 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -1542,7 +1542,7 @@ pub const E = struct { pub const Boolean = struct { value: bool, - pub fn toJS(this: @This(), ctx: JSC.C.JSContextRef, _: JSC.C.ExceptionRef) JSC.C.JSValueRef { + pub fn toJS(this: @This(), ctx: JSC.C.JSContextRef) JSC.C.JSValueRef { return JSC.C.JSValueMakeBoolean(ctx, this.value); } }; @@ -1913,32 +1913,6 @@ pub const E = struct { } }; - // pub fn toJS(this: Object, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.C.JSValueRef { - // const Creator = struct { - // object: Object, - // pub fn create(this: *@This(), obj: *JSObject, global: *JSGlobalObject) void { - // var iter = this.query.iter(); - // var str: ZigString = undefined; - // while (iter.next(&query_string_values_buf)) |entry| { - // str = ZigString.init(entry.name); - - // bun.assert(entry.values.len > 0); - // if (entry.values.len > 1) { - // var values = query_string_value_refs_buf[0..entry.values.len]; - // for (entry.values) |value, i| { - // values[i] = ZigString.init(value); - // } - // obj.putRecord(global, &str, values.ptr, values.len); - // } else { - // query_string_value_refs_buf[0] = ZigString.init(entry.values[0]); - - // obj.putRecord(global, &str, &query_string_value_refs_buf, 1); - // } - // } - // } - // }; - // } - pub fn get(self: *const Object, key: string) ?Expr { return if (asProperty(self, key)) |query| query.expr else @as(?Expr, null); } diff --git a/src/options.zig b/src/options.zig index 612977988a18ed..b516e206de6694 100644 --- a/src/options.zig +++ b/src/options.zig @@ -395,11 +395,10 @@ pub const Target = enum { .{ "node", .node }, }); - pub fn fromJS(global: *JSC.JSGlobalObject, value: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Target { + pub fn fromJS(global: *JSC.JSGlobalObject, value: JSC.JSValue) bun.JSError!?Target { if (!value.jsType().isStringLike()) { - JSC.throwInvalidArguments("target must be a string", .{}, global, exception); - - return null; + global.throwInvalidArguments("target must be a string", .{}); + return error.JSError; } return Map.fromJS(global, value); } @@ -612,17 +611,17 @@ pub const Format = enum { .{ "internal_bake_dev", .internal_bake_dev }, }); - pub fn fromJS(global: *JSC.JSGlobalObject, format: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Format { + pub fn fromJS(global: *JSC.JSGlobalObject, format: JSC.JSValue) bun.JSError!?Format { if (format.isUndefinedOrNull()) return null; if (!format.jsType().isStringLike()) { - JSC.throwInvalidArguments("format must be a string", .{}, global, exception); - return null; + global.throwInvalidArguments("format must be a string", .{}); + return error.JSError; } return Map.fromJS(global, format) orelse { - JSC.throwInvalidArguments("Invalid format - must be esm, cjs, or iife", .{}, global, exception); - return null; + global.throwInvalidArguments("Invalid format - must be esm, cjs, or iife", .{}); + return error.JSError; }; } @@ -731,12 +730,12 @@ pub const Loader = enum(u8) { return stdin_name.get(this); } - pub fn fromJS(global: *JSC.JSGlobalObject, loader: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Loader { + pub fn fromJS(global: *JSC.JSGlobalObject, loader: JSC.JSValue) bun.JSError!?Loader { if (loader.isUndefinedOrNull()) return null; if (!loader.jsType().isStringLike()) { - JSC.throwInvalidArguments("loader must be a string", .{}, global, exception); - return null; + global.throwInvalidArguments("loader must be a string", .{}); + return error.JSError; } var zig_str = JSC.ZigString.init(""); @@ -744,8 +743,8 @@ pub const Loader = enum(u8) { if (zig_str.len == 0) return null; return fromString(zig_str.slice()) orelse { - JSC.throwInvalidArguments("invalid loader - must be js, jsx, tsx, ts, css, file, toml, wasm, bunsh, or json", .{}, global, exception); - return null; + global.throwInvalidArguments("invalid loader - must be js, jsx, tsx, ts, css, file, toml, wasm, bunsh, or json", .{}); + return error.JSError; }; } diff --git a/src/string.zig b/src/string.zig index 2c694efbdddfba..8a55b187dbc943 100644 --- a/src/string.zig +++ b/src/string.zig @@ -720,7 +720,7 @@ pub const String = extern struct { if (BunString__fromJS(globalObject, value, &out)) { return out; } else { - return null; + return null; //TODO: return error.JSError } } diff --git a/test/js/bun/spawn/does-not-hang.js b/test/js/bun/spawn/does-not-hang.js index 32221f56d86787..3a06a045b6de65 100644 --- a/test/js/bun/spawn/does-not-hang.js +++ b/test/js/bun/spawn/does-not-hang.js @@ -1,7 +1,7 @@ import { shellExe } from "harness"; const s = Bun.spawn({ - cmd: [shellExe(), "-c", "sleep", "999999"], + cmd: [shellExe(), "-c", "sleep 999999"], }); s.unref();