Skip to content

Commit 791a511

Browse files
committed
Upgrade project to N-API for better ABI stability in Node
1 parent 32c2758 commit 791a511

File tree

3 files changed

+102
-94
lines changed

3 files changed

+102
-94
lines changed

binding.gyp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,28 @@
77
],
88
"include_dirs": [
99
"deps/cld/public",
10-
"<!(node -e \"require('nan')\")"
10+
"<!@(node -p \"require('node-addon-api').include\")"
1111
],
1212
"sources": ["src/constants.cc", "src/cld.cc"],
13-
"defines": [],
14-
"cflags_cc": ["-Wall"],
13+
"cflags!": ["-fno-exceptions"],
14+
"cflags_cc!": ["-Wall", "-fno-exceptions"],
1515
"xcode_settings": {
16+
"GCC_ENABLE_CPP_EXCEPTIONS": "YES",
17+
"CLANG_CXX_LIBRARY": "libc++",
18+
"MACOSX_DEPLOYMENT_TARGET": "10.7",
1619
"OTHER_CFLAGS": ["-Wall"]
17-
}
20+
},
21+
"msvs_settings": {
22+
"VCCLCompilerTool": { "ExceptionHandling": 1 }
23+
},
24+
"conditions": [
25+
['OS=="mac"', {
26+
"cflags+": ["-fvisibility=hidden"],
27+
"xcode_settings": {
28+
"GCC_SYMBOLS_PRIVATE_EXTERN": "YES"
29+
}
30+
}]
31+
]
1832
}
1933
]
2034
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"main": "./index",
1313
"dependencies": {
1414
"glob": "^5.0.10",
15-
"nan": "^2.9.2",
15+
"node-addon-api": "*",
1616
"rimraf": "^2.4.0",
1717
"underscore": "^1.6.0"
1818
},

src/cld.cc

Lines changed: 83 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -5,40 +5,50 @@
55
using std::terminate_handler;
66
using std::unexpected_handler;
77

8-
#include "nan.h"
8+
#include <napi.h>
99

1010
namespace NodeCld {
11+
Napi::Object Detect(const Napi::CallbackInfo& info) {
12+
auto env = info.Env();
1113

12-
NAN_METHOD(Detect) {
13-
v8::Local<v8::Object> results = Nan::New<v8::Object>();
14-
v8::String::Utf8Value text(v8::Isolate::GetCurrent(), Nan::To<v8::String>(info[0]).ToLocalChecked());
15-
16-
char *bytes = *text;
17-
int numBytes = text.length();
18-
bool isPlainText = Nan::To<bool>(info[1]).FromJust();
14+
std::string text = info[0].ToString().Utf8Value();
15+
const char *bytes = text.c_str();
16+
int numBytes = text.length();
17+
bool isPlainText = info[1].ToBoolean();
1918

2019
CLD2::CLDHints hints;
2120
hints.tld_hint = 0;
2221
hints.content_language_hint = 0;
2322
hints.language_hint = CLD2::UNKNOWN_LANGUAGE;
2423
hints.encoding_hint = CLD2::UNKNOWN_ENCODING;
2524

26-
v8::String::Utf8Value languageHint(v8::Isolate::GetCurrent(), Nan::To<v8::String>(info[2]).ToLocalChecked());
27-
v8::String::Utf8Value encodingHint(v8::Isolate::GetCurrent(), Nan::To<v8::String>(info[3]).ToLocalChecked());
28-
v8::String::Utf8Value tldHint(v8::Isolate::GetCurrent(), Nan::To<v8::String>(info[4]).ToLocalChecked());
29-
v8::String::Utf8Value httpHint(v8::Isolate::GetCurrent(), Nan::To<v8::String>(info[5]).ToLocalChecked());
3025

31-
if (tldHint.length() > 0) {
32-
hints.tld_hint = *tldHint;
26+
if (info[2].IsString()) {
27+
std::string languageHint = info[2].ToString().Utf8Value();
28+
if (languageHint.length() > 0) {
29+
hints.language_hint = Constants::getInstance().getLanguageFromName(languageHint.c_str());
30+
}
3331
}
34-
if (httpHint.length() > 0) {
35-
hints.content_language_hint = *httpHint;
32+
33+
if (info[3].IsString()) {
34+
std::string encodingHint = info[3].ToString().Utf8Value();
35+
if (encodingHint.length() > 0) {
36+
hints.encoding_hint = Constants::getInstance().getEncodingFromName(encodingHint.c_str());
37+
}
3638
}
37-
if (languageHint.length() > 0) {
38-
hints.language_hint = Constants::getInstance().getLanguageFromName(*languageHint);
39+
40+
if (info[4].IsString()) {
41+
std::string tldHint = info[4].ToString().Utf8Value();
42+
if (tldHint.length() > 0) {
43+
hints.tld_hint = tldHint.c_str();
44+
}
3945
}
40-
if (encodingHint.length() > 0) {
41-
hints.encoding_hint = Constants::getInstance().getEncodingFromName(*encodingHint);
46+
47+
if (info[5].IsString()) {
48+
std::string httpHint = info[5].ToString().Utf8Value();
49+
if (httpHint.length() > 0) {
50+
hints.content_language_hint = httpHint.c_str();
51+
}
4252
}
4353

4454
CLD2::Language language3[3];
@@ -48,7 +58,6 @@ namespace NodeCld {
4858
int textBytesFound;
4959
bool isReliable;
5060

51-
5261
CLD2::ExtDetectLanguageSummary(
5362
bytes, numBytes,
5463
isPlainText,
@@ -62,98 +71,83 @@ namespace NodeCld {
6271
&isReliable
6372
);
6473

65-
unsigned int languageIdx = 0;
66-
v8::Local<v8::Array> languages = v8::Local<v8::Array>(Nan::New<v8::Array>());
67-
for(int resultIdx = 0; resultIdx < 3; resultIdx++) {
74+
size_t languageIdx = 0;
75+
auto languages = Napi::Array::New(env);
76+
for (size_t resultIdx = 0; resultIdx < 3; resultIdx++) {
6877
CLD2::Language lang = language3[resultIdx];
6978

7079
if (lang == CLD2::UNKNOWN_LANGUAGE) {
7180
continue;
7281
}
7382

74-
v8::Local<v8::Object> item = Nan::New<v8::Object>();
75-
Nan::Set(item, Nan::New<v8::String>("name").ToLocalChecked(),
76-
Nan::New<v8::String>(Constants::getInstance().getLanguageName(lang)).ToLocalChecked());
77-
Nan::Set(item, Nan::New<v8::String>("code").ToLocalChecked(),
78-
Nan::New<v8::String>(Constants::getInstance().getLanguageCode(lang)).ToLocalChecked());
79-
Nan::Set(item, Nan::New<v8::String>("percent").ToLocalChecked(),
80-
Nan::New<v8::Number>(percent3[resultIdx]));
81-
Nan::Set(item, Nan::New<v8::String>("score").ToLocalChecked(),
82-
Nan::New<v8::Number>(normalized_score3[resultIdx]));
83-
84-
Nan::Set(languages, Nan::New<v8::Integer>(languageIdx), item);
85-
languageIdx++;
83+
auto item = Napi::Object::New(env);
84+
item["name"] = Napi::String::New(env, Constants::getInstance().getLanguageName(lang));
85+
item["code"] = Napi::String::New(env, Constants::getInstance().getLanguageCode(lang));
86+
item["percent"] = Napi::Number::New(env, percent3[resultIdx]);
87+
item["score"] = Napi::Number::New(env, normalized_score3[resultIdx]);
88+
89+
languages[languageIdx++] = item;
8690
}
8791

88-
unsigned int chunkIdx = 0;
89-
v8::Local<v8::Array> chunks = v8::Local<v8::Array>(Nan::New<v8::Array>());
90-
for(unsigned int resultIdx = 0; resultIdx < resultChunkVector.size(); resultIdx++) {
92+
size_t chunkIdx = 0;
93+
auto chunks = Napi::Array::New(env);
94+
for (size_t resultIdx = 0; resultIdx < resultChunkVector.size(); resultIdx++) {
9195
CLD2::ResultChunk chunk = resultChunkVector.at(resultIdx);
9296
CLD2::Language lang = static_cast<CLD2::Language>(chunk.lang1);
9397

9498
if (lang == CLD2::UNKNOWN_LANGUAGE) {
9599
continue;
96100
}
97101

98-
v8::Local<v8::Object> item = Nan::New<v8::Object>();
99-
Nan::Set(item, Nan::New<v8::String>("name").ToLocalChecked(),
100-
Nan::New<v8::String>(Constants::getInstance().getLanguageName(lang)).ToLocalChecked());
101-
Nan::Set(item, Nan::New<v8::String>("code").ToLocalChecked(),
102-
Nan::New<v8::String>(Constants::getInstance().getLanguageCode(lang)).ToLocalChecked());
103-
Nan::Set(item, Nan::New<v8::String>("offset").ToLocalChecked(),
104-
Nan::New<v8::Number>(chunk.offset));
105-
Nan::Set(item, Nan::New<v8::String>("bytes").ToLocalChecked(),
106-
Nan::New<v8::Number>(chunk.bytes));
107-
108-
Nan::Set(chunks, Nan::New<v8::Integer>(chunkIdx), item);
109-
chunkIdx++;
102+
auto item = Napi::Object::New(env);
103+
item["name"] = Napi::String::New(env, Constants::getInstance().getLanguageName(lang));
104+
item["code"] = Napi::String::New(env, Constants::getInstance().getLanguageCode(lang));
105+
item["offset"] = Napi::Number::New(env, chunk.offset);
106+
item["bytes"] = Napi::Number::New(env, chunk.bytes);
107+
108+
chunks[chunkIdx++] = item;
110109
}
111110

112-
Nan::Set(results, Nan::New<v8::String>("reliable").ToLocalChecked(),
113-
Nan::New<v8::Boolean>(isReliable));
114-
Nan::Set(results, Nan::New<v8::String>("textBytes").ToLocalChecked(),
115-
Nan::New<v8::Number>(textBytesFound));
116-
Nan::Set(results, Nan::New<v8::String>("languages").ToLocalChecked(),
117-
languages);
118-
Nan::Set(results, Nan::New<v8::String>("chunks").ToLocalChecked(),
119-
chunks);
111+
auto results = Napi::Object::New(env);
112+
results["reliable"] = Napi::Boolean::New(env, isReliable);
113+
results["textBytes"] = Napi::Number::New(env, textBytesFound);
114+
results["languages"] = languages;
115+
results["chunks"] = chunks;
120116

121-
info.GetReturnValue().Set(results);
117+
return results;
122118
}
123119

124-
extern "C" void init (v8::Local<v8::Object> target) {
125-
// set detected languages
126-
v8::Local<v8::Array> detected = Nan::New<v8::Array>();
127-
vector<NodeCldDetected>* rawDetected = Constants::getInstance().getDetected();
128-
for(vector<NodeCldDetected>::size_type i = 0; i < rawDetected->size(); i++) {
129-
NodeCldDetected rawLanguage = rawDetected->at(i);
130-
Nan::Set(detected, static_cast<uint32_t>(i),
131-
Nan::New<v8::String>(rawLanguage.name).ToLocalChecked());
120+
Napi::Object Init(Napi::Env env, Napi::Object exports) {
121+
auto rawDetected = Constants::getInstance().getDetected();
122+
auto numDetected = rawDetected->size();
123+
auto detected = Napi::Array::New(env, numDetected);
124+
for (size_t i = 0; i < rawDetected->size(); i++) {
125+
auto rawLanguage = rawDetected->at(i);
126+
detected[i] = Napi::String::New(env, rawLanguage.name);
132127
}
133-
Nan::Set(target, Nan::New<v8::String>("DETECTED_LANGUAGES").ToLocalChecked(), detected);
134-
135-
// set all languages
136-
v8::Local<v8::Object> languages = Nan::New<v8::Object>();
137-
vector<NodeCldLanguage>* rawLanguages = Constants::getInstance().getLanguages();
138-
for(vector<NodeCldLanguage>::size_type i = 0; i < rawLanguages->size(); i++) {
139-
NodeCldLanguage rawLanguage = rawLanguages->at(i);
140-
Nan::Set(languages, Nan::New<v8::String>(rawLanguage.name).ToLocalChecked(),
141-
Nan::New<v8::String>(rawLanguage.code).ToLocalChecked());
128+
exports["DETECTED_LANGUAGES"] = detected;
129+
130+
auto languages = Napi::Object::New(env);
131+
auto rawLanguages = Constants::getInstance().getLanguages();
132+
for (size_t i = 0; i < rawLanguages->size(); i++) {
133+
auto rawLanguage = rawLanguages->at(i);
134+
languages[rawLanguage.name] = Napi::String::New(env, rawLanguage.code);
142135
}
143-
Nan::Set(target, Nan::New<v8::String>("LANGUAGES").ToLocalChecked(), languages);
144-
145-
// set encodings
146-
v8::Local<v8::Array> encodings = Nan::New<v8::Array>();
147-
vector<NodeCldEncoding>* rawEncodings = Constants::getInstance().getEncodings();
148-
for(vector<NodeCldEncoding>::size_type i = 0; i < rawEncodings->size(); i++) {
149-
NodeCldEncoding rawEncoding = rawEncodings->at(i);
150-
Nan::Set(encodings, static_cast<uint32_t>(i),
151-
Nan::New<v8::String>(rawEncoding.name).ToLocalChecked());
136+
exports["LANGUAGES"] = languages;
137+
138+
auto rawEncodings = Constants::getInstance().getEncodings();
139+
auto numEncodings = rawEncodings->size();
140+
auto encodings = Napi::Array::New(env, numEncodings);
141+
for (size_t i = 0; i < numEncodings; i++) {
142+
auto rawEncoding = rawEncodings->at(i);
143+
encodings[i] = Napi::String::New(env, rawEncoding.name);
152144
}
153-
Nan::Set(target, Nan::New<v8::String>("ENCODINGS").ToLocalChecked(), encodings);
145+
exports["ENCODINGS"] = encodings;
146+
147+
exports["detect"] = Napi::Function::New(env, Detect);
154148

155-
Nan::SetMethod(target, "detect", Detect);
149+
return exports;
156150
}
157151

158-
NODE_MODULE(cld, init);
152+
NODE_API_MODULE(cld, Init);
159153
}

0 commit comments

Comments
 (0)