Skip to content

Commit 8996baa

Browse files
committed
feat: sync node-addon-api and add example test
1 parent 82eb56a commit 8996baa

53 files changed

Lines changed: 2521 additions & 19 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/simple-test.yml

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
# Action name
2-
name: Simple Test Action
1+
name: Tests
32

43
on:
5-
push
4+
push:
5+
pull_request:
6+
workflow_dispatch:
67

7-
# Jobs section
88
jobs:
9-
simple-test:
9+
build-ohos-example:
10+
name: Build OHOS example
1011
runs-on: ubuntu-latest
1112
steps:
1213
- uses: actions/checkout@v4
@@ -20,3 +21,51 @@ jobs:
2021
- name: Build example
2122
run: |
2223
bash ./scripts/build.sh
24+
25+
arkvm-tests:
26+
name: ArkVM tests
27+
runs-on: ubuntu-latest
28+
defaults:
29+
run:
30+
shell: bash
31+
steps:
32+
- uses: actions/checkout@v4
33+
34+
- name: Setup OpenHarmony SDK
35+
uses: openharmony-rs/setup-ohos-sdk@v0.1
36+
with:
37+
version: '5.0.0'
38+
39+
- name: Setup ArkVM
40+
id: setup-arkvm
41+
uses: harmony-contrib/arkts-vm@v2.0.0
42+
with:
43+
cache: true
44+
45+
- name: Validate ArkVM host bundle
46+
env:
47+
ARK_HOST_TOOLS_DIR: ${{ steps.setup-arkvm.outputs.arkvm-path }}
48+
run: |
49+
set -euo pipefail
50+
test -x "${ARK_HOST_TOOLS_DIR}/ark_js_napi_cli"
51+
test -x "${ARK_HOST_TOOLS_DIR}/es2abc"
52+
test -f "${ARK_HOST_TOOLS_DIR}/libace_napi.so"
53+
54+
- name: Build ArkVM host addon
55+
env:
56+
ARK_HOST_TOOLS_DIR: ${{ steps.setup-arkvm.outputs.arkvm-path }}
57+
run: bash ./scripts/arkvm/build_host_libs.sh
58+
59+
- name: Run ArkVM tests
60+
env:
61+
ARK_HOST_TOOLS_DIR: ${{ steps.setup-arkvm.outputs.arkvm-path }}
62+
run: bash ./scripts/arkvm/run_tests.sh
63+
64+
- name: Upload ArkVM logs
65+
if: failure()
66+
uses: actions/upload-artifact@v4
67+
with:
68+
name: arkvm-test-logs
69+
path: |
70+
.tmp_arkvm_runner/results.tsv
71+
.tmp_arkvm_runner/logs

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ cmake-build-debug/
88

99
*.har
1010
package/include
11-
*.so
11+
*.so
12+
.tmp_arkvm_runner/
13+
test/suites/
14+
test/suites.list
15+
example/build-arkvm-host/

example/CMakeLists.txt

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
include($ENV{OHOS_NDK_HOME}/native/build/cmake/ohos.toolchain.cmake)
1+
if(NOT NODE_ADDON_API_OHOS_ARKVM_HOST)
2+
include($ENV{OHOS_NDK_HOME}/native/build/cmake/ohos.toolchain.cmake)
3+
endif()
24

35
cmake_minimum_required(VERSION 3.5.0)
46
project(example)
@@ -13,7 +15,32 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
1315
add_compile_definitions(NAPI_DISABLE_CPP_EXCEPTIONS=1)
1416

1517
add_library(node_addon_api_ohos INTERFACE IMPORTED)
16-
target_include_directories(node_addon_api_ohos INTERFACE ${NODE_ADDON_API}/napi.h ${NODE_ADDON_API}/napi-inl.h ${NODE_ADDON_API}/napi-inl.deprecated.h)
18+
target_include_directories(node_addon_api_ohos INTERFACE ${NODE_ADDON_API})
19+
20+
if(NODE_ADDON_API_OHOS_ARKVM_HOST)
21+
if(NOT ARK_ACE_NAPI_LIB)
22+
if(ARK_HOST_BUNDLE_DIR)
23+
set(ARK_ACE_NAPI_LIB "${ARK_HOST_BUNDLE_DIR}/libace_napi.so")
24+
else()
25+
message(FATAL_ERROR "ARK_ACE_NAPI_LIB or ARK_HOST_BUNDLE_DIR is required")
26+
endif()
27+
endif()
28+
29+
if(NOT EXISTS "${ARK_ACE_NAPI_LIB}")
30+
message(FATAL_ERROR "ARK_ACE_NAPI_LIB does not exist: ${ARK_ACE_NAPI_LIB}")
31+
endif()
32+
33+
if(NOT ARK_NATIVE_API_INCLUDE_DIR)
34+
message(FATAL_ERROR "ARK_NATIVE_API_INCLUDE_DIR is required")
35+
endif()
36+
37+
if(NOT EXISTS "${ARK_NATIVE_API_INCLUDE_DIR}/napi/native_api.h")
38+
message(FATAL_ERROR "ARK_NATIVE_API_INCLUDE_DIR must contain napi/native_api.h")
39+
endif()
40+
41+
target_include_directories(node_addon_api_ohos INTERFACE ${ARK_NATIVE_API_INCLUDE_DIR})
42+
add_compile_definitions(OHOS=1 __OHOS__=1)
43+
endif()
1744

1845
file(GLOB_RECURSE
1946
SOURCES
@@ -60,6 +87,7 @@ add_library(example SHARED
6087
objectwrap.cpp
6188
promise.cpp
6289
reference.cpp
90+
run_script.cpp
6391
thunking_manual.cpp
6492
type_taggable.cpp
6593
typedarray.cpp
@@ -70,4 +98,10 @@ add_library(example SHARED
7098
)
7199

72100
target_include_directories(example PUBLIC ${NODE_ADDON_API})
73-
target_link_libraries(example PRIVATE node_addon_api_ohos libace_napi.z.so)
101+
target_link_libraries(example PRIVATE node_addon_api_ohos)
102+
103+
if(NODE_ADDON_API_OHOS_ARKVM_HOST)
104+
target_link_libraries(example PRIVATE "${ARK_ACE_NAPI_LIB}" pthread dl)
105+
else()
106+
target_link_libraries(example PRIVATE libace_napi.z.so)
107+
endif()

example/date.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ namespace {
1111
return Date::New(info.Env(), input);
1212
}
1313

14+
Value CreateDateFromTimePoint(const CallbackInfo& info) {
15+
auto input = std::chrono::system_clock::time_point{};
16+
return Date::New(info.Env(), input);
17+
}
18+
1419
Value IsDate(const CallbackInfo& info) {
1520
Date input = info[0].As<Date>();
1621

@@ -35,6 +40,8 @@ namespace {
3540
Object InitDate(Env env) {
3641
Object exports = Object::New(env);
3742
exports["CreateDate"] = Function::New(env, CreateDate);
43+
exports["CreateDateFromTimePoint"] =
44+
Function::New(env, CreateDateFromTimePoint);
3845
exports["IsDate"] = Function::New(env, IsDate);
3946
exports["ValueOf"] = Function::New(env, ValueOf);
4047
exports["OperatorValue"] = Function::New(env, OperatorValue);

example/name.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "napi.h"
22

3+
#include <string_view>
4+
35
using namespace Napi;
46

57
const char* testValueUtf8 = "123456789";
@@ -21,43 +23,49 @@ Value EchoString(const CallbackInfo& info) {
2123

2224
Value CreateString(const CallbackInfo& info) {
2325
String encoding = info[0].As<String>();
24-
Number length = info[1].As<Number>();
26+
Value length = info[1];
2527

2628
if (encoding.Utf8Value() == "utf8") {
2729
if (length.IsUndefined()) {
2830
return String::New(info.Env(), testValueUtf8);
2931
} else {
30-
return String::New(info.Env(), testValueUtf8, length.Uint32Value());
32+
return String::New(
33+
info.Env(), testValueUtf8, length.As<Number>().Uint32Value());
3134
}
3235
} else if (encoding.Utf8Value() == "utf16") {
3336
if (length.IsUndefined()) {
3437
return String::New(info.Env(), testValueUtf16);
3538
} else {
36-
return String::New(info.Env(), testValueUtf16, length.Uint32Value());
39+
return String::New(
40+
info.Env(), testValueUtf16, length.As<Number>().Uint32Value());
3741
}
3842
} else {
3943
Error::New(info.Env(), "Invalid encoding.").ThrowAsJavaScriptException();
4044
return Value();
4145
}
4246
}
4347

48+
Value CreateStringFromStringView(const CallbackInfo& info) {
49+
return String::New(info.Env(), std::string_view("hello1"));
50+
}
51+
4452
Value CheckString(const CallbackInfo& info) {
4553
String value = info[0].As<String>();
4654
String encoding = info[1].As<String>();
47-
Number length = info[2].As<Number>();
55+
Value length = info[2];
4856

4957
if (encoding.Utf8Value() == "utf8") {
5058
std::string testValue = testValueUtf8;
5159
if (!length.IsUndefined()) {
52-
testValue = testValue.substr(0, length.Uint32Value());
60+
testValue = testValue.substr(0, length.As<Number>().Uint32Value());
5361
}
5462

5563
std::string stringValue = value;
5664
return Boolean::New(info.Env(), stringValue == testValue);
5765
} else if (encoding.Utf8Value() == "utf16") {
5866
std::u16string testValue = testValueUtf16;
5967
if (!length.IsUndefined()) {
60-
testValue = testValue.substr(0, length.Uint32Value());
68+
testValue = testValue.substr(0, length.As<Number>().Uint32Value());
6169
}
6270

6371
std::u16string stringValue = value;
@@ -87,6 +95,8 @@ Object InitName(Env env) {
8795

8896
exports["echoString"] = Function::New(env, EchoString);
8997
exports["createString"] = Function::New(env, CreateString);
98+
exports["createStringFromStringView"] =
99+
Function::New(env, CreateStringFromStringView);
90100
exports["nullStringShouldThrow"] = Function::New(env, NullStringShouldThrow);
91101
exports["nullString16ShouldThrow"] =
92102
Function::New(env, NullString16ShouldThrow);

example/napi_init.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Object InitObject(Env env);
4747
Object InitObjectDeprecated(Env env);
4848
#endif // !NODE_ADDON_API_DISABLE_DEPRECATED
4949
Object InitPromise(Env env);
50-
//Object InitRunScript(Env env);
50+
Object InitRunScript(Env env);
5151
#if (NAPI_VERSION > 3)
5252
Object InitThreadSafeFunctionCtx(Env env);
5353
Object InitThreadSafeFunctionException(Env env);
@@ -137,6 +137,7 @@ Object Init(Env env, Object exports) {
137137
exports.Set("object_deprecated", InitObjectDeprecated(env));
138138
#endif // !NODE_ADDON_API_DISABLE_DEPRECATED
139139
exports.Set("promise", InitPromise(env));
140+
exports.Set("run_script", InitRunScript(env));
140141
// exports.Set("symbol", InitSymbol(env));
141142
#if (NAPI_VERSION > 3)
142143
exports.Set("threadsafe_function_ctx", InitThreadSafeFunctionCtx(env));

example/object/object.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,19 @@ Value InstanceOf(const CallbackInfo& info) {
343343
return Boolean::New(info.Env(), MaybeUnwrap(obj.InstanceOf(constructor)));
344344
}
345345

346+
Value GetPrototype(const CallbackInfo& info) {
347+
Object obj = info[0].UnsafeAs<Object>();
348+
return MaybeUnwrap(obj.GetPrototype());
349+
}
350+
351+
#ifdef NODE_API_EXPERIMENTAL_HAS_SET_PROTOTYPE
352+
Value SetPrototype(const CallbackInfo& info) {
353+
Object obj = info[0].UnsafeAs<Object>();
354+
Object prototype = info[1].UnsafeAs<Object>();
355+
return Boolean::New(info.Env(), MaybeUnwrap(obj.SetPrototype(prototype)));
356+
}
357+
#endif
358+
346359
Object InitObject(Env env) {
347360
Object exports = Object::New(env);
348361

@@ -426,5 +439,10 @@ Object InitObject(Env env) {
426439
Function::New(env, SubscriptSetWithCppStyleString);
427440
exports["subscriptSetAtIndex"] = Function::New(env, SubscriptSetAtIndex);
428441

442+
exports["getPrototype"] = Function::New(env, GetPrototype);
443+
#ifdef NODE_API_EXPERIMENTAL_HAS_SET_PROTOTYPE
444+
exports["setPrototype"] = Function::New(env, SetPrototype);
445+
#endif
446+
429447
return exports;
430448
}

example/promise.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "napi.h"
2+
#include "common/test_helper.h"
23

34
using namespace Napi;
45

@@ -23,6 +24,66 @@ Value PromiseReturnsCorrectEnv(const CallbackInfo& info) {
2324
return Boolean::New(info.Env(), deferred.Env() == info.Env());
2425
}
2526

27+
Value ThenMethodOnFulfilled(const CallbackInfo& info) {
28+
auto deferred = Promise::Deferred::New(info.Env());
29+
Function onFulfilled = info[0].As<Function>();
30+
31+
Promise resultPromise = MaybeUnwrap(deferred.Promise().Then(onFulfilled));
32+
bool isPromise = resultPromise.IsPromise();
33+
deferred.Resolve(Number::New(info.Env(), 42));
34+
35+
Object result = Object::New(info.Env());
36+
result["isPromise"] = Boolean::New(info.Env(), isPromise);
37+
result["promise"] = resultPromise;
38+
return result;
39+
}
40+
41+
Value ThenMethodOnFulfilledOnRejectedResolve(const CallbackInfo& info) {
42+
auto deferred = Promise::Deferred::New(info.Env());
43+
Function onFulfilled = info[0].As<Function>();
44+
Function onRejected = info[1].As<Function>();
45+
46+
Promise resultPromise =
47+
MaybeUnwrap(deferred.Promise().Then(onFulfilled, onRejected));
48+
bool isPromise = resultPromise.IsPromise();
49+
deferred.Resolve(Number::New(info.Env(), 42));
50+
51+
Object result = Object::New(info.Env());
52+
result["isPromise"] = Boolean::New(info.Env(), isPromise);
53+
result["promise"] = resultPromise;
54+
return result;
55+
}
56+
57+
Value ThenMethodOnFulfilledOnRejectedReject(const CallbackInfo& info) {
58+
auto deferred = Promise::Deferred::New(info.Env());
59+
Function onFulfilled = info[0].As<Function>();
60+
Function onRejected = info[1].As<Function>();
61+
62+
Promise resultPromise =
63+
MaybeUnwrap(deferred.Promise().Then(onFulfilled, onRejected));
64+
bool isPromise = resultPromise.IsPromise();
65+
deferred.Reject(String::New(info.Env(), "Rejected"));
66+
67+
Object result = Object::New(info.Env());
68+
result["isPromise"] = Boolean::New(info.Env(), isPromise);
69+
result["promise"] = resultPromise;
70+
return result;
71+
}
72+
73+
Value CatchMethod(const CallbackInfo& info) {
74+
auto deferred = Promise::Deferred::New(info.Env());
75+
Function onRejected = info[0].As<Function>();
76+
77+
Promise resultPromise = MaybeUnwrap(deferred.Promise().Catch(onRejected));
78+
bool isPromise = resultPromise.IsPromise();
79+
deferred.Reject(String::New(info.Env(), "Rejected"));
80+
81+
Object result = Object::New(info.Env());
82+
result["isPromise"] = Boolean::New(info.Env(), isPromise);
83+
result["promise"] = resultPromise;
84+
return result;
85+
}
86+
2687
Object InitPromise(Env env) {
2788
Object exports = Object::New(env);
2889

@@ -31,6 +92,12 @@ Object InitPromise(Env env) {
3192
exports["rejectPromise"] = Function::New(env, RejectPromise);
3293
exports["promiseReturnsCorrectEnv"] =
3394
Function::New(env, PromiseReturnsCorrectEnv);
95+
exports["thenMethodOnFulfilled"] = Function::New(env, ThenMethodOnFulfilled);
96+
exports["thenMethodOnFulfilledOnRejectedResolve"] =
97+
Function::New(env, ThenMethodOnFulfilledOnRejectedResolve);
98+
exports["thenMethodOnFulfilledOnRejectedReject"] =
99+
Function::New(env, ThenMethodOnFulfilledOnRejectedReject);
100+
exports["catchMethod"] = Function::New(env, CatchMethod);
34101

35102
return exports;
36103
}

0 commit comments

Comments
 (0)