From b96fca7c2350451fad19aa74b6b377e28cb6de65 Mon Sep 17 00:00:00 2001 From: Miguel Marcondes Date: Sat, 20 Sep 2025 17:29:16 -0300 Subject: [PATCH 01/15] node-api: add napi_create_object_with_properties --- src/js_native_api.h | 7 ++++++ src/js_native_api_v8.cc | 50 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/js_native_api.h b/src/js_native_api.h index df2380ad31f3a2..fa732daed7bbbc 100644 --- a/src/js_native_api.h +++ b/src/js_native_api.h @@ -628,6 +628,13 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_object_freeze(napi_env env, napi_value object); NAPI_EXTERN napi_status NAPI_CDECL napi_object_seal(napi_env env, napi_value object); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_object_with_properties( + napi_env env, + napi_value prototype_or_null, + napi_value* property_names, + napi_value* property_values, + size_t property_count, + napi_value* result); #endif // NAPI_VERSION >= 8 EXTERN_C_END diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index 153f49339f702e..bd359234dca0a2 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -1591,6 +1591,56 @@ napi_status NAPI_CDECL napi_create_object(napi_env env, napi_value* result) { return napi_clear_last_error(env); } +napi_status NAPI_CDECL napi_create_object_with_properties( + napi_env env, + napi_value prototype_or_null, + napi_value* property_names, + napi_value* property_values, + size_t property_count, + napi_value* result) { + CHECK_ENV_NOT_IN_GC(env); + CHECK_ARG(env, result); + + if (property_count > 0) { + CHECK_ARG(env, property_names); + CHECK_ARG(env, property_values); + } + + v8::Local v8_prototype_or_null = + v8impl::V8LocalValueFromJsValue(prototype_or_null); + + v8::Local obj; + + if (property_count > 0) { + v8::LocalVector v8_names(env->isolate, property_count); + v8::LocalVector v8_values(env->isolate, property_count); + + for (size_t i = 0; i < property_count; i++) { + v8::Local name_value = + v8impl::V8LocalValueFromJsValue(property_names[i]); + RETURN_STATUS_IF_FALSE(env, name_value->IsName(), napi_name_expected); + v8_names[i] = name_value.As(); + v8_values[i] = v8impl::V8LocalValueFromJsValue(property_values[i]); + } + + obj = v8::Object::New(env->isolate, + v8_prototype_or_null, + v8_names.data(), + v8_values.data(), + property_count); + } else { + obj = v8::Object::New(env->isolate, + v8_prototype_or_null, + nullptr, + nullptr, + 0); + } + + RETURN_STATUS_IF_FALSE(env, !obj.IsEmpty(), napi_generic_failure); + *result = v8impl::JsValueFromV8LocalValue(obj); + return napi_clear_last_error(env); +} + napi_status NAPI_CDECL napi_create_array(napi_env env, napi_value* result) { CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); From 69ba24be40e40a663f80bb53db5c42446b32ea02 Mon Sep 17 00:00:00 2001 From: Miguel Marcondes Date: Sat, 20 Sep 2025 17:44:59 -0300 Subject: [PATCH 02/15] test: add tests for creating objects with properties in js-native-api --- test/js-native-api/test_object/test.js | 18 +++++- test/js-native-api/test_object/test_object.c | 59 ++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/test/js-native-api/test_object/test.js b/test/js-native-api/test_object/test.js index a745d45e6f75e1..a1123ae23bfd64 100644 --- a/test/js-native-api/test_object/test.js +++ b/test/js-native-api/test_object/test.js @@ -5,7 +5,6 @@ const assert = require('assert'); // Testing api calls for objects const test_object = require(`./build/${common.buildType}/test_object`); - const object = { hello: 'world', array: [ @@ -391,3 +390,20 @@ assert.deepStrictEqual(test_object.TestGetProperty(), { delete obj.x; }, /Cannot delete property 'x' of #/); } + +{ + const objectWithProperties = test_object.TestCreateObjectWithProperties(); + assert.strictEqual(typeof objectWithProperties, 'object'); + assert.strictEqual(objectWithProperties.name, 'Foo'); + assert.strictEqual(objectWithProperties.age, 42); + assert.strictEqual(objectWithProperties.active, true); + + const emptyObject = test_object.TestCreateObjectWithPropertiesEmpty(); + assert.strictEqual(typeof emptyObject, 'object'); + assert.strictEqual(Object.keys(emptyObject).length, 0); + + const objectWithCustomPrototype = test_object.TestCreateObjectWithCustomPrototype(); + assert.strictEqual(typeof objectWithCustomPrototype, 'object'); + assert.strictEqual(objectWithCustomPrototype.value, 42); + assert.strictEqual(typeof objectWithCustomPrototype.test, 'function'); +} diff --git a/test/js-native-api/test_object/test_object.c b/test/js-native-api/test_object/test_object.c index 6d74128118f997..f2fd059eb5031a 100644 --- a/test/js-native-api/test_object/test_object.c +++ b/test/js-native-api/test_object/test_object.c @@ -710,6 +710,62 @@ CheckTypeTag(napi_env env, napi_callback_info info) { return js_result; } +static napi_value TestCreateObjectWithProperties(napi_env env, napi_callback_info info) { + napi_value names[3]; + napi_value values[3]; + napi_value result; + + NODE_API_CALL(env, napi_create_string_utf8(env, "name", NAPI_AUTO_LENGTH, &names[0])); + NODE_API_CALL(env, napi_create_string_utf8(env, "Foo", NAPI_AUTO_LENGTH, &values[0])); + + NODE_API_CALL(env, napi_create_string_utf8(env, "age", NAPI_AUTO_LENGTH, &names[1])); + NODE_API_CALL(env, napi_create_int32(env, 42, &values[1])); + + NODE_API_CALL(env, napi_create_string_utf8(env, "active", NAPI_AUTO_LENGTH, &names[2])); + NODE_API_CALL(env, napi_get_boolean(env, true, &values[2])); + + napi_value null_prototype; + NODE_API_CALL(env, napi_get_null(env, &null_prototype)); + NODE_API_CALL(env, napi_create_object_with_properties( + env, null_prototype, names, values, 3, &result)); + + return result; +} + +static napi_value TestCreateObjectWithPropertiesEmpty(napi_env env, napi_callback_info info) { + napi_value result; + + napi_value null_prototype; + NODE_API_CALL(env, napi_get_null(env, &null_prototype)); + NODE_API_CALL(env, napi_create_object_with_properties( + env, null_prototype, NULL, NULL, 0, &result)); + + return result; +} + +static napi_value TestCreateObjectWithCustomPrototype(napi_env env, napi_callback_info info) { + napi_value prototype; + napi_value method_name; + napi_value method_func; + napi_value names[1]; + napi_value values[1]; + napi_value result; + + NODE_API_CALL(env, napi_create_object(env, &prototype)); + NODE_API_CALL(env, napi_create_string_utf8(env, "test", NAPI_AUTO_LENGTH, &method_name)); + NODE_API_CALL(env, napi_create_function(env, "test", NAPI_AUTO_LENGTH, + TestCreateObjectWithProperties, NULL, &method_func)); + NODE_API_CALL(env, napi_set_property(env, prototype, method_name, method_func)); + + NODE_API_CALL(env, napi_create_string_utf8(env, "value", NAPI_AUTO_LENGTH, &names[0])); + NODE_API_CALL(env, napi_create_int32(env, 42, &values[0])); + + NODE_API_CALL(env, napi_create_object_with_properties( + env, prototype, names, values, 1, &result)); + + return result; +} + EXTERN_C_START napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { @@ -743,6 +799,9 @@ napi_value Init(napi_env env, napi_value exports) { DECLARE_NODE_API_PROPERTY("TestGetProperty", TestGetProperty), DECLARE_NODE_API_PROPERTY("TestFreeze", TestFreeze), DECLARE_NODE_API_PROPERTY("TestSeal", TestSeal), + DECLARE_NODE_API_PROPERTY("TestCreateObjectWithProperties", TestCreateObjectWithProperties), + DECLARE_NODE_API_PROPERTY("TestCreateObjectWithPropertiesEmpty", TestCreateObjectWithPropertiesEmpty), + DECLARE_NODE_API_PROPERTY("TestCreateObjectWithCustomPrototype", TestCreateObjectWithCustomPrototype), }; init_test_null(env, exports); From cdf53139e69a11df678c54146488cbe8437b21e7 Mon Sep 17 00:00:00 2001 From: Miguel Marcondes Date: Sat, 20 Sep 2025 19:15:48 -0300 Subject: [PATCH 03/15] node-api: add benchmark for new and old creation --- .../create_object_with_properties/.gitignore | 1 + .../create_object_with_properties/binding.cc | 150 ++++++++++++++++++ .../create_object_with_properties/binding.gyp | 9 ++ .../create_object_with_properties/index.js | 24 +++ 4 files changed, 184 insertions(+) create mode 100644 benchmark/napi/create_object_with_properties/.gitignore create mode 100644 benchmark/napi/create_object_with_properties/binding.cc create mode 100644 benchmark/napi/create_object_with_properties/binding.gyp create mode 100644 benchmark/napi/create_object_with_properties/index.js diff --git a/benchmark/napi/create_object_with_properties/.gitignore b/benchmark/napi/create_object_with_properties/.gitignore new file mode 100644 index 00000000000000..567609b1234a9b --- /dev/null +++ b/benchmark/napi/create_object_with_properties/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/benchmark/napi/create_object_with_properties/binding.cc b/benchmark/napi/create_object_with_properties/binding.cc new file mode 100644 index 00000000000000..0ed3438de006b7 --- /dev/null +++ b/benchmark/napi/create_object_with_properties/binding.cc @@ -0,0 +1,150 @@ +#include +#include + +// Creating with many options because complains are when ~20 properties +static void CreateTestProperties(napi_env env, + napi_value names[20], + napi_value values[20]) { + napi_create_string_utf8(env, "foo", NAPI_AUTO_LENGTH, &names[0]); + napi_create_string_utf8(env, "value1", NAPI_AUTO_LENGTH, &values[0]); + napi_create_string_utf8(env, "alpha", NAPI_AUTO_LENGTH, &names[1]); + napi_create_int32(env, 100, &values[1]); + napi_create_string_utf8(env, "beta", NAPI_AUTO_LENGTH, &names[2]); + napi_get_boolean(env, true, &values[2]); + napi_create_string_utf8(env, "gamma", NAPI_AUTO_LENGTH, &names[3]); + napi_create_double(env, 3.14159, &values[3]); + napi_create_string_utf8(env, "delta", NAPI_AUTO_LENGTH, &names[4]); + napi_create_int32(env, 42, &values[4]); + napi_create_string_utf8(env, "epsilon", NAPI_AUTO_LENGTH, &names[5]); + napi_create_string_utf8(env, "test", NAPI_AUTO_LENGTH, &values[5]); + napi_create_string_utf8(env, "zeta", NAPI_AUTO_LENGTH, &names[6]); + napi_create_string_utf8(env, "data", NAPI_AUTO_LENGTH, &values[6]); + napi_create_string_utf8(env, "eta", NAPI_AUTO_LENGTH, &names[7]); + napi_create_string_utf8(env, "info", NAPI_AUTO_LENGTH, &values[7]); + napi_create_string_utf8(env, "theta", NAPI_AUTO_LENGTH, &names[8]); + napi_create_string_utf8(env, "sample", NAPI_AUTO_LENGTH, &values[8]); + napi_create_string_utf8(env, "iota", NAPI_AUTO_LENGTH, &names[9]); + napi_create_double(env, 2.71828, &values[9]); + napi_create_string_utf8(env, "kappa", NAPI_AUTO_LENGTH, &names[10]); + napi_create_string_utf8(env, "benchmark", NAPI_AUTO_LENGTH, &values[10]); + napi_create_string_utf8(env, "lambda", NAPI_AUTO_LENGTH, &names[11]); + napi_create_string_utf8(env, "result", NAPI_AUTO_LENGTH, &values[11]); + napi_create_string_utf8(env, "mu", NAPI_AUTO_LENGTH, &names[12]); + napi_create_string_utf8(env, "output", NAPI_AUTO_LENGTH, &values[12]); + napi_create_string_utf8(env, "nu", NAPI_AUTO_LENGTH, &names[13]); + napi_get_boolean(env, false, &values[13]); + napi_create_string_utf8(env, "xi", NAPI_AUTO_LENGTH, &names[14]); + napi_create_int32(env, 7, &values[14]); + napi_create_string_utf8(env, "omicron", NAPI_AUTO_LENGTH, &names[15]); + napi_create_double(env, 1.618, &values[15]); + napi_create_string_utf8(env, "pi", NAPI_AUTO_LENGTH, &names[16]); + napi_create_string_utf8(env, "config", NAPI_AUTO_LENGTH, &values[16]); + napi_create_string_utf8(env, "rho", NAPI_AUTO_LENGTH, &names[17]); + napi_create_int32(env, 999, &values[17]); + napi_create_string_utf8(env, "sigma", NAPI_AUTO_LENGTH, &names[18]); + napi_create_double(env, 0.577, &values[18]); + napi_create_string_utf8(env, "tau", NAPI_AUTO_LENGTH, &names[19]); + napi_get_boolean(env, true, &values[19]); +} + +static napi_value CreateObjectWithPropertiesNew(napi_env env, + napi_callback_info info) { + size_t argc = 4; + napi_value args[4]; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_value count_val = args[0]; + napi_value bench_obj = args[1]; + napi_value start_fn = args[2]; + napi_value end_fn = args[3]; + + uint32_t count; + napi_get_value_uint32(env, count_val, &count); + + napi_value names[20]; + napi_value values[20]; + napi_value null_prototype; + + napi_get_null(env, &null_prototype); + CreateTestProperties(env, names, values); + + napi_call_function(env, bench_obj, start_fn, 0, nullptr, nullptr); + + for (uint32_t i = 0; i < count; i++) { + napi_value obj; + napi_create_object_with_properties(env, + null_prototype, + names, + values, + 20, + &obj); + } + + napi_call_function(env, bench_obj, end_fn, 1, &count_val, nullptr); + + return nullptr; +} + +static napi_value CreateObjectWithPropertiesOld(napi_env env, + napi_callback_info info) { + size_t argc = 4; + napi_value args[4]; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_value count_val = args[0]; + napi_value bench_obj = args[1]; + napi_value start_fn = args[2]; + napi_value end_fn = args[3]; + + uint32_t count; + napi_get_value_uint32(env, count_val, &count); + + napi_value names[20]; + napi_value values[20]; + + CreateTestProperties(env, names, values); + + napi_call_function(env, bench_obj, start_fn, 0, nullptr, nullptr); + + for (uint32_t i = 0; i < count; i++) { + napi_value obj; + napi_create_object(env, &obj); + napi_set_property(env, obj, names[0], values[0]); + napi_set_property(env, obj, names[1], values[1]); + napi_set_property(env, obj, names[2], values[2]); + napi_set_property(env, obj, names[3], values[3]); + napi_set_property(env, obj, names[4], values[4]); + napi_set_property(env, obj, names[5], values[5]); + napi_set_property(env, obj, names[6], values[6]); + napi_set_property(env, obj, names[7], values[7]); + napi_set_property(env, obj, names[8], values[8]); + napi_set_property(env, obj, names[9], values[9]); + napi_set_property(env, obj, names[10], values[10]); + napi_set_property(env, obj, names[11], values[11]); + napi_set_property(env, obj, names[12], values[12]); + napi_set_property(env, obj, names[13], values[13]); + napi_set_property(env, obj, names[14], values[14]); + napi_set_property(env, obj, names[15], values[15]); + napi_set_property(env, obj, names[16], values[16]); + napi_set_property(env, obj, names[17], values[17]); + napi_set_property(env, obj, names[18], values[18]); + napi_set_property(env, obj, names[19], values[19]); + } + + napi_call_function(env, bench_obj, end_fn, 1, &count_val, nullptr); + + return nullptr; +} + +NAPI_MODULE_INIT() { + napi_property_descriptor desc[] = { + { "createObjectWithPropertiesNew", 0, CreateObjectWithPropertiesNew, 0, 0, + 0, napi_default, 0 }, + { "createObjectWithPropertiesOld", 0, CreateObjectWithPropertiesOld, 0, 0, + 0, napi_default, 0 }, + }; + + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} + diff --git a/benchmark/napi/create_object_with_properties/binding.gyp b/benchmark/napi/create_object_with_properties/binding.gyp new file mode 100644 index 00000000000000..14e4bebc933376 --- /dev/null +++ b/benchmark/napi/create_object_with_properties/binding.gyp @@ -0,0 +1,9 @@ +{ + 'targets': [ + { + 'target_name': 'binding', + 'sources': [ 'binding.cc' ], + 'defines': ['NAPI_VERSION=8'] + } + ] +} \ No newline at end of file diff --git a/benchmark/napi/create_object_with_properties/index.js b/benchmark/napi/create_object_with_properties/index.js new file mode 100644 index 00000000000000..b099697dd0188f --- /dev/null +++ b/benchmark/napi/create_object_with_properties/index.js @@ -0,0 +1,24 @@ +'use strict'; + +const common = require('../../common.js'); + +let binding; +try { + binding = require(`./build/${common.buildType}/binding`); +} catch { + console.error(`${__filename}: Binding failed to load`); + process.exit(0); +} + +const bench = common.createBenchmark(main, { + n: [1e2, 1e3, 1e4, 1e5, 1e6], + method: ['new', 'old'], +}); + +function main({ n, method }) { + if (method === 'new') { + binding.createObjectWithPropertiesNew(n, bench, bench.start, bench.end); + } else { + binding.createObjectWithPropertiesOld(n, bench, bench.start, bench.end); + } +} From 1742953a222d2ecc0cca31cf56aa80403cb56924 Mon Sep 17 00:00:00 2001 From: Miguel Marcondes Date: Sat, 20 Sep 2025 19:25:06 -0300 Subject: [PATCH 04/15] doc: add napi_create_object_with_properties API --- doc/api/n-api.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 0309e36b82c34a..857f1ac5ec2a80 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -2637,6 +2637,41 @@ It is the equivalent of doing `new Object()` in JavaScript. The JavaScript `Object` type is described in [Section object type][] of the ECMAScript Language Specification. +#### `napi_create_object_with_properties` + + + +```c +napi_status napi_create_object_with_properties(napi_env env, + napi_value prototype_or_null, + const napi_value* property_names, + const napi_value* property_values, + size_t property_count, + napi_value* result) +``` + +* `[in] env`: The environment that the API is invoked under. +* `[in] prototype_or_null`: The prototype object for the new object, or `null` + for no prototype. +* `[in] property_names`: Array of `napi_value` representing the property names. +* `[in] property_values`: Array of `napi_value` representing the property values. +* `[in] property_count`: Number of properties in the arrays. +* `[out] result`: A `napi_value` representing a JavaScript `Object`. + +Returns `napi_ok` if the API succeeded. + +This API creates a JavaScript `Object` with the specified prototype and +properties. This is more efficient than calling `napi_create_object` followed +by multiple `napi_set_property` calls, as it can create the object with all +properties atomically, avoiding potential V8 map transitions. + +The arrays `property_names` and `property_values` must have the same length +specified by `property_count`. The properties are added to the object in the +order they appear in the arrays. + #### `napi_create_symbol` -```c +```cpp napi_status napi_create_object_with_properties(napi_env env, napi_value prototype_or_null, const napi_value* property_names, @@ -2654,8 +2654,9 @@ napi_status napi_create_object_with_properties(napi_env env, ``` * `[in] env`: The environment that the API is invoked under. -* `[in] prototype_or_null`: The prototype object for the new object, or `null` - for no prototype. +* `[in] prototype_or_null`: The prototype object for the new object. Can be a + `napi_value` representing a JavaScript object to use as the prototype, a + `napi_value` representing JavaScript `null`, or a `nullptr` that will be converted to `null`. * `[in] property_names`: Array of `napi_value` representing the property names. * `[in] property_values`: Array of `napi_value` representing the property values. * `[in] property_count`: Number of properties in the arrays. diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index 0f9f9c1278b68d..4effc878554f42 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -1606,8 +1606,12 @@ napi_create_object_with_properties(napi_env env, CHECK_ARG(env, property_values); } - v8::Local v8_prototype_or_null = - v8impl::V8LocalValueFromJsValue(prototype_or_null); + v8::Local v8_prototype_or_null; + if (prototype_or_null == nullptr) { + v8_prototype_or_null = v8::Null(env->isolate); + } else { + v8_prototype_or_null = v8impl::V8LocalValueFromJsValue(prototype_or_null); + } v8::LocalVector v8_names(env->isolate, property_count); v8::LocalVector v8_values(env->isolate, property_count); From d1c651989be4d48db12c8208f222049135512106 Mon Sep 17 00:00:00 2001 From: Miguel Marcondes Filho Date: Thu, 16 Oct 2025 16:30:54 -0300 Subject: [PATCH 10/15] test: asserting object is created with specified property Co-authored-by: Chengzhong Wu --- test/js-native-api/test_object/test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/js-native-api/test_object/test.js b/test/js-native-api/test_object/test.js index a1123ae23bfd64..603f7d765aa703 100644 --- a/test/js-native-api/test_object/test.js +++ b/test/js-native-api/test_object/test.js @@ -404,6 +404,7 @@ assert.deepStrictEqual(test_object.TestGetProperty(), { const objectWithCustomPrototype = test_object.TestCreateObjectWithCustomPrototype(); assert.strictEqual(typeof objectWithCustomPrototype, 'object'); + assert.deepStrictEqual(Object.getOwnPropertyNames(objectWithCustomPrototype), ['value']); assert.strictEqual(objectWithCustomPrototype.value, 42); assert.strictEqual(typeof objectWithCustomPrototype.test, 'function'); } From af3d9ecf34a0519ef81c7cf63dcaa9e2eb3dc7d3 Mon Sep 17 00:00:00 2001 From: Miguel Marcondes Filho Date: Thu, 16 Oct 2025 16:31:36 -0300 Subject: [PATCH 11/15] doc: add experimental flag Co-authored-by: Chengzhong Wu --- doc/api/n-api.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 3c47a7d2b728ad..4a8f434a3a17d8 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -2641,9 +2641,10 @@ ECMAScript Language Specification. +> Stability: 1 - Experimental + ```cpp napi_status napi_create_object_with_properties(napi_env env, napi_value prototype_or_null, From 4ada4c24d02e1f4981fc8cb2a657a9ab2d84d832 Mon Sep 17 00:00:00 2001 From: Miguel Marcondes Filho Date: Thu, 16 Oct 2025 16:32:09 -0300 Subject: [PATCH 12/15] test: test prototype with NULL value Co-authored-by: Chengzhong Wu --- test/js-native-api/test_object/test_object.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/js-native-api/test_object/test_object.c b/test/js-native-api/test_object/test_object.c index fb45d1b6da8caf..82085b9430a4be 100644 --- a/test/js-native-api/test_object/test_object.c +++ b/test/js-native-api/test_object/test_object.c @@ -743,10 +743,9 @@ static napi_value TestCreateObjectWithPropertiesEmpty(napi_env env, napi_value result; napi_value null_prototype; - NODE_API_CALL(env, napi_get_null(env, &null_prototype)); NODE_API_CALL(env, napi_create_object_with_properties( - env, null_prototype, NULL, NULL, 0, &result)); + env, NULL, NULL, NULL, 0, &result)); return result; } From 8866c025c1aac1a511259936fde41f7e9de818d4 Mon Sep 17 00:00:00 2001 From: Miguel Marcondes Date: Thu, 16 Oct 2025 16:42:55 -0300 Subject: [PATCH 13/15] test: format NODE_API_CALL --- test/js-native-api/test_object/test_object.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/js-native-api/test_object/test_object.c b/test/js-native-api/test_object/test_object.c index 82085b9430a4be..025419cf1d0740 100644 --- a/test/js-native-api/test_object/test_object.c +++ b/test/js-native-api/test_object/test_object.c @@ -743,9 +743,9 @@ static napi_value TestCreateObjectWithPropertiesEmpty(napi_env env, napi_value result; napi_value null_prototype; - NODE_API_CALL(env, - napi_create_object_with_properties( - env, NULL, NULL, NULL, 0, &result)); + NODE_API_CALL( + env, + napi_create_object_with_properties(env, NULL, NULL, NULL, 0, &result)); return result; } From 8de778245c751c46300f3c4db1764822d6029c84 Mon Sep 17 00:00:00 2001 From: Miguel Marcondes Date: Thu, 16 Oct 2025 16:45:42 -0300 Subject: [PATCH 14/15] test: remove unnecesary var --- test/js-native-api/test_object/test_object.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/js-native-api/test_object/test_object.c b/test/js-native-api/test_object/test_object.c index 025419cf1d0740..0b807f9a62342d 100644 --- a/test/js-native-api/test_object/test_object.c +++ b/test/js-native-api/test_object/test_object.c @@ -742,7 +742,6 @@ static napi_value TestCreateObjectWithPropertiesEmpty(napi_env env, napi_callback_info info) { napi_value result; - napi_value null_prototype; NODE_API_CALL( env, napi_create_object_with_properties(env, NULL, NULL, NULL, 0, &result)); From 000bfe79f523443c2c35da478d6cb2ce4e29a326 Mon Sep 17 00:00:00 2001 From: Miguel Marcondes Date: Fri, 17 Oct 2025 11:40:07 -0300 Subject: [PATCH 15/15] node-api: add experimental flag for new method --- src/js_native_api.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js_native_api.h b/src/js_native_api.h index e25295e4be5383..4e211128d5ada6 100644 --- a/src/js_native_api.h +++ b/src/js_native_api.h @@ -79,6 +79,7 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_get_boolean(napi_env env, NAPI_EXTERN napi_status NAPI_CDECL napi_create_object(napi_env env, napi_value* result); #ifdef NAPI_EXPERIMENTAL +#define NODE_API_EXPERIMENTAL_HAS_CREATE_OBJECT_WITH_PROPERTIES NAPI_EXTERN napi_status NAPI_CDECL napi_create_object_with_properties(napi_env env, napi_value prototype_or_null,