diff --git a/crates/napi/src/bindgen_runtime/iterator.rs b/crates/napi/src/bindgen_runtime/iterator.rs index 7d4a8dbe..3f71291d 100644 --- a/crates/napi/src/bindgen_runtime/iterator.rs +++ b/crates/napi/src/bindgen_runtime/iterator.rs @@ -16,19 +16,19 @@ pub trait Generator { type Return: FromNapiValue; /// Handle the `Generator.next()` - /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next + /// fn next(&mut self, value: Option) -> Option; #[allow(unused_variables)] /// Implement complete to handle the `Generator.return()` - /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/return + /// fn complete(&mut self, value: Option) -> Option { None } #[allow(unused_variables)] /// Implement catch to handle the `Generator.throw()` - /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/throw + /// fn catch(&mut self, env: Env, value: Unknown) -> Result, Unknown> { Err(value) } diff --git a/crates/napi/src/env.rs b/crates/napi/src/env.rs index f11b75bf..95eae3f5 100644 --- a/crates/napi/src/env.rs +++ b/crates/napi/src/env.rs @@ -7,6 +7,7 @@ use std::mem; use std::os::raw::{c_char, c_void}; use std::ptr; +use crate::bindgen_runtime::FromNapiValue; #[cfg(all(feature = "napi4"))] use crate::bindgen_runtime::ToNapiValue; use crate::{ @@ -1078,13 +1079,19 @@ impl Env { result } - pub fn run_script>(&self, script: S) -> Result { + /// Node-API provides an API for executing a string containing JavaScript using the underlying JavaScript engine. + /// This function executes a string of JavaScript code and returns its result with the following caveats: + /// - Unlike `eval`, this function does not allow the script to access the current lexical scope, and therefore also does not allow to access the [module scope](https://nodejs.org/api/modules.html#the-module-scope), meaning that pseudo-globals such as require will not be available. + /// - The script can access the [global scope](https://nodejs.org/api/globals.html). Function and `var` declarations in the script will be added to the [global](https://nodejs.org/api/globals.html#global) object. Variable declarations made using `let` and `const` will be visible globally, but will not be added to the global object. + /// - The value of this is [global](https://nodejs.org/api/globals.html) within the script. + pub fn run_script, V: FromNapiValue>(&self, script: S) -> Result { let s = self.create_string(script.as_ref())?; let mut raw_value = ptr::null_mut(); check_status!(unsafe { sys::napi_run_script(self.0, s.raw(), &mut raw_value) })?; - Ok(unsafe { JsObject::from_raw_unchecked(self.0, raw_value) }) + unsafe { V::from_napi_value(self.0, raw_value) } } + /// `process.versions.napi` pub fn get_napi_version(&self) -> Result { let global = self.get_global()?; let process: JsObject = global.get_named_property("process")?; diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index e94183a7..4177d83b 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -218,6 +218,7 @@ Generated by [AVA](https://avajs.dev). export function bufferPassThrough(buf: Buffer): Promise␊ export function arrayBufferPassThrough(buf: Uint8Array): Promise␊ export function asyncReduceBuffer(buf: Buffer): Promise␊ + export function runScript(script: string): unknown␊ /**␊ * \`constructor\` option for \`struct\` requires all fields to be public,␊ * otherwise tag impl fn as constructor␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index 46896230..84057f2f 100644 Binary files a/examples/napi/__test__/typegen.spec.ts.snap and b/examples/napi/__test__/typegen.spec.ts.snap differ diff --git a/examples/napi/__test__/values.spec.ts b/examples/napi/__test__/values.spec.ts index b6b98029..d06a870f 100644 --- a/examples/napi/__test__/values.spec.ts +++ b/examples/napi/__test__/values.spec.ts @@ -120,6 +120,7 @@ import { acceptThreadsafeFunction, acceptThreadsafeFunctionFatal, promiseInEither, + runScript, } from '../' test('export const', (t) => { @@ -630,6 +631,11 @@ test('external', (t) => { ) }) +test('should be able to run script', async (t) => { + t.is(runScript(`1 + 1`), 2) + t.is(await runScript(`Promise.resolve(1)`), 1) +}) + const AbortSignalTest = typeof AbortController !== 'undefined' ? test : test.skip diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 88078283..29ec410c 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -208,6 +208,7 @@ export function derefUint8Array(a: Uint8Array, b: Uint8ClampedArray): number export function bufferPassThrough(buf: Buffer): Promise export function arrayBufferPassThrough(buf: Uint8Array): Promise export function asyncReduceBuffer(buf: Buffer): Promise +export function runScript(script: string): unknown /** * `constructor` option for `struct` requires all fields to be public, * otherwise tag impl fn as constructor diff --git a/examples/napi/src/lib.rs b/examples/napi/src/lib.rs index fdd3e4fe..69d03eec 100644 --- a/examples/napi/src/lib.rs +++ b/examples/napi/src/lib.rs @@ -3,6 +3,8 @@ #![allow(clippy::disallowed_names)] #![allow(clippy::uninlined_format_args)] +use napi::{Env, JsUnknown}; + #[macro_use] extern crate napi_derive; #[macro_use] @@ -46,3 +48,8 @@ mod symbol; mod task; mod threadsafe_function; mod typed_array; + +#[napi] +pub fn run_script(env: Env, script: String) -> napi::Result { + env.run_script(&script) +}