Skip to content

Commit 2fe7d43

Browse files
GazHankreconbot
authored andcommitted
feat: Node-API migration (#2305)
Migrate from NAN to N-API - this should allow an easier time working with electron and all versions of nodejs * Change dependency to napi * include napi * update shared functionality to NAPI * update unix methods to include napi_env * Convert OpenBaton to AsyncWorker * SetError within Execute() * Replace napi_create_async_work for common methods * remove redundant ByteSize Setting * fix typo * NODE_ADDON_API_ENABLE_MAYBE * optional - remove warnings * Remove OnError logic BREAKING CHANGE: This release switches to NAPI which changes how many binaries are released and will potentially break your build system
1 parent e90a432 commit 2fe7d43

18 files changed

+3231
-4847
lines changed

package-lock.json

Lines changed: 2392 additions & 3359 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,21 @@
2727
},
2828
"devDependencies": {
2929
"cc": "^3.0.1",
30+
"chai-subset": "^1.6.0",
3031
"chai": "^4.3.4",
31-
"chai-subset": "^1.5.0",
3232
"codecov": "^3.8.3",
33-
"eslint": "^8.2.0",
3433
"eslint-config-prettier": "^8.3.0",
3534
"eslint-plugin-import": "^2.25.3",
3635
"eslint-plugin-mocha": "^9.0.0",
3736
"eslint-plugin-node": "^11.1.0",
3837
"eslint-plugin-prettier": "^4.0.0",
3938
"eslint-plugin-promise": "^5.1.1",
40-
"lerna": "^4.0.0",
39+
"eslint": "^8.2.0",
4140
"lerna-changelog": "^2.2.0",
41+
"lerna": "^4.0.0",
4242
"mocha": "^9.1.3",
4343
"node-abi": "3.5.0",
44+
"node-addon-api": "^4.2.0",
4445
"nyc": "^15.1.0",
4546
"plop": "^2.7.6",
4647
"prebuild": "^11.0.0",

packages/binding-mock/package-lock.json

Lines changed: 0 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/bindings/binding.gyp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
'sources': [
55
'src/serialport.cpp'
66
],
7-
'include_dirs': [
8-
'<!(node -e "require(\'nan\')")'
9-
],
7+
'include_dirs': ["<!(node -p \"require('node-addon-api').include_dir\")"],
8+
'dependencies': ["<!(node -p \"require('node-addon-api').gyp\")"],
9+
'cflags!': [ '-fno-exceptions' ],
10+
'cflags_cc!': [ '-fno-exceptions' ],
11+
"defines": ["NAPI_CPP_EXCEPTIONS"],
1012
'conditions': [
1113
['OS=="win"',
1214
{
@@ -16,7 +18,7 @@
1618
],
1719
'msvs_settings': {
1820
'VCCLCompilerTool': {
19-
'ExceptionHandling': '2',
21+
'ExceptionHandling': '1',
2022
'DisableSpecificWarnings': [ '4530', '4506' ],
2123
}
2224
}
@@ -30,6 +32,7 @@
3032
'src/darwin_list.cpp'
3133
],
3234
'xcode_settings': {
35+
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
3336
'MACOSX_DEPLOYMENT_TARGET': '10.9',
3437
'OTHER_LDFLAGS': [
3538
'-framework CoreFoundation -framework IOKit'

packages/bindings/package-lock.json

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/bindings/package.json

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
"@serialport/parser-readline": "9.2.4",
1111
"bindings": "^1.5.0",
1212
"debug": "^4.3.2",
13-
"nan": "^2.15.0",
14-
"prebuild-install": "^7.0.0"
13+
"prebuild-install": "^7.0.0",
14+
"node-addon-api": "4.2.0"
1515
},
1616
"devDependencies": {
1717
"@serialport/binding-mock": "9.2.4",
@@ -21,11 +21,9 @@
2121
"node": ">=10.0.0"
2222
},
2323
"scripts": {
24-
"install": "prebuild-install --tag-prefix @serialport/bindings@ || node-gyp rebuild",
24+
"install": "prebuild-install --tag-prefix @serialport/bindings@ --runtime napi --target 4 --verbose || node-gyp rebuild",
2525
"lint": "cc --verbose",
26-
"prebuild": "npm run prebuild-node && npm run prebuild-electron",
27-
"prebuild-node": "prebuild --force --strip --verbose --tag-prefix @serialport/bindings@ -t 12.0.0 -t 14.0.0 -t 16.0.0",
28-
"prebuild-electron": "prebuild --force --strip --verbose --tag-prefix @serialport/bindings@ -r electron -t 13.0.0 -t 14.0.0 -t 15.0.0 -t 16.0.0",
26+
"prebuild": "prebuild --runtime napi --target 4 --force --strip --verbose --tag-prefix @serialport/bindings@",
2927
"rebuild": "node-gyp rebuild"
3028
},
3129
"publishConfig": {
@@ -48,5 +46,10 @@
4846
],
4947
"linelength": "120"
5048
},
51-
"funding": "https://opencollective.com/serialport/donate"
49+
"funding": "https://opencollective.com/serialport/donate",
50+
"binary": {
51+
"napi_versions": [
52+
4
53+
]
54+
}
5255
}

packages/bindings/src/darwin_list.cpp

Lines changed: 16 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,28 @@
1616
uv_mutex_t list_mutex;
1717
Boolean lockInitialised = FALSE;
1818

19-
NAN_METHOD(List) {
19+
Napi::Value List(const Napi::CallbackInfo& info) {
20+
Napi::Env env = info.Env();
2021
// callback
21-
if (!info[0]->IsFunction()) {
22-
Nan::ThrowTypeError("First argument must be a function");
23-
return;
22+
if (!info[0].IsFunction()) {
23+
Napi::TypeError::New(env, "First argument must be a function").ThrowAsJavaScriptException();
24+
return env.Null();
2425
}
25-
26-
ListBaton* baton = new ListBaton();
26+
Napi::Function callback = info[0].As<Napi::Function>();
27+
ListBaton* baton = new ListBaton(callback);
2728
snprintf(baton->errorString, sizeof(baton->errorString), "");
28-
baton->callback.Reset(info[0].As<v8::Function>());
2929

30-
uv_work_t* req = new uv_work_t();
31-
req->data = baton;
32-
uv_queue_work(uv_default_loop(), req, EIO_List, (uv_after_work_cb)EIO_AfterList);
30+
baton->Queue();
31+
return env.Undefined();
3332
}
3433

35-
void setIfNotEmpty(v8::Local<v8::Object> item, std::string key, const char *value) {
36-
v8::Local<v8::String> v8key = Nan::New<v8::String>(key).ToLocalChecked();
34+
void setIfNotEmpty(Napi::Object item, std::string key, const char *value) {
35+
Napi::Env env = item.Env();
36+
Napi::String v8key = Napi::String::New(env, key);
3737
if (strlen(value) > 0) {
38-
Nan::Set(item, v8key, Nan::New<v8::String>(value).ToLocalChecked());
38+
(item).Set(v8key, Napi::String::New(env, value));
3939
} else {
40-
Nan::Set(item, v8key, Nan::Undefined());
40+
(item).Set(v8key, env.Undefined());
4141
}
4242
}
4343

@@ -271,8 +271,7 @@ static stDeviceListItem* GetSerialDevices() {
271271
return devices;
272272
}
273273

274-
void EIO_List(uv_work_t* req) {
275-
ListBaton* data = static_cast<ListBaton*>(req->data);
274+
void ListBaton::Execute() {
276275

277276
if (!lockInitialised) {
278277
uv_mutex_init(&list_mutex);
@@ -304,7 +303,7 @@ void EIO_List(uv_work_t* req) {
304303
if (*device.serialNumber) {
305304
resultItem->serialNumber = device.serialNumber;
306305
}
307-
data->results.push_back(resultItem);
306+
results.push_back(resultItem);
308307

309308
stDeviceListItem* current = next;
310309

@@ -316,40 +315,3 @@ void EIO_List(uv_work_t* req) {
316315
}
317316
}
318317
}
319-
320-
void EIO_AfterList(uv_work_t* req) {
321-
Nan::HandleScope scope;
322-
323-
ListBaton* data = static_cast<ListBaton*>(req->data);
324-
325-
v8::Local<v8::Value> argv[2];
326-
if (data->errorString[0]) {
327-
argv[0] = v8::Exception::Error(Nan::New<v8::String>(data->errorString).ToLocalChecked());
328-
argv[1] = Nan::Undefined();
329-
} else {
330-
v8::Local<v8::Array> results = Nan::New<v8::Array>();
331-
int i = 0;
332-
for (std::list<ListResultItem*>::iterator it = data->results.begin(); it != data->results.end(); ++it, i++) {
333-
v8::Local<v8::Object> item = Nan::New<v8::Object>();
334-
335-
setIfNotEmpty(item, "path", (*it)->path.c_str());
336-
setIfNotEmpty(item, "manufacturer", (*it)->manufacturer.c_str());
337-
setIfNotEmpty(item, "serialNumber", (*it)->serialNumber.c_str());
338-
setIfNotEmpty(item, "pnpId", (*it)->pnpId.c_str());
339-
setIfNotEmpty(item, "locationId", (*it)->locationId.c_str());
340-
setIfNotEmpty(item, "vendorId", (*it)->vendorId.c_str());
341-
setIfNotEmpty(item, "productId", (*it)->productId.c_str());
342-
343-
Nan::Set(results, i, item);
344-
}
345-
argv[0] = Nan::Null();
346-
argv[1] = results;
347-
}
348-
data->callback.Call(2, argv, data);
349-
350-
for (std::list<ListResultItem*>::iterator it = data->results.begin(); it != data->results.end(); ++it) {
351-
delete *it;
352-
}
353-
delete data;
354-
delete req;
355-
}

packages/bindings/src/darwin_list.h

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
#ifndef PACKAGES_SERIALPORT_SRC_DARWIN_LIST_H_
22
#define PACKAGES_SERIALPORT_SRC_DARWIN_LIST_H_
33
#include <sys/param.h> // For MAXPATHLEN
4-
#include <nan.h>
4+
#include <napi.h>
5+
#include <uv.h>
56
#include <list>
67
#include <string>
78

8-
#define ERROR_STRING_SIZE 1024
9+
#define ERROR_STRING_SIZE 1088
910

10-
NAN_METHOD(List);
11-
void EIO_List(uv_work_t* req);
12-
void EIO_AfterList(uv_work_t* req);
11+
Napi::Value List(const Napi::CallbackInfo& info);
12+
void setIfNotEmpty(Napi::Object item, std::string key, const char *value);
1313

1414
struct ListResultItem {
1515
std::string path;
@@ -21,11 +21,33 @@ struct ListResultItem {
2121
std::string productId;
2222
};
2323

24-
struct ListBaton : public Nan::AsyncResource {
25-
ListBaton() : AsyncResource("node-serialport:ListBaton"), errorString() {}
26-
Nan::Callback callback;
24+
struct ListBaton : public Napi::AsyncWorker {
25+
ListBaton(Napi::Function& callback) : Napi::AsyncWorker(callback, "node-serialport:ListBaton"),
26+
errorString() {}
2727
std::list<ListResultItem*> results;
2828
char errorString[ERROR_STRING_SIZE];
29+
void Execute() override;
30+
31+
void OnOK() override {
32+
Napi::Env env = Env();
33+
Napi::HandleScope scope(env);
34+
Napi::Array result = Napi::Array::New(env);
35+
int i = 0;
36+
for (std::list<ListResultItem*>::iterator it = results.begin(); it != results.end(); ++it, i++) {
37+
Napi::Object item = Napi::Object::New(env);
38+
39+
setIfNotEmpty(item, "path", (*it)->path.c_str());
40+
setIfNotEmpty(item, "manufacturer", (*it)->manufacturer.c_str());
41+
setIfNotEmpty(item, "serialNumber", (*it)->serialNumber.c_str());
42+
setIfNotEmpty(item, "pnpId", (*it)->pnpId.c_str());
43+
setIfNotEmpty(item, "locationId", (*it)->locationId.c_str());
44+
setIfNotEmpty(item, "vendorId", (*it)->vendorId.c_str());
45+
setIfNotEmpty(item, "productId", (*it)->productId.c_str());
46+
47+
(result).Set(i, item);
48+
}
49+
Callback().Call({env.Null(), result});
50+
}
2951
};
3052

3153
typedef struct SerialDevice {

0 commit comments

Comments
 (0)