Add generator for $ERR_* as fake private globals (#13843)

Co-authored-by: Jarred-Sumner <Jarred-Sumner@users.noreply.github.com>
This commit is contained in:
Jarred Sumner
2024-09-10 16:07:22 -07:00
committed by GitHub
parent d7f9346f67
commit 8d7d58606b
11 changed files with 291 additions and 81 deletions

View File

@@ -183,68 +183,166 @@ WTF::String JSValueToStringSafe(JSC::JSGlobalObject* globalObject, JSValue arg)
{
ASSERT(!arg.isEmpty());
if (!arg.isCell())
return arg.toString(globalObject)->getString(globalObject);
return arg.toWTFStringForConsole(globalObject);
auto cell = arg.asCell();
auto jstype = cell->type();
if (jstype == JSC::JSType::StringType) {
return cell->toStringInline(globalObject)->getString(globalObject);
switch (cell->type()) {
case JSC::JSType::StringType: {
return arg.toWTFStringForConsole(globalObject);
}
if (jstype == JSC::JSType::SymbolType) {
case JSC::JSType::SymbolType: {
auto symbol = jsCast<Symbol*>(cell);
auto result = symbol->tryGetDescriptiveString();
if (result.has_value())
return result.value();
return "Symbol"_s;
}
return arg.toString(globalObject)->getString(globalObject);
case JSC::JSType::InternalFunctionType:
case JSC::JSType::JSFunctionType: {
auto& vm = globalObject->vm();
auto catchScope = DECLARE_CATCH_SCOPE(vm);
auto name = JSC::getCalculatedDisplayName(vm, cell->getObject());
if (catchScope.exception()) {
catchScope.clearException();
name = "Function"_s;
}
if (!name.isNull() && name.length() > 0) {
return makeString("[Function: "_s, name, ']');
}
return "Function"_s;
break;
}
default: {
break;
}
}
return arg.toWTFStringForConsole(globalObject);
}
JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_INVALID_ARG_TYPE, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
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)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
EXPECT_ARG_COUNT(3);
auto actual_value_string = JSValueToStringSafe(globalObject, actual_value);
RETURN_IF_EXCEPTION(scope, {});
auto arg_name = callFrame->argument(0);
auto expected_type = callFrame->argument(1);
auto actual_value = callFrame->argument(2);
return Bun__ERR_INVALID_ARG_TYPE(globalObject, JSValue::encode(arg_name), JSValue::encode(expected_type), JSValue::encode(actual_value));
return makeString("The \""_s, arg_name, "\" argument must be of type "_s, expected_type, ". Received: "_s, actual_value_string);
}
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 = JSValueToStringSafe(globalObject, actual_value);
RETURN_IF_EXCEPTION(scope, {});
result.append("The \""_s, arg_name, "\" argument must be of type "_s);
unsigned length = expected_types.size();
if (length == 1) {
result.append(expected_types.at(0).toWTFString(globalObject));
} else if (length == 2) {
result.append(expected_types.at(0).toWTFString(globalObject));
result.append(" or "_s);
result.append(expected_types.at(1).toWTFString(globalObject));
} else {
for (unsigned i = 0; i < length - 1; i++) {
if (i > 0)
result.append(", "_s);
JSValue expected_type = expected_types.at(i);
result.append(expected_type.toWTFString(globalObject));
}
result.append(" or "_s);
result.append(expected_types.at(length - 1).toWTFString(globalObject));
}
result.append(". Received: "_s, actual_value_string);
return result.toString();
}
WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const ZigString* arg_name_string, const ZigString* expected_type_string, JSValue actual_value)
{
auto arg_name = std::span<const LChar>(arg_name_string->ptr, arg_name_string->len);
ASSERT(WTF::charactersAreAllASCII(arg_name));
auto expected_type = std::span<const LChar>(expected_type_string->ptr, expected_type_string->len);
ASSERT(WTF::charactersAreAllASCII(expected_type));
return ERR_INVALID_ARG_TYPE(scope, globalObject, arg_name, expected_type, actual_value);
}
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);
RETURN_IF_EXCEPTION(scope, {});
auto expected_type = val_expected_type.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
return ERR_INVALID_ARG_TYPE(scope, globalObject, arg_name, expected_type, val_actual_value);
}
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);
RETURN_IF_EXCEPTION(scope, {});
auto range = val_range.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto input = JSValueToStringSafe(globalObject, 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, '"');
}
}
static JSC::JSValue ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue arg0, JSValue arg1, JSValue arg2)
{
if (auto* array = jsDynamicCast<JSC::JSArray*>(arg1)) {
const WTF::String argName = arg0.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
MarkedArgumentBuffer expected_types;
for (unsigned i = 0, length = array->length(); i < length; i++) {
expected_types.append(array->getDirectIndex(globalObject, i));
RETURN_IF_EXCEPTION(scope, {});
}
const auto msg = Bun::Message::ERR_INVALID_ARG_TYPE(scope, globalObject, argName, expected_types, arg2);
return createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, msg);
}
const auto msg = Bun::Message::ERR_INVALID_ARG_TYPE(scope, globalObject, arg0, arg1, arg2);
return createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, msg);
}
extern "C" JSC::EncodedJSValue Bun__ERR_INVALID_ARG_TYPE(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue val_arg_name, JSC::EncodedJSValue val_expected_type, JSC::EncodedJSValue val_actual_value)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto arg_name = JSValue::decode(val_arg_name).toWTFString(globalObject);
auto message = Message::ERR_INVALID_ARG_TYPE(scope, globalObject, JSValue::decode(val_arg_name), JSValue::decode(val_expected_type), JSValue::decode(val_actual_value));
RETURN_IF_EXCEPTION(scope, {});
auto expected_type = JSValue::decode(val_expected_type).toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto actual_value = JSValueToStringSafe(globalObject, JSValue::decode(val_actual_value));
RETURN_IF_EXCEPTION(scope, {});
auto message = makeString("The \""_s, arg_name, "\" argument must be of type "_s, expected_type, ". Received "_s, actual_value);
return JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
}
extern "C" JSC::EncodedJSValue Bun__ERR_INVALID_ARG_TYPE_static(JSC::JSGlobalObject* globalObject, const ZigString* val_arg_name, const ZigString* val_expected_type, JSC::EncodedJSValue val_actual_value)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto arg_name = std::span<const unsigned char>(val_arg_name->ptr, val_arg_name->len);
ASSERT(WTF::charactersAreAllASCII(arg_name));
auto expected_type = std::span<const unsigned char>(val_expected_type->ptr, val_expected_type->len);
ASSERT(WTF::charactersAreAllASCII(expected_type));
auto actual_value = JSValueToStringSafe(globalObject, JSValue::decode(val_actual_value));
WTF::String message = Message::ERR_INVALID_ARG_TYPE(scope, globalObject, val_arg_name, val_expected_type, JSValue::decode(val_actual_value));
RETURN_IF_EXCEPTION(scope, {});
auto message = makeString("The \""_s, arg_name, "\" argument must be of type "_s, expected_type, ". Received "_s, actual_value);
return JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
}
JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_OUT_OF_RANGE, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
@@ -254,16 +352,8 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_OUT_OF_RANGE, (JSC::JSGlobalObject * glo
EXPECT_ARG_COUNT(3);
auto arg_name = callFrame->argument(0).toWTFString(globalObject);
auto message = Message::ERR_OUT_OF_RANGE(scope, globalObject, callFrame->argument(0), callFrame->argument(1), callFrame->argument(2));
RETURN_IF_EXCEPTION(scope, {});
auto range = callFrame->argument(1).toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto input = callFrame->argument(2).toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto message = makeString("The value of \""_s, arg_name, "\" is out of range. It must be "_s, range, ". Received "_s, input);
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message));
}
@@ -384,6 +474,19 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_INVALID_PROTOCOL, (JSC::JSGlobalObject *
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_PROTOCOL, message));
}
JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_INVALID_ARG_TYPE, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
EXPECT_ARG_COUNT(3);
auto arg_name = callFrame->argument(0);
auto expected_type = callFrame->argument(1);
auto actual_value = callFrame->argument(2);
return JSValue::encode(ERR_INVALID_ARG_TYPE(scope, globalObject, arg_name, expected_type, actual_value));
}
} // namespace Bun
JSC::JSValue WebCore::toJS(JSC::JSGlobalObject* globalObject, CommonAbortReason abortReason)
@@ -432,4 +535,52 @@ JSC::JSObject* Bun::createInvalidThisError(JSC::JSGlobalObject* globalObject, JS
JSC::EncodedJSValue Bun::throwError(JSC::JSGlobalObject* globalObject, JSC::ThrowScope& scope, Bun::ErrorCode code, const WTF::String& message)
{
return JSC::JSValue::encode(scope.throwException(globalObject, createError(globalObject, code, message)));
}
}
JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
EXPECT_ARG_COUNT(2);
JSC::JSValue codeValue = callFrame->argument(0);
RETURN_IF_EXCEPTION(scope, {});
#if BUN_DEBUG
if (!codeValue.isNumber()) {
JSC::throwTypeError(globalObject, scope, "First argument to $ERR_ must be a number"_s);
return {};
}
#endif
int code = codeValue.toInt32(globalObject);
#if BUN_DEBUG
if (code > Bun::NODE_ERROR_COUNT - 1 || code < 0) {
JSC::throwTypeError(globalObject, scope, "Invalid error code. Use $ERR_* constants"_s);
return {};
}
#endif
Bun::ErrorCode error = static_cast<Bun::ErrorCode>(code);
switch (error) {
case Bun::ErrorCode::ERR_INVALID_ARG_TYPE: {
JSValue arg0 = callFrame->argument(1);
JSValue arg1 = callFrame->argument(2);
JSValue arg2 = callFrame->argument(3);
return JSValue::encode(ERR_INVALID_ARG_TYPE(scope, globalObject, arg0, arg1, arg2));
}
default: {
break;
}
}
auto message = callFrame->argument(1).toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
return JSC::JSValue::encode(createError(globalObject, error, message));
}