From 1b271fd45ee203243c6da51f5f0089d67a3a431a Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 20 Feb 2025 12:09:27 -0800 Subject: [PATCH] Avoid creating temporary strings when throwing errors (#17179) Co-authored-by: Dylan Conway --- src/bun.js/bindings/BunCommonStrings.h | 6 +- src/bun.js/bindings/ErrorCode.cpp | 851 +++++++++++++----- src/bun.js/bindings/ModuleLoader.cpp | 15 +- test/js/bun/globals.test.js | 4 +- test/js/node/dns/node-dns.test.js | 2 +- test/js/node/events/event-emitter.test.ts | 2 +- test/js/node/process/process.test.js | 4 +- test/js/node/test/common/index.js | 1 - test/js/node/test/parallel/test-common-gc.js | 14 + .../test/parallel/test-console-tty-colors.js | 17 +- .../test-emit-after-uncaught-exception.js | 40 + ...test-http2-compat-serverrequest-headers.js | 2 +- .../test-process-exit-code-validation.js | 7 +- .../test/parallel/test-process-kill-pid.js | 8 +- .../node/test/parallel/test-require-json.js | 32 + .../parallel/test-streams-highwatermark.js | 2 +- .../test-timers-promises-scheduler.js | 4 +- .../test-zlib-deflate-constructors.js | 14 +- .../test/parallel/test-zlib-flush-flags.js | 4 +- 19 files changed, 726 insertions(+), 303 deletions(-) create mode 100644 test/js/node/test/parallel/test-common-gc.js create mode 100644 test/js/node/test/parallel/test-emit-after-uncaught-exception.js create mode 100644 test/js/node/test/parallel/test-require-json.js diff --git a/src/bun.js/bindings/BunCommonStrings.h b/src/bun.js/bindings/BunCommonStrings.h index 2d94453465..49e1377491 100644 --- a/src/bun.js/bindings/BunCommonStrings.h +++ b/src/bun.js/bindings/BunCommonStrings.h @@ -26,7 +26,11 @@ macro(rsaPss, "rsa-pss") \ macro(ec, "ec") \ macro(x25519, "x25519") \ - macro(ed25519, "ed25519") + macro(ed25519, "ed25519") \ + macro(OperationWasAborted, "The operation was aborted.") \ + macro(OperationTimedOut, "The operation timed out.") \ + macro(ConnectionWasClosed, "The connection was closed.") \ + macro(OperationFailed, "The operation failed.") // clang-format on diff --git a/src/bun.js/bindings/ErrorCode.cpp b/src/bun.js/bindings/ErrorCode.cpp index 573c71d0f3..db322a0582 100644 --- a/src/bun.js/bindings/ErrorCode.cpp +++ b/src/bun.js/bindings/ErrorCode.cpp @@ -26,6 +26,24 @@ #include "JSDOMException.h" #include #include "ErrorCode.h" +#include "ErrorStackTrace.h" + +namespace WTF { +template<> class StringTypeAdapter, void> { +public: + StringTypeAdapter(GCOwnedDataScope string) + : m_string { string } + { + } + + unsigned length() const { return m_string->length(); } + bool is8Bit() const { return m_string->is8Bit(); } + template void writeTo(std::span destination) { m_string->getCharacters(destination); } + +private: + GCOwnedDataScope m_string; +}; +} JSC_DEFINE_HOST_FUNCTION(NodeError_proto_toString, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { @@ -40,16 +58,46 @@ JSC_DEFINE_HOST_FUNCTION(NodeError_proto_toString, (JSC::JSGlobalObject * global auto message = thisVal.get(globalObject, vm.propertyNames->message); RETURN_IF_EXCEPTION(scope, {}); - auto name_s = name.toWTFString(globalObject); + auto* name_s = name.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto code_s = code.toWTFString(globalObject); + auto* code_s = code.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto message_s = message.toWTFString(globalObject); + auto* message_s = message.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - return JSC::JSValue::encode(JSC::jsString(vm, WTF::makeString(name_s, " ["_s, code_s, "]: "_s, message_s))); + auto nameView = name_s->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto codeView = code_s->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto messageView = message_s->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + + WTF::StringBuilder builder; + builder.append(nameView); + builder.append(" ["_s); + builder.append(codeView); + builder.append("]: "_s); + builder.append(messageView); + + return JSC::JSValue::encode(JSC::jsString(vm, builder.toString())); } +// clang-format on + +#define EXPECT_ARG_COUNT(count__) \ + do { \ + auto argCount = callFrame->argumentCount(); \ + if (argCount < count__) { \ + JSC::throwTypeError(globalObject, scope, "requires " #count__ " arguments"_s); \ + return {}; \ + } \ + } while (false) + +namespace Bun { + +using namespace JSC; +using namespace WTF; + static JSC::JSObject* createErrorPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::ErrorType type, WTF::ASCIILiteral name, WTF::ASCIILiteral code, bool isDOMExceptionPrototype) { JSC::JSObject* prototype; @@ -90,21 +138,6 @@ static JSC::JSObject* createErrorPrototype(JSC::VM& vm, JSC::JSGlobalObject* glo return prototype; } -// clang-format on - -#define EXPECT_ARG_COUNT(count__) \ - do { \ - auto argCount = callFrame->argumentCount(); \ - if (argCount < count__) { \ - JSC::throwTypeError(globalObject, scope, "requires " #count__ " arguments"_s); \ - return {}; \ - } \ - } while (false) - -namespace Bun { - -using namespace JSC; - #include "ErrorCode+Data.h" const ClassInfo ErrorCodeCache::s_info = { "ErrorCodeCache"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ErrorCodeCache) }; @@ -176,6 +209,16 @@ JSObject* createError(VM& vm, Zig::GlobalObject* globalObject, ErrorCode code, c return errorCache(globalObject)->createError(vm, globalObject, code, jsString(vm, message), jsUndefined(), isDOMExceptionPrototype); } +JSObject* createError(Zig::GlobalObject* globalObject, ErrorCode code, const String& message, bool isDOMExceptionPrototype) +{ + return createError(globalObject->vm(), globalObject, code, message, isDOMExceptionPrototype); +} + +JSObject* createError(VM& vm, JSC::JSGlobalObject* globalObject, ErrorCode code, const String& message, bool isDOMExceptionPrototype) +{ + return createError(vm, defaultGlobalObject(globalObject), code, message, isDOMExceptionPrototype); +} + JSObject* createError(VM& vm, JSC::JSGlobalObject* globalObject, ErrorCode code, JSValue message, bool isDOMExceptionPrototype) { if (auto* zigGlobalObject = jsDynamicCast(globalObject)) @@ -192,8 +235,7 @@ JSC::JSObject* createError(VM& vm, Zig::GlobalObject* globalObject, ErrorCode co JSObject* createError(JSC::JSGlobalObject* globalObject, ErrorCode code, const String& message, bool isDOMExceptionPrototype) { - auto& vm = JSC::getVM(globalObject); - return createError(vm, globalObject, code, jsString(vm, message), isDOMExceptionPrototype); + return createError(globalObject->vm(), globalObject, code, message, isDOMExceptionPrototype); } JSObject* createError(Zig::JSGlobalObject* globalObject, ErrorCode code, JSC::JSValue message, bool isDOMExceptionPrototype) @@ -202,44 +244,78 @@ JSObject* createError(Zig::JSGlobalObject* globalObject, ErrorCode code, JSC::JS return createError(vm, globalObject, code, message, isDOMExceptionPrototype); } -// export fn Bun__inspect(globalThis: *JSGlobalObject, value: JSValue) bun.String extern "C" BunString Bun__inspect(JSC::JSGlobalObject* globalObject, JSValue value); -// -WTF::String JSValueToStringSafe(JSC::JSGlobalObject* globalObject, JSValue arg) +void JSValueToStringSafe(JSC::JSGlobalObject* globalObject, WTF::StringBuilder& builder, JSValue arg, bool quotesLikeInspect = false) { ASSERT(!arg.isEmpty()); - if (!arg.isCell()) - return arg.toWTFStringForConsole(globalObject); + if (!arg.isCell()) { + builder.append(arg.toWTFStringForConsole(globalObject)); + return; + } auto cell = arg.asCell(); switch (cell->type()) { case JSC::JSType::StringType: { - return arg.toWTFStringForConsole(globalObject); + JSString* jsString = jsDynamicCast(cell); + auto str = jsString->view(globalObject); + if (quotesLikeInspect) { + if (str->contains('\'')) { + builder.append('"'); + if (str->is8Bit()) { + const auto span = str->span(); + for (const auto c : span) { + if (c == '"') { + builder.append("\\\""_s); + } else { + builder.append(c); + } + } + } else { + const auto span = str->span(); + for (const auto c : span) { + if (c == '"') { + builder.append("\\\""_s); + } else { + builder.append(c); + } + } + } + builder.append('"'); + return; + } + + builder.append('\''); + builder.append(str); + builder.append('\''); + return; + } + builder.append(str); + return; } case JSC::JSType::SymbolType: { auto symbol = jsCast(cell); auto result = symbol->tryGetDescriptiveString(); - if (result.has_value()) - return result.value(); - return "Symbol"_s; + if (result.has_value()) { + builder.append(result.value()); + } else { + builder.append("Symbol"_s); + } + return; } case JSC::JSType::InternalFunctionType: case JSC::JSType::JSFunctionType: { auto& vm = JSC::getVM(globalObject); - auto catchScope = DECLARE_CATCH_SCOPE(vm); - auto name = JSC::getCalculatedDisplayName(vm, cell->getObject()); - if (catchScope.exception()) { - catchScope.clearException(); - name = ""_s; - } + auto name = Zig::functionName(vm, globalObject, cell->getObject()); - if (!name.isNull() && name.length() > 0) { - return makeString("[Function: "_s, name, ']'); + if (!name.isEmpty()) { + builder.append("[Function: "_s); + builder.append(name); + builder.append(']'); + } else { + builder.append("[Function (anonymous)]"_s); } - - return "[Function (anonymous)]"_s; - break; + return; } default: { @@ -247,40 +323,48 @@ WTF::String JSValueToStringSafe(JSC::JSGlobalObject* globalObject, JSValue arg) } } - return Bun__inspect(globalObject, arg).transferToWTFString(); + auto bstring = Bun__inspect(globalObject, arg); + auto&& str = bstring.transferToWTFString(); + builder.append(str); } -WTF::String determineSpecificType(JSC::JSGlobalObject* globalObject, JSValue value) +void determineSpecificType(JSC::VM& vm, JSC::JSGlobalObject* globalObject, WTF::StringBuilder& builder, JSValue value) { - auto& vm = JSC::getVM(globalObject); auto scope = DECLARE_CATCH_SCOPE(vm); ASSERT(!value.isEmpty()); if (value.isNull()) { - return String("null"_s); + builder.append("null"_s); + return; } if (value.isUndefined()) { - return String("undefined"_s); + builder.append("undefined"_s); + return; } if (value.isNumber()) { double d = value.asNumber(); double infinity = std::numeric_limits::infinity(); - if (value == 0) return (1 / d == -infinity) ? String("type number (-0)"_s) : String("type number (0)"_s); - if (d != d) return String("type number (NaN)"_s); - if (d == infinity) return String("type number (Infinity)"_s); - if (d == -infinity) return String("type number (-Infinity)"_s); - auto str = value.toStringOrNull(globalObject); - if (!str) return {}; - return makeString("type number ("_s, str->getString(globalObject), ")"_s); + if (d != d) return builder.append("type number (NaN)"_s); + if (d == infinity) return builder.append("type number (Infinity)"_s); + if (d == -infinity) return builder.append("type number (-Infinity)"_s); + builder.append("type number ("_s); + builder.append(d); + builder.append(')'); + return; } if (value.isBoolean()) { - return value.asBoolean() ? String("type boolean (true)"_s) : String("type boolean (false)"_s); + builder.append(value.asBoolean() ? "type boolean (true)"_s : "type boolean (false)"_s); + return; } if (value.isBigInt()) { - auto str = value.toString(globalObject); - if (!str) return {}; - return makeString("type bigint ("_s, str->getString(globalObject), "n)"_s); + auto str = value.toStringOrNull(globalObject); + if (!str) return void(); + auto view = str->view(globalObject); + builder.append("type bigint ("_s); + builder.append(view); + builder.append("n)"_s); + return; } ASSERT(value.isCell()); @@ -289,80 +373,118 @@ WTF::String determineSpecificType(JSC::JSGlobalObject* globalObject, JSValue val if (cell->isSymbol()) { auto symbol = jsCast(cell); auto result = symbol->tryGetDescriptiveString(); - auto description = result.has_value() ? result.value() : String("Symbol()"_s); - return makeString("type symbol ("_s, description, ")"_s); + if (result.has_value()) { + builder.append("type symbol ("_s); + builder.append(result.value()); + builder.append(")"_s); + } else { + builder.append("type symbol (Symbol())"_s); + } + return; } if (cell->isCallable()) { - auto name = JSC::getCalculatedDisplayName(vm, cell->getObject()); - if (scope.exception()) { - scope.clearException(); - name = String(""_s); + builder.append("function "_s); + auto name = Zig::functionName(vm, globalObject, cell->getObject()); + + if (!name.isEmpty()) { + builder.append(name); } - if (!name.isNull() && name.length() > 0) { - return makeString("function "_s, name); - } - return String("function "_s); + return; } if (cell->isString()) { - auto str = value.toString(globalObject)->getString(globalObject); - if (str.length() > 28) { - str = str.substring(0, 25); - str = makeString(str, "..."_s); - if (!str.contains('\'')) { - return makeString("type string ('"_s, str, "')"_s); - } + auto* jsString = jsCast(cell); + auto str = jsString->view(globalObject); + + StringView view = str; + + const bool needsEllipsis = jsString->length() > 28; + const bool needsEscape = str->contains('\''); + if (needsEllipsis) { + view = str->substring(0, 25); } - // return `type string (${JSONStringify(value)})`; - str = value.toWTFStringForConsole(globalObject); - RETURN_IF_EXCEPTION(scope, {}); - return makeString("type string ("_s, str, ")"_s); + builder.append("type string ("_s); + if (UNLIKELY(needsEscape)) { + builder.append('"'); + if (view.is8Bit()) { + const auto span = view.span(); + for (const auto c : span) { + if (c == '"') { + builder.append("\\\""_s); + } else { + builder.append(c); + } + } + } else { + const auto span = view.span(); + for (const auto c : span) { + if (c == '"') { + builder.append("\\\""_s); + } else { + builder.append(c); + } + } + } + } else { + builder.append('\''); + builder.append(view); + } + if (needsEllipsis) { + builder.append("..."_s); + } + if (UNLIKELY(needsEscape)) { + builder.append('"'); + } else { + builder.append('\''); + } + builder.append(')'); + return; } if (cell->isObject()) { auto constructor = value.get(globalObject, vm.propertyNames->constructor); - RETURN_IF_EXCEPTION(scope, {}); + RETURN_IF_EXCEPTION(scope, void()); if (constructor.toBoolean(globalObject)) { auto name = constructor.get(globalObject, vm.propertyNames->name); - RETURN_IF_EXCEPTION(scope, {}); + RETURN_IF_EXCEPTION(scope, void()); auto str = name.toString(globalObject); - RETURN_IF_EXCEPTION(scope, {}); - return makeString("an instance of "_s, str->getString(globalObject)); + RETURN_IF_EXCEPTION(scope, void()); + builder.append("an instance of "_s); + auto view = str->view(globalObject); + builder.append(view); + return; } - // return `${lazyInternalUtilInspect().inspect(value, { depth: -1 })}`; - auto str = JSValueToStringSafe(globalObject, value); - RETURN_IF_EXCEPTION(scope, {}); - return str; } // value = lazyInternalUtilInspect().inspect(value, { colors: false }); - auto str = JSValueToStringSafe(globalObject, value); - RETURN_IF_EXCEPTION(scope, {}); - return str; + JSValueToStringSafe(globalObject, builder, value); } extern "C" BunString Bun__ErrorCode__determineSpecificType(JSC::JSGlobalObject* globalObject, EncodedJSValue value) { JSValue jsValue = JSValue::decode(value); - WTF::String typeString = determineSpecificType(globalObject, jsValue); - return Bun::toStringRef(typeString); + WTF::StringBuilder builder; + determineSpecificType(JSC::getVM(globalObject), globalObject, builder, jsValue); + return Bun::toStringRef(builder.toString()); } namespace Message { WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const StringView& arg_name, const StringView& expected_type, JSValue actual_value) { - auto actual_value_string = determineSpecificType(globalObject, actual_value); + WTF::StringBuilder result; + result.append("The \""_s); + result.append(arg_name); + result.append("\" argument must be of type "_s); + result.append(expected_type); + result.append(". Received "_s); + determineSpecificType(JSC::getVM(globalObject), globalObject, result, actual_value); RETURN_IF_EXCEPTION(scope, {}); - - return makeString("The \""_s, arg_name, "\" argument must be of type "_s, expected_type, ". Received "_s, actual_value_string); + return result.toString(); } WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const StringView& arg_name, ArgList expected_types, JSValue actual_value) { WTF::StringBuilder result; - auto actual_value_string = determineSpecificType(globalObject, actual_value); - RETURN_IF_EXCEPTION(scope, {}); - result.append("The "_s); if (arg_name.endsWith(" argument"_s)) { @@ -376,22 +498,34 @@ WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* gl unsigned length = expected_types.size(); if (length == 1) { - result.append(expected_types.at(0).toWTFString(globalObject)); + auto* str = expected_types.at(0).toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + result.append(str->view(globalObject)); } else if (length == 2) { - result.append(expected_types.at(0).toWTFString(globalObject)); + auto* str1 = expected_types.at(0).toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + result.append(str1->view(globalObject)); result.append(" or "_s); - result.append(expected_types.at(1).toWTFString(globalObject)); + auto* str2 = expected_types.at(1).toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + result.append(str2->view(globalObject)); } else { - for (unsigned i = 0; i < length - 1; i++) { + for (unsigned i = 0, end = length - 1; i < end; i++) { JSValue expected_type = expected_types.at(i); - result.append(expected_type.toWTFString(globalObject)); + auto* str = expected_type.toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + result.append(str->view(globalObject)); result.append(", "_s); } result.append("or "_s); - result.append(expected_types.at(length - 1).toWTFString(globalObject)); + auto* str = expected_types.at(length - 1).toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + result.append(str->view(globalObject)); } - result.append(". Received "_s, actual_value_string); + result.append(". Received "_s); + determineSpecificType(JSC::getVM(globalObject), globalObject, result, actual_value); + RETURN_IF_EXCEPTION(scope, {}); return result.toString(); } @@ -409,10 +543,14 @@ WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* gl WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue val_arg_name, JSValue val_expected_type, JSValue val_actual_value) { - auto arg_name = val_arg_name.toWTFString(globalObject); + auto* arg_name_str = val_arg_name.toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto arg_name = arg_name_str->view(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto expected_type = val_expected_type.toWTFString(globalObject); + auto* expected_type_str = val_expected_type.toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto expected_type = expected_type_str->view(globalObject); RETURN_IF_EXCEPTION(scope, {}); return ERR_INVALID_ARG_TYPE(scope, globalObject, arg_name, expected_type, val_actual_value); @@ -420,16 +558,26 @@ WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* gl WTF::String ERR_OUT_OF_RANGE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue val_arg_name, JSValue val_range, JSValue val_input) { - auto arg_name = val_arg_name.toWTFString(globalObject); + auto* arg_name_str = val_arg_name.toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto arg_name = arg_name_str->view(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto range = val_range.toWTFString(globalObject); + auto* range_str = val_range.toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto range = range_str->view(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto input = JSValueToStringSafe(globalObject, val_input); + WTF::StringBuilder builder; + builder.append("The value of \""_s); + builder.append(arg_name); + builder.append("\" is out of range. It must be "_s); + builder.append(range); + builder.append(". Received "_s); + JSValueToStringSafe(globalObject, builder, val_input); RETURN_IF_EXCEPTION(scope, {}); - return makeString("The value of \""_s, arg_name, "\" is out of range. It must be "_s, range, ". Received "_s, input); + return builder.toString(); } } @@ -438,96 +586,147 @@ namespace ERR { JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, const WTF::String& expected_type, JSC::JSValue val_actual_value) { + WTF::StringBuilder builder; auto arg_kind = arg_name.contains('.') ? "property"_s : "argument"_s; auto ty_first_char = expected_type[0]; auto ty_kind = ty_first_char >= 'A' && ty_first_char <= 'Z' ? "an instance of"_s : "of type"_s; - auto actual_value = determineSpecificType(globalObject, val_actual_value); + builder.append("The \""_s); + builder.append(arg_name); + builder.append("\" "_s); + builder.append(arg_kind); + builder.append(" must be "_s); + builder.append(ty_kind); + builder.append(" "_s); + builder.append(expected_type); + builder.append(". Received "_s); + determineSpecificType(globalObject->vm(), globalObject, builder, val_actual_value); RETURN_IF_EXCEPTION(throwScope, {}); - auto message = makeString("The \""_s, arg_name, "\" "_s, arg_kind, " must be "_s, ty_kind, " "_s, expected_type, ". Received "_s, actual_value); - throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message)); + throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, builder.toString())); return {}; } + JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue val_arg_name, const WTF::String& expected_type, JSC::JSValue val_actual_value) { - auto arg_name = val_arg_name.toWTFString(globalObject); + auto* jsString = val_arg_name.toString(globalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + auto arg_name = jsString->view(globalObject); RETURN_IF_EXCEPTION(throwScope, {}); - auto arg_kind = arg_name.contains('.') ? "property"_s : "argument"_s; + WTF::StringBuilder builder; + auto arg_kind = arg_name->contains('.') ? "property"_s : "argument"_s; auto ty_first_char = expected_type[0]; auto ty_kind = ty_first_char >= 'A' && ty_first_char <= 'Z' ? "an instance of"_s : "of type"_s; - auto actual_value = determineSpecificType(globalObject, val_actual_value); + builder.append("The \""_s); + builder.append(arg_name); + builder.append("\" "_s); + builder.append(arg_kind); + builder.append(" must be "_s); + builder.append(ty_kind); + builder.append(" "_s); + builder.append(expected_type); + builder.append(". Received "_s); + determineSpecificType(globalObject->vm(), globalObject, builder, val_actual_value); RETURN_IF_EXCEPTION(throwScope, {}); - auto message = makeString("The \""_s, arg_name, "\" "_s, arg_kind, " must be "_s, ty_kind, " "_s, expected_type, ". Received "_s, actual_value); - throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message)); + throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, builder.toString())); return {}; } JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, double lower, double upper, JSC::JSValue actual) { - auto lowerStr = jsNumber(lower).toWTFString(globalObject); - auto upperStr = jsNumber(upper).toWTFString(globalObject); - auto actual_value = JSValueToStringSafe(globalObject, actual); + WTF::StringBuilder builder; + builder.append("The value of \""_s); + builder.append(arg_name); + builder.append("\" is out of range. It must be >= "_s); + builder.append(lower); + builder.append(" and <= "_s); + builder.append(upper); + builder.append(". Received "_s); + JSValueToStringSafe(globalObject, builder, actual); RETURN_IF_EXCEPTION(throwScope, {}); - auto message = makeString("The value of \""_s, arg_name, "\" is out of range. It must be >= "_s, lowerStr, " and <= "_s, upperStr, ". Received "_s, actual_value); - throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message)); + throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, builder.toString())); return {}; } + JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, double lower, double upper, JSC::JSValue actual) { - auto arg_name = arg_name_val.toWTFString(globalObject); + auto* jsString = arg_name_val.toString(globalObject); RETURN_IF_EXCEPTION(throwScope, {}); - auto lowerStr = jsNumber(lower).toWTFString(globalObject); - auto upperStr = jsNumber(upper).toWTFString(globalObject); - auto actual_value = JSValueToStringSafe(globalObject, actual); + auto arg_name = jsString->view(globalObject); RETURN_IF_EXCEPTION(throwScope, {}); - auto message = makeString("The value of \""_s, arg_name, "\" is out of range. It must be >= "_s, lowerStr, " and <= "_s, upperStr, ". Received "_s, actual_value); - throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message)); + WTF::StringBuilder builder; + builder.append("The value of \""_s); + builder.append(arg_name); + builder.append("\" is out of range. It must be >= "_s); + builder.append(lower); + builder.append(" and <= "_s); + builder.append(upper); + builder.append(". Received "_s); + JSValueToStringSafe(globalObject, builder, actual); + RETURN_IF_EXCEPTION(throwScope, {}); + + throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, builder.toString())); return {}; } + JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, double bound_num, Bound bound, JSC::JSValue actual) { - auto arg_name = arg_name_val.toWTFString(globalObject); + auto* jsString = arg_name_val.toString(globalObject); RETURN_IF_EXCEPTION(throwScope, {}); - auto actual_value = JSValueToStringSafe(globalObject, actual); + auto arg_name = jsString->view(globalObject); RETURN_IF_EXCEPTION(throwScope, {}); - switch (bound) { - case LOWER: { - auto message = makeString("The value of \""_s, arg_name, "\" is out of range. It must be >= "_s, bound_num, ". Received "_s, actual_value); - throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message)); - return {}; - } - case UPPER: { - auto message = makeString("The value of \""_s, arg_name, "\" is out of range. It must be <= "_s, bound_num, ". Received "_s, actual_value); - throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message)); - return {}; - } - } -} -JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, const WTF::String& msg, JSC::JSValue actual) -{ - auto arg_name = arg_name_val.toWTFString(globalObject); - RETURN_IF_EXCEPTION(throwScope, {}); - auto actual_value = JSValueToStringSafe(globalObject, actual); + WTF::StringBuilder builder; + builder.append("The value of \""_s); + builder.append(arg_name); + builder.append("\" is out of range. It must be "_s); + builder.append(bound == LOWER ? ">= "_s : "<= "_s); + builder.append(bound_num); + builder.append(". Received "_s); + JSValueToStringSafe(globalObject, builder, actual); RETURN_IF_EXCEPTION(throwScope, {}); - auto message = makeString("The value of \""_s, arg_name, "\" is out of range. It must be "_s, msg, ". Received "_s, actual_value); - throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message)); + throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, builder.toString())); return {}; } -JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, const WTF::String& msg, JSC::JSValue actual) + +JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, const WTF::String& msg, JSC::JSValue actual) { - auto actual_value = JSValueToStringSafe(globalObject, actual); + auto* jsString = arg_name_val.toString(globalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + auto arg_name = jsString->view(globalObject); RETURN_IF_EXCEPTION(throwScope, {}); - auto message = makeString("The value of \""_s, arg_name, "\" is out of range. It must be "_s, msg, ". Received "_s, actual_value); - throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message)); + WTF::StringBuilder builder; + builder.append("The value of \""_s); + builder.append(arg_name); + builder.append("\" is out of range. It must be "_s); + builder.append(msg); + builder.append(". Received "_s); + JSValueToStringSafe(globalObject, builder, actual); + RETURN_IF_EXCEPTION(throwScope, {}); + + throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, builder.toString())); + return {}; +} + +JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, const WTF::String& msg, JSC::JSValue actual) +{ + WTF::StringBuilder builder; + builder.append("The value of \""_s); + builder.append(arg_name); + builder.append("\" is out of range. It must be "_s); + builder.append(msg); + builder.append(". Received "_s); + JSValueToStringSafe(globalObject, builder, actual); + RETURN_IF_EXCEPTION(throwScope, {}); + + throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, builder.toString())); return {}; } @@ -535,37 +734,56 @@ JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobal { ASCIILiteral type = String(name).contains('.') ? "property"_s : "argument"_s; - auto value_string = JSValueToStringSafe(globalObject, value); + WTF::StringBuilder builder; + builder.append("The "_s); + builder.append(type); + builder.append(" '"_s); + builder.append(name); + builder.append("' "_s); + builder.append(reason); + builder.append(". Received "_s); + JSValueToStringSafe(globalObject, builder, value, true); RETURN_IF_EXCEPTION(throwScope, {}); - auto message = makeString("The "_s, type, " '"_s, name, "' "_s, reason, ". Received "_s, value_string); - throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_VALUE, message)); + throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_VALUE, builder.toString())); return {}; } JSC::EncodedJSValue INVALID_ARG_VALUE_RangeError(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, WTF::ASCIILiteral name, JSC::JSValue value, const WTF::String& reason) { - ASCIILiteral type = String(name).contains('.') ? "property"_s : "argument"_s; + auto& vm = JSC::getVM(globalObject); + ASCIILiteral type = StringView(name).contains('.') ? "property"_s : "argument"_s; + WTF::StringBuilder builder; - auto value_string = JSValueToStringSafe(globalObject, value); + builder.append("The "_s); + builder.append(type); + builder.append(" '"_s); + builder.append(name); + builder.append("' "_s); + builder.append(reason); + builder.append(". Received "_s); + JSValueToStringSafe(globalObject, builder, value, true); RETURN_IF_EXCEPTION(throwScope, {}); - auto& vm = JSC::getVM(globalObject); - auto message = makeString("The "_s, type, " '"_s, name, "' "_s, reason, ". Received "_s, value_string); auto* structure = createErrorStructure(vm, globalObject, ErrorType::RangeError, "RangeError"_s, "ERR_INVALID_ARG_VALUE"_s, false); - auto error = JSC::ErrorInstance::create(vm, structure, message, jsUndefined(), nullptr, JSC::RuntimeType::TypeNothing, ErrorType::RangeError, true); + auto error = JSC::ErrorInstance::create(vm, structure, builder.toString(), jsUndefined(), nullptr, JSC::RuntimeType::TypeNothing, ErrorType::RangeError, true); throwScope.throwException(globalObject, error); return {}; } JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue name, JSC::JSValue value, const WTF::String& reason) { - auto name_string = JSValueToStringSafe(globalObject, name); + WTF::StringBuilder builder; + builder.append("The argument '"_s); + auto& vm = JSC::getVM(globalObject); + determineSpecificType(vm, globalObject, builder, name); RETURN_IF_EXCEPTION(throwScope, {}); - auto value_string = JSValueToStringSafe(globalObject, value); + builder.append("' "_s); + builder.append(reason); + builder.append(". Received "_s); + JSValueToStringSafe(globalObject, builder, value, true); RETURN_IF_EXCEPTION(throwScope, {}); - auto message = makeString("The argument '"_s, name_string, "' "_s, reason, ". Received "_s, value_string); - throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_VALUE, message)); + throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_VALUE, builder.toString())); return {}; } @@ -628,26 +846,30 @@ JSC::EncodedJSValue BUFFER_OUT_OF_BOUNDS(JSC::ThrowScope& throwScope, JSC::JSGlo JSC::EncodedJSValue UNKNOWN_SIGNAL(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue signal, bool triedUppercase) { - auto signal_string = signal.toWTFString(globalObject); + WTF::StringBuilder builder; + builder.append("Unknown signal: "_s); + JSValueToStringSafe(globalObject, builder, signal); RETURN_IF_EXCEPTION(throwScope, {}); - - auto message_extra = triedUppercase ? " (signals must use all capital letters)"_s : ""_s; - auto message = makeString("Unknown signal: "_s, signal_string, message_extra); - throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_UNKNOWN_SIGNAL, message)); + if (triedUppercase) { + builder.append(" (signals must use all capital letters)"_s); + } + throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_UNKNOWN_SIGNAL, builder.toString())); return {}; } JSC::EncodedJSValue SOCKET_BAD_PORT(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue name, JSC::JSValue port, bool allowZero) { ASCIILiteral op = allowZero ? ">="_s : ">"_s; - - auto name_string = JSValueToStringSafe(globalObject, name); + WTF::StringBuilder builder; + JSValueToStringSafe(globalObject, builder, name); RETURN_IF_EXCEPTION(throwScope, {}); - auto port_string = JSValueToStringSafe(globalObject, port); + builder.append(" should be "_s); + builder.append(op); + builder.append(" 0 and < 65536. Received "_s); + JSValueToStringSafe(globalObject, builder, port); RETURN_IF_EXCEPTION(throwScope, {}); - auto message = makeString(name_string, " should be "_s, op, " 0 and < 65536. Received "_s, port_string); - throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_SOCKET_BAD_PORT, message)); + throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_SOCKET_BAD_PORT, builder.toString())); return {}; } @@ -712,20 +934,44 @@ static JSC::JSValue ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalOb static JSValue ERR_INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue name, JSC::JSValue value, JSC::JSValue reason) { ASSERT(name.isString()); - auto name_string = name.toWTFString(globalObject); - ASCIILiteral type = name_string.contains('.') ? "property"_s : "argument"_s; + auto* jsNameString = name.toString(globalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + + auto nameView = jsNameString->view(globalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + + ASCIILiteral type = nameView->contains('.') ? "property"_s : "argument"_s; + WTF::StringBuilder builder; - auto value_string = JSValueToStringSafe(globalObject, value); RETURN_IF_EXCEPTION(throwScope, {}); ASSERT(reason.isUndefined() || reason.isString()); + + builder.append("The "_s); + builder.append(type); + builder.append(" '"_s); + builder.append(nameView); + builder.append("'"_s); + if (reason.isUndefined()) { - auto message = makeString("The "_s, type, " '"_s, name_string, "' is invalid. Received "_s, value_string); - return createError(globalObject, ErrorCode::ERR_INVALID_ARG_VALUE, message); + builder.append(" is invalid. Received "_s); + JSValueToStringSafe(globalObject, builder, value, true); + RETURN_IF_EXCEPTION(throwScope, {}); + return createError(globalObject, ErrorCode::ERR_INVALID_ARG_VALUE, builder.toString()); } - auto reason_string = reason.toWTFString(globalObject); - auto message = makeString("The "_s, type, " '"_s, name_string, "' "_s, reason_string, ". Received "_s, value_string); - return createError(globalObject, ErrorCode::ERR_INVALID_ARG_VALUE, message); + + auto* jsReasonString = reason.toString(globalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + + auto reasonView = jsReasonString->view(globalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + + builder.append(' '); + builder.append(reasonView); + builder.append(". Received "_s); + JSValueToStringSafe(globalObject, builder, value, true); + RETURN_IF_EXCEPTION(throwScope, {}); + return createError(globalObject, ErrorCode::ERR_INVALID_ARG_VALUE, builder.toString()); } extern "C" JSC::EncodedJSValue Bun__createErrorWithCode(JSC::JSGlobalObject* globalObject, ErrorCode code, BunString* message) @@ -750,30 +996,36 @@ void throwCryptoOperationFailed(JSGlobalObject* globalObject, JSC::ThrowScope& s JSC_DEFINE_HOST_FUNCTION(jsFunctionMakeAbortError, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame)) { - auto* globalObject = reinterpret_cast(lexicalGlobalObject); + auto* globalObject = defaultGlobalObject(lexicalGlobalObject); auto& vm = JSC::getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); auto message = callFrame->argument(0); - if (message.isUndefined()) message = JSC::jsString(vm, String("The operation was aborted"_s)); auto options = callFrame->argument(1); if (!options.isUndefined() && options.isCell() && !options.asCell()->isObject()) return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, "options"_s, "object"_s, options); + + if (message.isUndefined() && options.isUndefined()) { + return JSValue::encode(Bun::createError(vm, lexicalGlobalObject, Bun::ErrorCode::ABORT_ERR, JSValue(globalObject->commonStrings().OperationWasAbortedString(globalObject)), false)); + } + + if (message.isUndefined()) message = globalObject->commonStrings().OperationWasAbortedString(globalObject); auto error = Bun::createError(vm, globalObject, Bun::ErrorCode::ABORT_ERR, message, options, false); return JSC::JSValue::encode(error); } JSC::JSValue WebCore::toJS(JSC::JSGlobalObject* globalObject, CommonAbortReason abortReason) { + auto* zigGlobalObject = defaultGlobalObject(globalObject); switch (abortReason) { case CommonAbortReason::Timeout: { - return createError(globalObject, Bun::ErrorCode::ABORT_ERR, "The operation timed out"_s, true); + return createError(globalObject, Bun::ErrorCode::ABORT_ERR, zigGlobalObject->commonStrings().OperationWasAbortedString(globalObject), true); } case CommonAbortReason::UserAbort: { // This message is a standardized error message. We cannot change it. // https://webidl.spec.whatwg.org/#idl-DOMException:~:text=The%20operation%20was%20aborted. - return createError(globalObject, Bun::ErrorCode::ABORT_ERR, "The operation was aborted."_s, true); + return createError(globalObject, Bun::ErrorCode::ABORT_ERR, zigGlobalObject->commonStrings().OperationWasAbortedString(globalObject), true); } case CommonAbortReason::ConnectionClosed: { - return createError(globalObject, Bun::ErrorCode::ABORT_ERR, "The connection was closed"_s, true); + return createError(globalObject, Bun::ErrorCode::ABORT_ERR, zigGlobalObject->commonStrings().ConnectionWasClosedString(globalObject), true); } default: { break; @@ -800,8 +1052,12 @@ JSC::JSObject* Bun::createInvalidThisError(JSC::JSGlobalObject* globalObject, JS } // Pathological case: the this value returns a string which is extremely long or causes an out of memory error. - const auto& typeString = thisValue.isString() ? String("a string"_s) : JSC::errorDescriptionForValue(globalObject, thisValue); - return Bun::createError(globalObject, Bun::ErrorCode::ERR_INVALID_THIS, makeString("Expected this to be instanceof "_s, typeName, ", but received "_s, typeString)); + WTF::StringBuilder builder; + builder.append("Expected this to be instanceof "_s); + builder.append(typeName); + builder.append(", but received "_s); + determineSpecificType(JSC::getVM(globalObject), globalObject, builder, thisValue); + return Bun::createError(globalObject, Bun::ErrorCode::ERR_INVALID_THIS, builder.toString()); } JSC::EncodedJSValue Bun::throwError(JSC::JSGlobalObject* globalObject, JSC::ThrowScope& scope, Bun::ErrorCode code, const WTF::String& message) @@ -849,10 +1105,15 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject case Bun::ErrorCode::ERR_INVALID_IP_ADDRESS: { JSValue arg0 = callFrame->argument(1); - auto param = arg0.toWTFString(globalObject); + auto* jsString = arg0.toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto param = jsString->view(globalObject); RETURN_IF_EXCEPTION(scope, {}); - return JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_IP_ADDRESS, makeString("Invalid IP address: "_s, param))); + WTF::StringBuilder builder; + builder.append("Invalid IP address: "_s); + builder.append(param); + return JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_IP_ADDRESS, builder.toString())); } case Bun::ErrorCode::ERR_INVALID_ARG_VALUE: { @@ -864,33 +1125,53 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject case Bun::ErrorCode::ERR_UNKNOWN_ENCODING: { auto arg0 = callFrame->argument(1); - auto str0 = arg0.toWTFString(globalObject); + auto* jsString = arg0.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto message = makeString("Unknown encoding: "_s, str0); - return JSC::JSValue::encode(createError(globalObject, error, message)); + auto param = jsString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + WTF::StringBuilder builder; + builder.append("Unknown encoding: "_s); + builder.append(param); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); } case Bun::ErrorCode::ERR_STREAM_DESTROYED: { auto arg0 = callFrame->argument(1); - auto str0 = arg0.toWTFString(globalObject); + auto* jsString = arg0.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto message = makeString("Cannot call "_s, str0, " after a stream was destroyed"_s); - return JSC::JSValue::encode(createError(globalObject, error, message)); + auto param = jsString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + WTF::StringBuilder builder; + builder.append("Cannot call "_s); + builder.append(param); + builder.append(" after a stream was destroyed"_s); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); } case Bun::ErrorCode::ERR_METHOD_NOT_IMPLEMENTED: { auto arg0 = callFrame->argument(1); - auto str0 = arg0.toWTFString(globalObject); + auto* jsString = arg0.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - return JSC::JSValue::encode(createError(globalObject, error, makeString("The "_s, str0, " method is not implemented"_s))); + auto param = jsString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + WTF::StringBuilder builder; + builder.append("The "_s); + builder.append(param); + builder.append(" method is not implemented"_s); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); } case Bun::ErrorCode::ERR_STREAM_ALREADY_FINISHED: { auto arg0 = callFrame->argument(1); - auto str0 = arg0.toWTFString(globalObject); + auto* jsString = arg0.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto message = makeString("Cannot call "_s, str0, " after a stream was finished"_s); - return JSC::JSValue::encode(createError(globalObject, error, message)); + auto param = jsString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + WTF::StringBuilder builder; + builder.append("Cannot call "_s); + builder.append(param); + builder.append(" after a stream was finished"_s); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); } case Bun::ErrorCode::ERR_MISSING_ARGS: { @@ -903,18 +1184,34 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject } case 2: { JSValue arg0 = callFrame->argument(1); - auto str0 = arg0.toWTFString(globalObject); + auto* jsString = arg0.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - return JSC::JSValue::encode(createError(globalObject, error, makeString("The \""_s, str0, "\" argument must be specified"_s))); + auto str0 = jsString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + WTF::StringBuilder builder; + builder.append("The \""_s); + builder.append(str0); + builder.append("\" argument must be specified"_s); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); } case 3: { JSValue arg0 = callFrame->argument(1); - auto str0 = arg0.toWTFString(globalObject); + auto* jsString = arg0.toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto str0 = jsString->view(globalObject); RETURN_IF_EXCEPTION(scope, {}); JSValue arg1 = callFrame->argument(2); - auto str1 = arg1.toWTFString(globalObject); + auto* jsString1 = arg1.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - return JSC::JSValue::encode(createError(globalObject, error, makeString("The \""_s, str0, "\" and \""_s, str1, "\" arguments must be specified"_s))); + auto str1 = jsString1->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + WTF::StringBuilder builder; + builder.append("The \""_s); + builder.append(str0); + builder.append("\" and \""_s); + builder.append(str1); + builder.append("\" arguments must be specified"_s); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); } default: { WTF::StringBuilder result; @@ -922,12 +1219,14 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject auto argumentCount = callFrame->argumentCount(); for (int i = 1; i < argumentCount; i += 1) { if (i == argumentCount - 1) result.append("and "_s); - result.append("\""_s); + result.append('"'); JSValue arg = callFrame->argument(i); - auto str = arg.toWTFString(globalObject); + auto* jsString = arg.toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto str = jsString->view(globalObject); RETURN_IF_EXCEPTION(scope, {}); result.append(str); - result.append("\""_s); + result.append('"'); if (i != argumentCount - 1) result.append(','); result.append(' '); } @@ -939,16 +1238,28 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject case Bun::ErrorCode::ERR_INVALID_RETURN_VALUE: { auto arg0 = callFrame->argument(1); - auto str0 = arg0.toWTFString(globalObject); + auto str0 = arg0.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); + auto view0 = str0->view(globalObject); + auto arg1 = callFrame->argument(2); - auto str1 = arg1.toWTFString(globalObject); + auto str1 = arg1.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); + auto view1 = str1->view(globalObject); + auto arg2 = callFrame->argument(3); - auto str2 = determineSpecificType(globalObject, arg2); + + WTF::StringBuilder messageBuilder; + messageBuilder.append("Expected "_s); + messageBuilder.append(view0); + messageBuilder.append(" to be returned from the \""_s); + messageBuilder.append(view1); + messageBuilder.append("\" function but got "_s); + determineSpecificType(JSC::getVM(globalObject), globalObject, messageBuilder, arg2); RETURN_IF_EXCEPTION(scope, {}); - auto message = makeString("Expected "_s, str0, " to be returned from the \""_s, str1, "\" function but got "_s, str2, "."_s); - return JSC::JSValue::encode(createError(globalObject, error, message)); + messageBuilder.append('.'); + + return JSC::JSValue::encode(createError(globalObject, error, messageBuilder.toString())); } case Bun::ErrorCode::ERR_OUT_OF_RANGE: { @@ -962,37 +1273,59 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject case Bun::ErrorCode::ERR_INVALID_STATE_TypeError: case Bun::ErrorCode::ERR_INVALID_STATE_RangeError: { auto arg0 = callFrame->argument(1); - auto str0 = arg0.toWTFString(globalObject); + auto* jsString = arg0.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto message = makeString("Invalid state: "_s, str0); - return JSC::JSValue::encode(createError(globalObject, error, message)); + auto param = jsString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + WTF::StringBuilder builder; + builder.append("Invalid state: "_s); + builder.append(param); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); } case Bun::ErrorCode::ERR_INVALID_PROTOCOL: { auto arg0 = callFrame->argument(1); - auto str0 = arg0.toWTFString(globalObject); + auto* jsString0 = arg0.toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto param0 = jsString0->view(globalObject); RETURN_IF_EXCEPTION(scope, {}); auto arg1 = callFrame->argument(2); - auto str1 = arg1.toWTFString(globalObject); + auto* jsString1 = arg1.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto message = makeString("Protocol \""_s, str0, "\" not supported. Expected \""_s, str1, "\""_s); - return JSC::JSValue::encode(createError(globalObject, error, message)); + auto param1 = jsString1->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + WTF::StringBuilder builder; + builder.append("Protocol \""_s); + builder.append(param0); + builder.append("\" not supported. Expected \""_s); + builder.append(param1); + builder.append("\""_s); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); } case Bun::ErrorCode::ERR_BROTLI_INVALID_PARAM: { auto arg0 = callFrame->argument(1); - auto str0 = arg0.toWTFString(globalObject); + auto* jsString = arg0.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto message = makeString(str0, " is not a valid Brotli parameter"_s); - return JSC::JSValue::encode(createError(globalObject, error, message)); + auto param = jsString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + WTF::StringBuilder builder; + builder.append(param); + builder.append(" is not a valid Brotli parameter"_s); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); } case Bun::ErrorCode::ERR_BUFFER_TOO_LARGE: { auto arg0 = callFrame->argument(1); - auto str0 = arg0.toWTFString(globalObject); + auto* jsString = arg0.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto message = makeString("Cannot create a Buffer larger than "_s, str0, " bytes"_s); - return JSC::JSValue::encode(createError(globalObject, error, message)); + auto param = jsString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + WTF::StringBuilder builder; + builder.append("Cannot create a Buffer larger than "_s); + builder.append(param); + builder.append(" bytes"_s); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); } case Bun::ErrorCode::ERR_UNHANDLED_ERROR: { @@ -1002,38 +1335,64 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject auto message = "Unhandled error."_s; return JSC::JSValue::encode(createError(globalObject, error, message)); } - if (arg0.isString()) { - auto str0 = arg0.getString(globalObject); - auto message = makeString("Unhandled error. ("_s, str0, ")"_s); - return JSC::JSValue::encode(createError(globalObject, error, message)); - } if (arg0.isCell()) { auto cell = arg0.asCell(); if (cell->inherits()) { return JSC::JSValue::encode(jsCast(cell)->value()); } } - auto str0 = arg0.toWTFString(globalObject); + + if (arg0.isString()) { + auto* jsString = arg0.toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto str0 = jsString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + + WTF::StringBuilder builder; + builder.append("Unhandled error. ("_s); + builder.append(str0); + builder.append(")"_s); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); + } + + auto* jsString = arg0.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto message = makeString("Unhandled error. ("_s, str0, ")"_s); - return JSC::JSValue::encode(createError(globalObject, error, message)); + auto str0 = jsString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + + WTF::StringBuilder builder; + builder.append("Unhandled error. ("_s); + builder.append(str0); + builder.append(")"_s); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); } case Bun::ErrorCode::ERR_INVALID_THIS: { auto arg0 = callFrame->argument(1); - auto str0 = arg0.toWTFString(globalObject); + auto* jsString = arg0.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto message = makeString("Value of \"this\" must be of type "_s, str0); - return JSC::JSValue::encode(createError(globalObject, error, message)); + auto str0 = jsString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + + WTF::StringBuilder builder; + builder.append("Value of \"this\" must be of type "_s); + builder.append(str0); + return JSC::JSValue::encode(createError(globalObject, error, builder.toString())); } case ErrorCode::ERR_BUFFER_OUT_OF_BOUNDS: { auto arg0 = callFrame->argument(1); if (!arg0.isUndefined()) { - auto str0 = arg0.toWTFString(globalObject); + auto* jsString = arg0.toString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto message = makeString("\""_s, str0, "\" is outside of buffer bounds"_s); - return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_BUFFER_OUT_OF_BOUNDS, message)); + auto str0 = jsString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + + WTF::StringBuilder builder; + builder.append("\""_s); + builder.append(str0); + builder.append("\" is outside of buffer bounds"_s); + return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_BUFFER_OUT_OF_BOUNDS, builder.toString())); } return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_BUFFER_OUT_OF_BOUNDS, "Attempt to access memory outside buffer bounds"_s)); } @@ -1088,7 +1447,7 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject } } - auto message = callFrame->argument(1).toWTFString(globalObject); + auto&& message = callFrame->argument(1).toWTFString(globalObject); RETURN_IF_EXCEPTION(scope, {}); return JSC::JSValue::encode(createError(globalObject, error, message)); diff --git a/src/bun.js/bindings/ModuleLoader.cpp b/src/bun.js/bindings/ModuleLoader.cpp index fef63d1cca..041e69d8ab 100644 --- a/src/bun.js/bindings/ModuleLoader.cpp +++ b/src/bun.js/bindings/ModuleLoader.cpp @@ -669,11 +669,9 @@ JSValue fetchCommonJSModule( // When parsing tsconfig.*.json or jsconfig.*.json, we go through Bun's JSON // parser instead to support comments and trailing commas. if (res->result.value.tag == SyntheticModuleType::JSONForObjectLoader) { - JSC::JSValue value = JSC::JSONParse(globalObject, res->result.value.source_code.toWTFString(BunString::ZeroCopy)); - if (!value) { - JSC::throwException(globalObject, scope, JSC::createSyntaxError(globalObject, "Failed to parse JSON"_s)); - RELEASE_AND_RETURN(scope, {}); - } + WTF::String jsonSource = res->result.value.source_code.toWTFString(BunString::ZeroCopy); + JSC::JSValue value = JSC::JSONParseWithException(globalObject, jsonSource); + RETURN_IF_EXCEPTION(scope, {}); target->putDirect(vm, WebCore::clientData(vm)->builtinNames().exportsPublicName(), value, 0); target->hasEvaluated = true; @@ -861,10 +859,9 @@ static JSValue fetchESMSourceCode( // When parsing tsconfig.*.json or jsconfig.*.json, we go through Bun's JSON // parser instead to support comments and trailing commas. if (res->result.value.tag == SyntheticModuleType::JSONForObjectLoader) { - JSC::JSValue value = JSC::JSONParse(globalObject, res->result.value.source_code.toWTFString(BunString::ZeroCopy)); - if (!value) { - return reject(JSC::JSValue(JSC::createSyntaxError(globalObject, "Failed to parse JSON"_s))); - } + WTF::String jsonSource = res->result.value.source_code.toWTFString(BunString::ZeroCopy); + JSC::JSValue value = JSC::JSONParseWithException(globalObject, jsonSource); + RETURN_IF_EXCEPTION(scope, {}); // JSON can become strings, null, numbers, booleans so we must handle "export default 123" auto function = generateJSValueModuleSourceCode( diff --git a/test/js/bun/globals.test.js b/test/js/bun/globals.test.js index e109d04fd2..14d6449bda 100644 --- a/test/js/bun/globals.test.js +++ b/test/js/bun/globals.test.js @@ -27,7 +27,7 @@ it("ERR_INVALID_THIS", () => { } catch (e) { expect(e.code).toBe("ERR_INVALID_THIS"); expect(e.name).toBe("TypeError"); - expect(e.message).toBe("Expected this to be instanceof Request, but received Boop"); + expect(e.message).toBe("Expected this to be instanceof Request, but received an instance of Boop"); } try { @@ -36,7 +36,7 @@ it("ERR_INVALID_THIS", () => { } catch (e) { expect(e.code).toBe("ERR_INVALID_THIS"); expect(e.name).toBe("TypeError"); - expect(e.message).toBe("Expected this to be instanceof Request, but received a string"); + expect(e.message).toBe("Expected this to be instanceof Request, but received type string ('hellooo')"); } }); diff --git a/test/js/node/dns/node-dns.test.js b/test/js/node/dns/node-dns.test.js index 44924c3abd..0fedecf1f0 100644 --- a/test/js/node/dns/node-dns.test.js +++ b/test/js/node/dns/node-dns.test.js @@ -423,7 +423,7 @@ describe("test invalid arguments", () => { }).toThrow("Expected address to be a non-empty string for 'lookupService'."); expect(() => { dns.lookupService("google.com", 443, (err, hostname, service) => {}); - }).toThrow('The "address" argument is invalid. Received type string ("google.com")'); + }).toThrow("The \"address\" argument is invalid. Received type string ('google.com')"); }); }); diff --git a/test/js/node/events/event-emitter.test.ts b/test/js/node/events/event-emitter.test.ts index e1a63ead6d..e2a64b2b2d 100644 --- a/test/js/node/events/event-emitter.test.ts +++ b/test/js/node/events/event-emitter.test.ts @@ -565,7 +565,7 @@ describe("EventEmitter.on", () => { 2, { code: "ABORT_ERR", - message: "The operation was aborted", + message: "The operation was aborted.", }, ], ]); diff --git a/test/js/node/process/process.test.js b/test/js/node/process/process.test.js index b4c71924f9..c2b5d8e7ac 100644 --- a/test/js/node/process/process.test.js +++ b/test/js/node/process/process.test.js @@ -237,7 +237,7 @@ it("process.uptime()", () => { it("process.umask()", () => { expect(() => process.umask(265n)).toThrow('The "mask" argument must be of type number. Received type bigint (265n)'); - expect(() => process.umask("string")).toThrow(`The argument 'mask' must be a 32-bit unsigned integer or an octal string. Received "string"`); // prettier-ignore + expect(() => process.umask("string")).toThrow(`The argument 'mask' must be a 32-bit unsigned integer or an octal string. Received 'string'`); // prettier-ignore expect(() => process.umask(true)).toThrow('The "mask" argument must be of type number. Received type boolean (true)'); expect(() => process.umask(false)).toThrow('The "mask" argument must be of type number. Received type boolean (false)'); // prettier-ignore expect(() => process.umask(null)).toThrow('The "mask" argument must be of type number. Received null'); @@ -374,7 +374,7 @@ it("process.argv in testing", () => { describe("process.exitCode", () => { it("validates int", () => { expect(() => (process.exitCode = "potato")).toThrow( - `The "code" argument must be of type number. Received type string ("potato")`, + `The "code" argument must be of type number. Received type string ('potato')`, ); expect(() => (process.exitCode = 1.2)).toThrow( `The value of \"code\" is out of range. It must be an integer. Received 1.2`, diff --git a/test/js/node/test/common/index.js b/test/js/node/test/common/index.js index ef04b184e3..ff9255b51c 100644 --- a/test/js/node/test/common/index.js +++ b/test/js/node/test/common/index.js @@ -914,7 +914,6 @@ function invalidArgTypeHelper(input) { let inspected = inspect(input, { colors: false }); if (inspected.length > 28) { inspected = `${inspected.slice(inspected, 0, 25)}...`; } - if (inspected.startsWith("'") && inspected.endsWith("'")) inspected = `"${inspected.slice(1, inspected.length - 1)}"`; // BUN: util.inspect uses ' but bun uses " for strings return ` Received type ${typeof input} (${inspected})`; } diff --git a/test/js/node/test/parallel/test-common-gc.js b/test/js/node/test/parallel/test-common-gc.js new file mode 100644 index 0000000000..54abe3695c --- /dev/null +++ b/test/js/node/test/parallel/test-common-gc.js @@ -0,0 +1,14 @@ +'use strict'; +// Flags: --expose-gc +const common = require('../common'); +const { onGC } = require('../common/gc'); + +{ + onGC({}, { ongc: common.mustCall() }); + globalThis.gc(); +} + +{ + onGC(process, { ongc: common.mustNotCall() }); + globalThis.gc(); +} diff --git a/test/js/node/test/parallel/test-console-tty-colors.js b/test/js/node/test/parallel/test-console-tty-colors.js index 63ff42935b..00359ad5d7 100644 --- a/test/js/node/test/parallel/test-console-tty-colors.js +++ b/test/js/node/test/parallel/test-console-tty-colors.js @@ -19,7 +19,6 @@ function check(isTTY, colorMode, expectedColorMode, inspectOptions) { let i = 0; const stream = new Writable({ write: common.mustCall((chunk, enc, cb) => { - console.log("testing case", isTTY, colorMode, expectedColorMode, inspectOptions); assert.strictEqual(chunk.trim(), util.inspect(items[i++], { colors: expectedColorMode, @@ -60,21 +59,7 @@ check(false, false, false); write: common.mustNotCall() }); - assert.throws( - () => { - new Console({ - stdout: stream, - ignoreErrors: false, - colorMode: 'true' - }); - }, - { - message: `The argument 'colorMode' must be one of: 'auto', true, false. Received "true"`, - code: 'ERR_INVALID_ARG_VALUE' - } - ); - - [0, null, {}, [], () => {}].forEach((colorMode) => { + [0, 'true', null, {}, [], () => {}].forEach((colorMode) => { const received = util.inspect(colorMode); assert.throws( () => { diff --git a/test/js/node/test/parallel/test-emit-after-uncaught-exception.js b/test/js/node/test/parallel/test-emit-after-uncaught-exception.js new file mode 100644 index 0000000000..5003972e99 --- /dev/null +++ b/test/js/node/test/parallel/test-emit-after-uncaught-exception.js @@ -0,0 +1,40 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const async_hooks = require('async_hooks'); + +const id_obj = {}; +let collect = true; + +const hook = async_hooks.createHook({ + before(id) { if (collect) id_obj[id] = true; }, + after(id) { delete id_obj[id]; }, +}).enable(); + +process.once('uncaughtException', common.mustCall((er) => { + assert.strictEqual(er.message, 'bye'); + collect = false; +})); + +setImmediate(common.mustCall(() => { + process.nextTick(common.mustCall(() => { + assert.strictEqual(Object.keys(id_obj).length, 0); + hook.disable(); + })); + + // Create a stack of async ids that will need to be emitted in the case of + // an uncaught exception. + const ar1 = new async_hooks.AsyncResource('Mine'); + ar1.runInAsyncScope(() => { + const ar2 = new async_hooks.AsyncResource('Mine'); + ar2.runInAsyncScope(() => { + throw new Error('bye'); + }); + }); + + // TODO(trevnorris): This test shows that the after() hooks are always called + // correctly, but it doesn't solve where the emitDestroy() is missed because + // of the uncaught exception. Simple solution is to always call emitDestroy() + // before the emitAfter(), but how to codify this? +})); diff --git a/test/js/node/test/parallel/test-http2-compat-serverrequest-headers.js b/test/js/node/test/parallel/test-http2-compat-serverrequest-headers.js index a3a542ea5a..2028e672a7 100644 --- a/test/js/node/test/parallel/test-http2-compat-serverrequest-headers.js +++ b/test/js/node/test/parallel/test-http2-compat-serverrequest-headers.js @@ -51,7 +51,7 @@ const h2 = require('http2'); { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', - message: "The argument 'method' is invalid. Received \" \"" + message: "The argument 'method' is invalid. Received ' '" } ); assert.throws( diff --git a/test/js/node/test/parallel/test-process-exit-code-validation.js b/test/js/node/test/parallel/test-process-exit-code-validation.js index 59934fa31d..7548dcdc38 100644 --- a/test/js/node/test/parallel/test-process-exit-code-validation.js +++ b/test/js/node/test/parallel/test-process-exit-code-validation.js @@ -6,17 +6,17 @@ const invalids = [ { code: '', expected: 1, - pattern: 'Received type string \\(""\\)$', + pattern: "Received type string \\(''\\)$", }, { code: '1 one', expected: 1, - pattern: 'Received type string \\("1 one"\\)$', + pattern: "Received type string \\('1 one'\\)$", }, { code: 'two', expected: 1, - pattern: 'Received type string \\("two"\\)$', + pattern: "Received type string \\('two'\\)$", }, { code: {}, @@ -100,7 +100,6 @@ if (process.argv[2] === undefined) { index, useProcessExitCode, ]); - console.log(`actual: ${code}, ${args[index].expected} ${index} ${!!useProcessExitCode} ${args[index].code}`); debug(`actual: ${code}, ${inspect(args[index])} ${!!useProcessExitCode}`); strictEqual( code, diff --git a/test/js/node/test/parallel/test-process-kill-pid.js b/test/js/node/test/parallel/test-process-kill-pid.js index 1fa1d6c2ab..e5418f311c 100644 --- a/test/js/node/test/parallel/test-process-kill-pid.js +++ b/test/js/node/test/parallel/test-process-kill-pid.js @@ -39,13 +39,7 @@ const assert = require('assert'); // // process.pid, String(process.pid): ourself -assert.throws(() => process.kill('SIGTERM'), { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "pid" argument must be of type number. Received type string ("SIGTERM")' -}); - -[null, undefined, NaN, Infinity, -Infinity].forEach((val) => { +[null, undefined, NaN, Infinity, -Infinity, 'SIGTERM'].forEach((val) => { assert.throws(() => process.kill(val), { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', diff --git a/test/js/node/test/parallel/test-require-json.js b/test/js/node/test/parallel/test-require-json.js new file mode 100644 index 0000000000..c6cec5d650 --- /dev/null +++ b/test/js/node/test/parallel/test-require-json.js @@ -0,0 +1,32 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +require('../common'); +const assert = require('assert'); +const fixtures = require('../common/fixtures'); + +assert.throws(function() { + require(fixtures.path('invalid.json')); +}, { + name: 'SyntaxError', + message: 'JSON Parse error: Expected \'}\'', +}); diff --git a/test/js/node/test/parallel/test-streams-highwatermark.js b/test/js/node/test/parallel/test-streams-highwatermark.js index e5c2f0b597..978a53913b 100644 --- a/test/js/node/test/parallel/test-streams-highwatermark.js +++ b/test/js/node/test/parallel/test-streams-highwatermark.js @@ -3,7 +3,7 @@ const common = require('../common'); const assert = require('assert'); const stream = require('stream'); -const { inspect } = Bun; +const { inspect } = require('util'); { // This test ensures that the stream implementation correctly handles values diff --git a/test/js/node/test/parallel/test-timers-promises-scheduler.js b/test/js/node/test/parallel/test-timers-promises-scheduler.js index 7caf92fdf6..6b6858117e 100644 --- a/test/js/node/test/parallel/test-timers-promises-scheduler.js +++ b/test/js/node/test/parallel/test-timers-promises-scheduler.js @@ -33,7 +33,7 @@ async function testCancelableWait1() { ac.abort(); await rejects(wait, { code: 'ABORT_ERR', - message: 'The operation was aborted', + message: 'The operation was aborted.', }); } @@ -43,7 +43,7 @@ async function testCancelableWait2() { const wait = scheduler.wait(10000, { signal: AbortSignal.abort() }); await rejects(wait, { code: 'ABORT_ERR', - message: 'The operation was aborted', + message: 'The operation was aborted.', }); } diff --git a/test/js/node/test/parallel/test-zlib-deflate-constructors.js b/test/js/node/test/parallel/test-zlib-deflate-constructors.js index bf4b6d3374..9f918e13c9 100644 --- a/test/js/node/test/parallel/test-zlib-deflate-constructors.js +++ b/test/js/node/test/parallel/test-zlib-deflate-constructors.js @@ -19,7 +19,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.chunkSize" property must be of type number. ' + - 'Received type string ("test")' + "Received type string ('test')" } ); @@ -53,7 +53,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.windowBits" property must be of type number. ' + - 'Received type string ("test")' + "Received type string ('test')" } ); @@ -94,7 +94,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.level" property must be of type number. ' + - 'Received type string ("test")' + "Received type string ('test')" } ); @@ -135,7 +135,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "level" argument must be of type number. ' + - 'Received type string ("test")' + "Received type string ('test')" } ); @@ -176,7 +176,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.memLevel" property must be of type number. ' + - 'Received type string ("test")' + "Received type string ('test')" } ); @@ -224,7 +224,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.strategy" property must be of type number. ' + - 'Received type string ("test")' + "Received type string ('test')" } ); @@ -265,7 +265,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "strategy" argument must be of type number. ' + - 'Received type string ("test")' + "Received type string ('test')" } ); diff --git a/test/js/node/test/parallel/test-zlib-flush-flags.js b/test/js/node/test/parallel/test-zlib-flush-flags.js index f3392b7a41..3d8e609adb 100644 --- a/test/js/node/test/parallel/test-zlib-flush-flags.js +++ b/test/js/node/test/parallel/test-zlib-flush-flags.js @@ -11,7 +11,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.flush" property must be of type number. ' + - 'Received type string ("foobar")' + "Received type string ('foobar')" } ); @@ -33,7 +33,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.finishFlush" property must be of type number. ' + - 'Received type string ("foobar")' + "Received type string ('foobar')" } );