Skip to content

Commit

Permalink
src,doc: add SyntaxError napi support
Browse files Browse the repository at this point in the history
Add `napi_create_syntax_error` and `napi_throw_syntax_error`.

Fixes: nodejs/node-addon-api#1099

PR-URL: #40736
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Michael Dawson <[email protected]>
  • Loading branch information
Idan Attias authored and targos committed Nov 21, 2021
1 parent fa37428 commit 88b57bc
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 4 deletions.
52 changes: 48 additions & 4 deletions doc/api/n-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1065,12 +1065,11 @@ JavaScript value to be thrown.
The following utility functions are also available in case native code
needs to throw an exception or determine if a `napi_value` is an instance
of a JavaScript `Error` object: [`napi_throw_error`][],
[`napi_throw_type_error`][], [`napi_throw_range_error`][] and
[`napi_is_error`][].
[`napi_throw_type_error`][], [`napi_throw_range_error`][], [`node_api_throw_syntax_error`][] and [`napi_is_error`][].
The following utility functions are also available in case native
code needs to create an `Error` object: [`napi_create_error`][],
[`napi_create_type_error`][], and [`napi_create_range_error`][],
[`napi_create_type_error`][], [`napi_create_range_error`][] and [`node_api_create_syntax_error`][],
where result is the `napi_value` that refers to the newly created
JavaScript `Error` object.
Expand Down Expand Up @@ -1180,6 +1179,25 @@ Returns `napi_ok` if the API succeeded.

This API throws a JavaScript `RangeError` with the text provided.

#### `node_api_throw_syntax_error`

<!-- YAML
added: REPLACEME
-->

````c
NAPI_EXTERN napi_status node_api_throw_syntax_error(napi_env env,
const char* code,
const char* msg);

* `[in] env`: The environment that the API is invoked under.
* `[in] code`: Optional error code to be set on the error.
* `[in] msg`: C string representing the text to be associated with the error.

Returns `napi_ok` if the API succeeded.

This API throws a JavaScript `SyntaxError` with the text provided.

#### `napi_is_error`

<!-- YAML
Expand All @@ -1191,7 +1209,7 @@ napiVersion: 1
NAPI_EXTERN napi_status napi_is_error(napi_env env,
napi_value value,
bool* result);
```
````
* `[in] env`: The environment that the API is invoked under.
* `[in] value`: The `napi_value` to be checked.
Expand Down Expand Up @@ -1277,6 +1295,30 @@ Returns `napi_ok` if the API succeeded.
This API returns a JavaScript `RangeError` with the text provided.
#### `node_api_create_syntax_error`
<!-- YAML
added: REPLACEME
-->
```c
NAPI_EXTERN napi_status node_api_create_syntax_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);
```
* `[in] env`: The environment that the API is invoked under.
* `[in] code`: Optional `napi_value` with the string for the error code to be
associated with the error.
* `[in] msg`: `napi_value` that references a JavaScript `string` to be used as
the message for the `Error`.
* `[out] result`: `napi_value` representing the error created.
Returns `napi_ok` if the API succeeded.
This API returns a JavaScript `SyntaxError` with the text provided.
#### `napi_get_and_clear_last_exception`
<!-- YAML
Expand Down Expand Up @@ -6296,6 +6338,8 @@ the add-on's file name during loading.
[`napi_wrap`]: #napi_wrap
[`node-addon-api`]: https://github.com/nodejs/node-addon-api
[`node_api.h`]: https://github.com/nodejs/node/blob/HEAD/src/node_api.h
[`node_api_create_syntax_error`]: #node_api_create_syntax_error
[`node_api_throw_syntax_error`]: #node_api_throw_syntax_error
[`process.release`]: process.md#processrelease
[`uv_ref`]: https://docs.libuv.org/en/v1.x/handle.html#c.uv_ref
[`uv_unref`]: https://docs.libuv.org/en/v1.x/handle.html#c.uv_unref
Expand Down
11 changes: 11 additions & 0 deletions src/js_native_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ NAPI_EXTERN napi_status napi_create_range_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);
#ifdef NAPI_EXPERIMENTAL
NAPI_EXTERN napi_status node_api_create_syntax_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);
#endif // NAPI_EXPERIMENTAL

// Methods to get the native napi_value from Primitive type
NAPI_EXTERN napi_status napi_typeof(napi_env env,
Expand Down Expand Up @@ -370,6 +376,11 @@ NAPI_EXTERN napi_status napi_throw_type_error(napi_env env,
NAPI_EXTERN napi_status napi_throw_range_error(napi_env env,
const char* code,
const char* msg);
#ifdef NAPI_EXPERIMENTAL
NAPI_EXTERN napi_status node_api_throw_syntax_error(napi_env env,
const char* code,
const char* msg);
#endif // NAPI_EXPERIMENTAL
NAPI_EXTERN napi_status napi_is_error(napi_env env,
napi_value value,
bool* result);
Expand Down
38 changes: 38 additions & 0 deletions src/js_native_api_v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,26 @@ napi_status napi_create_range_error(napi_env env,
return napi_clear_last_error(env);
}

napi_status node_api_create_syntax_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result) {
CHECK_ENV(env);
CHECK_ARG(env, msg);
CHECK_ARG(env, result);

v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);

v8::Local<v8::Value> error_obj =
v8::Exception::SyntaxError(message_value.As<v8::String>());
STATUS_CALL(set_error_code(env, error_obj, code, nullptr));

*result = v8impl::JsValueFromV8LocalValue(error_obj);

return napi_clear_last_error(env);
}

napi_status napi_typeof(napi_env env,
napi_value value,
napi_valuetype* result) {
Expand Down Expand Up @@ -1964,6 +1984,24 @@ napi_status napi_throw_range_error(napi_env env,
return napi_clear_last_error(env);
}

napi_status node_api_throw_syntax_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);

v8::Local<v8::Value> error_obj = v8::Exception::SyntaxError(str);
STATUS_CALL(set_error_code(env, error_obj, nullptr, code));

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_is_error(napi_env env, napi_value value, bool* result) {
// Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot
// throw JS exceptions.
Expand Down
23 changes: 23 additions & 0 deletions test/js-native-api/test_error/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ assert.throws(() => {
test_error.throwTypeError();
}, /^TypeError: type error$/);

assert.throws(() => {
test_error.throwSyntaxError();
}, /^SyntaxError: syntax error$/);

[42, {}, [], Symbol('xyzzy'), true, 'ball', undefined, null, NaN]
.forEach((value) => assert.throws(
() => test_error.throwArbitrary(value),
Expand Down Expand Up @@ -90,6 +94,13 @@ assert.throws(
message: 'TypeError [type error]'
});

assert.throws(
() => test_error.throwSyntaxErrorCode(),
{
code: 'ERR_TEST_CODE',
message: 'SyntaxError [syntax error]'
});

let error = test_error.createError();
assert.ok(error instanceof Error, 'expected error to be an instance of Error');
assert.strictEqual(error.message, 'error');
Expand All @@ -104,6 +115,11 @@ assert.ok(error instanceof TypeError,
'expected error to be an instance of TypeError');
assert.strictEqual(error.message, 'type error');

error = test_error.createSyntaxError();
assert.ok(error instanceof SyntaxError,
'expected error to be an instance of SyntaxError');
assert.strictEqual(error.message, 'syntax error');

error = test_error.createErrorCode();
assert.ok(error instanceof Error, 'expected error to be an instance of Error');
assert.strictEqual(error.code, 'ERR_TEST_CODE');
Expand All @@ -123,3 +139,10 @@ assert.ok(error instanceof TypeError,
assert.strictEqual(error.message, 'TypeError [type error]');
assert.strictEqual(error.code, 'ERR_TEST_CODE');
assert.strictEqual(error.name, 'TypeError');

error = test_error.createSyntaxErrorCode();
assert.ok(error instanceof SyntaxError,
'expected error to be an instance of SyntaxError');
assert.strictEqual(error.message, 'SyntaxError [syntax error]');
assert.strictEqual(error.code, 'ERR_TEST_CODE');
assert.strictEqual(error.name, 'SyntaxError');
37 changes: 37 additions & 0 deletions test/js-native-api/test_error/test_error.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#define NAPI_EXPERIMENTAL
#include <js_native_api.h>
#include "../common.h"

Expand Down Expand Up @@ -40,6 +41,11 @@ static napi_value throwTypeError(napi_env env, napi_callback_info info) {
return NULL;
}

static napi_value throwSyntaxError(napi_env env, napi_callback_info info) {
NODE_API_CALL(env, node_api_throw_syntax_error(env, NULL, "syntax error"));
return NULL;
}

static napi_value throwErrorCode(napi_env env, napi_callback_info info) {
NODE_API_CALL(env, napi_throw_error(env, "ERR_TEST_CODE", "Error [error]"));
return NULL;
Expand All @@ -57,6 +63,11 @@ static napi_value throwTypeErrorCode(napi_env env, napi_callback_info info) {
return NULL;
}

static napi_value throwSyntaxErrorCode(napi_env env, napi_callback_info info) {
NODE_API_CALL(env,
node_api_throw_syntax_error(env, "ERR_TEST_CODE", "SyntaxError [syntax error]"));
return NULL;
}

static napi_value createError(napi_env env, napi_callback_info info) {
napi_value result;
Expand Down Expand Up @@ -85,6 +96,15 @@ static napi_value createTypeError(napi_env env, napi_callback_info info) {
return result;
}

static napi_value createSyntaxError(napi_env env, napi_callback_info info) {
napi_value result;
napi_value message;
NODE_API_CALL(env, napi_create_string_utf8(
env, "syntax error", NAPI_AUTO_LENGTH, &message));
NODE_API_CALL(env, node_api_create_syntax_error(env, NULL, message, &result));
return result;
}

static napi_value createErrorCode(napi_env env, napi_callback_info info) {
napi_value result;
napi_value message;
Expand Down Expand Up @@ -123,6 +143,19 @@ static napi_value createTypeErrorCode(napi_env env, napi_callback_info info) {
return result;
}

static napi_value createSyntaxErrorCode(napi_env env, napi_callback_info info) {
napi_value result;
napi_value message;
napi_value code;
NODE_API_CALL(env,
napi_create_string_utf8(
env, "SyntaxError [syntax error]", NAPI_AUTO_LENGTH, &message));
NODE_API_CALL(env, napi_create_string_utf8(
env, "ERR_TEST_CODE", NAPI_AUTO_LENGTH, &code));
NODE_API_CALL(env, node_api_create_syntax_error(env, code, message, &result));
return result;
}

static napi_value throwArbitrary(napi_env env, napi_callback_info info) {
napi_value arbitrary;
size_t argc = 1;
Expand All @@ -139,16 +172,20 @@ napi_value Init(napi_env env, napi_value exports) {
DECLARE_NODE_API_PROPERTY("throwError", throwError),
DECLARE_NODE_API_PROPERTY("throwRangeError", throwRangeError),
DECLARE_NODE_API_PROPERTY("throwTypeError", throwTypeError),
DECLARE_NODE_API_PROPERTY("throwSyntaxError", throwSyntaxError),
DECLARE_NODE_API_PROPERTY("throwErrorCode", throwErrorCode),
DECLARE_NODE_API_PROPERTY("throwRangeErrorCode", throwRangeErrorCode),
DECLARE_NODE_API_PROPERTY("throwTypeErrorCode", throwTypeErrorCode),
DECLARE_NODE_API_PROPERTY("throwSyntaxErrorCode", throwSyntaxErrorCode),
DECLARE_NODE_API_PROPERTY("throwArbitrary", throwArbitrary),
DECLARE_NODE_API_PROPERTY("createError", createError),
DECLARE_NODE_API_PROPERTY("createRangeError", createRangeError),
DECLARE_NODE_API_PROPERTY("createTypeError", createTypeError),
DECLARE_NODE_API_PROPERTY("createSyntaxError", createSyntaxError),
DECLARE_NODE_API_PROPERTY("createErrorCode", createErrorCode),
DECLARE_NODE_API_PROPERTY("createRangeErrorCode", createRangeErrorCode),
DECLARE_NODE_API_PROPERTY("createTypeErrorCode", createTypeErrorCode),
DECLARE_NODE_API_PROPERTY("createSyntaxErrorCode", createSyntaxErrorCode),
};

NODE_API_CALL(env, napi_define_properties(
Expand Down

0 comments on commit 88b57bc

Please sign in to comment.