diff --git a/.changeset/slimy-parts-admire.md b/.changeset/slimy-parts-admire.md new file mode 100644 index 00000000..de6b0ed2 --- /dev/null +++ b/.changeset/slimy-parts-admire.md @@ -0,0 +1,5 @@ +--- +"weak-node-api": minor +--- + +Renamed WeakNodeApiHost to NodeApiHost diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 63da3100..3676c622 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -99,7 +99,7 @@ jobs: - run: npm ci - run: npm run build - name: Prepare weak-node-api - run: npm run prepare-weak-node-api --workspace weak-node-api + run: npm run prebuild:prepare --workspace weak-node-api - name: Build and run weak-node-api C++ tests run: | cmake -S . -B build -DBUILD_TESTS=ON @@ -215,7 +215,7 @@ jobs: sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - name: Build weak-node-api for all Android architectures - run: npm run build-weak-node-api:android --workspace weak-node-api + run: npm run prebuild:build:android --workspace weak-node-api - name: Build ferric-example for all architectures run: npm run build -- --android working-directory: packages/ferric-example @@ -270,8 +270,8 @@ jobs: - run: npm run build - name: Build weak-node-api for all Apple architectures run: | - npm run prepare-weak-node-api --workspace weak-node-api - npm run build-weak-node-api:apple --workspace weak-node-api + npm run prebuild:prepare --workspace weak-node-api + npm run prebuild:build:apple --workspace weak-node-api # Build Ferric example for all Apple architectures - run: npx ferric --apple working-directory: packages/ferric-example diff --git a/package.json b/package.json index 7c4400dc..72dab66e 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "prettier:write": "prettier --experimental-cli --write .", "test": "npm test --workspace react-native-node-api --workspace cmake-rn --workspace gyp-to-cmake --workspace node-addon-examples", "bootstrap": "node --run build && npm run bootstrap --workspaces --if-present", - "prerelease": "node --run build && npm run prerelease --workspaces --if-present", "changeset": "changeset", "release": "changeset publish", "init-macos-test-app": "node scripts/init-macos-test-app.ts" diff --git a/packages/host/android/build.gradle b/packages/host/android/build.gradle index 46b7aae9..39204133 100644 --- a/packages/host/android/build.gradle +++ b/packages/host/android/build.gradle @@ -67,7 +67,7 @@ def supportsNamespace() { android { if (supportsNamespace()) { - namespace "com.callstack.node_api_modules" + namespace "com.callstack.react_native_node_api" sourceSets { main { diff --git a/packages/host/android/src/main/AndroidManifest.xml b/packages/host/android/src/main/AndroidManifest.xml index 99212aac..1b416675 100644 --- a/packages/host/android/src/main/AndroidManifest.xml +++ b/packages/host/android/src/main/AndroidManifest.xml @@ -1,3 +1,3 @@ + package="com.callstack.react_native_node_api"> diff --git a/packages/host/android/src/main/cpp/OnLoad.cpp b/packages/host/android/src/main/cpp/OnLoad.cpp index 35e27128..3cd6f306 100644 --- a/packages/host/android/src/main/cpp/OnLoad.cpp +++ b/packages/host/android/src/main/cpp/OnLoad.cpp @@ -7,13 +7,13 @@ // Called when the library is loaded jint JNI_OnLoad(JavaVM *vm, void *reserved) { - callstack::nodeapihost::injectIntoWeakNodeApi(); + callstack::react_native_node_api::injectIntoWeakNodeApi(); // Register the C++ TurboModule facebook::react::registerCxxModuleToGlobalModuleMap( - callstack::nodeapihost::CxxNodeApiHostModule::kModuleName, + callstack::react_native_node_api::CxxNodeApiHostModule::kModuleName, [](std::shared_ptr jsInvoker) { - return std::make_shared( - jsInvoker); + return std::make_shared< + callstack::react_native_node_api::CxxNodeApiHostModule>(jsInvoker); }); return JNI_VERSION_1_6; } diff --git a/packages/host/android/src/main/java/com/callstack/node_api_modules/NodeApiModulesPackage.kt b/packages/host/android/src/main/java/com/callstack/react_native_node_api/NodeApiHostPackage.kt similarity index 89% rename from packages/host/android/src/main/java/com/callstack/node_api_modules/NodeApiModulesPackage.kt rename to packages/host/android/src/main/java/com/callstack/react_native_node_api/NodeApiHostPackage.kt index 105d347e..38426367 100644 --- a/packages/host/android/src/main/java/com/callstack/node_api_modules/NodeApiModulesPackage.kt +++ b/packages/host/android/src/main/java/com/callstack/react_native_node_api/NodeApiHostPackage.kt @@ -1,4 +1,4 @@ -package com.callstack.node_api_modules +package com.callstack.react_native_node_api import com.facebook.hermes.reactexecutor.HermesExecutor import com.facebook.react.BaseReactPackage @@ -10,7 +10,7 @@ import com.facebook.soloader.SoLoader import java.util.HashMap -class NodeApiModulesPackage : BaseReactPackage() { +class NodeApiHostPackage : BaseReactPackage() { init { SoLoader.loadLibrary("node-api-host") } diff --git a/packages/host/apple/NodeApiHostModuleProvider.mm b/packages/host/apple/NodeApiHostModuleProvider.mm index b01c5306..1ea633fe 100644 --- a/packages/host/apple/NodeApiHostModuleProvider.mm +++ b/packages/host/apple/NodeApiHostModuleProvider.mm @@ -2,19 +2,19 @@ #import "WeakNodeApiInjector.hpp" #import -@interface NodeApiHost : NSObject +@interface NodeApiHostPackage : NSObject @end -@implementation NodeApiHost +@implementation NodeApiHostPackage + (void)load { - callstack::nodeapihost::injectIntoWeakNodeApi(); + callstack::react_native_node_api::injectIntoWeakNodeApi(); facebook::react::registerCxxModuleToGlobalModuleMap( - callstack::nodeapihost::CxxNodeApiHostModule::kModuleName, + callstack::react_native_node_api::CxxNodeApiHostModule::kModuleName, [](std::shared_ptr jsInvoker) { - return std::make_shared( - jsInvoker); + return std::make_shared< + callstack::react_native_node_api::CxxNodeApiHostModule>(jsInvoker); }); } diff --git a/packages/host/cpp/AddonLoaders.hpp b/packages/host/cpp/AddonLoaders.hpp index d0d5d269..2836bdfa 100644 --- a/packages/host/cpp/AddonLoaders.hpp +++ b/packages/host/cpp/AddonLoaders.hpp @@ -7,7 +7,7 @@ #include #include -using callstack::nodeapihost::log_debug; +using callstack::react_native_node_api::log_debug; struct PosixLoader { using Module = void *; diff --git a/packages/host/cpp/CxxNodeApiHostModule.cpp b/packages/host/cpp/CxxNodeApiHostModule.cpp index 950c7af6..0b1961ec 100644 --- a/packages/host/cpp/CxxNodeApiHostModule.cpp +++ b/packages/host/cpp/CxxNodeApiHostModule.cpp @@ -4,7 +4,7 @@ using namespace facebook; -namespace callstack::nodeapihost { +namespace callstack::react_native_node_api { CxxNodeApiHostModule::CxxNodeApiHostModule( std::shared_ptr jsInvoker) @@ -127,8 +127,8 @@ bool CxxNodeApiHostModule::initializeNodeModule(jsi::Runtime &rt, napi_set_named_property(env, global, addon.generatedName.data(), exports); assert(status == napi_ok); - callstack::nodeapihost::setCallInvoker(env, callInvoker_); + callstack::react_native_node_api::setCallInvoker(env, callInvoker_); return true; } -} // namespace callstack::nodeapihost +} // namespace callstack::react_native_node_api diff --git a/packages/host/cpp/CxxNodeApiHostModule.hpp b/packages/host/cpp/CxxNodeApiHostModule.hpp index 9445cdaf..4c753cfe 100644 --- a/packages/host/cpp/CxxNodeApiHostModule.hpp +++ b/packages/host/cpp/CxxNodeApiHostModule.hpp @@ -6,7 +6,7 @@ #include "AddonLoaders.hpp" -namespace callstack::nodeapihost { +namespace callstack::react_native_node_api { class JSI_EXPORT CxxNodeApiHostModule : public facebook::react::TurboModule { public: @@ -37,4 +37,4 @@ class JSI_EXPORT CxxNodeApiHostModule : public facebook::react::TurboModule { bool initializeNodeModule(facebook::jsi::Runtime &rt, NodeAddon &addon); }; -} // namespace callstack::nodeapihost +} // namespace callstack::react_native_node_api diff --git a/packages/host/cpp/Logger.cpp b/packages/host/cpp/Logger.cpp index 0d2a9c9f..b863fcdf 100644 --- a/packages/host/cpp/Logger.cpp +++ b/packages/host/cpp/Logger.cpp @@ -16,33 +16,33 @@ enum class LogLevel { Debug, Warning, Error }; constexpr std::string_view levelToString(LogLevel level) { switch (level) { - case LogLevel::Debug: - return "DEBUG"; - case LogLevel::Warning: - return "WARNING"; - case LogLevel::Error: - return "ERROR"; - default: - return "UNKNOWN"; + case LogLevel::Debug: + return "DEBUG"; + case LogLevel::Warning: + return "WARNING"; + case LogLevel::Error: + return "ERROR"; + default: + return "UNKNOWN"; } } #if defined(__ANDROID__) constexpr int androidLogLevel(LogLevel level) { switch (level) { - case LogLevel::Debug: - return ANDROID_LOG_DEBUG; - case LogLevel::Warning: - return ANDROID_LOG_WARN; - case LogLevel::Error: - return ANDROID_LOG_ERROR; - default: - return ANDROID_LOG_UNKNOWN; + case LogLevel::Debug: + return ANDROID_LOG_DEBUG; + case LogLevel::Warning: + return ANDROID_LOG_WARN; + case LogLevel::Error: + return ANDROID_LOG_ERROR; + default: + return ANDROID_LOG_UNKNOWN; } } #endif -void log_message_internal(LogLevel level, const char* format, va_list args) { +void log_message_internal(LogLevel level, const char *format, va_list args) { #if defined(__ANDROID__) __android_log_vprint(androidLogLevel(level), LOG_TAG, format, args); #elif defined(__APPLE__) @@ -59,27 +59,27 @@ void log_message_internal(LogLevel level, const char* format, va_list args) { fprintf(stdout, "\n"); #endif } -} // anonymous namespace +} // anonymous namespace -namespace callstack::nodeapihost { +namespace callstack::react_native_node_api { -void log_debug(const char* format, ...) { +void log_debug(const char *format, ...) { // TODO: Disable logging in release builds va_list args; va_start(args, format); log_message_internal(LogLevel::Debug, format, args); va_end(args); } -void log_warning(const char* format, ...) { +void log_warning(const char *format, ...) { va_list args; va_start(args, format); log_message_internal(LogLevel::Warning, format, args); va_end(args); } -void log_error(const char* format, ...) { +void log_error(const char *format, ...) { va_list args; va_start(args, format); log_message_internal(LogLevel::Error, format, args); va_end(args); } -} // namespace callstack::nodeapihost +} // namespace callstack::react_native_node_api diff --git a/packages/host/cpp/Logger.hpp b/packages/host/cpp/Logger.hpp index 350e3f21..c064e7da 100644 --- a/packages/host/cpp/Logger.hpp +++ b/packages/host/cpp/Logger.hpp @@ -2,8 +2,8 @@ #include -namespace callstack::nodeapihost { -void log_debug(const char* format, ...); -void log_warning(const char* format, ...); -void log_error(const char* format, ...); -} // namespace callstack::nodeapihost +namespace callstack::react_native_node_api { +void log_debug(const char *format, ...); +void log_warning(const char *format, ...); +void log_error(const char *format, ...); +} // namespace callstack::react_native_node_api diff --git a/packages/host/cpp/RuntimeNodeApi.cpp b/packages/host/cpp/RuntimeNodeApi.cpp index 3c4d773c..c4e1c44c 100644 --- a/packages/host/cpp/RuntimeNodeApi.cpp +++ b/packages/host/cpp/RuntimeNodeApi.cpp @@ -1,14 +1,14 @@ #include "RuntimeNodeApi.hpp" -#include #include "Logger.hpp" #include "Versions.hpp" +#include auto ArrayType = napi_uint8_array; -namespace callstack::nodeapihost { +namespace callstack::react_native_node_api { -napi_status napi_create_buffer( - napi_env env, size_t length, void** data, napi_value* result) { +napi_status napi_create_buffer(napi_env env, size_t length, void **data, + napi_value *result) { napi_value buffer; if (const auto status = napi_create_arraybuffer(env, length, data, &buffer); status != napi_ok) { @@ -22,17 +22,15 @@ napi_status napi_create_buffer( return napi_create_typedarray(env, ArrayType, length, buffer, 0, result); } -napi_status napi_create_buffer_copy(napi_env env, - size_t length, - const void* data, - void** result_data, - napi_value* result) { +napi_status napi_create_buffer_copy(napi_env env, size_t length, + const void *data, void **result_data, + napi_value *result) { if (!length || !data || !result) { return napi_invalid_arg; } void *buffer = nullptr; - if (const auto status = callstack::nodeapihost::napi_create_buffer( + if (const auto status = callstack::react_native_node_api::napi_create_buffer( env, length, &buffer, result); status != napi_ok) { return status; @@ -42,7 +40,7 @@ napi_status napi_create_buffer_copy(napi_env env, return napi_ok; } -napi_status napi_is_buffer(napi_env env, napi_value value, bool* result) { +napi_status napi_is_buffer(napi_env env, napi_value value, bool *result) { if (!result) { return napi_invalid_arg; } @@ -77,8 +75,8 @@ napi_status napi_is_buffer(napi_env env, napi_value value, bool* result) { return napi_ok; } -napi_status napi_get_buffer_info( - napi_env env, napi_value value, void** data, size_t* length) { +napi_status napi_get_buffer_info(napi_env env, napi_value value, void **data, + size_t *length) { if (!data || !length) { return napi_invalid_arg; } @@ -97,19 +95,17 @@ napi_status napi_get_buffer_info( auto isTypedArray{false}; if (const auto status = napi_is_typedarray(env, value, &isTypedArray); status == napi_ok && isTypedArray) { - return napi_get_typedarray_info( - env, value, &ArrayType, length, data, nullptr, nullptr); + return napi_get_typedarray_info(env, value, &ArrayType, length, data, + nullptr, nullptr); } return napi_ok; } -napi_status napi_create_external_buffer(napi_env env, - size_t length, - void* data, - node_api_basic_finalize basic_finalize_cb, - void* finalize_hint, - napi_value* result) { +napi_status +napi_create_external_buffer(napi_env env, size_t length, void *data, + node_api_basic_finalize basic_finalize_cb, + void *finalize_hint, napi_value *result) { napi_value buffer; if (const auto status = napi_create_external_arraybuffer( env, data, length, basic_finalize_cb, finalize_hint, &buffer); @@ -124,25 +120,20 @@ napi_status napi_create_external_buffer(napi_env env, return napi_create_typedarray(env, ArrayType, length, buffer, 0, result); } -void napi_fatal_error(const char* location, - size_t location_len, - const char* message, - size_t message_len) { +void napi_fatal_error(const char *location, size_t location_len, + const char *message, size_t message_len) { if (location && location_len) { - log_error("Fatal Node-API error: %.*s %.*s", - static_cast(location_len), - location, - static_cast(message_len), - message); + log_error("Fatal Node-API error: %.*s %.*s", static_cast(location_len), + location, static_cast(message_len), message); } else { - log_error( - "Fatal Node-API error: %.*s", static_cast(message_len), message); + log_error("Fatal Node-API error: %.*s", static_cast(message_len), + message); } abort(); } -napi_status napi_get_node_version( - node_api_basic_env env, const napi_node_version** result) { +napi_status napi_get_node_version(node_api_basic_env env, + const napi_node_version **result) { if (!result) { return napi_invalid_arg; } @@ -151,7 +142,7 @@ napi_status napi_get_node_version( return napi_generic_failure; } -napi_status napi_get_version(node_api_basic_env env, uint32_t* result) { +napi_status napi_get_version(node_api_basic_env env, uint32_t *result) { if (!result) { return napi_invalid_arg; } @@ -160,4 +151,4 @@ napi_status napi_get_version(node_api_basic_env env, uint32_t* result) { return napi_ok; } -} // namespace callstack::nodeapihost +} // namespace callstack::react_native_node_api diff --git a/packages/host/cpp/RuntimeNodeApi.hpp b/packages/host/cpp/RuntimeNodeApi.hpp index 67da7856..1a5e62ea 100644 --- a/packages/host/cpp/RuntimeNodeApi.hpp +++ b/packages/host/cpp/RuntimeNodeApi.hpp @@ -2,35 +2,31 @@ #include "node_api.h" -namespace callstack::nodeapihost { -napi_status napi_create_buffer( - napi_env env, size_t length, void** data, napi_value* result); - -napi_status napi_create_buffer_copy(napi_env env, - size_t length, - const void* data, - void** result_data, - napi_value* result); - -napi_status napi_is_buffer(napi_env env, napi_value value, bool* result); - -napi_status napi_get_buffer_info( - napi_env env, napi_value value, void** data, size_t* length); - -napi_status napi_create_external_buffer(napi_env env, - size_t length, - void* data, - node_api_basic_finalize basic_finalize_cb, - void* finalize_hint, - napi_value* result); - -void __attribute__((noreturn)) napi_fatal_error(const char* location, - size_t location_len, - const char* message, - size_t message_len); - -napi_status napi_get_node_version( - node_api_basic_env env, const napi_node_version** result); - -napi_status napi_get_version(node_api_basic_env env, uint32_t* result); -} // namespace callstack::nodeapihost +namespace callstack::react_native_node_api { +napi_status napi_create_buffer(napi_env env, size_t length, void **data, + napi_value *result); + +napi_status napi_create_buffer_copy(napi_env env, size_t length, + const void *data, void **result_data, + napi_value *result); + +napi_status napi_is_buffer(napi_env env, napi_value value, bool *result); + +napi_status napi_get_buffer_info(napi_env env, napi_value value, void **data, + size_t *length); + +napi_status +napi_create_external_buffer(napi_env env, size_t length, void *data, + node_api_basic_finalize basic_finalize_cb, + void *finalize_hint, napi_value *result); + +void __attribute__((noreturn)) napi_fatal_error(const char *location, + size_t location_len, + const char *message, + size_t message_len); + +napi_status napi_get_node_version(node_api_basic_env env, + const napi_node_version **result); + +napi_status napi_get_version(node_api_basic_env env, uint32_t *result); +} // namespace callstack::react_native_node_api diff --git a/packages/host/cpp/RuntimeNodeApiAsync.cpp b/packages/host/cpp/RuntimeNodeApiAsync.cpp index dd4c87c3..bee380a7 100644 --- a/packages/host/cpp/RuntimeNodeApiAsync.cpp +++ b/packages/host/cpp/RuntimeNodeApiAsync.cpp @@ -1,6 +1,6 @@ #include "RuntimeNodeApiAsync.hpp" -#include #include "Logger.hpp" +#include struct AsyncJob { using IdType = uint64_t; @@ -13,26 +13,25 @@ struct AsyncJob { napi_value async_resource_name; napi_async_execute_callback execute; napi_async_complete_callback complete; - void* data{nullptr}; + void *data{nullptr}; - static AsyncJob* fromWork(napi_async_work work) { - return reinterpret_cast(work); + static AsyncJob *fromWork(napi_async_work work) { + return reinterpret_cast(work); } - static napi_async_work toWork(AsyncJob* job) { + static napi_async_work toWork(AsyncJob *job) { return reinterpret_cast(job); } }; class AsyncWorkRegistry { - public: +public: using IdType = AsyncJob::IdType; - std::shared_ptr create(napi_env env, - napi_value async_resource, - napi_value async_resource_name, - napi_async_execute_callback execute, - napi_async_complete_callback complete, - void* data) { + std::shared_ptr create(napi_env env, napi_value async_resource, + napi_value async_resource_name, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void *data) { const auto job = std::shared_ptr(new AsyncJob{ .id = next_id(), .state = AsyncJob::State::Created, @@ -68,7 +67,7 @@ class AsyncWorkRegistry { return false; } - private: +private: IdType next_id() { if (current_id_ == std::numeric_limits::max()) [[unlikely]] { current_id_ = 0; @@ -84,10 +83,11 @@ static std::unordered_map> callInvokers; static AsyncWorkRegistry asyncWorkRegistry; -namespace callstack::nodeapihost { +namespace callstack::react_native_node_api { -void setCallInvoker(napi_env env, - const std::shared_ptr& invoker) { +void setCallInvoker( + napi_env env, + const std::shared_ptr &invoker) { callInvokers[env] = invoker; } @@ -97,13 +97,11 @@ std::weak_ptr getCallInvoker(napi_env env) { : std::weak_ptr{}; } -napi_status napi_create_async_work(napi_env env, - napi_value async_resource, - napi_value async_resource_name, - napi_async_execute_callback execute, - napi_async_complete_callback complete, - void* data, - napi_async_work* result) { +napi_status napi_create_async_work(napi_env env, napi_value async_resource, + napi_value async_resource_name, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void *data, napi_async_work *result) { const auto job = asyncWorkRegistry.create( env, async_resource, async_resource_name, execute, complete, data); if (!job) { @@ -115,8 +113,8 @@ napi_status napi_create_async_work(napi_env env, return napi_ok; } -napi_status napi_queue_async_work( - node_api_basic_env env, napi_async_work work) { +napi_status napi_queue_async_work(node_api_basic_env env, + napi_async_work work) { const auto job = asyncWorkRegistry.get(work); if (!job) { log_debug("Error: Received null job in napi_queue_async_work"); @@ -140,8 +138,9 @@ napi_status napi_queue_async_work( } job->complete(env, - job->state == AsyncJob::State::Cancelled ? napi_cancelled : napi_ok, - job->data); + job->state == AsyncJob::State::Cancelled ? napi_cancelled + : napi_ok, + job->data); job->state = AsyncJob::State::Completed; }); @@ -149,8 +148,8 @@ napi_status napi_queue_async_work( return napi_ok; } -napi_status napi_delete_async_work( - node_api_basic_env env, napi_async_work work) { +napi_status napi_delete_async_work(node_api_basic_env env, + napi_async_work work) { const auto job = asyncWorkRegistry.get(work); if (!job) { log_debug("Error: Received non-existent job in napi_delete_async_work"); @@ -165,26 +164,26 @@ napi_status napi_delete_async_work( return napi_ok; } -napi_status napi_cancel_async_work( - node_api_basic_env env, napi_async_work work) { +napi_status napi_cancel_async_work(node_api_basic_env env, + napi_async_work work) { const auto job = asyncWorkRegistry.get(work); if (!job) { log_debug("Error: Received null job in napi_cancel_async_work"); return napi_invalid_arg; } switch (job->state) { - case AsyncJob::State::Completed: - log_debug("Error: Cannot cancel async work that is already completed"); - return napi_generic_failure; - case AsyncJob::State::Deleted: - log_debug("Warning: Async work job is already deleted"); - return napi_generic_failure; - case AsyncJob::State::Cancelled: - log_debug("Warning: Async work job is already cancelled"); - return napi_ok; + case AsyncJob::State::Completed: + log_debug("Error: Cannot cancel async work that is already completed"); + return napi_generic_failure; + case AsyncJob::State::Deleted: + log_debug("Warning: Async work job is already deleted"); + return napi_generic_failure; + case AsyncJob::State::Cancelled: + log_debug("Warning: Async work job is already cancelled"); + return napi_ok; } job->state = AsyncJob::State::Cancelled; return napi_ok; } -} // namespace callstack::nodeapihost +} // namespace callstack::react_native_node_api diff --git a/packages/host/cpp/RuntimeNodeApiAsync.hpp b/packages/host/cpp/RuntimeNodeApiAsync.hpp index f0108e6d..be20128c 100644 --- a/packages/host/cpp/RuntimeNodeApiAsync.hpp +++ b/packages/host/cpp/RuntimeNodeApiAsync.hpp @@ -1,26 +1,24 @@ #pragma once +#include "node_api.h" #include #include -#include "node_api.h" -namespace callstack::nodeapihost { +namespace callstack::react_native_node_api { void setCallInvoker( - napi_env env, const std::shared_ptr& invoker); + napi_env env, const std::shared_ptr &invoker); -napi_status napi_create_async_work(napi_env env, - napi_value async_resource, - napi_value async_resource_name, - napi_async_execute_callback execute, - napi_async_complete_callback complete, - void* data, - napi_async_work* result); +napi_status napi_create_async_work(napi_env env, napi_value async_resource, + napi_value async_resource_name, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void *data, napi_async_work *result); napi_status napi_queue_async_work(node_api_basic_env env, napi_async_work work); -napi_status napi_delete_async_work( - node_api_basic_env env, napi_async_work work); +napi_status napi_delete_async_work(node_api_basic_env env, + napi_async_work work); -napi_status napi_cancel_async_work( - node_api_basic_env env, napi_async_work work); -} // namespace callstack::nodeapihost +napi_status napi_cancel_async_work(node_api_basic_env env, + napi_async_work work); +} // namespace callstack::react_native_node_api diff --git a/packages/host/cpp/WeakNodeApiInjector.hpp b/packages/host/cpp/WeakNodeApiInjector.hpp index 1b0a718d..52f9fd60 100644 --- a/packages/host/cpp/WeakNodeApiInjector.hpp +++ b/packages/host/cpp/WeakNodeApiInjector.hpp @@ -1,5 +1,5 @@ #include -namespace callstack::nodeapihost { +namespace callstack::react_native_node_api { void injectIntoWeakNodeApi(); } diff --git a/packages/host/package.json b/packages/host/package.json index 77b51b50..8bc1444e 100644 --- a/packages/host/package.json +++ b/packages/host/package.json @@ -42,11 +42,10 @@ ], "scripts": { "build": "tsc --build", - "generate-weak-node-api-injector": "node scripts/generate-weak-node-api-injector.mts", + "injector:generate": "node scripts/generate-injector.mts", "test": "tsx --test --test-reporter=@reporters/github --test-reporter-destination=stdout --test-reporter=spec --test-reporter-destination=stdout src/node/**/*.test.ts src/node/*.test.ts", "test:gradle": "ENABLE_GRADLE_TESTS=true node --run test", - "bootstrap": "node --run generate-weak-node-api-injector", - "prerelease": "node --run generate-weak-node-api-injector" + "bootstrap": "node --run injector:generate" }, "keywords": [ "node-api", diff --git a/packages/host/scripts/generate-weak-node-api-injector.mts b/packages/host/scripts/generate-injector.mts similarity index 93% rename from packages/host/scripts/generate-weak-node-api-injector.mts rename to packages/host/scripts/generate-injector.mts index 71acfe86..bfd6a150 100644 --- a/packages/host/scripts/generate-weak-node-api-injector.mts +++ b/packages/host/scripts/generate-injector.mts @@ -43,7 +43,7 @@ export function generateSource(functions: FunctionDecl[]) { #error "WEAK_NODE_API_LIBRARY_NAME cannot be defined for this platform" #endif - namespace callstack::nodeapihost { + namespace callstack::react_native_node_api { void injectIntoWeakNodeApi() { void *module = dlopen(WEAK_NODE_API_LIBRARY_NAME, RTLD_NOW | RTLD_LOCAL); @@ -59,8 +59,8 @@ export function generateSource(functions: FunctionDecl[]) { abort(); } - log_debug("Injecting WeakNodeApiHost"); - inject_weak_node_api_host(WeakNodeApiHost { + log_debug("Injecting NodeApiHost"); + inject_weak_node_api_host(NodeApiHost { ${functions .filter( ({ kind, name }) => @@ -70,7 +70,7 @@ export function generateSource(functions: FunctionDecl[]) { .join("\n")} }); } - } // namespace callstack::nodeapihost + } // namespace callstack::react_native_node_api `; } diff --git a/packages/weak-node-api/.gitignore b/packages/weak-node-api/.gitignore index 652a5f16..83e62995 100644 --- a/packages/weak-node-api/.gitignore +++ b/packages/weak-node-api/.gitignore @@ -5,8 +5,7 @@ /build-tests/ /*.xcframework /*.android.node -/generated/weak_node_api.cpp -/generated/weak_node_api.hpp +/generated/ # Copied from node-api-headers by scripts/copy-node-api-headers.ts /include/ diff --git a/packages/weak-node-api/CMakeLists.txt b/packages/weak-node-api/CMakeLists.txt index d61630f2..90525434 100644 --- a/packages/weak-node-api/CMakeLists.txt +++ b/packages/weak-node-api/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources(${PROJECT_NAME} PUBLIC FILE_SET HEADERS BASE_DIRS ${GENERATED_SOURCE_DIR} ${INCLUDE_DIR} FILES ${GENERATED_SOURCE_DIR}/weak_node_api.hpp + ${GENERATED_SOURCE_DIR}/NodeApiHost.hpp ${INCLUDE_DIR}/js_native_api_types.h ${INCLUDE_DIR}/js_native_api.h ${INCLUDE_DIR}/node_api_types.h diff --git a/packages/weak-node-api/package.json b/packages/weak-node-api/package.json index 84a510f3..2d2d0f5c 100644 --- a/packages/weak-node-api/package.json +++ b/packages/weak-node-api/package.json @@ -26,18 +26,17 @@ "scripts": { "build": "tsc --build", "copy-node-api-headers": "tsx scripts/copy-node-api-headers.ts", - "generate-weak-node-api": "tsx scripts/generate-weak-node-api.ts", - "prepare-weak-node-api": "node --run copy-node-api-headers && node --run generate-weak-node-api", - "build-weak-node-api": "cmake-rn --no-auto-link --no-weak-node-api-linkage --xcframework-extension", - "build-weak-node-api:android": "node --run build-weak-node-api -- --android", - "build-weak-node-api:apple": "node --run build-weak-node-api -- --apple", - "build-weak-node-api:all": "node --run build-weak-node-api -- --android --apple", + "generate": "tsx scripts/generate.ts", + "prebuild:prepare": "node --run copy-node-api-headers && node --run generate", + "prebuild:build": "cmake-rn --no-auto-link --no-weak-node-api-linkage --xcframework-extension", + "prebuild:build:android": "node --run prebuild:build -- --android", + "prebuild:build:apple": "node --run prebuild:build -- --apple", + "prebuild:build:all": "node --run prebuild:build -- --android --apple", "test": "tsx --test --test-reporter=@reporters/github --test-reporter-destination=stdout --test-reporter=spec --test-reporter-destination=stdout src/node/**/*.test.ts src/node/*.test.ts", "test:configure": "cmake -S . -B build-tests -DBUILD_TESTS=ON", "test:build": "cmake --build build-tests", "test:run": "ctest --test-dir build-tests --output-on-failure", - "bootstrap": "node --run prepare-weak-node-api && node --run build-weak-node-api", - "prerelease": "node --run prepare-weak-node-api && node --run build-weak-node-api:all" + "bootstrap": "node --run prebuild:prepare && node --run prebuild:build" }, "keywords": [ "react-native", diff --git a/packages/weak-node-api/scripts/generate-weak-node-api.ts b/packages/weak-node-api/scripts/generate.ts similarity index 54% rename from packages/weak-node-api/scripts/generate-weak-node-api.ts rename to packages/weak-node-api/scripts/generate.ts index 7b99d472..fc21e485 100644 --- a/packages/weak-node-api/scripts/generate-weak-node-api.ts +++ b/packages/weak-node-api/scripts/generate.ts @@ -9,6 +9,7 @@ import { } from "../src/node-api-functions.js"; import * as weakNodeApiGenerator from "./generators/weak-node-api.js"; +import * as hostGenerator from "./generators/NodeApiHost.js"; export const OUTPUT_PATH = path.join(import.meta.dirname, "../generated"); @@ -16,17 +17,32 @@ type GenerateFileOptions = { functions: FunctionDecl[]; fileName: string; generator: (functions: FunctionDecl[]) => string; + headingComment?: string; }; async function generateFile({ functions, fileName, generator, + headingComment = "", }: GenerateFileOptions) { const generated = generator(functions); - const output = `// This file is generated - don't edit it directly\n\n${generated}`; + const output = ` + /** + * @file ${fileName} + * ${headingComment + .trim() + .split("\n") + .map((l) => l.trim()) + .join("\n* ")} + * + * @note This file is generated - don't edit it directly + */ + + ${generated} + `; const outputPath = path.join(OUTPUT_PATH, fileName); - await fs.promises.writeFile(outputPath, output, "utf-8"); + await fs.promises.writeFile(outputPath, output.trim(), "utf-8"); const { status, stderr = "No error output" } = cp.spawnSync( "clang-format", ["-i", outputPath], @@ -41,15 +57,35 @@ async function run() { await fs.promises.mkdir(OUTPUT_PATH, { recursive: true }); const functions = getNodeApiFunctions(); + await generateFile({ + functions, + fileName: "NodeApiHost.hpp", + generator: hostGenerator.generateHeader, + headingComment: ` + @brief NodeApiHost struct. + + This header provides a struct of Node-API functions implemented by a host to inject its implementations. + `, + }); await generateFile({ functions, fileName: "weak_node_api.hpp", generator: weakNodeApiGenerator.generateHeader, + headingComment: ` + @brief Weak Node-API host injection interface. + + This header provides the struct and injection function for deferring Node-API function calls from addons into a Node-API host. + `, }); await generateFile({ functions, fileName: "weak_node_api.cpp", generator: weakNodeApiGenerator.generateSource, + headingComment: ` + @brief Weak Node-API host injection implementation. + + Provides the implementation for deferring Node-API function calls from addons into a Node-API host. + `, }); } diff --git a/packages/weak-node-api/scripts/generators/NodeApiHost.ts b/packages/weak-node-api/scripts/generators/NodeApiHost.ts new file mode 100644 index 00000000..c273cfe7 --- /dev/null +++ b/packages/weak-node-api/scripts/generators/NodeApiHost.ts @@ -0,0 +1,32 @@ +import type { FunctionDecl } from "../../src/node-api-functions.js"; + +export function generateFunctionDecl({ + returnType, + name, + argumentTypes, +}: FunctionDecl) { + return `${returnType} (*${name})(${argumentTypes.join(", ")});`; +} + +export function generateHeader(functions: FunctionDecl[]) { + return ` + #pragma once + + #include + + // Ideally we would have just used NAPI_NO_RETURN, but + // __declspec(noreturn) (when building with Microsoft Visual C++) cannot be used on members of a struct + // TODO: If we targeted C++23 we could use std::unreachable() + + #if defined(__GNUC__) + #define WEAK_NODE_API_UNREACHABLE __builtin_unreachable() + #else + #define WEAK_NODE_API_UNREACHABLE __assume(0) + #endif + + // Generate the struct of function pointers + struct NodeApiHost { + ${functions.map(generateFunctionDecl).join("\n")} + }; + `; +} diff --git a/packages/weak-node-api/scripts/generators/weak-node-api.ts b/packages/weak-node-api/scripts/generators/weak-node-api.ts index 964b3d73..62a1a026 100644 --- a/packages/weak-node-api/scripts/generators/weak-node-api.ts +++ b/packages/weak-node-api/scripts/generators/weak-node-api.ts @@ -1,41 +1,18 @@ import type { FunctionDecl } from "../../src/node-api-functions.js"; import { generateFunction } from "./shared.js"; -export function generateFunctionDecl({ - returnType, - name, - argumentTypes, -}: FunctionDecl) { - return `${returnType} (*${name})(${argumentTypes.join(", ")});`; -} - -/** - * Generates source code for a version script for the given Node API version. - */ -export function generateHeader(functions: FunctionDecl[]) { +export function generateHeader() { return ` #pragma once - #include // Node-API + #include #include // fprintf() #include // abort() - - // Ideally we would have just used NAPI_NO_RETURN, but - // __declspec(noreturn) (when building with Microsoft Visual C++) cannot be used on members of a struct - // TODO: If we targeted C++23 we could use std::unreachable() - - #if defined(__GNUC__) - #define WEAK_NODE_API_UNREACHABLE __builtin_unreachable() - #else - #define WEAK_NODE_API_UNREACHABLE __assume(0) - #endif - // Generate the struct of function pointers - struct WeakNodeApiHost { - ${functions.map(generateFunctionDecl).join("\n")} - }; - typedef void(*InjectHostFunction)(const WeakNodeApiHost&); - extern "C" void inject_weak_node_api_host(const WeakNodeApiHost& host); + #include "NodeApiHost.hpp" + + typedef void(*InjectHostFunction)(const NodeApiHost&); + extern "C" void inject_weak_node_api_host(const NodeApiHost& host); `; } @@ -56,15 +33,19 @@ function generateFunctionImpl(fn: FunctionDecl) { }); } -/** - * Generates source code for a version script for the given Node API version. - */ export function generateSource(functions: FunctionDecl[]) { return ` #include "weak_node_api.hpp" - WeakNodeApiHost g_host; - void inject_weak_node_api_host(const WeakNodeApiHost& host) { + /** + * @brief Global instance of the injected Node-API host. + * + * This variable holds the function table for Node-API calls. + * It is set via inject_weak_node_api_host() before any Node-API function is dispatched. + * All Node-API calls are routed through this host. + */ + NodeApiHost g_host; + void inject_weak_node_api_host(const NodeApiHost& host) { g_host = host; }; diff --git a/packages/weak-node-api/src/node-api-functions.ts b/packages/weak-node-api/src/node-api-functions.ts index 4290a471..f92bd956 100644 --- a/packages/weak-node-api/src/node-api-functions.ts +++ b/packages/weak-node-api/src/node-api-functions.ts @@ -49,10 +49,6 @@ const clangAstDump = z.object({ ), }); -/** - * Generates source code for a version script for the given Node API version. - * @param version - */ export function getNodeApiHeaderAST(version: NodeApiVersion) { const output = cp.execFileSync( "clang", diff --git a/packages/weak-node-api/tests/test_inject.cpp b/packages/weak-node-api/tests/test_inject.cpp index e2101c8c..5b35f15e 100644 --- a/packages/weak-node-api/tests/test_inject.cpp +++ b/packages/weak-node-api/tests/test_inject.cpp @@ -3,7 +3,7 @@ TEST_CASE("inject_weak_node_api_host") { SECTION("is callable") { - WeakNodeApiHost host{}; + NodeApiHost host{}; inject_weak_node_api_host(host); } @@ -14,7 +14,7 @@ TEST_CASE("inject_weak_node_api_host") { called = true; return napi_status::napi_ok; }; - WeakNodeApiHost host{.napi_create_object = my_create_object}; + NodeApiHost host{.napi_create_object = my_create_object}; inject_weak_node_api_host(host); napi_value result;