diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 6f4d9b00205e1c..7bdbe58d07e2a2 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -3134,6 +3134,30 @@ overhead in creating/storing strings with this method. The JavaScript `string` type is described in [Section 6.1.4][] of the ECMAScript Language Specification. +> **Stability**: 1 - Experimental + +```c +napi_status NAPI_CDECL napi_set_named_property_len(napi_env env, + napi_value object, + const char* utf8name, + size_t name_length, + napi_value value); +``` + +* `[in] env`: The environment that the API is invoked under. +* `[in] object`: The JavaScript object on which to set the named property. +* `[in] utf8name`: Character buffer representing a UTF-8-encoded string. +* `[in] name_length`: The length of the string in bytes, or NAPI\_AUTO\_LENGTH if it is null-terminated. +* `[in] value`: The napi\_value representing the value to set as the named property. + Returns napi\_ok if the API succeeded. + +This API sets a named property on a JavaScript object, treating '\0' +characters as values rather than terminators. This allows for more +flexible property names, especially when dealing with virtual module +names or other scenarios where '\0' characters are used as part of the name. + +Note: This function is experimental and its stability may change in future releases. + ### Functions to convert from Node-API to C types #### `napi_get_array_length` diff --git a/src/js_native_api.h b/src/js_native_api.h index c5114651dc6b00..1f43706319e7d4 100644 --- a/src/js_native_api.h +++ b/src/js_native_api.h @@ -118,6 +118,13 @@ NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf16( napi_env env, const char16_t* str, size_t length, napi_value* result); #endif // NAPI_EXPERIMENTAL +#ifdef NAPI_EXPERIMENTAL +#define NODE_API_EXPERIMENTAL_HAS_PROPERTY_KEYS +NAPI_EXTERN napi_status NAPI_CDECL napi_set_named_property_len( + napi_env env, napi_value object, const char* utf8name, + size_t name_length, napi_value value); +#endif // NAPI_EXPERIMENTAL + NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(napi_env env, napi_value description, napi_value* result); diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index 44270df350c174..dd2a7fd5811b9f 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -1718,6 +1718,32 @@ napi_status NAPI_CDECL node_api_create_property_key_utf16(napi_env env, }); } +napi_status NAPI_CDECL napi_set_named_property_len(napi_env env, + napi_value object, + const char* utf8name, + size_t name_length, + napi_value value) { + std::u16string utf16name; + utf16name.reserve(name_length); + for (size_t i = 0; i < name_length; ++i) { + if (utf8name[i] == '\0') { + utf16name.push_back(static_cast('\0')); + } else { + utf16name.push_back(static_cast(utf8name[i])); + } + } + + napi_value result; + napi_status status = napi_set_named_property( + env, object, utf16name.data(), utf16name.length(), value); + + if (status != napi_ok) { + return status; + } + + return napi_ok; +} + napi_status NAPI_CDECL napi_create_double(napi_env env, double value, napi_value* result) { diff --git a/test/js-native-api/test_string/test_string.c b/test/js-native-api/test_string/test_string.c index 48d70bedde554b..dd1f47c48609d5 100644 --- a/test/js-native-api/test_string/test_string.c +++ b/test/js-native-api/test_string/test_string.c @@ -310,6 +310,56 @@ static napi_value TestPropertyKeyUtf16AutoLength(napi_env env, auto_length); } +static napi_value TestSetNamedPropertyLen(napi_env env, napi_callback_info info) { + size_t argc = 0; + napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr); + + if (argc < 1) { + napi_throw_error(env, nullptr, "Invalid number of arguments"); + return nullptr; + } + + napi_value object; + napi_create_object(env, &object); + + const char* key = "\0test"; + napi_value value; + napi_create_int32(env, 42, &value); + + napi_status status = napi_set_named_property_len(env, object, key, strlen(key), value); + if (status != napi_ok) { + napi_throw_error(env, nullptr, "Failed to set named property"); + return nullptr; + } + + return object; +} + +static napi_value TestSetNamedPropertyLenAutoLength(napi_env env, napi_callback_info info) { + size_t argc = 0; + napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr); + + if (argc < 1) { + napi_throw_error(env, nullptr, "Invalid number of arguments"); + return nullptr; + } + + napi_value object; + napi_create_object(env, &object); + + const char* key = "\0test"; + napi_value value; + napi_create_int32(env, 42, &value); + + napi_status status = napi_set_named_property_len(env, object, key, strlen(key), value); + if (status != napi_ok) { + napi_throw_error(env, nullptr, "Failed to set named property"); + return nullptr; + } + + return object; +} + static napi_value Utf16Length(napi_env env, napi_callback_info info) { napi_value args[1]; NODE_API_CALL(env, validate_and_retrieve_single_string_arg(env, info, args));