Skip to content
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
6 changes: 6 additions & 0 deletions packages/emnapi/include/node/js_native_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,12 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_string(napi_env env,
napi_value* result);

// Methods to work with Objects
#ifdef NAPI_EXPERIMENTAL
#define NODE_API_EXPERIMENTAL_HAS_SET_PROTOTYPE
NAPI_EXTERN napi_status NAPI_CDECL node_api_set_prototype(napi_env env,
napi_value object,
napi_value value);
#endif
NAPI_EXTERN napi_status NAPI_CDECL napi_get_prototype(napi_env env,
napi_value object,
napi_value* result);
Expand Down
24 changes: 24 additions & 0 deletions packages/emnapi/src/value/convert2c.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,30 @@ export function napi_get_arraybuffer_info (env: napi_env, arraybuffer: napi_valu
return envObject.clearLastError()
}

/**
* @__sig ippp
*/
export function node_api_set_prototype (env: napi_env, object: napi_value, value: napi_value): napi_status {
return $PREAMBLE!(env, (envObject) => {
$CHECK_ARG!(envObject, value)
const obj = emnapiCtx.jsValueFromNapiValue(object)!
if (obj == null) {
throw new TypeError('Cannot convert undefined or null to object')
}
const type = typeof obj
let v: any
try {
v = (type === 'object' && obj !== null) || type === 'function' ? obj : Object(obj)
} catch (_) {
return envObject.setLastError(napi_status.napi_object_expected)
}
const val = emnapiCtx.jsValueFromNapiValue(value)!
Object.setPrototypeOf(v, val)

return $GET_RETURN_STATUS!(envObject)
})
}

/**
* @__sig ippp
*/
Expand Down
1 change: 1 addition & 0 deletions packages/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ add_test("callback" "./callback/binding.c" OFF)
add_test("objfac" "./objfac/binding.c" OFF)
add_test("fnfac" "./fnfac/binding.c" OFF)
add_test("general" "./general/binding.c" OFF)
target_compile_definitions("general" PRIVATE "NAPI_EXPERIMENTAL")
add_test("filename" "./filename/binding.c" OFF)
add_test("string" "./string/binding.c;./string/test_null.c" OFF)
target_compile_definitions("string" PRIVATE "NAPI_VERSION=10")
Expand Down
71 changes: 47 additions & 24 deletions packages/test/general/binding.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ static napi_value testStrictEquals(napi_env env, napi_callback_info info) {
return result;
}

static napi_value testSetPrototype(napi_env env, napi_callback_info info) {
size_t argc = 2;
napi_value args[2];
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));

NODE_API_CALL(env, node_api_set_prototype(env, args[0], args[1]));

return NULL;
}

static napi_value testGetPrototype(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value args[1];
Expand Down Expand Up @@ -133,7 +143,7 @@ static napi_value testNapiTypeof(napi_env env, napi_callback_info info) {
}

static bool deref_item_called = false;
static void deref_item(napi_env env, void* data, void* hint) {
static void deref_item(node_api_nogc_env env, void* data, void* hint) {
(void) hint;

NODE_API_ASSERT_RETURN_VOID(env, data == &deref_item_called,
Expand All @@ -152,7 +162,7 @@ static napi_value deref_item_was_called(napi_env env, napi_callback_info info) {

static napi_value wrap_first_arg(napi_env env,
napi_callback_info info,
napi_finalize finalizer,
node_api_basic_finalize finalizer,
void* data) {
size_t argc = 1;
napi_value to_wrap;
Expand Down Expand Up @@ -191,7 +201,7 @@ static napi_value remove_wrap(napi_env env, napi_callback_info info) {
}

static bool finalize_called = false;
static void test_finalize(napi_env env, void* data, void* hint) {
static void test_finalize(node_api_nogc_env env, void* data, void* hint) {
finalize_called = true;
}

Expand Down Expand Up @@ -238,6 +248,15 @@ static void finalizer_only_callback(napi_env env, void* data, void* hint) {
NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, js_cb_ref));
}

static void schedule_finalizer_only_callback(node_api_nogc_env env,
void* data,
void* hint) {
NODE_API_CALL_RETURN_VOID(
(napi_env)env,
node_api_post_finalizer(
(napi_env)env, finalizer_only_callback, data, NULL));
}

static napi_value add_finalizer_only(napi_env env, napi_callback_info info) {
size_t argc = 2;
napi_value argv[2];
Expand All @@ -249,7 +268,7 @@ static napi_value add_finalizer_only(napi_env env, napi_callback_info info) {
napi_add_finalizer(env,
argv[0],
js_cb_ref,
finalizer_only_callback,
schedule_finalizer_only_callback,
NULL,
NULL));
return NULL;
Expand All @@ -264,7 +283,9 @@ static const char* env_cleanup_finalizer_messages[] = {
};
#endif

static void cleanup_env_finalizer(napi_env env, void* data, void* hint) {
static void cleanup_env_finalizer(node_api_nogc_env env,
void* data,
void* hint) {
(void) env;
(void) hint;
#if !defined(__wasm__) || (defined(__EMSCRIPTEN__) || defined(__wasi__))
Expand Down Expand Up @@ -304,25 +325,27 @@ static napi_value getDynamicallyInitialized(napi_env env) {
EXTERN_C_START
napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor descriptors[] = {
DECLARE_NODE_API_PROPERTY("testStrictEquals", testStrictEquals),
DECLARE_NODE_API_PROPERTY("testGetPrototype", testGetPrototype),
DECLARE_NODE_API_PROPERTY("testGetVersion", testGetVersion),
DECLARE_NODE_API_PROPERTY("testNapiRun", testNapiRun),
DECLARE_NODE_API_PROPERTY("doInstanceOf", doInstanceOf),
DECLARE_NODE_API_PROPERTY("getUndefined", getUndefined),
DECLARE_NODE_API_PROPERTY("getNull", getNull),
DECLARE_NODE_API_PROPERTY("createNapiError", createNapiError),
DECLARE_NODE_API_PROPERTY("testNapiErrorCleanup", testNapiErrorCleanup),
DECLARE_NODE_API_PROPERTY("testNapiTypeof", testNapiTypeof),
DECLARE_NODE_API_PROPERTY("wrap", wrap),
DECLARE_NODE_API_PROPERTY("envCleanupWrap", env_cleanup_wrap),
DECLARE_NODE_API_PROPERTY("unwrap", unwrap),
DECLARE_NODE_API_PROPERTY("removeWrap", remove_wrap),
DECLARE_NODE_API_PROPERTY("addFinalizerOnly", add_finalizer_only),
DECLARE_NODE_API_PROPERTY("testFinalizeWrap", test_finalize_wrap),
DECLARE_NODE_API_PROPERTY("finalizeWasCalled", finalize_was_called),
DECLARE_NODE_API_PROPERTY("derefItemWasCalled", deref_item_was_called),
DECLARE_NODE_API_PROPERTY("testAdjustExternalMemory", testAdjustExternalMemory),
DECLARE_NODE_API_PROPERTY("testStrictEquals", testStrictEquals),
DECLARE_NODE_API_PROPERTY("testSetPrototype", testSetPrototype),
DECLARE_NODE_API_PROPERTY("testGetPrototype", testGetPrototype),
DECLARE_NODE_API_PROPERTY("testGetVersion", testGetVersion),
DECLARE_NODE_API_PROPERTY("testNapiRun", testNapiRun),
DECLARE_NODE_API_PROPERTY("doInstanceOf", doInstanceOf),
DECLARE_NODE_API_PROPERTY("getUndefined", getUndefined),
DECLARE_NODE_API_PROPERTY("getNull", getNull),
DECLARE_NODE_API_PROPERTY("createNapiError", createNapiError),
DECLARE_NODE_API_PROPERTY("testNapiErrorCleanup", testNapiErrorCleanup),
DECLARE_NODE_API_PROPERTY("testNapiTypeof", testNapiTypeof),
DECLARE_NODE_API_PROPERTY("wrap", wrap),
DECLARE_NODE_API_PROPERTY("envCleanupWrap", env_cleanup_wrap),
DECLARE_NODE_API_PROPERTY("unwrap", unwrap),
DECLARE_NODE_API_PROPERTY("removeWrap", remove_wrap),
DECLARE_NODE_API_PROPERTY("addFinalizerOnly", add_finalizer_only),
DECLARE_NODE_API_PROPERTY("testFinalizeWrap", test_finalize_wrap),
DECLARE_NODE_API_PROPERTY("finalizeWasCalled", finalize_was_called),
DECLARE_NODE_API_PROPERTY("derefItemWasCalled", deref_item_was_called),
DECLARE_NODE_API_PROPERTY("testAdjustExternalMemory",
testAdjustExternalMemory),
#ifdef __wasm__
{
.utf8name = "dynamicallyInitialized",
Expand Down
6 changes: 6 additions & 0 deletions packages/test/general/general.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module.exports = load('general').then(async test_general => {

const baseObject = new BaseClass()
const extendedObject = new ExtendedClass()
const nullProtoObject = { __proto__: null }

if (!process.env.EMNAPI_TEST_NATIVE) {
assert.ok(test_general.dynamicallyInitialized)
Expand All @@ -30,6 +31,11 @@ module.exports = load('general').then(async test_general => {
assert.ok(test_general.testStrictEquals(val2, val3))
assert.strictEqual(test_general.testStrictEquals(NaN, NaN), false)

// Test napi_set_prototype
test_general.testSetPrototype(nullProtoObject, Object.prototype)
assert.strictEqual(Object.getPrototypeOf(nullProtoObject),
Object.prototype)

// Test napi_get_prototype
assert.strictEqual(test_general.testGetPrototype(baseObject),
Object.getPrototypeOf(baseObject))
Expand Down