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

n-api: implement napi_run_script #15216

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 21 additions & 0 deletions doc/api/n-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ The documentation for N-API is structured as follows:
* [Object Wrap][]
* [Asynchronous Operations][]
* [Promises][]
* [Script Execution][]

The N-API is a C API that ensures ABI stability across Node.js versions
and different compiler levels. However, we also understand that a C++
Expand Down Expand Up @@ -3556,6 +3557,25 @@ NAPI_EXTERN napi_status napi_is_promise(napi_env env,
- `[out] is_promise`: Flag indicating whether `promise` is a native promise
object - that is, a promise object created by the underlying engine.

## Script execution

N-API provides an API for executing a string containing JavaScript using the
underlying JavaScript engine.

### napi_run_script
<!-- YAML
added: REPLACEME
-->
```C
NAPI_EXTERN napi_status napi_run_script(napi_env env,
napi_value script,
napi_value* result);
```

- `[in] env`: The environment that the API is invoked under.
- `[in] script`: A JavaScript string containing the script to execute.
- `[out] result`: The value resulting from having executed the script.

[Promises]: #n_api_promises
[Asynchronous Operations]: #n_api_asynchronous_operations
[Basic N-API Data Types]: #n_api_basic_n_api_data_types
Expand All @@ -3565,6 +3585,7 @@ object - that is, a promise object created by the underlying engine.
[Native Abstractions for Node.js]: https://github.com/nodejs/nan
[Object Lifetime Management]: #n_api_object_lifetime_management
[Object Wrap]: #n_api_object_wrap
[Script Execution]: #n_api_script_execution
[Section 9.1.6]: https://tc39.github.io/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-defineownproperty-p-desc
[Section 12.5.5]: https://tc39.github.io/ecma262/#sec-typeof-operator
[Section 24.3]: https://tc39.github.io/ecma262/#sec-dataview-objects
Expand Down
27 changes: 27 additions & 0 deletions src/node_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3423,3 +3423,30 @@ NAPI_EXTERN napi_status napi_is_promise(napi_env env,

return napi_clear_last_error(env);
}

NAPI_EXTERN napi_status napi_run_script(napi_env env,
napi_value script,
napi_value* result) {
NAPI_PREAMBLE(env);
CHECK_ARG(env, script);
CHECK_ARG(env, result);

v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script);

if (!v8_script->IsString()) {
return napi_set_last_error(env, napi_string_expected);
}

v8::Local<v8::Context> context = env->isolate->GetCurrentContext();

auto maybe_script = v8::Script::Compile(context,
v8::Local<v8::String>::Cast(v8_script));
CHECK_MAYBE_EMPTY(env, maybe_script, napi_generic_failure);

auto script_result =
maybe_script.ToLocalChecked()->Run(context);
CHECK_MAYBE_EMPTY(env, script_result, napi_generic_failure);

*result = v8impl::JsValueFromV8LocalValue(script_result.ToLocalChecked());
return GET_RETURN_STATUS(env);
}
5 changes: 5 additions & 0 deletions src/node_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,11 @@ NAPI_EXTERN napi_status napi_adjust_external_memory(napi_env env,
int64_t change_in_bytes,
int64_t* adjusted_value);

// Runnig a script
NAPI_EXTERN napi_status napi_run_script(napi_env env,
napi_value script,
napi_value* result);

EXTERN_C_END

#endif // SRC_NODE_API_H_
12 changes: 12 additions & 0 deletions test/addons-napi/test_general/testNapiRun.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict';

const common = require('../../common');
const assert = require('assert');

// addon is referenced through the eval expression in testFile
// eslint-disable-next-line no-unused-vars
const addon = require(`./build/${common.buildType}/test_general`);

assert.strictEqual(addon.testNapiRun('(41.92 + 0.08);'), 42,
'napi_run_script() works correctly');
assert.throws(() => addon.testNapiRun({ abc: 'def' }), /string was expected/);
13 changes: 13 additions & 0 deletions test/addons-napi/test_general/test_general.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <node_api.h>
#include <stdlib.h>
#include "../common.h"

napi_value testStrictEquals(napi_env env, napi_callback_info info) {
Expand Down Expand Up @@ -215,12 +216,24 @@ napi_value testAdjustExternalMemory(napi_env env, napi_callback_info info) {
return result;
}

napi_value testNapiRun(napi_env env, napi_callback_info info) {
napi_value script, result;
size_t argc = 1;

NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &script, NULL, NULL));

NAPI_CALL(env, napi_run_script(env, script, &result));

return result;
}

void Init(napi_env env, napi_value exports, napi_value module, void* priv) {
napi_property_descriptor descriptors[] = {
DECLARE_NAPI_PROPERTY("testStrictEquals", testStrictEquals),
DECLARE_NAPI_PROPERTY("testGetPrototype", testGetPrototype),
DECLARE_NAPI_PROPERTY("testGetVersion", testGetVersion),
DECLARE_NAPI_PROPERTY("testGetNodeVersion", testGetNodeVersion),
DECLARE_NAPI_PROPERTY("testNapiRun", testNapiRun),
DECLARE_NAPI_PROPERTY("doInstanceOf", doInstanceOf),
DECLARE_NAPI_PROPERTY("getUndefined", getUndefined),
DECLARE_NAPI_PROPERTY("getNull", getNull),
Expand Down