From 0add1306f60b81432da94d13683aa0b06aa52925 Mon Sep 17 00:00:00 2001 From: Charles Cabergs Date: Sat, 4 Apr 2026 17:54:13 +0200 Subject: [PATCH 1/4] feat: add String::New overload for string_view (#1706) * Add String::New overload for string_view * Add Symbol::New with string_view * Add String/Symbol::New with string view unit tests * Add doc for String and Symbol string_view constructors --- doc/string.md | 2 ++ doc/symbol.md | 4 +++- napi-inl.h | 10 ++++++++++ napi.h | 13 +++++++++++++ test/name.cc | 14 ++++++++++++++ test/name.js | 5 +++++ 6 files changed, 47 insertions(+), 1 deletion(-) diff --git a/doc/string.md b/doc/string.md index bb04f664b..7a94a4d3d 100644 --- a/doc/string.md +++ b/doc/string.md @@ -60,6 +60,7 @@ Napi::String::New(napi_env env, const char* value); Napi::String::New(napi_env env, const char16_t* value); Napi::String::New(napi_env env, const char* value, size_t length); Napi::String::New(napi_env env, const char16_t* value, size_t length); +Napi::String::New(napi_env env, std::string_view value); ``` - `[in] env`: The `napi_env` environment in which to construct the `Napi::Value` object. @@ -68,6 +69,7 @@ Napi::String::New(napi_env env, const char16_t* value, size_t length); - `std::u16string&` - represents a UTF16-LE string. - `const char*` - represents a UTF8 string. - `const char16_t*` - represents a UTF16-LE string. + - `std::string_view` - represents a UTF8 string view. - `[in] length`: The length of the string (not necessarily null-terminated) in code units. Returns a new `Napi::String` that represents the passed in C++ string. diff --git a/doc/symbol.md b/doc/symbol.md index e2332674d..d94a618ec 100644 --- a/doc/symbol.md +++ b/doc/symbol.md @@ -18,6 +18,7 @@ Returns a new empty `Napi::Symbol`. ```cpp Napi::Symbol::New(napi_env env, const std::string& description); Napi::Symbol::New(napi_env env, const char* description); +Napi::Symbol::New(napi_env env, std::string_view description); Napi::Symbol::New(napi_env env, Napi::String description); Napi::Symbol::New(napi_env env, napi_value description); ``` @@ -27,6 +28,7 @@ Napi::Symbol::New(napi_env env, napi_value description); `description` may be any of: - `std::string&` - UTF8 string description. - `const char*` - represents a UTF8 string description. + - `std::string_view` - represents a UTF8 string view. - `String` - Node addon API String description. - `napi_value` - Node-API `napi_value` description. @@ -58,4 +60,4 @@ static Napi::Symbol Napi::Symbol::For(napi_env env, napi_value description); Searches in the global registry for existing symbol with the given name. If the symbol already exist it will be returned, otherwise a new symbol will be created in the registry. It's equivalent to Symbol.for() called from JavaScript. -[`Napi::Name`]: ./name.md \ No newline at end of file +[`Napi::Name`]: ./name.md diff --git a/napi-inl.h b/napi-inl.h index 568a6baa5..7824562a3 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -18,6 +18,7 @@ #if NAPI_HAS_THREADS #include #endif // NAPI_HAS_THREADS +#include #include #include @@ -1262,6 +1263,10 @@ inline String String::New(napi_env env, const std::u16string& val) { return String::New(env, val.c_str(), val.size()); } +inline String String::New(napi_env env, std::string_view val) { + return String::New(env, val.data(), val.size()); +} + inline String String::New(napi_env env, const char* val) { // TODO(@gabrielschulhof) Remove if-statement when core's error handling is // available in all supported versions. @@ -1371,6 +1376,11 @@ inline Symbol Symbol::New(napi_env env, const std::string& description) { return Symbol::New(env, descriptionValue); } +inline Symbol Symbol::New(napi_env env, std::string_view description) { + napi_value descriptionValue = String::New(env, description); + return Symbol::New(env, descriptionValue); +} + inline Symbol Symbol::New(napi_env env, String description) { napi_value descriptionValue = description; return Symbol::New(env, descriptionValue); diff --git a/napi.h b/napi.h index 4efe551e0..ba5c5576e 100644 --- a/napi.h +++ b/napi.h @@ -19,6 +19,7 @@ #endif // NAPI_HAS_THREADS #include #include +#include #include // VS2015 RTM has bugs with constexpr, so require min of VS2015 Update 3 (known @@ -725,6 +726,11 @@ class String : public Name { const std::u16string& value ///< UTF-16 encoded C++ string ); + /// Creates a new String value from a UTF-8 encoded C++ string view. + static String New(napi_env env, ///< Node-API environment + std::string_view value ///< UTF-8 encoded C++ string view + ); + /// Creates a new String value from a UTF-8 encoded C string. static String New( napi_env env, ///< Node-API environment @@ -798,6 +804,13 @@ class Symbol : public Name { description ///< UTF-8 encoded C++ string describing the symbol ); + /// Creates a new Symbol value with a description. + static Symbol New( + napi_env env, ///< Node-API environment + std::string_view + description ///< UTF-8 encoded C++ string view describing the symbol + ); + /// Creates a new Symbol value with a description. static Symbol New(napi_env env, ///< Node-API environment String description ///< String value describing the symbol diff --git a/test/name.cc b/test/name.cc index 27bab9312..d94a3937f 100644 --- a/test/name.cc +++ b/test/name.cc @@ -1,5 +1,7 @@ #include "napi.h" +#include + using namespace Napi; const char* testValueUtf8 = "123456789"; @@ -43,6 +45,10 @@ Value CreateString(const CallbackInfo& info) { } } +Value CreateStringFromStringView(const CallbackInfo& info) { + return String::New(info.Env(), std::string_view("hello1")); +} + Value CheckString(const CallbackInfo& info) { String value = info[0].As(); String encoding = info[1].As(); @@ -80,6 +86,10 @@ Value CreateSymbol(const CallbackInfo& info) { } } +Value CreateSymbolFromStringView(const CallbackInfo& info) { + return Symbol::New(info.Env(), std::string_view("hello2")); +} + Value CheckSymbol(const CallbackInfo& info) { return Boolean::New(info.Env(), info[0].Type() == napi_symbol); } @@ -99,11 +109,15 @@ Object InitName(Env env) { exports["echoString"] = Function::New(env, EchoString); exports["createString"] = Function::New(env, CreateString); + exports["createStringFromStringView"] = + Function::New(env, CreateStringFromStringView); exports["nullStringShouldThrow"] = Function::New(env, NullStringShouldThrow); exports["nullString16ShouldThrow"] = Function::New(env, NullString16ShouldThrow); exports["checkString"] = Function::New(env, CheckString); exports["createSymbol"] = Function::New(env, CreateSymbol); + exports["createSymbolFromStringView"] = + Function::New(env, CreateSymbolFromStringView); exports["checkSymbol"] = Function::New(env, CheckSymbol); return exports; diff --git a/test/name.js b/test/name.js index 406c533e3..8113565c8 100644 --- a/test/name.js +++ b/test/name.js @@ -56,4 +56,9 @@ function test (binding) { assert.strictEqual(binding.name.echoString(str, 'utf8'), str); assert.strictEqual(binding.name.echoString(str, 'utf16'), str); } + + assert.strictEqual(binding.name.createStringFromStringView(), 'hello1'); + const symFromStringView = binding.name.createSymbolFromStringView(); + assert.strictEqual(typeof symFromStringView, 'symbol'); + assert.strictEqual(symFromStringView.description, 'hello2'); } From f65113b6ce54271b0a26f97fc624b5574b64a048 Mon Sep 17 00:00:00 2001 From: Yilong Li Date: Wed, 15 Apr 2026 22:02:33 +0800 Subject: [PATCH 2/4] feat: add std::string_view overload for Symbol::For (#1722) --- doc/symbol.md | 9 ++++++++- napi-inl.h | 6 ++++++ napi.h | 3 +++ test/symbol.cc | 12 ++++++++++++ test/symbol.js | 1 + 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/doc/symbol.md b/doc/symbol.md index d94a618ec..4fa1ae0da 100644 --- a/doc/symbol.md +++ b/doc/symbol.md @@ -26,7 +26,7 @@ Napi::Symbol::New(napi_env env, napi_value description); - `[in] env`: The `napi_env` environment in which to construct the `Napi::Symbol` object. - `[in] value`: The C++ primitive which represents the description hint for the `Napi::Symbol`. `description` may be any of: - - `std::string&` - UTF8 string description. + - `const std::string&` - UTF8 string description. - `const char*` - represents a UTF8 string description. - `std::string_view` - represents a UTF8 string view. - `String` - Node addon API String description. @@ -50,6 +50,7 @@ Returns a `Napi::Symbol` representing a well-known `Symbol` from the ### For ```cpp static Napi::Symbol Napi::Symbol::For(napi_env env, const std::string& description); +static Napi::Symbol Napi::Symbol::For(napi_env env, std::string_view description); static Napi::Symbol Napi::Symbol::For(napi_env env, const char* description); static Napi::Symbol Napi::Symbol::For(napi_env env, String description); static Napi::Symbol Napi::Symbol::For(napi_env env, napi_value description); @@ -57,6 +58,12 @@ static Napi::Symbol Napi::Symbol::For(napi_env env, napi_value description); - `[in] env`: The `napi_env` environment in which to construct the `Napi::Symbol` object. - `[in] description`: The C++ string representing the `Napi::Symbol` in the global registry to retrieve. + `description` may be any of: + - `const std::string&` - UTF8 string description. + - `std::string_view` - represents a UTF8 string view. + - `const char*` - represents a UTF8 string description. + - `String` - Node addon API String description. + - `napi_value` - Node-API `napi_value` description. Searches in the global registry for existing symbol with the given name. If the symbol already exist it will be returned, otherwise a new symbol will be created in the registry. It's equivalent to Symbol.for() called from JavaScript. diff --git a/napi-inl.h b/napi-inl.h index 7824562a3..cc2fad6f7 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -1422,6 +1422,12 @@ inline MaybeOrValue Symbol::For(napi_env env, return Symbol::For(env, descriptionValue); } +inline MaybeOrValue Symbol::For(napi_env env, + std::string_view description) { + napi_value descriptionValue = String::New(env, description); + return Symbol::For(env, descriptionValue); +} + inline MaybeOrValue Symbol::For(napi_env env, const char* description) { napi_value descriptionValue = String::New(env, description); return Symbol::For(env, descriptionValue); diff --git a/napi.h b/napi.h index ba5c5576e..eaae1e711 100644 --- a/napi.h +++ b/napi.h @@ -828,6 +828,9 @@ class Symbol : public Name { // Create a symbol in the global registry, UTF-8 Encoded cpp string static MaybeOrValue For(napi_env env, const std::string& description); + // Create a symbol in the global registry, UTF-8 encoded cpp string view + static MaybeOrValue For(napi_env env, std::string_view description); + // Create a symbol in the global registry, C style string (null terminated) static MaybeOrValue For(napi_env env, const char* description); diff --git a/test/symbol.cc b/test/symbol.cc index 08ea80393..d978739ff 100644 --- a/test/symbol.cc +++ b/test/symbol.cc @@ -1,4 +1,7 @@ #include + +#include + #include "test_helper.h" using namespace Napi; @@ -37,6 +40,13 @@ Symbol FetchSymbolFromGlobalRegistryWithCppKey(const Napi::CallbackInfo& info) { return MaybeUnwrap(Napi::Symbol::For(info.Env(), cppStringKey.Utf8Value())); } +Symbol FetchSymbolFromGlobalRegistryWithStringViewKey( + const Napi::CallbackInfo& info) { + String cppStringKey = info[0].As(); + std::string key = cppStringKey.Utf8Value(); + return MaybeUnwrap(Napi::Symbol::For(info.Env(), std::string_view(key))); +} + Symbol FetchSymbolFromGlobalRegistryWithCKey(const Napi::CallbackInfo& info) { String cppStringKey = info[0].As(); return MaybeUnwrap( @@ -71,6 +81,8 @@ Object InitSymbol(Env env) { Function::New(env, FetchSymbolFromGlobalRegistryWithCKey); exports["getSymbolFromGlobalRegistryWithCppKey"] = Function::New(env, FetchSymbolFromGlobalRegistryWithCppKey); + exports["getSymbolFromGlobalRegistryWithStringViewKey"] = + Function::New(env, FetchSymbolFromGlobalRegistryWithStringViewKey); exports["testUndefinedSymbolCanBeCreated"] = Function::New(env, TestUndefinedSymbolsCanBeCreated); exports["testNullSymbolCanBeCreated"] = diff --git a/test/symbol.js b/test/symbol.js index bd2e3c83e..baf39c81b 100644 --- a/test/symbol.js +++ b/test/symbol.js @@ -54,6 +54,7 @@ function test (binding) { assertCanCreateOrFetchGlobalSymbols('data', binding.symbol.getSymbolFromGlobalRegistry); assertCanCreateOrFetchGlobalSymbols('CppKey', binding.symbol.getSymbolFromGlobalRegistryWithCppKey); + assertCanCreateOrFetchGlobalSymbols('StringViewKey', binding.symbol.getSymbolFromGlobalRegistryWithStringViewKey); assertCanCreateOrFetchGlobalSymbols('CKey', binding.symbol.getSymbolFromGlobalRegistryWithCKey); assert(binding.symbol.createNewSymbolWithNoArgs() === undefined); From 4de06fac744e2f16d196b14f62203e26f3ea9551 Mon Sep 17 00:00:00 2001 From: Yilong Li Date: Thu, 14 May 2026 05:04:29 +0800 Subject: [PATCH 3/4] doc: clarify filtered test behavior (#1725) - fix outdated `npm run unit` examples - explain that `--filter` affects test execution, not compilation scope - note that `npm test --filter=...` still triggers the default full rebuild --- CONTRIBUTING.md | 29 +++++++++++++++++++---------- unit-test/README.md | 22 ++++++++++++++++------ 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6485f4279..663fc2304 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -70,27 +70,37 @@ npm test --NAPI_VERSION=X where X is the version of Node-API you want to target. -To run a specific unit test, filter conditions are available +To run a subset of the test suite, filter conditions are available. +The `--filter` option limits which JavaScript test modules are executed by +`node test`. The default `pretest` step is still `node-gyp rebuild -C test`, +so `npm test --filter=...` still performs a full rebuild of the test addon +targets before the filtered tests run. **Example:** - compile and run only tests on objectwrap.cc and objectwrap.js + perform the default test rebuild, then run only the `objectwrap` test module ``` - npm run unit --filter=objectwrap + npm test --filter=objectwrap ``` -Multiple unit tests cane be selected with wildcards +Multiple test modules can be selected with wildcards. **Example:** -compile and run all test files ending with "reference" -> function_reference.cc, object_reference.cc, reference.cc +perform the default test rebuild, then run all test modules ending with +`reference`: +`function_reference`, `object_reference`, and `reference` ``` - npm run unit --filter=*reference + npm test --filter=*reference ``` -Multiple filter conditions can be joined to broaden the test selection +Multiple filter conditions can be joined to broaden the test selection. **Example:** - compile and run all tests under folders threadsafe_function and typed_threadsafe_function and also the objectwrap.cc file - npm run unit --filter='*function objectwrap' + perform the default test rebuild, then run all tests under + `threadsafe_function` and `typed_threadsafe_function`, and also the + `objectwrap` test module + ``` + npm test --filter='*function objectwrap' + ``` As an alternative, `ninja` can be used to build the tests. Please follow the instructions in [Build with ninja](doc/contributing/build_with_ninja.md). @@ -203,4 +213,3 @@ The downside of this approach is the following: authors might not find the right patterns and instead implement things themselves - There might be greater friction for the Node-API WG in evolving APIs since the ecosystem would have taken dependencies on the API shape of **node-addon-api** - diff --git a/unit-test/README.md b/unit-test/README.md index e10b1c448..2dfd5abfb 100644 --- a/unit-test/README.md +++ b/unit-test/README.md @@ -1,11 +1,17 @@ # Enable running tests with specific filter conditions: +The `--filter` option limits which test modules are executed by `node test`. +The default `pretest` step is still `node-gyp rebuild -C test`, so +`npm test --filter=...` still performs a full rebuild of the test addon +targets before the filtered tests run. + ### Example: - - compile and run only tests on objectwrap.cc and objectwrap.js + - perform the default test rebuild, then run only the `objectwrap` + test module ``` - npm run test --filter=objectwrap + npm test --filter=objectwrap ``` @@ -13,16 +19,20 @@ ### Example: - - compile and run all tests files ending with reference -> function_reference.cc object_reference.cc reference.cc + - perform the default test rebuild, then run all test modules ending + with `reference` + (`function_reference`, `object_reference`, and `reference`) ``` - npm run test --filter=*reference + npm test --filter=*reference ``` # Multiple filter conditions are also allowed ### Example: - - compile and run all tests under folders threadsafe_function and typed_threadsafe_function and also the objectwrap.cc file + - perform the default test rebuild, then run all tests under + `threadsafe_function` and `typed_threadsafe_function`, and also the + `objectwrap` test module ``` - npm run test --filter='*function objectwrap' + npm test --filter='*function objectwrap' ``` From 6a9456fa9e05b1f9886b9eeccbb8b73379f74c4a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 10:20:27 -0400 Subject: [PATCH 4/4] chore: release v8.8.0 (#1721) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ README.md | 2 +- package.json | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5fd9048a6..6139450aa 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "8.7.0" + ".": "8.8.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 69bb7d160..7917ee681 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # node-addon-api Changelog +## [8.8.0](https://github.com/nodejs/node-addon-api/compare/v8.7.0...v8.8.0) (2026-05-13) + + +### Features + +* add std::string_view overload for Symbol::For ([#1722](https://github.com/nodejs/node-addon-api/issues/1722)) ([f65113b](https://github.com/nodejs/node-addon-api/commit/f65113b6ce54271b0a26f97fc624b5574b64a048)) +* add String::New overload for string_view ([#1706](https://github.com/nodejs/node-addon-api/issues/1706)) ([0add130](https://github.com/nodejs/node-addon-api/commit/0add1306f60b81432da94d13683aa0b06aa52925)) + ## [8.7.0](https://github.com/nodejs/node-addon-api/compare/v8.6.0...v8.7.0) (2026-03-23) diff --git a/README.md b/README.md index 72a449eb2..221592218 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ and exception handling semantics with low overhead. API references are available in the [doc](doc/README.md) directory. -## Current version: 8.7.0 +## Current version: 8.8.0 (See [CHANGELOG.md](CHANGELOG.md) for complete Changelog) diff --git a/package.json b/package.json index d9b2e39bf..f245983d4 100644 --- a/package.json +++ b/package.json @@ -472,7 +472,7 @@ "lint:fix": "eslint --fix && node tools/clang-format --fix" }, "pre-commit": "lint", - "version": "8.7.0", + "version": "8.8.0", "support": true, "engines": { "node": "^18 || ^20 || >= 21"