Skip to content
Draft
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
5 changes: 5 additions & 0 deletions .changeset/slimy-parts-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"weak-node-api": minor
---

Renamed WeakNodeApiHost to NodeApiHost
8 changes: 4 additions & 4 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,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
Expand Down Expand Up @@ -213,7 +213,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
Expand Down Expand Up @@ -268,8 +268,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
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
5 changes: 2 additions & 3 deletions packages/host/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) =>
Expand Down
3 changes: 1 addition & 2 deletions packages/weak-node-api/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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/
Expand Down
1 change: 1 addition & 0 deletions packages/weak-node-api/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 7 additions & 8 deletions packages/weak-node-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,40 @@ 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");

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],
Expand All @@ -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.
`,
});
}

Expand Down
32 changes: 32 additions & 0 deletions packages/weak-node-api/scripts/generators/NodeApiHost.ts
Original file line number Diff line number Diff line change
@@ -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 <node_api.h>

// 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")}
};
`;
}
49 changes: 15 additions & 34 deletions packages/weak-node-api/scripts/generators/weak-node-api.ts
Original file line number Diff line number Diff line change
@@ -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.h> // Node-API
#include <node_api.h>
#include <stdio.h> // fprintf()
#include <stdlib.h> // 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);
`;
}

Expand All @@ -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;
};

Expand Down
4 changes: 0 additions & 4 deletions packages/weak-node-api/src/node-api-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions packages/weak-node-api/tests/test_inject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

TEST_CASE("inject_weak_node_api_host") {
SECTION("is callable") {
WeakNodeApiHost host{};
NodeApiHost host{};
inject_weak_node_api_host(host);
}

Expand All @@ -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;
Expand Down
Loading