diff options
author | 2023-01-08 07:36:42 -0800 | |
---|---|---|
committer | 2023-01-08 07:37:51 -0800 | |
commit | 83a5c9f3da91b677fd6c9f1bc06b69f292997bd6 (patch) | |
tree | 19b6b2fce484999da8e2499926f6eda5b704379b | |
parent | 791f8ab0a17d87d5fed6c53033d7f3d3b5dad6cc (diff) | |
download | bun-83a5c9f3da91b677fd6c9f1bc06b69f292997bd6.tar.gz bun-83a5c9f3da91b677fd6c9f1bc06b69f292997bd6.tar.zst bun-83a5c9f3da91b677fd6c9f1bc06b69f292997bd6.zip |
[internal] Fix checking for Error object
-rw-r--r-- | src/bun.js/api/bun.zig | 2 | ||||
-rw-r--r-- | src/bun.js/api/bun/socket.zig | 34 | ||||
-rw-r--r-- | src/bun.js/api/bun/subprocess.zig | 2 | ||||
-rw-r--r-- | src/bun.js/base.zig | 4 | ||||
-rw-r--r-- | src/bun.js/bindings/FFI.zig | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.cpp | 38 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.zig | 137 | ||||
-rw-r--r-- | src/bun.js/bindings/headers-cpp.h | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/headers.h | 8 | ||||
-rw-r--r-- | src/bun.js/bindings/headers.zig | 4 | ||||
-rw-r--r-- | src/bun.js/test/jest.zig | 20 | ||||
-rw-r--r-- | src/bun.js/webcore/response.zig | 4 | ||||
-rw-r--r-- | src/napi/napi.zig | 6 | ||||
-rw-r--r-- | test/bun.js/serve.test.ts | 68 |
14 files changed, 259 insertions, 72 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index 6b19f138d..e9b760de5 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -2849,7 +2849,7 @@ pub const Timer = struct { return; } - if (result.isAnyError(globalThis)) { + if (result.isAnyError()) { vm.runErrorHandlerWithDedupe(result, null); this.deinit(); return; diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig index 329a6bbed..4073decde 100644 --- a/src/bun.js/api/bun/socket.zig +++ b/src/bun.js/api/bun/socket.zig @@ -117,7 +117,7 @@ const Handlers = struct { } const result = onError.callWithThis(this.globalObject, thisValue, err); - if (result.isAnyError(this.globalObject)) { + if (result.isAnyError()) { this.vm.onUnhandledError(this.globalObject, result); } @@ -862,8 +862,8 @@ fn NewSocket(comptime ssl: bool) type { this_value, }); - if (result.isAnyError(globalObject)) { - _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result }); + if (result.toError()) |err_value| { + _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, err_value }); } } pub fn onTimeout( @@ -888,8 +888,8 @@ fn NewSocket(comptime ssl: bool) type { this_value, }); - if (result.isAnyError(globalObject)) { - _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result }); + if (result.toError()) |err_value| { + _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, err_value }); } } pub fn onConnectError(this: *This, _: Socket, errno: c_int) void { @@ -927,9 +927,9 @@ fn NewSocket(comptime ssl: bool) type { err_value, }); - if (result.isAnyError(globalObject)) { - if (handlers.rejectPromise(result)) return; - _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result }); + if (result.toError()) |err_val| { + if (handlers.rejectPromise(err_val)) return; + _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, err_val }); } else if (handlers.promise.trySwap()) |val| { // They've defined a `connectError` callback // The error is effectively handled, but we should still reject the promise. @@ -987,7 +987,7 @@ fn NewSocket(comptime ssl: bool) type { this_value, }); - if (result.isAnyError(globalObject)) { + if (result.toError()) |err| { this.detached = true; defer this.markInactive(); if (!this.socket.isClosed()) { @@ -996,8 +996,8 @@ fn NewSocket(comptime ssl: bool) type { log("Already closed", .{}); } - if (handlers.rejectPromise(result)) return; - _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result }); + if (handlers.rejectPromise(err)) return; + _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, err }); } } @@ -1030,8 +1030,8 @@ fn NewSocket(comptime ssl: bool) type { this_value, }); - if (result.isAnyError(globalObject)) { - _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result }); + if (result.toError()) |err_value| { + _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, err_value }); } } @@ -1054,8 +1054,8 @@ fn NewSocket(comptime ssl: bool) type { JSValue.jsNumber(@as(i32, err)), }); - if (result.isAnyError(globalObject)) { - _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result }); + if (result.toError()) |err_value| { + _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, err_value }); } } @@ -1077,8 +1077,8 @@ fn NewSocket(comptime ssl: bool) type { output_value, }); - if (result.isAnyError(globalObject)) { - _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result }); + if (result.toError()) |err_value| { + _ = handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, err_value }); } } diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index 3f667491b..614bff0ad 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -1553,7 +1553,7 @@ pub const Subprocess = struct { &args, ); - if (result.isAnyError(globalThis)) { + if (result.isAnyError()) { globalThis.bunVM().onUnhandledError(globalThis, result); } } diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig index 333ea36c9..8e1ce2d59 100644 --- a/src/bun.js/base.zig +++ b/src/bun.js/base.zig @@ -2185,7 +2185,7 @@ pub fn getterWrap(comptime Container: type, comptime name: string) GetterType(Co }) else @call(.auto, @field(Container, name), .{ this, ctx.ptr() }); - if (!result.isUndefinedOrNull() and result.isError()) { + if (result.isError()) { exception.* = result.asObjectRef(); return null; } @@ -2816,7 +2816,7 @@ pub fn wrapWithHasContainer( } var result: JSValue = @call(.auto, @field(Container, name), args); - if (!result.isEmptyOrUndefinedOrNull() and result.isError()) { + if (result.isError()) { exception.* = result.asObjectRef(); iter.deinit(); return null; diff --git a/src/bun.js/bindings/FFI.zig b/src/bun.js/bindings/FFI.zig index e9d55c9f3..087d8308c 100644 --- a/src/bun.js/bindings/FFI.zig +++ b/src/bun.js/bindings/FFI.zig @@ -24,7 +24,7 @@ pub export var ValueTrue: EncodedJSValue = EncodedJSValue{ .asInt64 = @bitCast(i64, @as(c_longlong, (@as(c_int, 2) | @as(c_int, 4)) | @as(c_int, 1))), }; pub const JSContext = ?*anyopaque; -pub inline fn JSVALUE_IS_CELL(arg_val: EncodedJSValue) @"bool" { +pub inline fn JSVALUE_IS_CELL(arg_val: EncodedJSValue) bool { const val = arg_val; return !(((@bitCast(c_ulonglong, val.asInt64) & @as(c_ulonglong, 18446181123756130304)) | @bitCast(c_ulonglong, @as(c_longlong, @as(c_int, 2)))) != 0); } diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index ebe23c09e..74ac79501 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -2005,6 +2005,20 @@ void JSC__JSPromise__resolveOnNextTick(JSC__JSPromise* promise, JSC__JSGlobalObj } } +bool JSC__JSValue__isAnyError(JSC__JSValue JSValue0) +{ + JSC::JSValue value = JSC::JSValue::decode(JSValue0); + + JSC::JSCell* cell = value.asCell(); + JSC::JSType type = cell->type(); + + if (type == JSC::CellType) { + return cell->inherits<JSC::Exception>(); + } + + return type == JSC::ErrorInstanceType; +} + // This implementation closely mimicks the one in JSC::JSPromise::reject void JSC__JSPromise__rejectOnNextTickWithHandled(JSC__JSPromise* promise, JSC__JSGlobalObject* lexicalGlobalObject, JSC__JSValue encoedValue, bool handled) @@ -3168,18 +3182,28 @@ void JSC__JSValue__getNameProperty(JSC__JSValue JSValue0, JSC__JSGlobalObject* a arg2->len = 0; } -JSC__JSValue JSC__JSValue__toError(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1) +JSC__JSValue JSC__JSValue__toError_(JSC__JSValue JSValue0) { JSC::JSValue value = JSC::JSValue::decode(JSValue0); - if (JSC::Exception* jscException = JSC::jsDynamicCast<JSC::Exception*>(value)) { - if (JSC::ErrorInstance* error = JSC::jsDynamicCast<JSC::ErrorInstance*>(jscException->value())) { - return JSC::JSValue::encode(JSC::JSValue(error)); + if (!value.isCell()) + return JSC::JSValue::encode({}); + + JSC::JSCell* cell = value.asCell(); + + switch (cell->type()) { + case JSC::ErrorInstanceType: + return JSC::JSValue::encode(value); + + case JSC::CellType: + if (cell->inherits<JSC::Exception>()) { + JSC::Exception* exception = jsCast<JSC::Exception*>(cell); + return JSC::JSValue::encode(exception->value()); } + default: { } - if (JSC::ErrorInstance* error = JSC::jsDynamicCast<JSC::ErrorInstance*>(value)) { - return JSC::JSValue::encode(JSC::JSValue(error)); } - return JSC::JSValue::encode(JSC::jsUndefined()); + + return JSC::JSValue::encode({}); } void JSC__JSValue__toZigException(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index d1861966e..415c48612 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -1514,7 +1514,7 @@ pub const JSPromise = extern struct { return value; } - if (value.isAnyError(globalObject)) { + if (value.isAnyError()) { return rejectedPromiseValue(globalObject, value); } @@ -3064,14 +3064,30 @@ pub const JSValue = enum(JSValueReprInt) { } pub fn isError(this: JSValue) bool { - return cppFn("isError", .{this}); + if (!this.isCell()) + return false; + + return this.jsType() == JSType.ErrorInstance; } - pub fn isAnyError(this: JSValue, global: *JSGlobalObject) bool { - if (this.isEmptyOrUndefinedOrNull()) return false; + pub fn isAnyError(this: JSValue) bool { + if (!this.isCell()) + return false; + + return cppFn("isAnyError", .{this}); + } - return this.isError() or this.isException(global.vm()) or this.isAggregateError(global); + pub fn toError_(this: JSValue) JSValue { + return cppFn("toError_", .{this}); + } + + pub fn toError(this: JSValue) ?JSValue { + const res = this.toError_(); + if (res == .zero) + return null; + return res; } + pub fn isString(this: JSValue) bool { return cppFn("isString", .{this}); } @@ -3122,8 +3138,8 @@ pub const JSValue = enum(JSValueReprInt) { cppFn("getClassName", .{ this, global, ret }); } - pub fn isCell(this: JSValue) bool { - return cppFn("isCell", .{this}); + pub inline fn isCell(this: JSValue) bool { + return (@bitCast(u64, @enumToInt(this)) & FFI.NotCellMask) == 0; } pub fn asCell(this: JSValue) *JSCell { @@ -3142,10 +3158,6 @@ pub const JSValue = enum(JSValueReprInt) { return cppFn("isTerminationException", .{ this, vm }); } - pub fn toError(this: JSValue, global: *JSGlobalObject) JSValue { - return cppFn("toError", .{ this, global }); - } - pub fn toZigException(this: JSValue, global: *JSGlobalObject, exception: *ZigException) void { return cppFn("toZigException", .{ this, global, exception }); } @@ -3515,7 +3527,108 @@ pub const JSValue = enum(JSValueReprInt) { return this.asNullableVoid().?; } - pub const Extern = [_][]const u8{ "putIndex", "createRopeString", "forEachProperty", "coerceToInt32", "fastGet_", "getStaticProperty", "createUninitializedUint8Array", "fromInt64NoTruncate", "fromUInt64NoTruncate", "toUInt64NoTruncate", "asPromise", "toInt64", "_then", "put", "makeWithNameAndPrototype", "parseJSON", "symbolKeyFor", "symbolFor", "getSymbolDescription", "createInternalPromise", "asInternalPromise", "asArrayBuffer_", "fromEntries", "createTypeError", "createRangeError", "createObject2", "getIfPropertyExistsImpl", "jsType", "jsonStringify", "kind_", "isTerminationException", "isSameValue", "getLengthOfArray", "toZigString", "createStringArray", "createEmptyObject", "createEmptyArray", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt64", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable", "toBooleanSlow", "deepEquals", "strictDeepEquals", "getIfPropertyExistsFromPath", "asBigIntCompare" }; + pub const Extern = [_][]const u8{ + "_then", + "asArrayBuffer_", + "asBigIntCompare", + "asCell", + "asInternalPromise", + "asNumber", + "asObject", + "asPromise", + "asString", + "coerceToInt32", + "createEmptyArray", + "createEmptyObject", + "createInternalPromise", + "createObject2", + "createRangeError", + "createRopeString", + "createStringArray", + "createTypeError", + "createUninitializedUint8Array", + "deepEquals", + "eqlCell", + "eqlValue", + "fastGet_", + "forEach", + "forEachProperty", + "fromEntries", + "fromInt64NoTruncate", + "fromUInt64NoTruncate", + "getClassName", + "getDirect", + "getErrorsProperty", + "getIfExists", + "getIfPropertyExistsFromPath", + "getIfPropertyExistsImpl", + "getLengthOfArray", + "getNameProperty", + "getPropertyByPropertyName", + "getPropertyNames", + "getPrototype", + "getStaticProperty", + "getSymbolDescription", + "hasProperty", + "isAggregateError", + "isAnyError", + "isAnyInt", + "isBigInt", + "isBigInt32", + "isBoolean", + "isCallable", + "isClass", + "isCustomGetterSetter", + "isError", + "isException", + "isGetterSetter", + "isHeapBigInt", + "isInt32", + "isInt32AsAnyInt", + "isIterable", + "isNumber", + "isObject", + "isPrimitive", + "isSameValue", + "isString", + "isSymbol", + "isTerminationException", + "isUInt32AsAnyInt", + "jsBoolean", + "jsDoubleNumber", + "jsNull", + "jsNumberFromChar", + "jsNumberFromDouble", + "jsNumberFromInt64", + "jsNumberFromU16", + "jsTDZValue", + "jsType", + "jsUndefined", + "jsonStringify", + "kind_", + "makeWithNameAndPrototype", + "parseJSON", + "put", + "putDirect", + "putIndex", + "putRecord", + "strictDeepEquals", + "symbolFor", + "symbolKeyFor", + "toBoolean", + "toBooleanSlow", + "toError_", + "toInt32", + "toInt64", + "toObject", + "toPropertyKeyValue", + "toString", + "toStringOrNull", + "toUInt64NoTruncate", + "toWTFString", + "toZigException", + "toZigString", + }; }; extern "c" fn Microtask__run(*Microtask, *JSGlobalObject) void; diff --git a/src/bun.js/bindings/headers-cpp.h b/src/bun.js/bindings/headers-cpp.h index a37d11b37..5fe2fcf1c 100644 --- a/src/bun.js/bindings/headers-cpp.h +++ b/src/bun.js/bindings/headers-cpp.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1673163040 +//-- AUTOGENERATED FILE -- 1673176089 // clang-format off #pragma once diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h index 1c0581c81..51f1ad00c 100644 --- a/src/bun.js/bindings/headers.h +++ b/src/bun.js/bindings/headers.h @@ -1,5 +1,5 @@ // clang-format off -//-- AUTOGENERATED FILE -- 1673163040 +//-- AUTOGENERATED FILE -- 1673176089 #pragma once #include <stddef.h> @@ -252,7 +252,6 @@ CPP_DECL JSC__JSInternalPromise* JSC__JSValue__asInternalPromise(JSC__JSValue JS CPP_DECL double JSC__JSValue__asNumber(JSC__JSValue JSValue0); CPP_DECL bJSC__JSObject JSC__JSValue__asObject(JSC__JSValue JSValue0); CPP_DECL JSC__JSPromise* JSC__JSValue__asPromise(JSC__JSValue JSValue0); -CPP_DECL JSC__JSPromise* JSC__JSValue__asPromise(JSC__JSValue JSValue0); CPP_DECL JSC__JSString* JSC__JSValue__asString(JSC__JSValue JSValue0); CPP_DECL int32_t JSC__JSValue__coerceToInt32(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL JSC__JSValue JSC__JSValue__createEmptyArray(JSC__JSGlobalObject* arg0, size_t arg1); @@ -282,12 +281,12 @@ CPP_DECL void JSC__JSValue__getNameProperty(JSC__JSValue JSValue0, JSC__JSGlobal CPP_DECL JSC__JSValue JSC__JSValue__getPrototype(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL void JSC__JSValue__getSymbolDescription(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2); CPP_DECL bool JSC__JSValue__isAggregateError(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); +CPP_DECL bool JSC__JSValue__isAnyError(JSC__JSValue JSValue0); CPP_DECL bool JSC__JSValue__isAnyInt(JSC__JSValue JSValue0); CPP_DECL bool JSC__JSValue__isBigInt(JSC__JSValue JSValue0); CPP_DECL bool JSC__JSValue__isBigInt32(JSC__JSValue JSValue0); CPP_DECL bool JSC__JSValue__isBoolean(JSC__JSValue JSValue0); CPP_DECL bool JSC__JSValue__isCallable(JSC__JSValue JSValue0, JSC__VM* arg1); -CPP_DECL bool JSC__JSValue__isCell(JSC__JSValue JSValue0); CPP_DECL bool JSC__JSValue__isClass(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL bool JSC__JSValue__isCustomGetterSetter(JSC__JSValue JSValue0); CPP_DECL bool JSC__JSValue__isError(JSC__JSValue JSValue0); @@ -326,12 +325,11 @@ CPP_DECL JSC__JSValue JSC__JSValue__symbolFor(JSC__JSGlobalObject* arg0, ZigStri CPP_DECL bool JSC__JSValue__symbolKeyFor(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2); CPP_DECL bool JSC__JSValue__toBoolean(JSC__JSValue JSValue0); CPP_DECL bool JSC__JSValue__toBooleanSlow(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); -CPP_DECL JSC__JSValue JSC__JSValue__toError(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); +CPP_DECL JSC__JSValue JSC__JSValue__toError_(JSC__JSValue JSValue0); CPP_DECL int32_t JSC__JSValue__toInt32(JSC__JSValue JSValue0); CPP_DECL int64_t JSC__JSValue__toInt64(JSC__JSValue JSValue0); CPP_DECL JSC__JSObject* JSC__JSValue__toObject(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL JSC__JSString* JSC__JSValue__toString(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); -CPP_DECL JSC__JSString* JSC__JSValue__toString(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL JSC__JSString* JSC__JSValue__toStringOrNull(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL uint64_t JSC__JSValue__toUInt64NoTruncate(JSC__JSValue JSValue0); CPP_DECL void JSC__JSValue__toZigException(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigException* arg2); diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig index 095fe30f6..207327b67 100644 --- a/src/bun.js/bindings/headers.zig +++ b/src/bun.js/bindings/headers.zig @@ -206,12 +206,12 @@ pub extern fn JSC__JSValue__getNameProperty(JSValue0: JSC__JSValue, arg1: *bindi pub extern fn JSC__JSValue__getPrototype(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) JSC__JSValue; pub extern fn JSC__JSValue__getSymbolDescription(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) void; pub extern fn JSC__JSValue__isAggregateError(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) bool; +pub extern fn JSC__JSValue__isAnyError(JSValue0: JSC__JSValue) bool; pub extern fn JSC__JSValue__isAnyInt(JSValue0: JSC__JSValue) bool; pub extern fn JSC__JSValue__isBigInt(JSValue0: JSC__JSValue) bool; pub extern fn JSC__JSValue__isBigInt32(JSValue0: JSC__JSValue) bool; pub extern fn JSC__JSValue__isBoolean(JSValue0: JSC__JSValue) bool; pub extern fn JSC__JSValue__isCallable(JSValue0: JSC__JSValue, arg1: *bindings.VM) bool; -pub extern fn JSC__JSValue__isCell(JSValue0: JSC__JSValue) bool; pub extern fn JSC__JSValue__isClass(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) bool; pub extern fn JSC__JSValue__isCustomGetterSetter(JSValue0: JSC__JSValue) bool; pub extern fn JSC__JSValue__isError(JSValue0: JSC__JSValue) bool; @@ -250,7 +250,7 @@ pub extern fn JSC__JSValue__symbolFor(arg0: *bindings.JSGlobalObject, arg1: [*c] pub extern fn JSC__JSValue__symbolKeyFor(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) bool; pub extern fn JSC__JSValue__toBoolean(JSValue0: JSC__JSValue) bool; pub extern fn JSC__JSValue__toBooleanSlow(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) bool; -pub extern fn JSC__JSValue__toError(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern fn JSC__JSValue__toError_(JSValue0: JSC__JSValue) JSC__JSValue; pub extern fn JSC__JSValue__toInt32(JSValue0: JSC__JSValue) i32; pub extern fn JSC__JSValue__toInt64(JSValue0: JSC__JSValue) i64; pub extern fn JSC__JSValue__toObject(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) [*c]bindings.JSObject; diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 590d5ec2b..68469c7e8 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -1098,7 +1098,7 @@ pub const Expect = struct { const value = arguments[0]; if (value.isEmptyOrUndefinedOrNull() or !value.isObject() and !value.isString()) { var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; - globalObject.throw("Expected value must be string or Error: {any}", .{ value.toFmt(globalObject, &fmt) }); + globalObject.throw("Expected value must be string or Error: {any}", .{value.toFmt(globalObject, &fmt)}); return .zero; } break :brk value; @@ -1117,19 +1117,19 @@ pub const Expect = struct { } const not = this.op.contains(.not); - const result = value.call(globalObject, &.{}).toError(globalObject); - if (result.isUndefined()) { + const result = value.call(globalObject, &.{}).toError_(); + if (result == .zero) { if (not) return thisValue; globalObject.throw("Expected function to throw", .{}); return .zero; - } else if(not) { + } else if (not) { globalObject.throw("Expected function not to throw", .{}); return .zero; } - if (expected_value == .zero) return thisValue; + if (expected_value == .zero or !expected_value.isCell()) return thisValue; - const expected_error = expected_value.toError(globalObject); + const expected_error = expected_value.toError() orelse expected_value; if (expected_value.isString() or !expected_error.isUndefined()) { const expected = brk: { @@ -1401,7 +1401,7 @@ pub const TestScope = struct { initial_value = js.JSObjectCallAsFunctionReturnValue(vm.global, callback, null, 0, null); } - if (initial_value.isAnyError(vm.global)) { + if (initial_value.isAnyError()) { vm.runErrorHandler(initial_value, null); return .{ .fail = active_test_expectation_counter.actual }; } @@ -1640,7 +1640,7 @@ pub const DescribeScope = struct { } Jest.runner.?.pending_test = pending_test; - if (result.isAnyError(ctx)) return result; + if (result.isAnyError()) return result; if (comptime hook == .beforeAll or hook == .afterAll) { hooks[i] = JSC.JSValue.zero; @@ -1725,8 +1725,8 @@ pub const DescribeScope = struct { return null; }, } - } else if (result.isAnyError(ctx)) { - exception.* = result.asObjectRef(); + } else if (result.toError()) |err| { + exception.* = err.asObjectRef(); return null; } } diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index 20a04137f..7ee20fdd5 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -3484,7 +3484,7 @@ pub const Blob = struct { const value = Function(&blob, globalThis, bytes, .temporary); // invalid JSON needs to be rejected - if (value.isAnyError(globalThis)) { + if (value.isAnyError()) { promise.reject(globalThis, value); } else { promise.resolve(globalThis, value); @@ -4904,7 +4904,7 @@ pub const Body = struct { const json_value = blob.toJSON(global, .share); blob.detach(); - if (json_value.isAnyError(global)) { + if (json_value.isAnyError()) { promise.reject(global, json_value); } else { promise.resolve(global, json_value); diff --git a/src/napi/napi.zig b/src/napi/napi.zig index b4f054a21..da7191590 100644 --- a/src/napi/napi.zig +++ b/src/napi/napi.zig @@ -656,7 +656,7 @@ pub export fn napi_make_callback(env: napi_env, _: *anyopaque, recv: napi_value, result.* = res; // TODO: this is likely incorrect - if (res.isAnyError(env)) { + if (res.isAnyError()) { return .pending_exception; } @@ -713,8 +713,8 @@ pub extern fn napi_throw(env: napi_env, @"error": napi_value) napi_status; pub extern fn napi_throw_error(env: napi_env, code: [*c]const u8, msg: [*c]const u8) napi_status; pub extern fn napi_throw_type_error(env: napi_env, code: [*c]const u8, msg: [*c]const u8) napi_status; pub extern fn napi_throw_range_error(env: napi_env, code: [*c]const u8, msg: [*c]const u8) napi_status; -pub export fn napi_is_error(env: napi_env, value: napi_value, result: *bool) napi_status { - result.* = value.isAnyError(env); +pub export fn napi_is_error(_: napi_env, value: napi_value, result: *bool) napi_status { + result.* = value.isAnyError(); return .ok; } pub extern fn napi_is_exception_pending(env: napi_env, result: *bool) napi_status; diff --git a/test/bun.js/serve.test.ts b/test/bun.js/serve.test.ts index c050e29b0..3e2e70bb1 100644 --- a/test/bun.js/serve.test.ts +++ b/test/bun.js/serve.test.ts @@ -39,6 +39,21 @@ afterAll(() => { } }); +it("should display a welcome message when the response value type is incorrect", async () => { + await runTest( + { + fetch(req) { + return Symbol("invalid response type"); + }, + }, + async (server) => { + const response = await fetch(`http://${server.hostname}:${server.port}`); + const text = await response.text(); + expect(text).toContain("Welcome to Bun!"); + }, + ); +}); + it("should work for a file", async () => { const fixture = resolve(import.meta.dir, "./fetch.js.txt"); const textToExpect = readFileSync(fixture, "utf-8"); @@ -104,7 +119,6 @@ describe("streaming", () => { var pass = false; await runTest( { - development: false, error(e) { pass = true; return new Response("PASS", { status: 555 }); @@ -136,16 +150,16 @@ describe("streaming", () => { var pass = true; await runTest( { - development: false, error(e) { - pass = true; + pass = false; return new Response("FAIL", { status: 555 }); }, fetch(req) { return new Response( new ReadableStream({ - pull(controller) { + async pull(controller) { controller.enqueue("PASS"); + controller.close(); throw new Error("error"); }, }), @@ -157,7 +171,7 @@ describe("streaming", () => { `http://${server.hostname}:${server.port}`, ); // connection terminated - expect(response.status).toBe(500); + expect(response.status).toBe(200); expect(await response.text()).toBe("PASS"); expect(pass).toBe(true); }, @@ -217,11 +231,14 @@ describe("streaming", () => { ); }); - it("text from JS throws on start no error handler", async () => { + it("Error handler is called when a throwing stream hasn't written anything", async () => { await runTest( { port: port++, - development: false, + error(e) { + return new Response("Test Passed", { status: 200 }); + }, + fetch(req) { return new Response( new ReadableStream({ @@ -229,6 +246,42 @@ describe("streaming", () => { throw new Error("Test Passed"); }, }), + { + status: 404, + }, + ); + }, + }, + async (server) => { + const response = await fetch( + `http://${server.hostname}:${server.port}`, + ); + expect(response.status).toBe(200); + expect(await response.text()).toBe("Test Passed"); + }, + ); + }); + + // TODO: this test fails because we write status/headers at start of stream + it("text from JS throws on start with no error handler", async () => { + await runTest( + { + port: port++, + error: undefined, + + fetch(req) { + return new Response( + new ReadableStream({ + start(controller) { + throw new Error("Test Passed"); + }, + }), + { + status: 420, + headers: { + "x-what": "123", + }, + }, ); }, }, @@ -246,7 +299,6 @@ describe("streaming", () => { var err; await runTest( { - development: false, error(e) { pass = true; err = e; |