Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: add SyntaxError #1326

Merged
merged 1 commit into from
Jun 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ The following is the documentation for node-addon-api.
- [Error](doc/error.md)
- [TypeError](doc/type_error.md)
- [RangeError](doc/range_error.md)
- [SyntaxError](doc/syntax_error.md)
- [Object Lifetime Management](doc/object_lifetime_management.md)
- [HandleScope](doc/handle_scope.md)
- [EscapableHandleScope](doc/escapable_handle_scope.md)
Expand Down
2 changes: 2 additions & 0 deletions doc/hierarchy.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
| [`Napi::Reference`] | |
| [`Napi::String`][] | [`Napi::Name`][] |
| [`Napi::Symbol`][] | [`Napi::Name`][] |
| [`Napi::SyntaxError`][] | [`Napi::Error`][] |
| [`Napi::ThreadSafeFunction`][] | |
| [`Napi::TypeTaggable`][] | [`Napi::Value][] |
| [`Napi::TypeError`][] | [`Napi::Error`][] |
Expand Down Expand Up @@ -82,6 +83,7 @@
[`Napi::Reference<Napi::Object>`]: ./reference.md
[`Napi::String`]: ./string.md
[`Napi::Symbol`]: ./symbol.md
[`Napi::SyntaxError`]: ./syntax_error.md
[`Napi::ThreadSafeFunction`]: ./threadsafe_function.md
[`Napi::TypeError`]: ./type_error.md
[`Napi::TypeTaggable`]: ./type_taggable.md
Expand Down
66 changes: 66 additions & 0 deletions doc/syntax_error.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# SyntaxError

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it say here that it's only supported in node-api version 9 and higher?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so... We don't have any other node-api version information in our docs, eg. Napi::Object::Freeze() does not mention being Node-API v8 only.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That might be a gap though ? I go to try to use an API and it's not there? Either way agree that we don't need to be block this PR on it, but might be worth thinking about wether adding that info makes sense.

The `Napi::SyntaxError` class is a representation of the JavaScript
`SyntaxError` that is thrown when the engine encounters tokens or token order
that does not conform to the syntax of the language when parsing code.

The `Napi::SyntaxError` class inherits its behaviors from the `Napi::Error`
class (for more info see: [`Napi::Error`](error.md)).

For more details about error handling refer to the section titled [Error
handling](error_handling.md).

## Methods

### New

Creates a new instance of a `Napi::SyntaxError` object.

```cpp
Napi::SyntaxError::New(Napi::Env env, const char* message);
```

- `[in] Env`: The environment in which to construct the `Napi::SyntaxError`
object.
- `[in] message`: Null-terminated string to be used as the message for the
`Napi::SyntaxError`.

Returns an instance of a `Napi::SyntaxError` object.

### New

Creates a new instance of a `Napi::SyntaxError` object.

```cpp
Napi::SyntaxError::New(Napi::Env env, const std::string& message);
```

- `[in] Env`: The environment in which to construct the `Napi::SyntaxError`
object.
- `[in] message`: Reference string to be used as the message for the
`Napi::SyntaxError`.

Returns an instance of a `Napi::SyntaxError` object.

### Constructor

Creates a new empty instance of a `Napi::SyntaxError`.

```cpp
Napi::SyntaxError::SyntaxError();
```

### Constructor

Initializes a `Napi::SyntaxError` instance from an existing Javascript error
object.

```cpp
Napi::SyntaxError::SyntaxError(napi_env env, napi_value value);
```

- `[in] Env`: The environment in which to construct the `Napi::SyntaxError`
object.
- `[in] value`: The `Napi::Error` reference to wrap.

Returns an instance of a `Napi::SyntaxError` object.
17 changes: 17 additions & 0 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3157,6 +3157,23 @@ inline RangeError::RangeError() : Error() {}
inline RangeError::RangeError(napi_env env, napi_value value)
: Error(env, value) {}

#if NAPI_VERSION > 8
inline SyntaxError SyntaxError::New(napi_env env, const char* message) {
return Error::New<SyntaxError>(
env, message, std::strlen(message), node_api_create_syntax_error);
}

inline SyntaxError SyntaxError::New(napi_env env, const std::string& message) {
return Error::New<SyntaxError>(
env, message.c_str(), message.size(), node_api_create_syntax_error);
}

inline SyntaxError::SyntaxError() : Error() {}

inline SyntaxError::SyntaxError(napi_env env, napi_value value)
: Error(env, value) {}
#endif // NAPI_VERSION > 8

////////////////////////////////////////////////////////////////////////////////
// Reference<T> class
////////////////////////////////////////////////////////////////////////////////
Expand Down
11 changes: 11 additions & 0 deletions napi.h
Original file line number Diff line number Diff line change
Expand Up @@ -1853,6 +1853,17 @@ class RangeError : public Error {
RangeError(napi_env env, napi_value value);
};

#if NAPI_VERSION > 8
class SyntaxError : public Error {
public:
static SyntaxError New(napi_env env, const char* message);
static SyntaxError New(napi_env env, const std::string& message);

SyntaxError();
SyntaxError(napi_env env, napi_value value);
};
#endif // NAPI_VERSION > 8

class CallbackInfo {
public:
CallbackInfo(napi_env env, napi_callback_info info);
Expand Down
47 changes: 47 additions & 0 deletions test/error.cc
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,27 @@ void ThrowRangeError(const CallbackInfo& info) {
throw RangeError::New(info.Env(), message);
}

#if NAPI_VERSION > 8
void ThrowSyntaxErrorCStr(const CallbackInfo& info) {
std::string message = info[0].As<String>().Utf8Value();
ReleaseAndWaitForChildProcess(info, 1);
throw SyntaxError::New(info.Env(), message.c_str());
}

void ThrowSyntaxErrorCtor(const CallbackInfo& info) {
Napi::Value js_range_err = info[0];
ReleaseAndWaitForChildProcess(info, 1);
throw Napi::SyntaxError(info.Env(), js_range_err);
}

void ThrowSyntaxError(const CallbackInfo& info) {
std::string message = info[0].As<String>().Utf8Value();

ReleaseAndWaitForChildProcess(info, 1);
throw SyntaxError::New(info.Env(), message);
}
#endif // NAPI_VERSION > 8

Value CatchError(const CallbackInfo& info) {
Function thrower = info[0].As<Function>();
try {
Expand Down Expand Up @@ -255,6 +276,27 @@ void ThrowEmptyRangeError(const CallbackInfo& info) {
RangeError().ThrowAsJavaScriptException();
}

#if NAPI_VERSION > 8
void ThrowSyntaxError(const CallbackInfo& info) {
std::string message = info[0].As<String>().Utf8Value();

ReleaseAndWaitForChildProcess(info, 1);
SyntaxError::New(info.Env(), message).ThrowAsJavaScriptException();
}

void ThrowSyntaxErrorCtor(const CallbackInfo& info) {
Napi::Value js_range_err = info[0];
ReleaseAndWaitForChildProcess(info, 1);
SyntaxError(info.Env(), js_range_err).ThrowAsJavaScriptException();
}

void ThrowSyntaxErrorCStr(const CallbackInfo& info) {
std::string message = info[0].As<String>().Utf8Value();
ReleaseAndWaitForChildProcess(info, 1);
SyntaxError::New(info.Env(), message.c_str()).ThrowAsJavaScriptException();
}
#endif // NAPI_VERSION > 8

Value CatchError(const CallbackInfo& info) {
Function thrower = info[0].As<Function>();
thrower({});
Expand Down Expand Up @@ -372,6 +414,11 @@ Object InitError(Env env) {
exports["throwRangeErrorCtor"] = Function::New(env, ThrowRangeErrorCtor);
exports["throwRangeErrorCStr"] = Function::New(env, ThrowRangeErrorCStr);
exports["throwEmptyRangeError"] = Function::New(env, ThrowEmptyRangeError);
#if NAPI_VERSION > 8
exports["throwSyntaxError"] = Function::New(env, ThrowSyntaxError);
exports["throwSyntaxErrorCtor"] = Function::New(env, ThrowSyntaxErrorCtor);
exports["throwSyntaxErrorCStr"] = Function::New(env, ThrowSyntaxErrorCStr);
#endif // NAPI_VERSION > 8
exports["catchError"] = Function::New(env, CatchError);
exports["catchErrorMessage"] = Function::New(env, CatchErrorMessage);
exports["doNotCatch"] = Function::New(env, DoNotCatch);
Expand Down
16 changes: 16 additions & 0 deletions test/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ if (process.argv[2] === 'fatal') {

module.exports = require('./common').runTestWithBindingPath(test);

const napiVersion = Number(process.env.NAPI_VERSION ?? process.versions.napi);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be better to move the napiVersion definition in test/index.js to test/common/index.js so that we don't have to repeat it.


function test (bindingPath) {
const binding = require(bindingPath);
binding.error.testErrorCopySemantics();
Expand Down Expand Up @@ -46,6 +48,20 @@ function test (bindingPath) {
return err instanceof RangeError && err.message === 'rangeTypeError';
});

if (napiVersion > 8) {
assert.throws(() => binding.error.throwSyntaxErrorCStr('test'), function (err) {
return err instanceof SyntaxError && err.message === 'test';
});

assert.throws(() => binding.error.throwSyntaxError('test'), function (err) {
return err instanceof SyntaxError && err.message === 'test';
});

assert.throws(() => binding.error.throwSyntaxErrorCtor(new SyntaxError('syntaxTypeError')), function (err) {
return err instanceof SyntaxError && err.message === 'syntaxTypeError';
});
}

assert.throws(
() => binding.error.doNotCatch(
() => {
Expand Down