node-addon-api 2.0.1 → 3.0.2

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 (63) hide show
  1. package/.travis.yml +1 -4
  2. package/CHANGELOG.md +172 -10
  3. package/README.md +81 -30
  4. package/appveyor.yml +3 -14
  5. package/benchmark/README.md +47 -0
  6. package/benchmark/binding.gyp +25 -0
  7. package/benchmark/function_args.cc +217 -0
  8. package/benchmark/function_args.js +60 -0
  9. package/benchmark/index.js +34 -0
  10. package/benchmark/property_descriptor.cc +91 -0
  11. package/benchmark/property_descriptor.js +37 -0
  12. package/common.gypi +21 -0
  13. package/doc/addon.md +157 -0
  14. package/doc/array.md +81 -0
  15. package/doc/array_buffer.md +4 -0
  16. package/doc/async_worker.md +33 -4
  17. package/doc/{async_progress_worker.md → async_worker_variants.md} +115 -3
  18. package/doc/bigint.md +7 -2
  19. package/doc/boolean.md +4 -0
  20. package/doc/buffer.md +4 -0
  21. package/doc/class_property_descriptor.md +3 -3
  22. package/doc/creating_a_release.md +5 -5
  23. package/doc/dataview.md +4 -0
  24. package/doc/date.md +2 -2
  25. package/doc/env.md +69 -0
  26. package/doc/error.md +5 -0
  27. package/doc/external.md +4 -0
  28. package/doc/function.md +109 -1
  29. package/doc/hierarchy.md +91 -0
  30. package/doc/instance_wrap.md +408 -0
  31. package/doc/name.md +29 -0
  32. package/doc/object.md +44 -1
  33. package/doc/object_lifetime_management.md +1 -1
  34. package/doc/object_wrap.md +219 -215
  35. package/doc/promises.md +5 -0
  36. package/doc/property_descriptor.md +64 -9
  37. package/doc/setup.md +1 -2
  38. package/doc/string.md +5 -1
  39. package/doc/symbol.md +5 -1
  40. package/doc/typed_array.md +4 -0
  41. package/doc/typed_array_of.md +4 -0
  42. package/doc/value.md +166 -104
  43. package/except.gypi +16 -0
  44. package/index.js +7 -41
  45. package/napi-inl.h +1116 -400
  46. package/napi.h +414 -142
  47. package/node_api.gyp +9 -0
  48. package/noexcept.gypi +16 -0
  49. package/{src/nothing.c → nothing.c} +0 -0
  50. package/package.json +63 -1
  51. package/tools/README.md +4 -4
  52. package/tools/conversion.js +4 -8
  53. package/doc/basic_types.md +0 -423
  54. package/doc/working_with_javascript_values.md +0 -14
  55. package/external-napi/node_api.h +0 -7
  56. package/src/node_api.cc +0 -3655
  57. package/src/node_api.gyp +0 -21
  58. package/src/node_api.h +0 -588
  59. package/src/node_api_types.h +0 -115
  60. package/src/node_internals.cc +0 -142
  61. package/src/node_internals.h +0 -157
  62. package/src/util-inl.h +0 -38
  63. package/src/util.h +0 -7
package/napi-inl.h CHANGED
@@ -82,6 +82,24 @@ inline napi_value WrapCallback(Callable callback) {
82
82
  #endif // NAPI_CPP_EXCEPTIONS
83
83
  }
84
84
 
85
+ // For use in JS to C++ void callback wrappers to catch any Napi::Error
86
+ // exceptions and rethrow them as JavaScript exceptions before returning from the
87
+ // callback.
88
+ template <typename Callable>
89
+ inline void WrapVoidCallback(Callable callback) {
90
+ #ifdef NAPI_CPP_EXCEPTIONS
91
+ try {
92
+ callback();
93
+ } catch (const Error& e) {
94
+ e.ThrowAsJavaScriptException();
95
+ }
96
+ #else // NAPI_CPP_EXCEPTIONS
97
+ // When C++ exceptions are disabled, errors are immediately thrown as JS
98
+ // exceptions, so there is no need to catch and rethrow them here.
99
+ callback();
100
+ #endif // NAPI_CPP_EXCEPTIONS
101
+ }
102
+
85
103
  template <typename Callable, typename Return>
86
104
  struct CallbackData {
87
105
  static inline
@@ -117,27 +135,73 @@ struct CallbackData<Callable, void> {
117
135
  void* data;
118
136
  };
119
137
 
138
+ template <void (*Callback)(const CallbackInfo& info)>
139
+ static napi_value
140
+ TemplatedVoidCallback(napi_env env, napi_callback_info info) NAPI_NOEXCEPT {
141
+ return details::WrapCallback([&] {
142
+ CallbackInfo cbInfo(env, info);
143
+ Callback(cbInfo);
144
+ return nullptr;
145
+ });
146
+ }
147
+
148
+ template <Napi::Value (*Callback)(const CallbackInfo& info)>
149
+ static napi_value
150
+ TemplatedCallback(napi_env env, napi_callback_info info) NAPI_NOEXCEPT {
151
+ return details::WrapCallback([&] {
152
+ CallbackInfo cbInfo(env, info);
153
+ return Callback(cbInfo);
154
+ });
155
+ }
156
+
157
+ template <typename T,
158
+ Napi::Value (T::*UnwrapCallback)(const CallbackInfo& info)>
159
+ static napi_value
160
+ TemplatedInstanceCallback(napi_env env, napi_callback_info info) NAPI_NOEXCEPT {
161
+ return details::WrapCallback([&] {
162
+ CallbackInfo cbInfo(env, info);
163
+ T* instance = T::Unwrap(cbInfo.This().As<Object>());
164
+ return (instance->*UnwrapCallback)(cbInfo);
165
+ });
166
+ }
167
+
168
+ template <typename T, void (T::*UnwrapCallback)(const CallbackInfo& info)>
169
+ static napi_value
170
+ TemplatedInstanceVoidCallback(napi_env env,
171
+ napi_callback_info info) NAPI_NOEXCEPT {
172
+ return details::WrapCallback([&] {
173
+ CallbackInfo cbInfo(env, info);
174
+ T* instance = T::Unwrap(cbInfo.This().As<Object>());
175
+ (instance->*UnwrapCallback)(cbInfo);
176
+ return nullptr;
177
+ });
178
+ }
179
+
120
180
  template <typename T, typename Finalizer, typename Hint = void>
121
181
  struct FinalizeData {
122
182
  static inline
123
- void Wrapper(napi_env env, void* data, void* finalizeHint) {
124
- FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
125
- finalizeData->callback(Env(env), static_cast<T*>(data));
126
- delete finalizeData;
183
+ void Wrapper(napi_env env, void* data, void* finalizeHint) noexcept {
184
+ WrapVoidCallback([&] {
185
+ FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
186
+ finalizeData->callback(Env(env), static_cast<T*>(data));
187
+ delete finalizeData;
188
+ });
127
189
  }
128
190
 
129
191
  static inline
130
- void WrapperWithHint(napi_env env, void* data, void* finalizeHint) {
131
- FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
132
- finalizeData->callback(Env(env), static_cast<T*>(data), finalizeData->hint);
133
- delete finalizeData;
192
+ void WrapperWithHint(napi_env env, void* data, void* finalizeHint) noexcept {
193
+ WrapVoidCallback([&] {
194
+ FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
195
+ finalizeData->callback(Env(env), static_cast<T*>(data), finalizeData->hint);
196
+ delete finalizeData;
197
+ });
134
198
  }
135
199
 
136
200
  Finalizer callback;
137
201
  Hint* hint;
138
202
  };
139
203
 
140
- #if (NAPI_VERSION > 3)
204
+ #if (NAPI_VERSION > 3 && !defined(__wasm32__))
141
205
  template <typename ContextType=void,
142
206
  typename Finalizer=std::function<void(Env, void*, ContextType*)>,
143
207
  typename FinalizerDataType=void>
@@ -150,9 +214,6 @@ struct ThreadSafeFinalize {
150
214
  ThreadSafeFinalize* finalizeData =
151
215
  static_cast<ThreadSafeFinalize*>(rawFinalizeData);
152
216
  finalizeData->callback(Env(env));
153
- if (finalizeData->tsfn) {
154
- *finalizeData->tsfn = nullptr;
155
- }
156
217
  delete finalizeData;
157
218
  }
158
219
 
@@ -166,9 +227,6 @@ struct ThreadSafeFinalize {
166
227
  ThreadSafeFinalize* finalizeData =
167
228
  static_cast<ThreadSafeFinalize*>(rawFinalizeData);
168
229
  finalizeData->callback(Env(env), finalizeData->data);
169
- if (finalizeData->tsfn) {
170
- *finalizeData->tsfn = nullptr;
171
- }
172
230
  delete finalizeData;
173
231
  }
174
232
 
@@ -182,9 +240,6 @@ struct ThreadSafeFinalize {
182
240
  ThreadSafeFinalize* finalizeData =
183
241
  static_cast<ThreadSafeFinalize*>(rawFinalizeData);
184
242
  finalizeData->callback(Env(env), static_cast<ContextType*>(rawContext));
185
- if (finalizeData->tsfn) {
186
- *finalizeData->tsfn = nullptr;
187
- }
188
243
  delete finalizeData;
189
244
  }
190
245
 
@@ -199,17 +254,13 @@ struct ThreadSafeFinalize {
199
254
  static_cast<ThreadSafeFinalize*>(rawFinalizeData);
200
255
  finalizeData->callback(Env(env), finalizeData->data,
201
256
  static_cast<ContextType*>(rawContext));
202
- if (finalizeData->tsfn) {
203
- *finalizeData->tsfn = nullptr;
204
- }
205
257
  delete finalizeData;
206
258
  }
207
259
 
208
260
  FinalizerDataType* data;
209
261
  Finalizer callback;
210
- napi_threadsafe_function* tsfn;
211
262
  };
212
- #endif
263
+ #endif // NAPI_VERSION > 3 && !defined(__wasm32__)
213
264
 
214
265
  template <typename Getter, typename Setter>
215
266
  struct AccessorCallbackData {
@@ -251,6 +302,7 @@ struct AccessorCallbackData {
251
302
  // Module registration
252
303
  ////////////////////////////////////////////////////////////////////////////////
253
304
 
305
+ // Register an add-on based on an initializer function.
254
306
  #define NODE_API_MODULE(modname, regfunc) \
255
307
  napi_value __napi_ ## regfunc(napi_env env, \
256
308
  napi_value exports) { \
@@ -258,6 +310,20 @@ struct AccessorCallbackData {
258
310
  } \
259
311
  NAPI_MODULE(modname, __napi_ ## regfunc)
260
312
 
313
+ // Register an add-on based on a subclass of `Addon<T>` with a custom Node.js
314
+ // module name.
315
+ #define NODE_API_NAMED_ADDON(modname, classname) \
316
+ static napi_value __napi_ ## classname(napi_env env, \
317
+ napi_value exports) { \
318
+ return Napi::RegisterModule(env, exports, &classname::Init); \
319
+ } \
320
+ NAPI_MODULE(modname, __napi_ ## classname)
321
+
322
+ // Register an add-on based on a subclass of `Addon<T>` with the Node.js module
323
+ // name given by node-gyp from the `target_name` in binding.gyp.
324
+ #define NODE_API_ADDON(classname) \
325
+ NODE_API_NAMED_ADDON(NODE_GYP_MODULE_NAME, classname)
326
+
261
327
  // Adapt the NAPI_MODULE registration function:
262
328
  // - Wrap the arguments in NAPI wrappers.
263
329
  // - Catch any NAPI errors and rethrow as JS exceptions.
@@ -319,6 +385,64 @@ inline Error Env::GetAndClearPendingException() {
319
385
  return Error(_env, value);
320
386
  }
321
387
 
388
+ inline Value Env::RunScript(const char* utf8script) {
389
+ String script = String::New(_env, utf8script);
390
+ return RunScript(script);
391
+ }
392
+
393
+ inline Value Env::RunScript(const std::string& utf8script) {
394
+ return RunScript(utf8script.c_str());
395
+ }
396
+
397
+ inline Value Env::RunScript(String script) {
398
+ napi_value result;
399
+ napi_status status = napi_run_script(_env, script, &result);
400
+ NAPI_THROW_IF_FAILED(_env, status, Undefined());
401
+ return Value(_env, result);
402
+ }
403
+
404
+ #if NAPI_VERSION > 5
405
+ template <typename T, Env::Finalizer<T> fini>
406
+ inline void Env::SetInstanceData(T* data) {
407
+ napi_status status =
408
+ napi_set_instance_data(_env, data, [](napi_env env, void* data, void*) {
409
+ fini(env, static_cast<T*>(data));
410
+ }, nullptr);
411
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
412
+ }
413
+
414
+ template <typename DataType,
415
+ typename HintType,
416
+ Napi::Env::FinalizerWithHint<DataType, HintType> fini>
417
+ inline void Env::SetInstanceData(DataType* data, HintType* hint) {
418
+ napi_status status =
419
+ napi_set_instance_data(_env, data,
420
+ [](napi_env env, void* data, void* hint) {
421
+ fini(env, static_cast<DataType*>(data), static_cast<HintType*>(hint));
422
+ }, hint);
423
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
424
+ }
425
+
426
+ template <typename T>
427
+ inline T* Env::GetInstanceData() {
428
+ void* data = nullptr;
429
+
430
+ napi_status status = napi_get_instance_data(_env, &data);
431
+ NAPI_THROW_IF_FAILED(_env, status, nullptr);
432
+
433
+ return static_cast<T*>(data);
434
+ }
435
+
436
+ template <typename T> void Env::DefaultFini(Env, T* data) {
437
+ delete data;
438
+ }
439
+
440
+ template <typename DataType, typename HintType>
441
+ void Env::DefaultFiniWithHint(Env, DataType* data, HintType*) {
442
+ delete data;
443
+ }
444
+ #endif // NAPI_VERSION > 5
445
+
322
446
  ////////////////////////////////////////////////////////////////////////////////
323
447
  // Value class
324
448
  ////////////////////////////////////////////////////////////////////////////////
@@ -383,14 +507,11 @@ inline bool Value::IsNumber() const {
383
507
  return Type() == napi_number;
384
508
  }
385
509
 
386
- // Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
387
- // Once it is no longer experimental guard with the NAPI_VERSION in which it is
388
- // released instead.
389
- #ifdef NAPI_EXPERIMENTAL
510
+ #if NAPI_VERSION > 5
390
511
  inline bool Value::IsBigInt() const {
391
512
  return Type() == napi_bigint;
392
513
  }
393
- #endif // NAPI_EXPERIMENTAL
514
+ #endif // NAPI_VERSION > 5
394
515
 
395
516
  #if (NAPI_VERSION > 4)
396
517
  inline bool Value::IsDate() const {
@@ -621,10 +742,7 @@ inline double Number::DoubleValue() const {
621
742
  return result;
622
743
  }
623
744
 
624
- // Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
625
- // Once it is no longer experimental guard with the NAPI_VERSION in which it is
626
- // released instead.
627
- #ifdef NAPI_EXPERIMENTAL
745
+ #if NAPI_VERSION > 5
628
746
  ////////////////////////////////////////////////////////////////////////////////
629
747
  // BigInt Class
630
748
  ////////////////////////////////////////////////////////////////////////////////
@@ -685,7 +803,7 @@ inline void BigInt::ToWords(int* sign_bit, size_t* word_count, uint64_t* words)
685
803
  _env, _value, sign_bit, word_count, words);
686
804
  NAPI_THROW_IF_FAILED_VOID(_env, status);
687
805
  }
688
- #endif // NAPI_EXPERIMENTAL
806
+ #endif // NAPI_VERSION > 5
689
807
 
690
808
  #if (NAPI_VERSION > 4)
691
809
  ////////////////////////////////////////////////////////////////////////////////
@@ -1330,7 +1448,7 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env, size_t byteLength) {
1330
1448
  napi_status status = napi_create_arraybuffer(env, byteLength, &data, &value);
1331
1449
  NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
1332
1450
 
1333
- return ArrayBuffer(env, value, data, byteLength);
1451
+ return ArrayBuffer(env, value);
1334
1452
  }
1335
1453
 
1336
1454
  inline ArrayBuffer ArrayBuffer::New(napi_env env,
@@ -1341,7 +1459,7 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
1341
1459
  env, externalData, byteLength, nullptr, nullptr, &value);
1342
1460
  NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
1343
1461
 
1344
- return ArrayBuffer(env, value, externalData, byteLength);
1462
+ return ArrayBuffer(env, value);
1345
1463
  }
1346
1464
 
1347
1465
  template <typename Finalizer>
@@ -1364,7 +1482,7 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
1364
1482
  NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
1365
1483
  }
1366
1484
 
1367
- return ArrayBuffer(env, value, externalData, byteLength);
1485
+ return ArrayBuffer(env, value);
1368
1486
  }
1369
1487
 
1370
1488
  template <typename Finalizer, typename Hint>
@@ -1388,38 +1506,28 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
1388
1506
  NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
1389
1507
  }
1390
1508
 
1391
- return ArrayBuffer(env, value, externalData, byteLength);
1509
+ return ArrayBuffer(env, value);
1392
1510
  }
1393
1511
 
1394
- inline ArrayBuffer::ArrayBuffer() : Object(), _data(nullptr), _length(0) {
1512
+ inline ArrayBuffer::ArrayBuffer() : Object() {
1395
1513
  }
1396
1514
 
1397
1515
  inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value)
1398
- : Object(env, value), _data(nullptr), _length(0) {
1399
- }
1400
-
1401
- inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value, void* data, size_t length)
1402
- : Object(env, value), _data(data), _length(length) {
1516
+ : Object(env, value) {
1403
1517
  }
1404
1518
 
1405
1519
  inline void* ArrayBuffer::Data() {
1406
- EnsureInfo();
1407
- return _data;
1520
+ void* data;
1521
+ napi_status status = napi_get_arraybuffer_info(_env, _value, &data, nullptr);
1522
+ NAPI_THROW_IF_FAILED(_env, status, nullptr);
1523
+ return data;
1408
1524
  }
1409
1525
 
1410
1526
  inline size_t ArrayBuffer::ByteLength() {
1411
- EnsureInfo();
1412
- return _length;
1413
- }
1414
-
1415
- inline void ArrayBuffer::EnsureInfo() const {
1416
- // The ArrayBuffer instance may have been constructed from a napi_value whose
1417
- // length/data are not yet known. Fetch and cache these values just once,
1418
- // since they can never change during the lifetime of the ArrayBuffer.
1419
- if (_data == nullptr) {
1420
- napi_status status = napi_get_arraybuffer_info(_env, _value, &_data, &_length);
1421
- NAPI_THROW_IF_FAILED_VOID(_env, status);
1422
- }
1527
+ size_t length;
1528
+ napi_status status = napi_get_arraybuffer_info(_env, _value, nullptr, &length);
1529
+ NAPI_THROW_IF_FAILED(_env, status, 0);
1530
+ return length;
1423
1531
  }
1424
1532
 
1425
1533
  ////////////////////////////////////////////////////////////////////////////////
@@ -1635,6 +1743,10 @@ inline uint8_t TypedArray::ElementSize() const {
1635
1743
  case napi_float32_array:
1636
1744
  return 4;
1637
1745
  case napi_float64_array:
1746
+ #if (NAPI_VERSION > 5)
1747
+ case napi_bigint64_array:
1748
+ case napi_biguint64_array:
1749
+ #endif // (NAPI_VERSION > 5)
1638
1750
  return 8;
1639
1751
  default:
1640
1752
  return 0;
@@ -1707,8 +1819,14 @@ inline TypedArrayOf<T>::TypedArrayOf() : TypedArray(), _data(nullptr) {
1707
1819
  template <typename T>
1708
1820
  inline TypedArrayOf<T>::TypedArrayOf(napi_env env, napi_value value)
1709
1821
  : TypedArray(env, value), _data(nullptr) {
1710
- napi_status status = napi_get_typedarray_info(
1711
- _env, _value, &_type, &_length, reinterpret_cast<void**>(&_data), nullptr, nullptr);
1822
+ napi_status status = napi_ok;
1823
+ if (value != nullptr) {
1824
+ status = napi_get_typedarray_info(
1825
+ _env, _value, &_type, &_length, reinterpret_cast<void**>(&_data), nullptr, nullptr);
1826
+ } else {
1827
+ _type = TypedArrayTypeForPrimitiveType<T>();
1828
+ _length = 0;
1829
+ }
1712
1830
  NAPI_THROW_IF_FAILED_VOID(_env, status);
1713
1831
  }
1714
1832
 
@@ -1766,6 +1884,46 @@ CreateFunction(napi_env env,
1766
1884
  return status;
1767
1885
  }
1768
1886
 
1887
+ template <Function::VoidCallback cb>
1888
+ inline Function Function::New(napi_env env, const char* utf8name, void* data) {
1889
+ napi_value result = nullptr;
1890
+ napi_status status = napi_create_function(env,
1891
+ utf8name,
1892
+ NAPI_AUTO_LENGTH,
1893
+ details::TemplatedVoidCallback<cb>,
1894
+ data,
1895
+ &result);
1896
+ NAPI_THROW_IF_FAILED(env, status, Function());
1897
+ return Function(env, result);
1898
+ }
1899
+
1900
+ template <Function::Callback cb>
1901
+ inline Function Function::New(napi_env env, const char* utf8name, void* data) {
1902
+ napi_value result = nullptr;
1903
+ napi_status status = napi_create_function(env,
1904
+ utf8name,
1905
+ NAPI_AUTO_LENGTH,
1906
+ details::TemplatedCallback<cb>,
1907
+ data,
1908
+ &result);
1909
+ NAPI_THROW_IF_FAILED(env, status, Function());
1910
+ return Function(env, result);
1911
+ }
1912
+
1913
+ template <Function::VoidCallback cb>
1914
+ inline Function Function::New(napi_env env,
1915
+ const std::string& utf8name,
1916
+ void* data) {
1917
+ return Function::New<cb>(env, utf8name.c_str(), data);
1918
+ }
1919
+
1920
+ template <Function::Callback cb>
1921
+ inline Function Function::New(napi_env env,
1922
+ const std::string& utf8name,
1923
+ void* data) {
1924
+ return Function::New<cb>(env, utf8name.c_str(), data);
1925
+ }
1926
+
1769
1927
  template <typename Callable>
1770
1928
  inline Function Function::New(napi_env env,
1771
1929
  Callable cb,
@@ -2037,12 +2195,19 @@ inline void Buffer<T>::EnsureInfo() const {
2037
2195
  inline Error Error::New(napi_env env) {
2038
2196
  napi_status status;
2039
2197
  napi_value error = nullptr;
2040
-
2198
+ bool is_exception_pending;
2041
2199
  const napi_extended_error_info* info;
2200
+
2201
+ // We must retrieve the last error info before doing anything else, because
2202
+ // doing anything else will replace the last error info.
2042
2203
  status = napi_get_last_error_info(env, &info);
2043
2204
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info");
2044
2205
 
2045
- if (info->error_code == napi_pending_exception) {
2206
+ status = napi_is_exception_pending(env, &is_exception_pending);
2207
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending");
2208
+
2209
+ // A pending exception takes precedence over any internal error status.
2210
+ if (is_exception_pending) {
2046
2211
  status = napi_get_and_clear_last_exception(env, &error);
2047
2212
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
2048
2213
  }
@@ -2050,15 +2215,6 @@ inline Error Error::New(napi_env env) {
2050
2215
  const char* error_message = info->error_message != nullptr ?
2051
2216
  info->error_message : "Error in native callback";
2052
2217
 
2053
- bool isExceptionPending;
2054
- status = napi_is_exception_pending(env, &isExceptionPending);
2055
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending");
2056
-
2057
- if (isExceptionPending) {
2058
- status = napi_get_and_clear_last_exception(env, &error);
2059
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
2060
- }
2061
-
2062
2218
  napi_value message;
2063
2219
  status = napi_create_string_utf8(
2064
2220
  env,
@@ -2120,7 +2276,7 @@ inline Error& Error::operator =(Error&& other) {
2120
2276
  inline Error::Error(const Error& other) : ObjectReference(other) {
2121
2277
  }
2122
2278
 
2123
- inline Error& Error::operator =(Error& other) {
2279
+ inline Error& Error::operator =(const Error& other) {
2124
2280
  Reset();
2125
2281
 
2126
2282
  _env = other.Env();
@@ -2732,6 +2888,91 @@ inline void CallbackInfo::SetData(void* data) {
2732
2888
  // PropertyDescriptor class
2733
2889
  ////////////////////////////////////////////////////////////////////////////////
2734
2890
 
2891
+ template <typename PropertyDescriptor::GetterCallback Getter>
2892
+ PropertyDescriptor
2893
+ PropertyDescriptor::Accessor(const char* utf8name,
2894
+ napi_property_attributes attributes,
2895
+ void* data) {
2896
+ napi_property_descriptor desc = napi_property_descriptor();
2897
+
2898
+ desc.utf8name = utf8name;
2899
+ desc.getter = details::TemplatedCallback<Getter>;
2900
+ desc.attributes = attributes;
2901
+ desc.data = data;
2902
+
2903
+ return desc;
2904
+ }
2905
+
2906
+ template <typename PropertyDescriptor::GetterCallback Getter>
2907
+ PropertyDescriptor
2908
+ PropertyDescriptor::Accessor(const std::string& utf8name,
2909
+ napi_property_attributes attributes,
2910
+ void* data) {
2911
+ return Accessor<Getter>(utf8name.c_str(), attributes, data);
2912
+ }
2913
+
2914
+ template <typename PropertyDescriptor::GetterCallback Getter>
2915
+ PropertyDescriptor
2916
+ PropertyDescriptor::Accessor(Name name,
2917
+ napi_property_attributes attributes,
2918
+ void* data) {
2919
+ napi_property_descriptor desc = napi_property_descriptor();
2920
+
2921
+ desc.name = name;
2922
+ desc.getter = details::TemplatedCallback<Getter>;
2923
+ desc.attributes = attributes;
2924
+ desc.data = data;
2925
+
2926
+ return desc;
2927
+ }
2928
+
2929
+ template <
2930
+ typename PropertyDescriptor::GetterCallback Getter,
2931
+ typename PropertyDescriptor::SetterCallback Setter>
2932
+ PropertyDescriptor
2933
+ PropertyDescriptor::Accessor(const char* utf8name,
2934
+ napi_property_attributes attributes,
2935
+ void* data) {
2936
+
2937
+ napi_property_descriptor desc = napi_property_descriptor();
2938
+
2939
+ desc.utf8name = utf8name;
2940
+ desc.getter = details::TemplatedCallback<Getter>;
2941
+ desc.setter = details::TemplatedVoidCallback<Setter>;
2942
+ desc.attributes = attributes;
2943
+ desc.data = data;
2944
+
2945
+ return desc;
2946
+ }
2947
+
2948
+ template <
2949
+ typename PropertyDescriptor::GetterCallback Getter,
2950
+ typename PropertyDescriptor::SetterCallback Setter>
2951
+ PropertyDescriptor
2952
+ PropertyDescriptor::Accessor(const std::string& utf8name,
2953
+ napi_property_attributes attributes,
2954
+ void* data) {
2955
+ return Accessor<Getter, Setter>(utf8name.c_str(), attributes, data);
2956
+ }
2957
+
2958
+ template <
2959
+ typename PropertyDescriptor::GetterCallback Getter,
2960
+ typename PropertyDescriptor::SetterCallback Setter>
2961
+ PropertyDescriptor
2962
+ PropertyDescriptor::Accessor(Name name,
2963
+ napi_property_attributes attributes,
2964
+ void* data) {
2965
+ napi_property_descriptor desc = napi_property_descriptor();
2966
+
2967
+ desc.name = name;
2968
+ desc.getter = details::TemplatedCallback<Getter>;
2969
+ desc.setter = details::TemplatedVoidCallback<Setter>;
2970
+ desc.attributes = attributes;
2971
+ desc.data = data;
2972
+
2973
+ return desc;
2974
+ }
2975
+
2735
2976
  template <typename Getter>
2736
2977
  inline PropertyDescriptor
2737
2978
  PropertyDescriptor::Accessor(Napi::Env env,
@@ -2959,137 +3200,453 @@ inline PropertyDescriptor::operator const napi_property_descriptor&() const {
2959
3200
  }
2960
3201
 
2961
3202
  ////////////////////////////////////////////////////////////////////////////////
2962
- // ObjectWrap<T> class
3203
+ // InstanceWrap<T> class
2963
3204
  ////////////////////////////////////////////////////////////////////////////////
2964
3205
 
2965
3206
  template <typename T>
2966
- inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
2967
- napi_env env = callbackInfo.Env();
2968
- napi_value wrapper = callbackInfo.This();
2969
- napi_status status;
2970
- napi_ref ref;
2971
- T* instance = static_cast<T*>(this);
2972
- status = napi_wrap(env, wrapper, instance, FinalizeCallback, nullptr, &ref);
2973
- NAPI_THROW_IF_FAILED_VOID(env, status);
2974
-
2975
- Reference<Object>* instanceRef = instance;
2976
- *instanceRef = Reference<Object>(env, ref);
2977
- }
2978
-
2979
- template<typename T>
2980
- inline ObjectWrap<T>::~ObjectWrap() {}
2981
-
2982
- template<typename T>
2983
- inline T* ObjectWrap<T>::Unwrap(Object wrapper) {
2984
- T* unwrapped;
2985
- napi_status status = napi_unwrap(wrapper.Env(), wrapper, reinterpret_cast<void**>(&unwrapped));
2986
- NAPI_THROW_IF_FAILED(wrapper.Env(), status, nullptr);
2987
- return unwrapped;
2988
- }
2989
-
2990
- template <typename T>
2991
- inline Function
2992
- ObjectWrap<T>::DefineClass(Napi::Env env,
2993
- const char* utf8name,
2994
- const size_t props_count,
2995
- const napi_property_descriptor* descriptors,
2996
- void* data) {
3207
+ inline void InstanceWrap<T>::AttachPropData(napi_env env,
3208
+ napi_value value,
3209
+ const napi_property_descriptor* prop) {
2997
3210
  napi_status status;
2998
- std::vector<napi_property_descriptor> props(props_count);
2999
-
3000
- // We copy the descriptors to a local array because before defining the class
3001
- // we must replace static method property descriptors with value property
3002
- // descriptors such that the value is a function-valued `napi_value` created
3003
- // with `CreateFunction()`.
3004
- //
3005
- // This replacement could be made for instance methods as well, but V8 aborts
3006
- // if we do that, because it expects methods defined on the prototype template
3007
- // to have `FunctionTemplate`s.
3008
- for (size_t index = 0; index < props_count; index++) {
3009
- props[index] = descriptors[index];
3010
- napi_property_descriptor* prop = &props[index];
3011
- if (prop->method == T::StaticMethodCallbackWrapper) {
3012
- status = CreateFunction(env,
3013
- utf8name,
3014
- prop->method,
3015
- static_cast<StaticMethodCallbackData*>(prop->data),
3016
- &(prop->value));
3017
- NAPI_THROW_IF_FAILED(env, status, Function());
3018
- prop->method = nullptr;
3019
- prop->data = nullptr;
3020
- } else if (prop->method == T::StaticVoidMethodCallbackWrapper) {
3021
- status = CreateFunction(env,
3022
- utf8name,
3023
- prop->method,
3024
- static_cast<StaticVoidMethodCallbackData*>(prop->data),
3025
- &(prop->value));
3026
- NAPI_THROW_IF_FAILED(env, status, Function());
3027
- prop->method = nullptr;
3028
- prop->data = nullptr;
3029
- }
3030
- }
3031
-
3032
- napi_value value;
3033
- status = napi_define_class(env,
3034
- utf8name,
3035
- NAPI_AUTO_LENGTH,
3036
- T::ConstructorCallbackWrapper,
3037
- data,
3038
- props_count,
3039
- props.data(),
3040
- &value);
3041
- NAPI_THROW_IF_FAILED(env, status, Function());
3042
-
3043
- // After defining the class we iterate once more over the property descriptors
3044
- // and attach the data associated with accessors and instance methods to the
3045
- // newly created JavaScript class.
3046
- for (size_t idx = 0; idx < props_count; idx++) {
3047
- const napi_property_descriptor* prop = &props[idx];
3048
-
3049
- if (prop->getter == T::StaticGetterCallbackWrapper ||
3050
- prop->setter == T::StaticSetterCallbackWrapper) {
3211
+ if (prop->method != nullptr && !(prop->attributes & napi_static)) {
3212
+ if (prop->method == T::InstanceVoidMethodCallbackWrapper) {
3051
3213
  status = Napi::details::AttachData(env,
3052
- value,
3053
- static_cast<StaticAccessorCallbackData*>(prop->data));
3054
- NAPI_THROW_IF_FAILED(env, status, Function());
3214
+ value,
3215
+ static_cast<InstanceVoidMethodCallbackData*>(prop->data));
3216
+ NAPI_THROW_IF_FAILED_VOID(env, status);
3217
+ } else if (prop->method == T::InstanceMethodCallbackWrapper) {
3218
+ status = Napi::details::AttachData(env,
3219
+ value,
3220
+ static_cast<InstanceMethodCallbackData*>(prop->data));
3221
+ NAPI_THROW_IF_FAILED_VOID(env, status);
3055
3222
  } else if (prop->getter == T::InstanceGetterCallbackWrapper ||
3056
3223
  prop->setter == T::InstanceSetterCallbackWrapper) {
3057
3224
  status = Napi::details::AttachData(env,
3058
3225
  value,
3059
3226
  static_cast<InstanceAccessorCallbackData*>(prop->data));
3060
- NAPI_THROW_IF_FAILED(env, status, Function());
3061
- } else if (prop->method != nullptr && !(prop->attributes & napi_static)) {
3062
- if (prop->method == T::InstanceVoidMethodCallbackWrapper) {
3063
- status = Napi::details::AttachData(env,
3064
- value,
3065
- static_cast<InstanceVoidMethodCallbackData*>(prop->data));
3066
- NAPI_THROW_IF_FAILED(env, status, Function());
3067
- } else if (prop->method == T::InstanceMethodCallbackWrapper) {
3068
- status = Napi::details::AttachData(env,
3069
- value,
3070
- static_cast<InstanceMethodCallbackData*>(prop->data));
3071
- NAPI_THROW_IF_FAILED(env, status, Function());
3072
- }
3227
+ NAPI_THROW_IF_FAILED_VOID(env, status);
3073
3228
  }
3074
3229
  }
3075
-
3076
- return Function(env, value);
3077
3230
  }
3078
3231
 
3079
3232
  template <typename T>
3080
- inline Function ObjectWrap<T>::DefineClass(
3081
- Napi::Env env,
3233
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3082
3234
  const char* utf8name,
3083
- const std::initializer_list<ClassPropertyDescriptor<T>>& properties,
3235
+ InstanceVoidMethodCallback method,
3236
+ napi_property_attributes attributes,
3084
3237
  void* data) {
3085
- return DefineClass(env,
3086
- utf8name,
3087
- properties.size(),
3088
- reinterpret_cast<const napi_property_descriptor*>(properties.begin()),
3089
- data);
3090
- }
3238
+ InstanceVoidMethodCallbackData* callbackData =
3239
+ new InstanceVoidMethodCallbackData({ method, data});
3091
3240
 
3092
- template <typename T>
3241
+ napi_property_descriptor desc = napi_property_descriptor();
3242
+ desc.utf8name = utf8name;
3243
+ desc.method = T::InstanceVoidMethodCallbackWrapper;
3244
+ desc.data = callbackData;
3245
+ desc.attributes = attributes;
3246
+ return desc;
3247
+ }
3248
+
3249
+ template <typename T>
3250
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3251
+ const char* utf8name,
3252
+ InstanceMethodCallback method,
3253
+ napi_property_attributes attributes,
3254
+ void* data) {
3255
+ InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data });
3256
+
3257
+ napi_property_descriptor desc = napi_property_descriptor();
3258
+ desc.utf8name = utf8name;
3259
+ desc.method = T::InstanceMethodCallbackWrapper;
3260
+ desc.data = callbackData;
3261
+ desc.attributes = attributes;
3262
+ return desc;
3263
+ }
3264
+
3265
+ template <typename T>
3266
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3267
+ Symbol name,
3268
+ InstanceVoidMethodCallback method,
3269
+ napi_property_attributes attributes,
3270
+ void* data) {
3271
+ InstanceVoidMethodCallbackData* callbackData =
3272
+ new InstanceVoidMethodCallbackData({ method, data});
3273
+
3274
+ napi_property_descriptor desc = napi_property_descriptor();
3275
+ desc.name = name;
3276
+ desc.method = T::InstanceVoidMethodCallbackWrapper;
3277
+ desc.data = callbackData;
3278
+ desc.attributes = attributes;
3279
+ return desc;
3280
+ }
3281
+
3282
+ template <typename T>
3283
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3284
+ Symbol name,
3285
+ InstanceMethodCallback method,
3286
+ napi_property_attributes attributes,
3287
+ void* data) {
3288
+ InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data });
3289
+
3290
+ napi_property_descriptor desc = napi_property_descriptor();
3291
+ desc.name = name;
3292
+ desc.method = T::InstanceMethodCallbackWrapper;
3293
+ desc.data = callbackData;
3294
+ desc.attributes = attributes;
3295
+ return desc;
3296
+ }
3297
+
3298
+ template <typename T>
3299
+ template <typename InstanceWrap<T>::InstanceVoidMethodCallback method>
3300
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3301
+ const char* utf8name,
3302
+ napi_property_attributes attributes,
3303
+ void* data) {
3304
+ napi_property_descriptor desc = napi_property_descriptor();
3305
+ desc.utf8name = utf8name;
3306
+ desc.method = details::TemplatedInstanceVoidCallback<T, method>;
3307
+ desc.data = data;
3308
+ desc.attributes = attributes;
3309
+ return desc;
3310
+ }
3311
+
3312
+ template <typename T>
3313
+ template <typename InstanceWrap<T>::InstanceMethodCallback method>
3314
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3315
+ const char* utf8name,
3316
+ napi_property_attributes attributes,
3317
+ void* data) {
3318
+ napi_property_descriptor desc = napi_property_descriptor();
3319
+ desc.utf8name = utf8name;
3320
+ desc.method = details::TemplatedInstanceCallback<T, method>;
3321
+ desc.data = data;
3322
+ desc.attributes = attributes;
3323
+ return desc;
3324
+ }
3325
+
3326
+ template <typename T>
3327
+ template <typename InstanceWrap<T>::InstanceVoidMethodCallback method>
3328
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3329
+ Symbol name,
3330
+ napi_property_attributes attributes,
3331
+ void* data) {
3332
+ napi_property_descriptor desc = napi_property_descriptor();
3333
+ desc.name = name;
3334
+ desc.method = details::TemplatedInstanceVoidCallback<T, method>;
3335
+ desc.data = data;
3336
+ desc.attributes = attributes;
3337
+ return desc;
3338
+ }
3339
+
3340
+ template <typename T>
3341
+ template <typename InstanceWrap<T>::InstanceMethodCallback method>
3342
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3343
+ Symbol name,
3344
+ napi_property_attributes attributes,
3345
+ void* data) {
3346
+ napi_property_descriptor desc = napi_property_descriptor();
3347
+ desc.name = name;
3348
+ desc.method = details::TemplatedInstanceCallback<T, method>;
3349
+ desc.data = data;
3350
+ desc.attributes = attributes;
3351
+ return desc;
3352
+ }
3353
+
3354
+ template <typename T>
3355
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceAccessor(
3356
+ const char* utf8name,
3357
+ InstanceGetterCallback getter,
3358
+ InstanceSetterCallback setter,
3359
+ napi_property_attributes attributes,
3360
+ void* data) {
3361
+ InstanceAccessorCallbackData* callbackData =
3362
+ new InstanceAccessorCallbackData({ getter, setter, data });
3363
+
3364
+ napi_property_descriptor desc = napi_property_descriptor();
3365
+ desc.utf8name = utf8name;
3366
+ desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr;
3367
+ desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr;
3368
+ desc.data = callbackData;
3369
+ desc.attributes = attributes;
3370
+ return desc;
3371
+ }
3372
+
3373
+ template <typename T>
3374
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceAccessor(
3375
+ Symbol name,
3376
+ InstanceGetterCallback getter,
3377
+ InstanceSetterCallback setter,
3378
+ napi_property_attributes attributes,
3379
+ void* data) {
3380
+ InstanceAccessorCallbackData* callbackData =
3381
+ new InstanceAccessorCallbackData({ getter, setter, data });
3382
+
3383
+ napi_property_descriptor desc = napi_property_descriptor();
3384
+ desc.name = name;
3385
+ desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr;
3386
+ desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr;
3387
+ desc.data = callbackData;
3388
+ desc.attributes = attributes;
3389
+ return desc;
3390
+ }
3391
+
3392
+ template <typename T>
3393
+ template <typename InstanceWrap<T>::InstanceGetterCallback getter,
3394
+ typename InstanceWrap<T>::InstanceSetterCallback setter>
3395
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceAccessor(
3396
+ const char* utf8name,
3397
+ napi_property_attributes attributes,
3398
+ void* data) {
3399
+ napi_property_descriptor desc = napi_property_descriptor();
3400
+ desc.utf8name = utf8name;
3401
+ desc.getter = details::TemplatedInstanceCallback<T, getter>;
3402
+ desc.setter = This::WrapSetter(This::SetterTag<setter>());
3403
+ desc.data = data;
3404
+ desc.attributes = attributes;
3405
+ return desc;
3406
+ }
3407
+
3408
+ template <typename T>
3409
+ template <typename InstanceWrap<T>::InstanceGetterCallback getter,
3410
+ typename InstanceWrap<T>::InstanceSetterCallback setter>
3411
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceAccessor(
3412
+ Symbol name,
3413
+ napi_property_attributes attributes,
3414
+ void* data) {
3415
+ napi_property_descriptor desc = napi_property_descriptor();
3416
+ desc.name = name;
3417
+ desc.getter = details::TemplatedInstanceCallback<T, getter>;
3418
+ desc.setter = This::WrapSetter(This::SetterTag<setter>());
3419
+ desc.data = data;
3420
+ desc.attributes = attributes;
3421
+ return desc;
3422
+ }
3423
+
3424
+ template <typename T>
3425
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceValue(
3426
+ const char* utf8name,
3427
+ Napi::Value value,
3428
+ napi_property_attributes attributes) {
3429
+ napi_property_descriptor desc = napi_property_descriptor();
3430
+ desc.utf8name = utf8name;
3431
+ desc.value = value;
3432
+ desc.attributes = attributes;
3433
+ return desc;
3434
+ }
3435
+
3436
+ template <typename T>
3437
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceValue(
3438
+ Symbol name,
3439
+ Napi::Value value,
3440
+ napi_property_attributes attributes) {
3441
+ napi_property_descriptor desc = napi_property_descriptor();
3442
+ desc.name = name;
3443
+ desc.value = value;
3444
+ desc.attributes = attributes;
3445
+ return desc;
3446
+ }
3447
+
3448
+ template <typename T>
3449
+ inline napi_value InstanceWrap<T>::InstanceVoidMethodCallbackWrapper(
3450
+ napi_env env,
3451
+ napi_callback_info info) {
3452
+ return details::WrapCallback([&] {
3453
+ CallbackInfo callbackInfo(env, info);
3454
+ InstanceVoidMethodCallbackData* callbackData =
3455
+ reinterpret_cast<InstanceVoidMethodCallbackData*>(callbackInfo.Data());
3456
+ callbackInfo.SetData(callbackData->data);
3457
+ T* instance = T::Unwrap(callbackInfo.This().As<Object>());
3458
+ auto cb = callbackData->callback;
3459
+ (instance->*cb)(callbackInfo);
3460
+ return nullptr;
3461
+ });
3462
+ }
3463
+
3464
+ template <typename T>
3465
+ inline napi_value InstanceWrap<T>::InstanceMethodCallbackWrapper(
3466
+ napi_env env,
3467
+ napi_callback_info info) {
3468
+ return details::WrapCallback([&] {
3469
+ CallbackInfo callbackInfo(env, info);
3470
+ InstanceMethodCallbackData* callbackData =
3471
+ reinterpret_cast<InstanceMethodCallbackData*>(callbackInfo.Data());
3472
+ callbackInfo.SetData(callbackData->data);
3473
+ T* instance = T::Unwrap(callbackInfo.This().As<Object>());
3474
+ auto cb = callbackData->callback;
3475
+ return (instance->*cb)(callbackInfo);
3476
+ });
3477
+ }
3478
+
3479
+ template <typename T>
3480
+ inline napi_value InstanceWrap<T>::InstanceGetterCallbackWrapper(
3481
+ napi_env env,
3482
+ napi_callback_info info) {
3483
+ return details::WrapCallback([&] {
3484
+ CallbackInfo callbackInfo(env, info);
3485
+ InstanceAccessorCallbackData* callbackData =
3486
+ reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
3487
+ callbackInfo.SetData(callbackData->data);
3488
+ T* instance = T::Unwrap(callbackInfo.This().As<Object>());
3489
+ auto cb = callbackData->getterCallback;
3490
+ return (instance->*cb)(callbackInfo);
3491
+ });
3492
+ }
3493
+
3494
+ template <typename T>
3495
+ inline napi_value InstanceWrap<T>::InstanceSetterCallbackWrapper(
3496
+ napi_env env,
3497
+ napi_callback_info info) {
3498
+ return details::WrapCallback([&] {
3499
+ CallbackInfo callbackInfo(env, info);
3500
+ InstanceAccessorCallbackData* callbackData =
3501
+ reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
3502
+ callbackInfo.SetData(callbackData->data);
3503
+ T* instance = T::Unwrap(callbackInfo.This().As<Object>());
3504
+ auto cb = callbackData->setterCallback;
3505
+ (instance->*cb)(callbackInfo, callbackInfo[0]);
3506
+ return nullptr;
3507
+ });
3508
+ }
3509
+
3510
+ template <typename T>
3511
+ template <typename InstanceWrap<T>::InstanceSetterCallback method>
3512
+ inline napi_value InstanceWrap<T>::WrappedMethod(napi_env env, napi_callback_info info) noexcept {
3513
+ return details::WrapCallback([&] {
3514
+ const CallbackInfo cbInfo(env, info);
3515
+ T* instance = T::Unwrap(cbInfo.This().As<Object>());
3516
+ (instance->*method)(cbInfo, cbInfo[0]);
3517
+ return nullptr;
3518
+ });
3519
+ }
3520
+
3521
+ ////////////////////////////////////////////////////////////////////////////////
3522
+ // ObjectWrap<T> class
3523
+ ////////////////////////////////////////////////////////////////////////////////
3524
+
3525
+ template <typename T>
3526
+ inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
3527
+ napi_env env = callbackInfo.Env();
3528
+ napi_value wrapper = callbackInfo.This();
3529
+ napi_status status;
3530
+ napi_ref ref;
3531
+ T* instance = static_cast<T*>(this);
3532
+ status = napi_wrap(env, wrapper, instance, FinalizeCallback, nullptr, &ref);
3533
+ NAPI_THROW_IF_FAILED_VOID(env, status);
3534
+
3535
+ Reference<Object>* instanceRef = instance;
3536
+ *instanceRef = Reference<Object>(env, ref);
3537
+ }
3538
+
3539
+ template <typename T>
3540
+ inline ObjectWrap<T>::~ObjectWrap() {
3541
+ // If the JS object still exists at this point, remove the finalizer added
3542
+ // through `napi_wrap()`.
3543
+ if (!IsEmpty()) {
3544
+ Object object = Value();
3545
+ // It is not valid to call `napi_remove_wrap()` with an empty `object`.
3546
+ // This happens e.g. during garbage collection.
3547
+ if (!object.IsEmpty() && _construction_failed) {
3548
+ napi_remove_wrap(Env(), object, nullptr);
3549
+ }
3550
+ }
3551
+ }
3552
+
3553
+ template<typename T>
3554
+ inline T* ObjectWrap<T>::Unwrap(Object wrapper) {
3555
+ T* unwrapped;
3556
+ napi_status status = napi_unwrap(wrapper.Env(), wrapper, reinterpret_cast<void**>(&unwrapped));
3557
+ NAPI_THROW_IF_FAILED(wrapper.Env(), status, nullptr);
3558
+ return unwrapped;
3559
+ }
3560
+
3561
+ template <typename T>
3562
+ inline Function
3563
+ ObjectWrap<T>::DefineClass(Napi::Env env,
3564
+ const char* utf8name,
3565
+ const size_t props_count,
3566
+ const napi_property_descriptor* descriptors,
3567
+ void* data) {
3568
+ napi_status status;
3569
+ std::vector<napi_property_descriptor> props(props_count);
3570
+
3571
+ // We copy the descriptors to a local array because before defining the class
3572
+ // we must replace static method property descriptors with value property
3573
+ // descriptors such that the value is a function-valued `napi_value` created
3574
+ // with `CreateFunction()`.
3575
+ //
3576
+ // This replacement could be made for instance methods as well, but V8 aborts
3577
+ // if we do that, because it expects methods defined on the prototype template
3578
+ // to have `FunctionTemplate`s.
3579
+ for (size_t index = 0; index < props_count; index++) {
3580
+ props[index] = descriptors[index];
3581
+ napi_property_descriptor* prop = &props[index];
3582
+ if (prop->method == T::StaticMethodCallbackWrapper) {
3583
+ status = CreateFunction(env,
3584
+ utf8name,
3585
+ prop->method,
3586
+ static_cast<StaticMethodCallbackData*>(prop->data),
3587
+ &(prop->value));
3588
+ NAPI_THROW_IF_FAILED(env, status, Function());
3589
+ prop->method = nullptr;
3590
+ prop->data = nullptr;
3591
+ } else if (prop->method == T::StaticVoidMethodCallbackWrapper) {
3592
+ status = CreateFunction(env,
3593
+ utf8name,
3594
+ prop->method,
3595
+ static_cast<StaticVoidMethodCallbackData*>(prop->data),
3596
+ &(prop->value));
3597
+ NAPI_THROW_IF_FAILED(env, status, Function());
3598
+ prop->method = nullptr;
3599
+ prop->data = nullptr;
3600
+ }
3601
+ }
3602
+
3603
+ napi_value value;
3604
+ status = napi_define_class(env,
3605
+ utf8name,
3606
+ NAPI_AUTO_LENGTH,
3607
+ T::ConstructorCallbackWrapper,
3608
+ data,
3609
+ props_count,
3610
+ props.data(),
3611
+ &value);
3612
+ NAPI_THROW_IF_FAILED(env, status, Function());
3613
+
3614
+ // After defining the class we iterate once more over the property descriptors
3615
+ // and attach the data associated with accessors and instance methods to the
3616
+ // newly created JavaScript class.
3617
+ for (size_t idx = 0; idx < props_count; idx++) {
3618
+ const napi_property_descriptor* prop = &props[idx];
3619
+
3620
+ if (prop->getter == T::StaticGetterCallbackWrapper ||
3621
+ prop->setter == T::StaticSetterCallbackWrapper) {
3622
+ status = Napi::details::AttachData(env,
3623
+ value,
3624
+ static_cast<StaticAccessorCallbackData*>(prop->data));
3625
+ NAPI_THROW_IF_FAILED(env, status, Function());
3626
+ } else {
3627
+ // InstanceWrap<T>::AttachPropData is responsible for attaching the data
3628
+ // of instance methods and accessors.
3629
+ T::AttachPropData(env, value, prop);
3630
+ }
3631
+ }
3632
+
3633
+ return Function(env, value);
3634
+ }
3635
+
3636
+ template <typename T>
3637
+ inline Function ObjectWrap<T>::DefineClass(
3638
+ Napi::Env env,
3639
+ const char* utf8name,
3640
+ const std::initializer_list<ClassPropertyDescriptor<T>>& properties,
3641
+ void* data) {
3642
+ return DefineClass(env,
3643
+ utf8name,
3644
+ properties.size(),
3645
+ reinterpret_cast<const napi_property_descriptor*>(properties.begin()),
3646
+ data);
3647
+ }
3648
+
3649
+ template <typename T>
3093
3650
  inline Function ObjectWrap<T>::DefineClass(
3094
3651
  Napi::Env env,
3095
3652
  const char* utf8name,
@@ -3167,188 +3724,148 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3167
3724
  }
3168
3725
 
3169
3726
  template <typename T>
3170
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3727
+ template <typename ObjectWrap<T>::StaticVoidMethodCallback method>
3728
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3171
3729
  const char* utf8name,
3172
- StaticGetterCallback getter,
3173
- StaticSetterCallback setter,
3174
3730
  napi_property_attributes attributes,
3175
3731
  void* data) {
3176
- StaticAccessorCallbackData* callbackData =
3177
- new StaticAccessorCallbackData({ getter, setter, data });
3178
-
3179
3732
  napi_property_descriptor desc = napi_property_descriptor();
3180
3733
  desc.utf8name = utf8name;
3181
- desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr;
3182
- desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr;
3183
- desc.data = callbackData;
3734
+ desc.method = details::TemplatedVoidCallback<method>;
3735
+ desc.data = data;
3184
3736
  desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3185
3737
  return desc;
3186
3738
  }
3187
3739
 
3188
3740
  template <typename T>
3189
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3741
+ template <typename ObjectWrap<T>::StaticVoidMethodCallback method>
3742
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3190
3743
  Symbol name,
3191
- StaticGetterCallback getter,
3192
- StaticSetterCallback setter,
3193
3744
  napi_property_attributes attributes,
3194
3745
  void* data) {
3195
- StaticAccessorCallbackData* callbackData =
3196
- new StaticAccessorCallbackData({ getter, setter, data });
3197
-
3198
3746
  napi_property_descriptor desc = napi_property_descriptor();
3199
3747
  desc.name = name;
3200
- desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr;
3201
- desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr;
3202
- desc.data = callbackData;
3748
+ desc.method = details::TemplatedVoidCallback<method>;
3749
+ desc.data = data;
3203
3750
  desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3204
3751
  return desc;
3205
3752
  }
3206
3753
 
3207
3754
  template <typename T>
3208
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3209
- const char* utf8name,
3210
- InstanceVoidMethodCallback method,
3211
- napi_property_attributes attributes,
3212
- void* data) {
3213
- InstanceVoidMethodCallbackData* callbackData =
3214
- new InstanceVoidMethodCallbackData({ method, data});
3215
-
3216
- napi_property_descriptor desc = napi_property_descriptor();
3217
- desc.utf8name = utf8name;
3218
- desc.method = T::InstanceVoidMethodCallbackWrapper;
3219
- desc.data = callbackData;
3220
- desc.attributes = attributes;
3221
- return desc;
3222
- }
3223
-
3224
- template <typename T>
3225
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3226
- const char* utf8name,
3227
- InstanceMethodCallback method,
3228
- napi_property_attributes attributes,
3229
- void* data) {
3230
- InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data });
3231
-
3232
- napi_property_descriptor desc = napi_property_descriptor();
3233
- desc.utf8name = utf8name;
3234
- desc.method = T::InstanceMethodCallbackWrapper;
3235
- desc.data = callbackData;
3236
- desc.attributes = attributes;
3237
- return desc;
3238
- }
3239
-
3240
- template <typename T>
3241
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3242
- Symbol name,
3243
- InstanceVoidMethodCallback method,
3755
+ template <typename ObjectWrap<T>::StaticMethodCallback method>
3756
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3757
+ const char* utf8name,
3244
3758
  napi_property_attributes attributes,
3245
3759
  void* data) {
3246
- InstanceVoidMethodCallbackData* callbackData =
3247
- new InstanceVoidMethodCallbackData({ method, data});
3248
-
3249
3760
  napi_property_descriptor desc = napi_property_descriptor();
3250
- desc.name = name;
3251
- desc.method = T::InstanceVoidMethodCallbackWrapper;
3252
- desc.data = callbackData;
3253
- desc.attributes = attributes;
3761
+ desc.utf8name = utf8name;
3762
+ desc.method = details::TemplatedCallback<method>;
3763
+ desc.data = data;
3764
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3254
3765
  return desc;
3255
3766
  }
3256
3767
 
3257
3768
  template <typename T>
3258
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3769
+ template <typename ObjectWrap<T>::StaticMethodCallback method>
3770
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3259
3771
  Symbol name,
3260
- InstanceMethodCallback method,
3261
3772
  napi_property_attributes attributes,
3262
3773
  void* data) {
3263
- InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data });
3264
-
3265
3774
  napi_property_descriptor desc = napi_property_descriptor();
3266
3775
  desc.name = name;
3267
- desc.method = T::InstanceMethodCallbackWrapper;
3268
- desc.data = callbackData;
3269
- desc.attributes = attributes;
3776
+ desc.method = details::TemplatedCallback<method>;
3777
+ desc.data = data;
3778
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3270
3779
  return desc;
3271
3780
  }
3272
3781
 
3273
3782
  template <typename T>
3274
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceAccessor(
3783
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3275
3784
  const char* utf8name,
3276
- InstanceGetterCallback getter,
3277
- InstanceSetterCallback setter,
3785
+ StaticGetterCallback getter,
3786
+ StaticSetterCallback setter,
3278
3787
  napi_property_attributes attributes,
3279
3788
  void* data) {
3280
- InstanceAccessorCallbackData* callbackData =
3281
- new InstanceAccessorCallbackData({ getter, setter, data });
3789
+ StaticAccessorCallbackData* callbackData =
3790
+ new StaticAccessorCallbackData({ getter, setter, data });
3282
3791
 
3283
3792
  napi_property_descriptor desc = napi_property_descriptor();
3284
3793
  desc.utf8name = utf8name;
3285
- desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr;
3286
- desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr;
3794
+ desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr;
3795
+ desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr;
3287
3796
  desc.data = callbackData;
3288
- desc.attributes = attributes;
3797
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3289
3798
  return desc;
3290
3799
  }
3291
3800
 
3292
3801
  template <typename T>
3293
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceAccessor(
3802
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3294
3803
  Symbol name,
3295
- InstanceGetterCallback getter,
3296
- InstanceSetterCallback setter,
3804
+ StaticGetterCallback getter,
3805
+ StaticSetterCallback setter,
3297
3806
  napi_property_attributes attributes,
3298
3807
  void* data) {
3299
- InstanceAccessorCallbackData* callbackData =
3300
- new InstanceAccessorCallbackData({ getter, setter, data });
3808
+ StaticAccessorCallbackData* callbackData =
3809
+ new StaticAccessorCallbackData({ getter, setter, data });
3301
3810
 
3302
3811
  napi_property_descriptor desc = napi_property_descriptor();
3303
3812
  desc.name = name;
3304
- desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr;
3305
- desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr;
3813
+ desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr;
3814
+ desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr;
3306
3815
  desc.data = callbackData;
3307
- desc.attributes = attributes;
3816
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3308
3817
  return desc;
3309
3818
  }
3310
3819
 
3311
3820
  template <typename T>
3312
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(const char* utf8name,
3313
- Napi::Value value, napi_property_attributes attributes) {
3821
+ template <typename ObjectWrap<T>::StaticGetterCallback getter,
3822
+ typename ObjectWrap<T>::StaticSetterCallback setter>
3823
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3824
+ const char* utf8name,
3825
+ napi_property_attributes attributes,
3826
+ void* data) {
3314
3827
  napi_property_descriptor desc = napi_property_descriptor();
3315
3828
  desc.utf8name = utf8name;
3316
- desc.value = value;
3829
+ desc.getter = details::TemplatedCallback<getter>;
3830
+ desc.setter = This::WrapStaticSetter(This::StaticSetterTag<setter>());
3831
+ desc.data = data;
3317
3832
  desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3318
3833
  return desc;
3319
3834
  }
3320
3835
 
3321
3836
  template <typename T>
3322
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(Symbol name,
3323
- Napi::Value value, napi_property_attributes attributes) {
3837
+ template <typename ObjectWrap<T>::StaticGetterCallback getter,
3838
+ typename ObjectWrap<T>::StaticSetterCallback setter>
3839
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3840
+ Symbol name,
3841
+ napi_property_attributes attributes,
3842
+ void* data) {
3324
3843
  napi_property_descriptor desc = napi_property_descriptor();
3325
3844
  desc.name = name;
3326
- desc.value = value;
3845
+ desc.getter = details::TemplatedCallback<getter>;
3846
+ desc.setter = This::WrapStaticSetter(This::StaticSetterTag<setter>());
3847
+ desc.data = data;
3327
3848
  desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3328
3849
  return desc;
3329
3850
  }
3330
3851
 
3331
3852
  template <typename T>
3332
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceValue(
3333
- const char* utf8name,
3334
- Napi::Value value,
3335
- napi_property_attributes attributes) {
3853
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(const char* utf8name,
3854
+ Napi::Value value, napi_property_attributes attributes) {
3336
3855
  napi_property_descriptor desc = napi_property_descriptor();
3337
3856
  desc.utf8name = utf8name;
3338
3857
  desc.value = value;
3339
- desc.attributes = attributes;
3858
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3340
3859
  return desc;
3341
3860
  }
3342
3861
 
3343
3862
  template <typename T>
3344
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceValue(
3345
- Symbol name,
3346
- Napi::Value value,
3347
- napi_property_attributes attributes) {
3863
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(Symbol name,
3864
+ Napi::Value value, napi_property_attributes attributes) {
3348
3865
  napi_property_descriptor desc = napi_property_descriptor();
3349
3866
  desc.name = name;
3350
3867
  desc.value = value;
3351
- desc.attributes = attributes;
3868
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3352
3869
  return desc;
3353
3870
  }
3354
3871
 
@@ -3369,10 +3886,21 @@ inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
3369
3886
  return nullptr;
3370
3887
  }
3371
3888
 
3372
- T* instance;
3373
3889
  napi_value wrapper = details::WrapCallback([&] {
3374
3890
  CallbackInfo callbackInfo(env, info);
3375
- instance = new T(callbackInfo);
3891
+ T* instance = new T(callbackInfo);
3892
+ #ifdef NAPI_CPP_EXCEPTIONS
3893
+ instance->_construction_failed = false;
3894
+ #else
3895
+ if (callbackInfo.Env().IsExceptionPending()) {
3896
+ // We need to clear the exception so that removing the wrap might work.
3897
+ Error e = callbackInfo.Env().GetAndClearPendingException();
3898
+ delete instance;
3899
+ e.ThrowAsJavaScriptException();
3900
+ } else {
3901
+ instance->_construction_failed = false;
3902
+ }
3903
+ # endif // NAPI_CPP_EXCEPTIONS
3376
3904
  return callbackInfo.This();
3377
3905
  });
3378
3906
 
@@ -3434,74 +3962,22 @@ inline napi_value ObjectWrap<T>::StaticSetterCallbackWrapper(
3434
3962
  }
3435
3963
 
3436
3964
  template <typename T>
3437
- inline napi_value ObjectWrap<T>::InstanceVoidMethodCallbackWrapper(
3438
- napi_env env,
3439
- napi_callback_info info) {
3440
- return details::WrapCallback([&] {
3441
- CallbackInfo callbackInfo(env, info);
3442
- InstanceVoidMethodCallbackData* callbackData =
3443
- reinterpret_cast<InstanceVoidMethodCallbackData*>(callbackInfo.Data());
3444
- callbackInfo.SetData(callbackData->data);
3445
- T* instance = Unwrap(callbackInfo.This().As<Object>());
3446
- auto cb = callbackData->callback;
3447
- (instance->*cb)(callbackInfo);
3448
- return nullptr;
3449
- });
3450
- }
3451
-
3452
- template <typename T>
3453
- inline napi_value ObjectWrap<T>::InstanceMethodCallbackWrapper(
3454
- napi_env env,
3455
- napi_callback_info info) {
3456
- return details::WrapCallback([&] {
3457
- CallbackInfo callbackInfo(env, info);
3458
- InstanceMethodCallbackData* callbackData =
3459
- reinterpret_cast<InstanceMethodCallbackData*>(callbackInfo.Data());
3460
- callbackInfo.SetData(callbackData->data);
3461
- T* instance = Unwrap(callbackInfo.This().As<Object>());
3462
- auto cb = callbackData->callback;
3463
- return (instance->*cb)(callbackInfo);
3464
- });
3465
- }
3466
-
3467
- template <typename T>
3468
- inline napi_value ObjectWrap<T>::InstanceGetterCallbackWrapper(
3469
- napi_env env,
3470
- napi_callback_info info) {
3471
- return details::WrapCallback([&] {
3472
- CallbackInfo callbackInfo(env, info);
3473
- InstanceAccessorCallbackData* callbackData =
3474
- reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
3475
- callbackInfo.SetData(callbackData->data);
3476
- T* instance = Unwrap(callbackInfo.This().As<Object>());
3477
- auto cb = callbackData->getterCallback;
3478
- return (instance->*cb)(callbackInfo);
3479
- });
3965
+ inline void ObjectWrap<T>::FinalizeCallback(napi_env env, void* data, void* /*hint*/) {
3966
+ T* instance = static_cast<T*>(data);
3967
+ instance->Finalize(Napi::Env(env));
3968
+ delete instance;
3480
3969
  }
3481
3970
 
3482
3971
  template <typename T>
3483
- inline napi_value ObjectWrap<T>::InstanceSetterCallbackWrapper(
3484
- napi_env env,
3485
- napi_callback_info info) {
3972
+ template <typename ObjectWrap<T>::StaticSetterCallback method>
3973
+ inline napi_value ObjectWrap<T>::WrappedMethod(napi_env env, napi_callback_info info) noexcept {
3486
3974
  return details::WrapCallback([&] {
3487
- CallbackInfo callbackInfo(env, info);
3488
- InstanceAccessorCallbackData* callbackData =
3489
- reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
3490
- callbackInfo.SetData(callbackData->data);
3491
- T* instance = Unwrap(callbackInfo.This().As<Object>());
3492
- auto cb = callbackData->setterCallback;
3493
- (instance->*cb)(callbackInfo, callbackInfo[0]);
3975
+ const CallbackInfo cbInfo(env, info);
3976
+ method(cbInfo, cbInfo[0]);
3494
3977
  return nullptr;
3495
3978
  });
3496
3979
  }
3497
3980
 
3498
- template <typename T>
3499
- inline void ObjectWrap<T>::FinalizeCallback(napi_env env, void* data, void* /*hint*/) {
3500
- T* instance = reinterpret_cast<T*>(data);
3501
- instance->Finalize(Napi::Env(env));
3502
- delete instance;
3503
- }
3504
-
3505
3981
  ////////////////////////////////////////////////////////////////////////////////
3506
3982
  // HandleScope class
3507
3983
  ////////////////////////////////////////////////////////////////////////////////
@@ -3699,8 +4175,8 @@ inline AsyncWorker::AsyncWorker(const Object& receiver,
3699
4175
  _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
3700
4176
  NAPI_THROW_IF_FAILED_VOID(_env, status);
3701
4177
 
3702
- status = napi_create_async_work(_env, resource, resource_id, OnExecute,
3703
- OnWorkComplete, this, &_work);
4178
+ status = napi_create_async_work(_env, resource, resource_id, OnAsyncWorkExecute,
4179
+ OnAsyncWorkComplete, this, &_work);
3704
4180
  NAPI_THROW_IF_FAILED_VOID(_env, status);
3705
4181
  }
3706
4182
 
@@ -3725,8 +4201,8 @@ inline AsyncWorker::AsyncWorker(Napi::Env env,
3725
4201
  _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
3726
4202
  NAPI_THROW_IF_FAILED_VOID(_env, status);
3727
4203
 
3728
- status = napi_create_async_work(_env, resource, resource_id, OnExecute,
3729
- OnWorkComplete, this, &_work);
4204
+ status = napi_create_async_work(_env, resource, resource_id, OnAsyncWorkExecute,
4205
+ OnAsyncWorkComplete, this, &_work);
3730
4206
  NAPI_THROW_IF_FAILED_VOID(_env, status);
3731
4207
  }
3732
4208
 
@@ -3813,44 +4289,55 @@ inline void AsyncWorker::SetError(const std::string& error) {
3813
4289
  inline std::vector<napi_value> AsyncWorker::GetResult(Napi::Env /*env*/) {
3814
4290
  return {};
3815
4291
  }
4292
+ // The OnAsyncWorkExecute method receives an napi_env argument. However, do NOT
4293
+ // use it within this method, as it does not run on the JavaScript thread and
4294
+ // must not run any method that would cause JavaScript to run. In practice,
4295
+ // this means that almost any use of napi_env will be incorrect.
4296
+ inline void AsyncWorker::OnAsyncWorkExecute(napi_env env, void* asyncworker) {
4297
+ AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker);
4298
+ self->OnExecute(env);
4299
+ }
3816
4300
  // The OnExecute method receives an napi_env argument. However, do NOT
3817
- // use it within this method, as it does not run on the main thread and must
3818
- // not run any method that would cause JavaScript to run. In practice, this
3819
- // means that almost any use of napi_env will be incorrect.
3820
- inline void AsyncWorker::OnExecute(napi_env /*DO_NOT_USE*/, void* this_pointer) {
3821
- AsyncWorker* self = static_cast<AsyncWorker*>(this_pointer);
4301
+ // use it within this method, as it does not run on the JavaScript thread and
4302
+ // must not run any method that would cause JavaScript to run. In practice,
4303
+ // this means that almost any use of napi_env will be incorrect.
4304
+ inline void AsyncWorker::OnExecute(Napi::Env /*DO_NOT_USE*/) {
3822
4305
  #ifdef NAPI_CPP_EXCEPTIONS
3823
4306
  try {
3824
- self->Execute();
4307
+ Execute();
3825
4308
  } catch (const std::exception& e) {
3826
- self->SetError(e.what());
4309
+ SetError(e.what());
3827
4310
  }
3828
4311
  #else // NAPI_CPP_EXCEPTIONS
3829
- self->Execute();
4312
+ Execute();
3830
4313
  #endif // NAPI_CPP_EXCEPTIONS
3831
4314
  }
3832
4315
 
3833
- inline void AsyncWorker::OnWorkComplete(
3834
- napi_env /*env*/, napi_status status, void* this_pointer) {
3835
- AsyncWorker* self = static_cast<AsyncWorker*>(this_pointer);
4316
+ inline void AsyncWorker::OnAsyncWorkComplete(napi_env env,
4317
+ napi_status status,
4318
+ void* asyncworker) {
4319
+ AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker);
4320
+ self->OnWorkComplete(env, status);
4321
+ }
4322
+ inline void AsyncWorker::OnWorkComplete(Napi::Env /*env*/, napi_status status) {
3836
4323
  if (status != napi_cancelled) {
3837
- HandleScope scope(self->_env);
4324
+ HandleScope scope(_env);
3838
4325
  details::WrapCallback([&] {
3839
- if (self->_error.size() == 0) {
3840
- self->OnOK();
4326
+ if (_error.size() == 0) {
4327
+ OnOK();
3841
4328
  }
3842
4329
  else {
3843
- self->OnError(Error::New(self->_env, self->_error));
4330
+ OnError(Error::New(_env, _error));
3844
4331
  }
3845
4332
  return nullptr;
3846
4333
  });
3847
4334
  }
3848
- if (!self->_suppress_destruct) {
3849
- self->Destroy();
4335
+ if (!_suppress_destruct) {
4336
+ Destroy();
3850
4337
  }
3851
4338
  }
3852
4339
 
3853
- #if (NAPI_VERSION > 3)
4340
+ #if (NAPI_VERSION > 3 && !defined(__wasm32__))
3854
4341
  ////////////////////////////////////////////////////////////////////////////////
3855
4342
  // ThreadSafeFunction class
3856
4343
  ////////////////////////////////////////////////////////////////////////////////
@@ -4142,7 +4629,7 @@ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
4142
4629
 
4143
4630
  ThreadSafeFunction tsfn;
4144
4631
  auto* finalizeData = new details::ThreadSafeFinalize<ContextType, Finalizer,
4145
- FinalizerDataType>({ data, finalizeCallback, &tsfn._tsfn });
4632
+ FinalizerDataType>({ data, finalizeCallback });
4146
4633
  napi_status status = napi_create_threadsafe_function(env, callback, resource,
4147
4634
  Value::From(env, resourceName), maxQueueSize, initialThreadCount,
4148
4635
  finalizeData, wrapper, context, CallJS, &tsfn._tsfn);
@@ -4185,9 +4672,89 @@ inline void ThreadSafeFunction::CallJS(napi_env env,
4185
4672
  }
4186
4673
 
4187
4674
  ////////////////////////////////////////////////////////////////////////////////
4188
- // Async Progress Worker class
4675
+ // Async Progress Worker Base class
4189
4676
  ////////////////////////////////////////////////////////////////////////////////
4677
+ template <typename DataType>
4678
+ inline AsyncProgressWorkerBase<DataType>::AsyncProgressWorkerBase(const Object& receiver,
4679
+ const Function& callback,
4680
+ const char* resource_name,
4681
+ const Object& resource,
4682
+ size_t queue_size)
4683
+ : AsyncWorker(receiver, callback, resource_name, resource) {
4684
+ // Fill all possible arguments to work around ambiguous ThreadSafeFunction::New signatures.
4685
+ _tsfn = ThreadSafeFunction::New(callback.Env(),
4686
+ callback,
4687
+ resource,
4688
+ resource_name,
4689
+ queue_size,
4690
+ /** initialThreadCount */ 1,
4691
+ /** context */ this,
4692
+ OnThreadSafeFunctionFinalize,
4693
+ /** finalizeData */ this);
4694
+ }
4695
+
4696
+ #if NAPI_VERSION > 4
4697
+ template <typename DataType>
4698
+ inline AsyncProgressWorkerBase<DataType>::AsyncProgressWorkerBase(Napi::Env env,
4699
+ const char* resource_name,
4700
+ const Object& resource,
4701
+ size_t queue_size)
4702
+ : AsyncWorker(env, resource_name, resource) {
4703
+ // TODO: Once the changes to make the callback optional for threadsafe
4704
+ // functions are available on all versions we can remove the dummy Function here.
4705
+ Function callback;
4706
+ // Fill all possible arguments to work around ambiguous ThreadSafeFunction::New signatures.
4707
+ _tsfn = ThreadSafeFunction::New(env,
4708
+ callback,
4709
+ resource,
4710
+ resource_name,
4711
+ queue_size,
4712
+ /** initialThreadCount */ 1,
4713
+ /** context */ this,
4714
+ OnThreadSafeFunctionFinalize,
4715
+ /** finalizeData */ this);
4716
+ }
4717
+ #endif
4718
+
4719
+ template<typename DataType>
4720
+ inline AsyncProgressWorkerBase<DataType>::~AsyncProgressWorkerBase() {
4721
+ // Abort pending tsfn call.
4722
+ // Don't send progress events after we've already completed.
4723
+ // It's ok to call ThreadSafeFunction::Abort and ThreadSafeFunction::Release duplicated.
4724
+ _tsfn.Abort();
4725
+ }
4726
+
4727
+ template <typename DataType>
4728
+ inline void AsyncProgressWorkerBase<DataType>::OnAsyncWorkProgress(Napi::Env /* env */,
4729
+ Napi::Function /* jsCallback */,
4730
+ void* data) {
4731
+ ThreadSafeData* tsd = static_cast<ThreadSafeData*>(data);
4732
+ tsd->asyncprogressworker()->OnWorkProgress(tsd->data());
4733
+ }
4734
+
4735
+ template <typename DataType>
4736
+ inline napi_status AsyncProgressWorkerBase<DataType>::NonBlockingCall(DataType* data) {
4737
+ auto tsd = new AsyncProgressWorkerBase::ThreadSafeData(this, data);
4738
+ return _tsfn.NonBlockingCall(tsd, OnAsyncWorkProgress);
4739
+ }
4740
+
4741
+ template <typename DataType>
4742
+ inline void AsyncProgressWorkerBase<DataType>::OnWorkComplete(Napi::Env /* env */, napi_status status) {
4743
+ _work_completed = true;
4744
+ _complete_status = status;
4745
+ _tsfn.Release();
4746
+ }
4747
+
4748
+ template <typename DataType>
4749
+ inline void AsyncProgressWorkerBase<DataType>::OnThreadSafeFunctionFinalize(Napi::Env env, void* /* data */, AsyncProgressWorkerBase* context) {
4750
+ if (context->_work_completed) {
4751
+ context->AsyncWorker::OnWorkComplete(env, context->_complete_status);
4752
+ }
4753
+ }
4190
4754
 
4755
+ ////////////////////////////////////////////////////////////////////////////////
4756
+ // Async Progress Worker class
4757
+ ////////////////////////////////////////////////////////////////////////////////
4191
4758
  template<class T>
4192
4759
  inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback)
4193
4760
  : AsyncProgressWorker(callback, "generic") {
@@ -4211,14 +4778,14 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback,
4211
4778
 
4212
4779
  template<class T>
4213
4780
  inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4214
- const Function& callback)
4781
+ const Function& callback)
4215
4782
  : AsyncProgressWorker(receiver, callback, "generic") {
4216
4783
  }
4217
4784
 
4218
4785
  template<class T>
4219
4786
  inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4220
- const Function& callback,
4221
- const char* resource_name)
4787
+ const Function& callback,
4788
+ const char* resource_name)
4222
4789
  : AsyncProgressWorker(receiver,
4223
4790
  callback,
4224
4791
  resource_name,
@@ -4230,10 +4797,9 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4230
4797
  const Function& callback,
4231
4798
  const char* resource_name,
4232
4799
  const Object& resource)
4233
- : AsyncWorker(receiver, callback, resource_name, resource),
4800
+ : AsyncProgressWorkerBase(receiver, callback, resource_name, resource),
4234
4801
  _asyncdata(nullptr),
4235
4802
  _asyncsize(0) {
4236
- _tsfn = ThreadSafeFunction::New(callback.Env(), callback, resource_name, 1, 1);
4237
4803
  }
4238
4804
 
4239
4805
  #if NAPI_VERSION > 4
@@ -4244,35 +4810,27 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env)
4244
4810
 
4245
4811
  template<class T>
4246
4812
  inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4247
- const char* resource_name)
4813
+ const char* resource_name)
4248
4814
  : AsyncProgressWorker(env, resource_name, Object::New(env)) {
4249
4815
  }
4250
4816
 
4251
4817
  template<class T>
4252
4818
  inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4253
- const char* resource_name,
4254
- const Object& resource)
4255
- : AsyncWorker(env, resource_name, resource),
4819
+ const char* resource_name,
4820
+ const Object& resource)
4821
+ : AsyncProgressWorkerBase(env, resource_name, resource),
4256
4822
  _asyncdata(nullptr),
4257
4823
  _asyncsize(0) {
4258
- // TODO: Once the changes to make the callback optional for threadsafe
4259
- // functions are no longer optional we can remove the dummy Function here.
4260
- Function callback;
4261
- _tsfn = ThreadSafeFunction::New(env, callback, resource_name, 1, 1);
4262
4824
  }
4263
4825
  #endif
4264
4826
 
4265
4827
  template<class T>
4266
4828
  inline AsyncProgressWorker<T>::~AsyncProgressWorker() {
4267
- // Abort pending tsfn call.
4268
- // Don't send progress events after we've already completed.
4269
- _tsfn.Abort();
4270
4829
  {
4271
- std::lock_guard<std::mutex> lock(_mutex);
4830
+ std::lock_guard<std::mutex> lock(this->_mutex);
4272
4831
  _asyncdata = nullptr;
4273
4832
  _asyncsize = 0;
4274
4833
  }
4275
- _tsfn.Release();
4276
4834
  }
4277
4835
 
4278
4836
  template<class T>
@@ -4282,20 +4840,18 @@ inline void AsyncProgressWorker<T>::Execute() {
4282
4840
  }
4283
4841
 
4284
4842
  template<class T>
4285
- inline void AsyncProgressWorker<T>::WorkProgress_(Napi::Env /* env */, Napi::Function /* jsCallback */, void* _data) {
4286
- AsyncProgressWorker* self = static_cast<AsyncProgressWorker*>(_data);
4287
-
4843
+ inline void AsyncProgressWorker<T>::OnWorkProgress(void*) {
4288
4844
  T* data;
4289
4845
  size_t size;
4290
4846
  {
4291
- std::lock_guard<std::mutex> lock(self->_mutex);
4292
- data = self->_asyncdata;
4293
- size = self->_asyncsize;
4294
- self->_asyncdata = nullptr;
4295
- self->_asyncsize = 0;
4847
+ std::lock_guard<std::mutex> lock(this->_mutex);
4848
+ data = this->_asyncdata;
4849
+ size = this->_asyncsize;
4850
+ this->_asyncdata = nullptr;
4851
+ this->_asyncsize = 0;
4296
4852
  }
4297
4853
 
4298
- self->OnProgress(data, size);
4854
+ this->OnProgress(data, size);
4299
4855
  delete[] data;
4300
4856
  }
4301
4857
 
@@ -4306,19 +4862,19 @@ inline void AsyncProgressWorker<T>::SendProgress_(const T* data, size_t count) {
4306
4862
 
4307
4863
  T* old_data;
4308
4864
  {
4309
- std::lock_guard<std::mutex> lock(_mutex);
4865
+ std::lock_guard<std::mutex> lock(this->_mutex);
4310
4866
  old_data = _asyncdata;
4311
4867
  _asyncdata = new_data;
4312
4868
  _asyncsize = count;
4313
4869
  }
4314
- _tsfn.NonBlockingCall(this, WorkProgress_);
4870
+ this->NonBlockingCall(nullptr);
4315
4871
 
4316
4872
  delete[] old_data;
4317
4873
  }
4318
4874
 
4319
4875
  template<class T>
4320
4876
  inline void AsyncProgressWorker<T>::Signal() const {
4321
- _tsfn.NonBlockingCall(this, WorkProgress_);
4877
+ this->NonBlockingCall(static_cast<T*>(nullptr));
4322
4878
  }
4323
4879
 
4324
4880
  template<class T>
@@ -4331,8 +4887,125 @@ inline void AsyncProgressWorker<T>::ExecutionProgress::Send(const T* data, size_
4331
4887
  _worker->SendProgress_(data, count);
4332
4888
  }
4333
4889
 
4890
+ ////////////////////////////////////////////////////////////////////////////////
4891
+ // Async Progress Queue Worker class
4892
+ ////////////////////////////////////////////////////////////////////////////////
4893
+ template<class T>
4894
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Function& callback)
4895
+ : AsyncProgressQueueWorker(callback, "generic") {
4896
+ }
4897
+
4898
+ template<class T>
4899
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Function& callback,
4900
+ const char* resource_name)
4901
+ : AsyncProgressQueueWorker(callback, resource_name, Object::New(callback.Env())) {
4902
+ }
4903
+
4904
+ template<class T>
4905
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Function& callback,
4906
+ const char* resource_name,
4907
+ const Object& resource)
4908
+ : AsyncProgressQueueWorker(Object::New(callback.Env()),
4909
+ callback,
4910
+ resource_name,
4911
+ resource) {
4912
+ }
4913
+
4914
+ template<class T>
4915
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Object& receiver,
4916
+ const Function& callback)
4917
+ : AsyncProgressQueueWorker(receiver, callback, "generic") {
4918
+ }
4919
+
4920
+ template<class T>
4921
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Object& receiver,
4922
+ const Function& callback,
4923
+ const char* resource_name)
4924
+ : AsyncProgressQueueWorker(receiver,
4925
+ callback,
4926
+ resource_name,
4927
+ Object::New(callback.Env())) {
4928
+ }
4929
+
4930
+ template<class T>
4931
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Object& receiver,
4932
+ const Function& callback,
4933
+ const char* resource_name,
4934
+ const Object& resource)
4935
+ : AsyncProgressWorkerBase<std::pair<T*, size_t>>(receiver, callback, resource_name, resource, /** unlimited queue size */0) {
4936
+ }
4937
+
4938
+ #if NAPI_VERSION > 4
4939
+ template<class T>
4940
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env)
4941
+ : AsyncProgressQueueWorker(env, "generic") {
4942
+ }
4943
+
4944
+ template<class T>
4945
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env,
4946
+ const char* resource_name)
4947
+ : AsyncProgressQueueWorker(env, resource_name, Object::New(env)) {
4948
+ }
4949
+
4950
+ template<class T>
4951
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env,
4952
+ const char* resource_name,
4953
+ const Object& resource)
4954
+ : AsyncProgressWorkerBase<std::pair<T*, size_t>>(env, resource_name, resource, /** unlimited queue size */0) {
4955
+ }
4334
4956
  #endif
4335
4957
 
4958
+ template<class T>
4959
+ inline void AsyncProgressQueueWorker<T>::Execute() {
4960
+ ExecutionProgress progress(this);
4961
+ Execute(progress);
4962
+ }
4963
+
4964
+ template<class T>
4965
+ inline void AsyncProgressQueueWorker<T>::OnWorkProgress(std::pair<T*, size_t>* datapair) {
4966
+ if (datapair == nullptr) {
4967
+ return;
4968
+ }
4969
+
4970
+ T *data = datapair->first;
4971
+ size_t size = datapair->second;
4972
+
4973
+ this->OnProgress(data, size);
4974
+ delete datapair;
4975
+ delete[] data;
4976
+ }
4977
+
4978
+ template<class T>
4979
+ inline void AsyncProgressQueueWorker<T>::SendProgress_(const T* data, size_t count) {
4980
+ T* new_data = new T[count];
4981
+ std::copy(data, data + count, new_data);
4982
+
4983
+ auto pair = new std::pair<T*, size_t>(new_data, count);
4984
+ this->NonBlockingCall(pair);
4985
+ }
4986
+
4987
+ template<class T>
4988
+ inline void AsyncProgressQueueWorker<T>::Signal() const {
4989
+ this->NonBlockingCall(nullptr);
4990
+ }
4991
+
4992
+ template<class T>
4993
+ inline void AsyncProgressQueueWorker<T>::OnWorkComplete(Napi::Env env, napi_status status) {
4994
+ // Draining queued items in TSFN.
4995
+ AsyncProgressWorkerBase<std::pair<T*, size_t>>::OnWorkComplete(env, status);
4996
+ }
4997
+
4998
+ template<class T>
4999
+ inline void AsyncProgressQueueWorker<T>::ExecutionProgress::Signal() const {
5000
+ _worker->Signal();
5001
+ }
5002
+
5003
+ template<class T>
5004
+ inline void AsyncProgressQueueWorker<T>::ExecutionProgress::Send(const T* data, size_t count) const {
5005
+ _worker->SendProgress_(data, count);
5006
+ }
5007
+ #endif // NAPI_VERSION > 3 && !defined(__wasm32__)
5008
+
4336
5009
  ////////////////////////////////////////////////////////////////////////////////
4337
5010
  // Memory Management class
4338
5011
  ////////////////////////////////////////////////////////////////////////////////
@@ -4362,6 +5035,49 @@ inline const napi_node_version* VersionManagement::GetNodeVersion(Env env) {
4362
5035
  return result;
4363
5036
  }
4364
5037
 
5038
+ #if NAPI_VERSION > 5
5039
+ ////////////////////////////////////////////////////////////////////////////////
5040
+ // Addon<T> class
5041
+ ////////////////////////////////////////////////////////////////////////////////
5042
+
5043
+ template <typename T>
5044
+ inline Object Addon<T>::Init(Env env, Object exports) {
5045
+ T* addon = new T(env, exports);
5046
+ env.SetInstanceData(addon);
5047
+ return addon->entry_point_;
5048
+ }
5049
+
5050
+ template <typename T>
5051
+ inline T* Addon<T>::Unwrap(Object wrapper) {
5052
+ return wrapper.Env().GetInstanceData<T>();
5053
+ }
5054
+
5055
+ template <typename T>
5056
+ inline void
5057
+ Addon<T>::DefineAddon(Object exports,
5058
+ const std::initializer_list<AddonProp>& props) {
5059
+ DefineProperties(exports, props);
5060
+ entry_point_ = exports;
5061
+ }
5062
+
5063
+ template <typename T>
5064
+ inline Napi::Object
5065
+ Addon<T>::DefineProperties(Object object,
5066
+ const std::initializer_list<AddonProp>& props) {
5067
+ const napi_property_descriptor* properties =
5068
+ reinterpret_cast<const napi_property_descriptor*>(props.begin());
5069
+ size_t size = props.size();
5070
+ napi_status status = napi_define_properties(object.Env(),
5071
+ object,
5072
+ size,
5073
+ properties);
5074
+ NAPI_THROW_IF_FAILED(object.Env(), status, object);
5075
+ for (size_t idx = 0; idx < size; idx++)
5076
+ T::AttachPropData(object.Env(), object, &properties[idx]);
5077
+ return object;
5078
+ }
5079
+ #endif // NAPI_VERSION > 5
5080
+
4365
5081
  } // namespace Napi
4366
5082
 
4367
5083
  #endif // SRC_NAPI_INL_H_