node-addon-api 1.7.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/.travis.yml +3 -9
  2. package/CHANGELOG.md +154 -9
  3. package/README.md +58 -9
  4. package/benchmark/README.md +47 -0
  5. package/benchmark/binding.gyp +25 -0
  6. package/benchmark/function_args.cc +153 -0
  7. package/benchmark/function_args.js +52 -0
  8. package/benchmark/index.js +34 -0
  9. package/benchmark/property_descriptor.cc +60 -0
  10. package/benchmark/property_descriptor.js +29 -0
  11. package/common.gypi +21 -0
  12. package/doc/array_buffer.md +1 -1
  13. package/doc/async_context.md +10 -0
  14. package/doc/async_operations.md +1 -1
  15. package/doc/async_worker.md +56 -26
  16. package/doc/async_worker_variants.md +456 -0
  17. package/doc/basic_types.md +8 -0
  18. package/doc/bigint.md +2 -1
  19. package/doc/class_property_descriptor.md +5 -6
  20. package/doc/cmake-js.md +58 -9
  21. package/doc/creating_a_release.md +5 -5
  22. package/doc/date.md +68 -0
  23. package/doc/env.md +14 -0
  24. package/doc/function.md +108 -1
  25. package/doc/object.md +74 -1
  26. package/doc/object_lifetime_management.md +1 -1
  27. package/doc/object_wrap.md +291 -4
  28. package/doc/prebuild_tools.md +1 -1
  29. package/doc/property_descriptor.md +64 -9
  30. package/doc/setup.md +0 -1
  31. package/doc/string.md +1 -1
  32. package/doc/symbol.md +1 -1
  33. package/doc/threadsafe_function.md +18 -1
  34. package/doc/value.md +10 -1
  35. package/except.gypi +16 -0
  36. package/index.js +5 -42
  37. package/napi-inl.h +1048 -147
  38. package/napi.h +424 -49
  39. package/node_api.gyp +9 -0
  40. package/noexcept.gypi +16 -0
  41. package/{src/nothing.c → nothing.c} +0 -0
  42. package/package.json +244 -47
  43. package/tools/README.md +4 -4
  44. package/tools/conversion.js +0 -4
  45. package/external-napi/node_api.h +0 -7
  46. package/src/node_api.cc +0 -3655
  47. package/src/node_api.gyp +0 -21
  48. package/src/node_api.h +0 -588
  49. package/src/node_api_types.h +0 -115
  50. package/src/node_internals.cc +0 -142
  51. package/src/node_internals.h +0 -157
  52. package/src/util-inl.h +0 -38
  53. package/src/util.h +0 -7
@@ -0,0 +1,52 @@
1
+ const path = require('path');
2
+ const Benchmark = require('benchmark');
3
+ const addonName = path.basename(__filename, '.js');
4
+
5
+ [ addonName, addonName + '_noexcept' ]
6
+ .forEach((addonName) => {
7
+ const rootAddon = require(`./build/Release/${addonName}`);
8
+ const implems = Object.keys(rootAddon);
9
+ const anObject = {};
10
+
11
+ console.log(`${addonName}: `);
12
+
13
+ console.log('no arguments:');
14
+ implems.reduce((suite, implem) => {
15
+ const fn = rootAddon[implem].noArgFunction;
16
+ return suite.add(implem, () => fn());
17
+ }, new Benchmark.Suite)
18
+ .on('cycle', (event) => console.log(String(event.target)))
19
+ .run();
20
+
21
+ console.log('one argument:');
22
+ implems.reduce((suite, implem) => {
23
+ const fn = rootAddon[implem].oneArgFunction;
24
+ return suite.add(implem, () => fn('x'));
25
+ }, new Benchmark.Suite)
26
+ .on('cycle', (event) => console.log(String(event.target)))
27
+ .run();
28
+
29
+ console.log('two arguments:');
30
+ implems.reduce((suite, implem) => {
31
+ const fn = rootAddon[implem].twoArgFunction;
32
+ return suite.add(implem, () => fn('x', 12));
33
+ }, new Benchmark.Suite)
34
+ .on('cycle', (event) => console.log(String(event.target)))
35
+ .run();
36
+
37
+ console.log('three arguments:');
38
+ implems.reduce((suite, implem) => {
39
+ const fn = rootAddon[implem].threeArgFunction;
40
+ return suite.add(implem, () => fn('x', 12, true));
41
+ }, new Benchmark.Suite)
42
+ .on('cycle', (event) => console.log(String(event.target)))
43
+ .run();
44
+
45
+ console.log('four arguments:');
46
+ implems.reduce((suite, implem) => {
47
+ const fn = rootAddon[implem].fourArgFunction;
48
+ return suite.add(implem, () => fn('x', 12, true, anObject));
49
+ }, new Benchmark.Suite)
50
+ .on('cycle', (event) => console.log(String(event.target)))
51
+ .run();
52
+ });
@@ -0,0 +1,34 @@
1
+ 'use strict';
2
+
3
+ const { readdirSync } = require('fs');
4
+ const { spawnSync } = require('child_process');
5
+ const path = require('path');
6
+
7
+ let benchmarks = [];
8
+
9
+ if (!!process.env.npm_config_benchmarks) {
10
+ benchmarks = process.env.npm_config_benchmarks
11
+ .split(';')
12
+ .map((item) => (item + '.js'));
13
+ }
14
+
15
+ // Run each file in this directory or the list given on the command line except
16
+ // index.js as a Node.js process.
17
+ (benchmarks.length > 0 ? benchmarks : readdirSync(__dirname))
18
+ .filter((item) => (item !== 'index.js' && item.match(/\.js$/)))
19
+ .map((item) => path.join(__dirname, item))
20
+ .forEach((item) => {
21
+ const child = spawnSync(process.execPath, [
22
+ '--expose-gc',
23
+ item
24
+ ], { stdio: 'inherit' });
25
+ if (child.signal) {
26
+ console.error(`Tests aborted with ${child.signal}`);
27
+ process.exitCode = 1;
28
+ } else {
29
+ process.exitCode = child.status;
30
+ }
31
+ if (child.status !== 0) {
32
+ process.exit(process.exitCode);
33
+ }
34
+ });
@@ -0,0 +1,60 @@
1
+ #include "napi.h"
2
+
3
+ static napi_value Getter_Core(napi_env env, napi_callback_info info) {
4
+ (void) info;
5
+ napi_value result;
6
+ napi_status status = napi_create_uint32(env, 42, &result);
7
+ NAPI_THROW_IF_FAILED(env, status, nullptr);
8
+ return result;
9
+ }
10
+
11
+ static napi_value Setter_Core(napi_env env, napi_callback_info info) {
12
+ size_t argc = 1;
13
+ napi_value argv;
14
+ napi_status status =
15
+ napi_get_cb_info(env, info, &argc, &argv, nullptr, nullptr);
16
+ NAPI_THROW_IF_FAILED(env, status, nullptr);
17
+ (void) argv;
18
+ return nullptr;
19
+ }
20
+
21
+ static Napi::Value Getter(const Napi::CallbackInfo& info) {
22
+ return Napi::Number::New(info.Env(), 42);
23
+ }
24
+
25
+ static void Setter(const Napi::CallbackInfo& info) {
26
+ (void) info[0];
27
+ }
28
+
29
+ static Napi::Object Init(Napi::Env env, Napi::Object exports) {
30
+ napi_status status;
31
+ napi_property_descriptor core_prop = {
32
+ "core",
33
+ nullptr,
34
+ nullptr,
35
+ Getter_Core,
36
+ Setter_Core,
37
+ nullptr,
38
+ napi_enumerable,
39
+ nullptr
40
+ };
41
+
42
+ status = napi_define_properties(env, exports, 1, &core_prop);
43
+ NAPI_THROW_IF_FAILED(env, status, Napi::Object());
44
+
45
+ exports.DefineProperty(
46
+ Napi::PropertyDescriptor::Accessor(env,
47
+ exports,
48
+ "cplusplus",
49
+ Getter,
50
+ Setter,
51
+ napi_enumerable));
52
+
53
+ exports.DefineProperty(
54
+ Napi::PropertyDescriptor::Accessor<Getter, Setter>("templated",
55
+ napi_enumerable));
56
+
57
+ return exports;
58
+ }
59
+
60
+ NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
@@ -0,0 +1,29 @@
1
+ const path = require('path');
2
+ const Benchmark = require('benchmark');
3
+ const addonName = path.basename(__filename, '.js');
4
+
5
+ [ addonName, addonName + '_noexcept' ]
6
+ .forEach((addonName) => {
7
+ const rootAddon = require(`./build/Release/${addonName}`);
8
+ const getters = new Benchmark.Suite;
9
+ const setters = new Benchmark.Suite;
10
+
11
+ console.log(`${addonName}: `);
12
+
13
+ Object.keys(rootAddon).forEach((key) => {
14
+ getters.add(`${key} getter`, () => {
15
+ const x = rootAddon[key];
16
+ });
17
+ setters.add(`${key} setter`, () => {
18
+ rootAddon[key] = 5;
19
+ })
20
+ });
21
+
22
+ getters
23
+ .on('cycle', (event) => console.log(String(event.target)))
24
+ .run();
25
+
26
+ setters
27
+ .on('cycle', (event) => console.log(String(event.target)))
28
+ .run();
29
+ });
package/common.gypi ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ 'variables': {
3
+ 'NAPI_VERSION%': "<!(node -p \"process.versions.napi\")",
4
+ 'disable_deprecated': "<!(node -p \"process.env['npm_config_disable_deprecated']\")"
5
+ },
6
+ 'conditions': [
7
+ ['NAPI_VERSION!=""', { 'defines': ['NAPI_VERSION=<@(NAPI_VERSION)'] } ],
8
+ ['disable_deprecated=="true"', {
9
+ 'defines': ['NODE_ADDON_API_DISABLE_DEPRECATED']
10
+ }],
11
+ ['OS=="mac"', {
12
+ 'cflags+': ['-fvisibility=hidden'],
13
+ 'xcode_settings': {
14
+ 'OTHER_CFLAGS': ['-fvisibility=hidden']
15
+ }
16
+ }]
17
+ ],
18
+ 'include_dirs': ["<!@(node -p \"require('../').include\")"],
19
+ 'cflags': [ '-Werror', '-Wall', '-Wextra', '-Wpedantic', '-Wunused-parameter' ],
20
+ 'cflags_cc': [ '-Werror', '-Wall', '-Wextra', '-Wpedantic', '-Wunused-parameter' ]
21
+ }
@@ -123,7 +123,7 @@ Returns the length of the wrapped data, in bytes.
123
123
  ### Data
124
124
 
125
125
  ```cpp
126
- T* Napi::ArrayBuffer::Data() const;
126
+ void* Napi::ArrayBuffer::Data() const;
127
127
  ```
128
128
 
129
129
  Returns a pointer the wrapped data.
@@ -45,6 +45,16 @@ The `Napi::AsyncContext` to be destroyed.
45
45
  virtual Napi::AsyncContext::~AsyncContext();
46
46
  ```
47
47
 
48
+ ### Env
49
+
50
+ Requests the environment in which the async context has been initially created.
51
+
52
+ ```cpp
53
+ Napi::Env Env() const;
54
+ ```
55
+
56
+ Returns the `Napi::Env` environment in which the async context has been created.
57
+
48
58
  ## Operator
49
59
 
50
60
  ```cpp
@@ -4,7 +4,7 @@ Node.js native add-ons often need to execute long running tasks and to avoid
4
4
  blocking the **event loop** they have to run them asynchronously from the
5
5
  **event loop**.
6
6
  In the Node.js model of execution the event loop thread represents the thread
7
- where JavaScript code is executing. The node.js guidance is to avoid blocking
7
+ where JavaScript code is executing. The Node.js guidance is to avoid blocking
8
8
  other work queued on the event loop thread. Therefore, we need to do this work on
9
9
  another thread.
10
10
 
@@ -7,8 +7,8 @@ operation.
7
7
 
8
8
  Once created, execution is requested by calling `Napi::AsyncWorker::Queue`. When
9
9
  a thread is available for execution the `Napi::AsyncWorker::Execute` method will
10
- be invoked. Once `Napi::AsyncWorker::Execute` completes either
11
- `Napi::AsyncWorker::OnOK` or `Napi::AsyncWorker::OnError` will be invoked. Once
10
+ be invoked. Once `Napi::AsyncWorker::Execute` completes either
11
+ `Napi::AsyncWorker::OnOK` or `Napi::AsyncWorker::OnError` will be invoked. Once
12
12
  the `Napi::AsyncWorker::OnOK` or `Napi::AsyncWorker::OnError` methods are
13
13
  complete the `Napi::AsyncWorker` instance is destructed.
14
14
 
@@ -38,7 +38,7 @@ void Napi::AsyncWorker::Queue();
38
38
  ### Cancel
39
39
 
40
40
  Cancels queued work if it has not yet been started. If it has already started
41
- executing, it cannot be cancelled. If cancelled successfully neither
41
+ executing, it cannot be cancelled. If cancelled successfully neither
42
42
  `OnOK` nor `OnError` will be called.
43
43
 
44
44
  ```cpp
@@ -90,14 +90,14 @@ void Napi::AsyncWorker::SetError(const std::string& error);
90
90
 
91
91
  ### Execute
92
92
 
93
- This method is used to execute some tasks out of the **event loop** on a libuv
93
+ This method is used to execute some tasks outside of the **event loop** on a libuv
94
94
  worker thread. Subclasses must implement this method and the method is run on
95
- a thread other than that running the main event loop. As the method is not
95
+ a thread other than that running the main event loop. As the method is not
96
96
  running on the main event loop, it must avoid calling any methods from node-addon-api
97
97
  or running any code that might invoke JavaScript. Instead, once this method is
98
98
  complete any interaction through node-addon-api with JavaScript should be implemented
99
- in the `Napi::AsyncWorker::OnOK` method which runs on the main thread and is
100
- invoked when the `Napi::AsyncWorker::Execute` method completes.
99
+ in the `Napi::AsyncWorker::OnOK` method and `Napi::AsyncWorker::OnError` which run
100
+ on the main thread and are invoked when the `Napi::AsyncWorker::Execute` method completes.
101
101
 
102
102
  ```cpp
103
103
  virtual void Napi::AsyncWorker::Execute() = 0;
@@ -106,18 +106,19 @@ virtual void Napi::AsyncWorker::Execute() = 0;
106
106
  ### OnOK
107
107
 
108
108
  This method is invoked when the computation in the `Execute` method ends.
109
- The default implementation runs the Callback optionally provided when the AsyncWorker class
110
- was created. The callback will by default receive no arguments. To provide arguments,
111
- override the `GetResult()` method.
109
+ The default implementation runs the `Callback` optionally provided when the
110
+ `AsyncWorker` class was created. The `Callback` will by default receive no
111
+ arguments. The arguments to the `Callback` can be provided by overriding the
112
+ `GetResult()` method.
112
113
 
113
114
  ```cpp
114
115
  virtual void Napi::AsyncWorker::OnOK();
115
116
  ```
116
117
  ### GetResult
117
118
 
118
- This method returns the arguments passed to the Callback invoked by the default
119
+ This method returns the arguments passed to the `Callback` invoked by the default
119
120
  `OnOK()` implementation. The default implementation returns an empty vector,
120
- providing no arguments to the Callback.
121
+ providing no arguments to the `Callback`.
121
122
 
122
123
  ```cpp
123
124
  virtual std::vector<napi_value> Napi::AsyncWorker::GetResult(Napi::Env env);
@@ -128,13 +129,42 @@ virtual std::vector<napi_value> Napi::AsyncWorker::GetResult(Napi::Env env);
128
129
  This method is invoked after `Napi::AsyncWorker::Execute` completes if an error
129
130
  occurs while `Napi::AsyncWorker::Execute` is running and C++ exceptions are
130
131
  enabled or if an error was set through a call to `Napi::AsyncWorker::SetError`.
131
- The default implementation calls the callback provided when the `Napi::AsyncWorker`
132
+ The default implementation calls the `Callback` provided when the `Napi::AsyncWorker`
132
133
  class was created, passing in the error as the first parameter.
133
134
 
134
135
  ```cpp
135
136
  virtual void Napi::AsyncWorker::OnError(const Napi::Error& e);
136
137
  ```
137
138
 
139
+ ### OnWorkComplete
140
+
141
+ This method is invoked after the work has completed on JavaScript thread.
142
+ The default implementation of this method checks the status of the work and
143
+ tries to dispatch the result to `Napi::AsyncWorker::OnOk` or `Napi::AsyncWorker::Error`
144
+ if the work has committed an error. If the work was cancelled, neither
145
+ `Napi::AsyncWorker::OnOk` nor `Napi::AsyncWorker::Error` will be invoked.
146
+ After the result is dispatched, the default implementation will call into
147
+ `Napi::AsyncWorker::Destroy` if `SuppressDestruct()` was not called.
148
+
149
+ ```cpp
150
+ virtual void OnWorkComplete(Napi::Env env, napi_status status);
151
+ ```
152
+
153
+ ### OnExecute
154
+
155
+ This method is invoked immediately on the work thread when scheduled.
156
+ The default implementation of this method just calls the `Napi::AsyncWorker::Execute`
157
+ and handles exceptions if cpp exceptions were enabled.
158
+
159
+ The `OnExecute` method receives an `napi_env` argument. However, the `napi_env`
160
+ must NOT be used within this method, as it does not run on the JavaScript
161
+ thread and must not run any method that would cause JavaScript to run. In
162
+ practice, this means that almost any use of `napi_env` will be incorrect.
163
+
164
+ ```cpp
165
+ virtual void OnExecute(Napi::Env env);
166
+ ```
167
+
138
168
  ### Destroy
139
169
 
140
170
  This method is invoked when the instance must be deallocated. If
@@ -172,7 +202,7 @@ explicit Napi::AsyncWorker(const Napi::Function& callback, const char* resource_
172
202
 
173
203
  - `[in] callback`: The function which will be called when an asynchronous
174
204
  operations ends. The given function is called from the main event loop thread.
175
- - `[in] resource_name`: Null-terminated strings that represents the
205
+ - `[in] resource_name`: Null-terminated string that represents the
176
206
  identifier for the kind of resource that is being provided for diagnostic
177
207
  information exposed by the async_hooks API.
178
208
 
@@ -189,7 +219,7 @@ explicit Napi::AsyncWorker(const Napi::Function& callback, const char* resource_
189
219
 
190
220
  - `[in] callback`: The function which will be called when an asynchronous
191
221
  operations ends. The given function is called from the main event loop thread.
192
- - `[in] resource_name`: Null-terminated strings that represents the
222
+ - `[in] resource_name`: Null-terminated string that represents the
193
223
  identifier for the kind of resource that is being provided for diagnostic
194
224
  information exposed by the async_hooks API.
195
225
  - `[in] resource`: Object associated with the asynchronous operation that
@@ -224,7 +254,7 @@ explicit Napi::AsyncWorker(const Napi::Object& receiver, const Napi::Function& c
224
254
  - `[in] receiver`: The `this` object passed to the called function.
225
255
  - `[in] callback`: The function which will be called when an asynchronous
226
256
  operations ends. The given function is called from the main event loop thread.
227
- - `[in] resource_name`: Null-terminated strings that represents the
257
+ - `[in] resource_name`: Null-terminated string that represents the
228
258
  identifier for the kind of resource that is being provided for diagnostic
229
259
  information exposed by the async_hooks API.
230
260
 
@@ -242,7 +272,7 @@ explicit Napi::AsyncWorker(const Napi::Object& receiver, const Napi::Function& c
242
272
  - `[in] receiver`: The `this` object passed to the called function.
243
273
  - `[in] callback`: The function which will be called when an asynchronous
244
274
  operations ends. The given function is called from the main event loop thread.
245
- - `[in] resource_name`: Null-terminated strings that represents the
275
+ - `[in] resource_name`: Null-terminated string that represents the
246
276
  identifier for the kind of resource that is being provided for diagnostic
247
277
  information exposed by the async_hooks API.
248
278
  - `[in] resource`: Object associated with the asynchronous operation that
@@ -274,7 +304,7 @@ explicit Napi::AsyncWorker(Napi::Env env, const char* resource_name);
274
304
  ```
275
305
 
276
306
  - `[in] env`: The environment in which to create the `Napi::AsyncWorker`.
277
- - `[in] resource_name`: Null-terminated strings that represents the
307
+ - `[in] resource_name`: Null-terminated string that represents the
278
308
  identifier for the kind of resource that is being provided for diagnostic
279
309
  information exposed by the async_hooks API.
280
310
 
@@ -290,7 +320,7 @@ explicit Napi::AsyncWorker(Napi::Env env, const char* resource_name, const Napi:
290
320
  ```
291
321
 
292
322
  - `[in] env`: The environment in which to create the `Napi::AsyncWorker`.
293
- - `[in] resource_name`: Null-terminated strings that represents the
323
+ - `[in] resource_name`: Null-terminated string that represents the
294
324
  identifier for the kind of resource that is being provided for diagnostic
295
325
  information exposed by the async_hooks API.
296
326
  - `[in] resource`: Object associated with the asynchronous operation that
@@ -333,7 +363,7 @@ function runs in the background out of the **event loop** thread and at the end
333
363
  the `Napi::AsyncWorker::OnOK` or `Napi::AsyncWorker::OnError` function will be
334
364
  called and are executed as part of the event loop.
335
365
 
336
- The code below show a basic example of `Napi::AsyncWorker` the implementation:
366
+ The code below shows a basic example of `Napi::AsyncWorker` the implementation:
337
367
 
338
368
  ```cpp
339
369
  #include<napi.h>
@@ -341,7 +371,7 @@ The code below show a basic example of `Napi::AsyncWorker` the implementation:
341
371
  #include <chrono>
342
372
  #include <thread>
343
373
 
344
- use namespace Napi;
374
+ using namespace Napi;
345
375
 
346
376
  class EchoWorker : public AsyncWorker {
347
377
  public:
@@ -350,12 +380,12 @@ class EchoWorker : public AsyncWorker {
350
380
 
351
381
  ~EchoWorker() {}
352
382
  // This code will be executed on the worker thread
353
- void Execute() {
383
+ void Execute() override {
354
384
  // Need to simulate cpu heavy task
355
385
  std::this_thread::sleep_for(std::chrono::seconds(1));
356
386
  }
357
387
 
358
- void OnOK() {
388
+ void OnOK() override {
359
389
  HandleScope scope(Env());
360
390
  Callback().Call({Env().Null(), String::New(Env(), echo)});
361
391
  }
@@ -371,7 +401,7 @@ the work on the `Napi::AsyncWorker::Execute` method is done the
371
401
  `Napi::AsyncWorker::OnOk` method is called and the results return back to
372
402
  JavaScript invoking the stored callback with its associated environment.
373
403
 
374
- The following code shows an example on how to create and use an `Napi::AsyncWorker`
404
+ The following code shows an example of how to create and use an `Napi::AsyncWorker`.
375
405
 
376
406
  ```cpp
377
407
  #include<napi.h>
@@ -379,10 +409,10 @@ The following code shows an example on how to create and use an `Napi::AsyncWork
379
409
  // Include EchoWorker class
380
410
  // ..
381
411
 
382
- use namespace Napi;
412
+ using namespace Napi;
383
413
 
384
414
  Value Echo(const CallbackInfo& info) {
385
- // You need to check the input data here
415
+ // You need to validate the arguments here.
386
416
  Function cb = info[1].As<Function>();
387
417
  std::string in = info[0].As<String>();
388
418
  EchoWorker* wk = new EchoWorker(cb, in);