Skip to content

Commit

Permalink
Add Env::RunScript
Browse files Browse the repository at this point in the history
This is a thin wrapper around napi_run_script.

Refs: nodejs/node#15216
  • Loading branch information
tniessen committed Dec 1, 2019
1 parent f677794 commit 92dc802
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 0 deletions.
14 changes: 14 additions & 0 deletions doc/env.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,17 @@ Napi::Error Napi::Env::GetAndClearPendingException();
```

Returns an `Napi::Error` object representing the environment's pending exception, if any.

### RunScript

```cpp
Napi::Value Napi::Env::RunScript(____ script);
```
- `[in] script`: A string of JavaScript code.
Runs a string containing JavaScript code and returns its result.
The `script` can be any of the following types:
- [`Napi::Value`](value.md)
- `const char *`
- `const std::string &`
16 changes: 16 additions & 0 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,22 @@ inline Error Env::GetAndClearPendingException() {
return Error(_env, value);
}

inline Value Env::RunScript(const char* utf8script) {
Value script = Value::From(_env, utf8script);
return RunScript(script);
}

inline Value Env::RunScript(const std::string& utf8script) {
return RunScript(utf8script.c_str());
}

inline Value Env::RunScript(Value script) {
napi_value result;
napi_status status = napi_run_script(_env, script, &result);
NAPI_THROW_IF_FAILED(_env, status, Undefined());
return Value(_env, result);
}

////////////////////////////////////////////////////////////////////////////////
// Value class
////////////////////////////////////////////////////////////////////////////////
Expand Down
4 changes: 4 additions & 0 deletions napi.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ namespace Napi {
bool IsExceptionPending() const;
Error GetAndClearPendingException();

Value RunScript(const char* utf8script);
Value RunScript(const std::string& utf8script);
Value RunScript(Value script);

private:
napi_env _env;
};
Expand Down
2 changes: 2 additions & 0 deletions test/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Object InitObject(Env env);
Object InitObjectDeprecated(Env env);
#endif // !NODE_ADDON_API_DISABLE_DEPRECATED
Object InitPromise(Env env);
Object InitRunScript(Env env);
#if (NAPI_VERSION > 3)
Object InitThreadSafeFunctionCtx(Env env);
Object InitThreadSafeFunctionExistingTsfn(Env env);
Expand Down Expand Up @@ -92,6 +93,7 @@ Object Init(Env env, Object exports) {
exports.Set("object_deprecated", InitObjectDeprecated(env));
#endif // !NODE_ADDON_API_DISABLE_DEPRECATED
exports.Set("promise", InitPromise(env));
exports.Set("run_script", InitRunScript(env));
#if (NAPI_VERSION > 3)
exports.Set("threadsafe_function_ctx", InitThreadSafeFunctionCtx(env));
exports.Set("threadsafe_function_existing_tsfn", InitThreadSafeFunctionExistingTsfn(env));
Expand Down
1 change: 1 addition & 0 deletions test/binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
'object/object.cc',
'object/set_property.cc',
'promise.cc',
'run_script.cc',
'threadsafe_function/threadsafe_function_ctx.cc',
'threadsafe_function/threadsafe_function_existing_tsfn.cc',
'threadsafe_function/threadsafe_function_ptr.cc',
Expand Down
1 change: 1 addition & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ let testModules = [
'object/object_deprecated',
'object/set_property',
'promise',
'run_script',
'threadsafe_function/threadsafe_function_ctx',
'threadsafe_function/threadsafe_function_existing_tsfn',
'threadsafe_function/threadsafe_function_ptr',
Expand Down
55 changes: 55 additions & 0 deletions test/run_script.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "napi.h"

using namespace Napi;

namespace {

Value RunPlainString(const CallbackInfo& info) {
Env env = info.Env();
return env.RunScript("1 + 2 + 3");
}

Value RunStdString(const CallbackInfo& info) {
Env env = info.Env();
std::string str = "1 + 2 + 3";
return env.RunScript(str);
}

Value RunJsString(const CallbackInfo& info) {
Env env = info.Env();
return env.RunScript(info[0]);
}

Value RunWithContext(const CallbackInfo& info) {
Env env = info.Env();

Array keys = info[1].As<Object>().GetPropertyNames();
std::string code = "(";
for (unsigned int i = 0; i < keys.Length(); i++) {
if (i != 0) code += ",";
code += keys.Get(i).As<String>().Utf8Value();
}
code += ") => " + info[0].As<String>().Utf8Value();

Value ret = env.RunScript(code);
Function fn = ret.As<Function>();
std::vector<napi_value> args;
for (unsigned int i = 0; i < keys.Length(); i++) {
Value key = keys.Get(i);
args.push_back(info[1].As<Object>().Get(key));
}
return fn.Call(args);
}

} // end anonymous namespace

Object InitRunScript(Env env) {
Object exports = Object::New(env);

exports["plainString"] = Function::New(env, RunPlainString);
exports["stdString"] = Function::New(env, RunStdString);
exports["jsString"] = Function::New(env, RunJsString);
exports["withContext"] = Function::New(env, RunWithContext);

return exports;
}
46 changes: 46 additions & 0 deletions test/run_script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict';
const buildType = process.config.target_defaults.default_configuration;
const assert = require('assert');
const testUtil = require('./testUtil');

test(require(`./build/${buildType}/binding.node`));
test(require(`./build/${buildType}/binding_noexcept.node`));

function test(binding) {
testUtil.runGCTests([
'Plain C string',
() => {
const sum = binding.run_script.plainString();
assert.strictEqual(sum, 1 + 2 + 3);
},

'std::string',
() => {
const sum = binding.run_script.stdString();
assert.strictEqual(sum, 1 + 2 + 3);
},

'JavaScript string',
() => {
const sum = binding.run_script.jsString("1 + 2 + 3");
assert.strictEqual(sum, 1 + 2 + 3);
},

'JavaScript, but not a string',
() => {
assert.throws(() => {
binding.run_script.jsString(true);
}, {
name: 'Error',
message: 'A string was expected'
});
},

'With context',
() => {
const a = 1, b = 2, c = 3;
const sum = binding.run_script.withContext("a + b + c", { a, b, c });
assert.strictEqual(sum, a + b + c);
}
]);
}

0 comments on commit 92dc802

Please sign in to comment.