Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: nodejs/node-addon-api
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 685c2152536f146200c3f46337e97985b6422453
Choose a base ref
..
head repository: nodejs/node-addon-api
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: a4aaeaa49bb85b43877eaf19ce613c3d18f94a3d
Choose a head ref
Showing with 123 additions and 22 deletions.
  1. +4 −4 napi-inl.h
  2. +1 −1 napi.h
  3. +106 −14 src/node_api.cc
  4. +12 −3 src/node_api.h
8 changes: 4 additions & 4 deletions napi-inl.h
Original file line number Diff line number Diff line change
@@ -1458,10 +1458,10 @@ inline Error Error::New(napi_env env) {
case napi_string_expected:
case napi_boolean_expected:
case napi_number_expected:
status = napi_create_type_error(env, message, &error);
status = napi_create_type_error(env, nullptr, message, &error);
break;
default:
status = napi_create_error(env, message, &error);
status = napi_create_error(env, nullptr, message, &error);
break;
}
NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_error");
@@ -1566,7 +1566,7 @@ inline TError Error::New(napi_env env,
NAPI_THROW_IF_FAILED(env, status, TError());

napi_value error;
status = create_error(env, str, &error);
status = create_error(env, nullptr, str, &error);
NAPI_THROW_IF_FAILED(env, status, TError());

return TError(env, error);
@@ -2475,7 +2475,7 @@ inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
if (status != napi_ok) return nullptr;

if (!isConstructCall) {
napi_throw_type_error(env, "Class constructors cannot be invoked without 'new'");
napi_throw_type_error(env, nullptr, "Class constructors cannot be invoked without 'new'");
return nullptr;
}

2 changes: 1 addition & 1 deletion napi.h
Original file line number Diff line number Diff line change
@@ -1087,7 +1087,7 @@ namespace Napi {

protected:
/// !cond INTERNAL
typedef napi_status (*create_error_fn)(napi_env envb, napi_value msg, napi_value* result);
typedef napi_status (*create_error_fn)(napi_env envb, napi_value code, napi_value msg, napi_value* result);

template <typename TError>
static TError New(napi_env env,
120 changes: 106 additions & 14 deletions src/node_api.cc
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
#include "uv.h"
#include "node_api.h"
#include "node_internals.h"
#include "util.h"

#define NAPI_VERSION 1

@@ -1528,7 +1529,61 @@ napi_status napi_create_symbol(napi_env env,
return GET_RETURN_STATUS(env);
}

static napi_status set_error_code(napi_env env,
v8::Local<v8::Value> error,
napi_value code,
const char* code_cstring) {
if ((code != nullptr) || (code_cstring != nullptr)) {
v8::Isolate* isolate = env->isolate;
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Object> err_object = error.As<v8::Object>();

v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
if (code != nullptr) {
code_value = v8impl::V8LocalValueFromJsValue(code);
RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
} else {
CHECK_NEW_FROM_UTF8(env, code_value, code_cstring);
}

v8::Local<v8::Name> code_key;
CHECK_NEW_FROM_UTF8(env, code_key, "code");

v8::Maybe<bool> set_maybe = err_object->Set(context, code_key, code_value);
RETURN_STATUS_IF_FALSE(env,
set_maybe.FromMaybe(false),
napi_generic_failure);

// now update the name to be "name [code]" where name is the
// original name and code is the code associated with the Error
v8::Local<v8::String> name_string;
CHECK_NEW_FROM_UTF8(env, name_string, "");
v8::Local<v8::Name> name_key;
CHECK_NEW_FROM_UTF8(env, name_key, "name");

auto maybe_name = err_object->Get(context, name_key);
if (!maybe_name.IsEmpty()) {
v8::Local<v8::Value> name = maybe_name.ToLocalChecked();
if (name->IsString()) {
name_string = v8::String::Concat(name_string, name.As<v8::String>());
}
}
name_string = v8::String::Concat(name_string,
FIXED_ONE_BYTE_STRING(isolate, " ["));
name_string = v8::String::Concat(name_string, code_value.As<v8::String>());
name_string = v8::String::Concat(name_string,
FIXED_ONE_BYTE_STRING(isolate, "]"));

set_maybe = err_object->Set(context, name_key, name_string);
RETURN_STATUS_IF_FALSE(env,
set_maybe.FromMaybe(false),
napi_generic_failure);
}
return napi_ok;
}

napi_status napi_create_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result) {
NAPI_PREAMBLE(env);
@@ -1538,13 +1593,18 @@ napi_status napi_create_error(napi_env env,
v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);

*result = v8impl::JsValueFromV8LocalValue(v8::Exception::Error(
message_value.As<v8::String>()));
v8::Local<v8::Value> error_obj =
v8::Exception::Error(message_value.As<v8::String>());
napi_status status = set_error_code(env, error_obj, code, nullptr);
if (status != napi_ok) return status;

*result = v8impl::JsValueFromV8LocalValue(error_obj);

return GET_RETURN_STATUS(env);
}

napi_status napi_create_type_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result) {
NAPI_PREAMBLE(env);
@@ -1554,13 +1614,18 @@ napi_status napi_create_type_error(napi_env env,
v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);

*result = v8impl::JsValueFromV8LocalValue(v8::Exception::TypeError(
message_value.As<v8::String>()));
v8::Local<v8::Value> error_obj =
v8::Exception::TypeError(message_value.As<v8::String>());
napi_status status = set_error_code(env, error_obj, code, nullptr);
if (status != napi_ok) return status;

*result = v8impl::JsValueFromV8LocalValue(error_obj);

return GET_RETURN_STATUS(env);
}

napi_status napi_create_range_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result) {
NAPI_PREAMBLE(env);
@@ -1570,8 +1635,12 @@ napi_status napi_create_range_error(napi_env env,
v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);

*result = v8impl::JsValueFromV8LocalValue(v8::Exception::RangeError(
message_value.As<v8::String>()));
v8::Local<v8::Value> error_obj =
v8::Exception::RangeError(message_value.As<v8::String>());
napi_status status = set_error_code(env, error_obj, code, nullptr);
if (status != napi_ok) return status;

*result = v8impl::JsValueFromV8LocalValue(error_obj);

return GET_RETURN_STATUS(env);
}
@@ -1744,40 +1813,58 @@ napi_status napi_throw(napi_env env, napi_value error) {
return napi_clear_last_error(env);
}

napi_status napi_throw_error(napi_env env, const char* msg) {
napi_status napi_throw_error(napi_env env,
const char* code,
const char* msg) {
NAPI_PREAMBLE(env);

v8::Isolate* isolate = env->isolate;
v8::Local<v8::String> str;
CHECK_NEW_FROM_UTF8(env, str, msg);

isolate->ThrowException(v8::Exception::Error(str));
v8::Local<v8::Value> error_obj = v8::Exception::Error(str);
napi_status status = set_error_code(env, error_obj, nullptr, code);
if (status != napi_ok) return status;

isolate->ThrowException(error_obj);
// any VM calls after this point and before returning
// to the javascript invoker will fail
return napi_clear_last_error(env);
}

napi_status napi_throw_type_error(napi_env env, const char* msg) {
napi_status napi_throw_type_error(napi_env env,
const char* code,
const char* msg) {
NAPI_PREAMBLE(env);

v8::Isolate* isolate = env->isolate;
v8::Local<v8::String> str;
CHECK_NEW_FROM_UTF8(env, str, msg);

isolate->ThrowException(v8::Exception::TypeError(str));
v8::Local<v8::Value> error_obj = v8::Exception::TypeError(str);
napi_status status = set_error_code(env, error_obj, nullptr, code);
if (status != napi_ok) return status;

isolate->ThrowException(error_obj);
// any VM calls after this point and before returning
// to the javascript invoker will fail
return napi_clear_last_error(env);
}

napi_status napi_throw_range_error(napi_env env, const char* msg) {
napi_status napi_throw_range_error(napi_env env,
const char* code,
const char* msg) {
NAPI_PREAMBLE(env);

v8::Isolate* isolate = env->isolate;
v8::Local<v8::String> str;
CHECK_NEW_FROM_UTF8(env, str, msg);

isolate->ThrowException(v8::Exception::RangeError(str));
v8::Local<v8::Value> error_obj = v8::Exception::RangeError(str);
napi_status status = set_error_code(env, error_obj, nullptr, code);
if (status != napi_ok) return status;

isolate->ThrowException(error_obj);
// any VM calls after this point and before returning
// to the javascript invoker will fail
return napi_clear_last_error(env);
@@ -2397,7 +2484,9 @@ napi_status napi_instanceof(napi_env env,
CHECK_TO_OBJECT(env, context, ctor, constructor);

if (!ctor->IsFunction()) {
napi_throw_type_error(env, "constructor must be a function");
napi_throw_type_error(env,
"ERR_NAPI_CONS_FUNCTION",
"Constructor must be a function");

return napi_set_last_error(env, napi_function_expected);
}
@@ -2465,7 +2554,10 @@ napi_status napi_instanceof(napi_env env,

v8::Local<v8::Value> prototype_property = maybe_prototype.ToLocalChecked();
if (!prototype_property->IsObject()) {
napi_throw_type_error(env, "constructor.prototype must be an object");
napi_throw_type_error(
env,
"ERR_NAPI_CONS_PROTOTYPE_OBJECT",
"Constructor.prototype must be an object");

return napi_set_last_error(env, napi_object_expected);
}
15 changes: 12 additions & 3 deletions src/node_api.h
Original file line number Diff line number Diff line change
@@ -151,12 +151,15 @@ NAPI_EXTERN napi_status napi_create_function(napi_env env,
void* data,
napi_value* result);
NAPI_EXTERN napi_status napi_create_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);
NAPI_EXTERN napi_status napi_create_type_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);
NAPI_EXTERN napi_status napi_create_range_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);

@@ -413,9 +416,15 @@ NAPI_EXTERN napi_status napi_escape_handle(napi_env env,

// Methods to support error handling
NAPI_EXTERN napi_status napi_throw(napi_env env, napi_value error);
NAPI_EXTERN napi_status napi_throw_error(napi_env env, const char* msg);
NAPI_EXTERN napi_status napi_throw_type_error(napi_env env, const char* msg);
NAPI_EXTERN napi_status napi_throw_range_error(napi_env env, const char* msg);
NAPI_EXTERN napi_status napi_throw_error(napi_env env,
const char* code,
const char* msg);
NAPI_EXTERN napi_status napi_throw_type_error(napi_env env,
const char* code,
const char* msg);
NAPI_EXTERN napi_status napi_throw_range_error(napi_env env,
const char* code,
const char* msg);
NAPI_EXTERN napi_status napi_is_error(napi_env env,
napi_value value,
bool* result);