node-addon-api 4.2.0 → 4.3.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.
package/README.md CHANGED
@@ -70,7 +70,7 @@ and node-addon-api.
70
70
  - **[Contributors](#contributors)**
71
71
  - **[License](#license)**
72
72
 
73
- ## **Current version: 4.2.0**
73
+ ## **Current version: 4.3.0**
74
74
 
75
75
  (See [CHANGELOG.md](CHANGELOG.md) for complete Changelog)
76
76
 
package/napi-inl.h CHANGED
@@ -1306,6 +1306,14 @@ inline Object::PropertyLValue<uint32_t> Object::operator [](uint32_t index) {
1306
1306
  return PropertyLValue<uint32_t>(*this, index);
1307
1307
  }
1308
1308
 
1309
+ inline Object::PropertyLValue<Value> Object::operator[](Value index) {
1310
+ return PropertyLValue<Value>(*this, index);
1311
+ }
1312
+
1313
+ inline Object::PropertyLValue<Value> Object::operator[](Value index) const {
1314
+ return PropertyLValue<Value>(*this, index);
1315
+ }
1316
+
1309
1317
  inline MaybeOrValue<Value> Object::operator[](const char* utf8name) const {
1310
1318
  return Get(utf8name);
1311
1319
  }
@@ -1530,6 +1538,83 @@ inline void Object::AddFinalizer(Finalizer finalizeCallback,
1530
1538
  }
1531
1539
  }
1532
1540
 
1541
+ #ifdef NAPI_CPP_EXCEPTIONS
1542
+ inline Object::const_iterator::const_iterator(const Object* object,
1543
+ const Type type) {
1544
+ _object = object;
1545
+ _keys = object->GetPropertyNames();
1546
+ _index = type == Type::BEGIN ? 0 : _keys.Length();
1547
+ }
1548
+
1549
+ inline Object::const_iterator Napi::Object::begin() const {
1550
+ const_iterator it(this, Object::const_iterator::Type::BEGIN);
1551
+ return it;
1552
+ }
1553
+
1554
+ inline Object::const_iterator Napi::Object::end() const {
1555
+ const_iterator it(this, Object::const_iterator::Type::END);
1556
+ return it;
1557
+ }
1558
+
1559
+ inline Object::const_iterator& Object::const_iterator::operator++() {
1560
+ ++_index;
1561
+ return *this;
1562
+ }
1563
+
1564
+ inline bool Object::const_iterator::operator==(
1565
+ const const_iterator& other) const {
1566
+ return _index == other._index;
1567
+ }
1568
+
1569
+ inline bool Object::const_iterator::operator!=(
1570
+ const const_iterator& other) const {
1571
+ return _index != other._index;
1572
+ }
1573
+
1574
+ inline const std::pair<Value, Object::PropertyLValue<Value>>
1575
+ Object::const_iterator::operator*() const {
1576
+ const Value key = _keys[_index];
1577
+ const PropertyLValue<Value> value = (*_object)[key];
1578
+ return {key, value};
1579
+ }
1580
+
1581
+ inline Object::iterator::iterator(Object* object, const Type type) {
1582
+ _object = object;
1583
+ _keys = object->GetPropertyNames();
1584
+ _index = type == Type::BEGIN ? 0 : _keys.Length();
1585
+ }
1586
+
1587
+ inline Object::iterator Napi::Object::begin() {
1588
+ iterator it(this, Object::iterator::Type::BEGIN);
1589
+ return it;
1590
+ }
1591
+
1592
+ inline Object::iterator Napi::Object::end() {
1593
+ iterator it(this, Object::iterator::Type::END);
1594
+ return it;
1595
+ }
1596
+
1597
+ inline Object::iterator& Object::iterator::operator++() {
1598
+ ++_index;
1599
+ return *this;
1600
+ }
1601
+
1602
+ inline bool Object::iterator::operator==(const iterator& other) const {
1603
+ return _index == other._index;
1604
+ }
1605
+
1606
+ inline bool Object::iterator::operator!=(const iterator& other) const {
1607
+ return _index != other._index;
1608
+ }
1609
+
1610
+ inline std::pair<Value, Object::PropertyLValue<Value>>
1611
+ Object::iterator::operator*() {
1612
+ Value key = _keys[_index];
1613
+ PropertyLValue<Value> value = (*_object)[key];
1614
+ return {key, value};
1615
+ }
1616
+ #endif // NAPI_CPP_EXCEPTIONS
1617
+
1533
1618
  #if NAPI_VERSION >= 8
1534
1619
  inline MaybeOrValue<bool> Object::Freeze() {
1535
1620
  napi_status status = napi_object_freeze(_env, _value);
@@ -2435,12 +2520,23 @@ inline Error Error::New(napi_env env) {
2435
2520
  napi_status status;
2436
2521
  napi_value error = nullptr;
2437
2522
  bool is_exception_pending;
2438
- const napi_extended_error_info* info;
2523
+ napi_extended_error_info last_error_info_copy;
2524
+
2525
+ {
2526
+ // We must retrieve the last error info before doing anything else because
2527
+ // doing anything else will replace the last error info.
2528
+ const napi_extended_error_info* last_error_info;
2529
+ status = napi_get_last_error_info(env, &last_error_info);
2530
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info");
2439
2531
 
2440
- // We must retrieve the last error info before doing anything else, because
2441
- // doing anything else will replace the last error info.
2442
- status = napi_get_last_error_info(env, &info);
2443
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info");
2532
+ // All fields of the `napi_extended_error_info` structure gets reset in
2533
+ // subsequent Node-API function calls on the same `env`. This includes a
2534
+ // call to `napi_is_exception_pending()`. So here it is necessary to make a
2535
+ // copy of the information as the `error_code` field is used later on.
2536
+ memcpy(&last_error_info_copy,
2537
+ last_error_info,
2538
+ sizeof(napi_extended_error_info));
2539
+ }
2444
2540
 
2445
2541
  status = napi_is_exception_pending(env, &is_exception_pending);
2446
2542
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending");
@@ -2451,8 +2547,9 @@ inline Error Error::New(napi_env env) {
2451
2547
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
2452
2548
  }
2453
2549
  else {
2454
- const char* error_message = info->error_message != nullptr ?
2455
- info->error_message : "Error in native callback";
2550
+ const char* error_message = last_error_info_copy.error_message != nullptr
2551
+ ? last_error_info_copy.error_message
2552
+ : "Error in native callback";
2456
2553
 
2457
2554
  napi_value message;
2458
2555
  status = napi_create_string_utf8(
@@ -2462,16 +2559,16 @@ inline Error Error::New(napi_env env) {
2462
2559
  &message);
2463
2560
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_string_utf8");
2464
2561
 
2465
- switch (info->error_code) {
2466
- case napi_object_expected:
2467
- case napi_string_expected:
2468
- case napi_boolean_expected:
2469
- case napi_number_expected:
2470
- status = napi_create_type_error(env, nullptr, message, &error);
2471
- break;
2472
- default:
2473
- status = napi_create_error(env, nullptr, message, &error);
2474
- break;
2562
+ switch (last_error_info_copy.error_code) {
2563
+ case napi_object_expected:
2564
+ case napi_string_expected:
2565
+ case napi_boolean_expected:
2566
+ case napi_number_expected:
2567
+ status = napi_create_type_error(env, nullptr, message, &error);
2568
+ break;
2569
+ default:
2570
+ status = napi_create_error(env, nullptr, message, &error);
2571
+ break;
2475
2572
  }
2476
2573
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_error");
2477
2574
  }
@@ -2496,14 +2593,80 @@ inline Error::Error() : ObjectReference() {
2496
2593
 
2497
2594
  inline Error::Error(napi_env env, napi_value value) : ObjectReference(env, nullptr) {
2498
2595
  if (value != nullptr) {
2596
+ // Attempting to create a reference on the error object.
2597
+ // If it's not a Object/Function/Symbol, this call will return an error
2598
+ // status.
2499
2599
  napi_status status = napi_create_reference(env, value, 1, &_ref);
2500
2600
 
2601
+ if (status != napi_ok) {
2602
+ napi_value wrappedErrorObj;
2603
+
2604
+ // Create an error object
2605
+ status = napi_create_object(env, &wrappedErrorObj);
2606
+ NAPI_FATAL_IF_FAILED(status, "Error::Error", "napi_create_object");
2607
+
2608
+ // property flag that we attach to show the error object is wrapped
2609
+ napi_property_descriptor wrapObjFlag = {
2610
+ ERROR_WRAP_VALUE, // Unique GUID identifier since Symbol isn't a
2611
+ // viable option
2612
+ nullptr,
2613
+ nullptr,
2614
+ nullptr,
2615
+ nullptr,
2616
+ Value::From(env, value),
2617
+ napi_enumerable,
2618
+ nullptr};
2619
+
2620
+ status = napi_define_properties(env, wrappedErrorObj, 1, &wrapObjFlag);
2621
+ NAPI_FATAL_IF_FAILED(status, "Error::Error", "napi_define_properties");
2622
+
2623
+ // Create a reference on the newly wrapped object
2624
+ status = napi_create_reference(env, wrappedErrorObj, 1, &_ref);
2625
+ }
2626
+
2501
2627
  // Avoid infinite recursion in the failure case.
2502
- // Don't try to construct & throw another Error instance.
2503
2628
  NAPI_FATAL_IF_FAILED(status, "Error::Error", "napi_create_reference");
2504
2629
  }
2505
2630
  }
2506
2631
 
2632
+ inline Object Error::Value() const {
2633
+ if (_ref == nullptr) {
2634
+ return Object(_env, nullptr);
2635
+ }
2636
+
2637
+ napi_value refValue;
2638
+ napi_status status = napi_get_reference_value(_env, _ref, &refValue);
2639
+ NAPI_THROW_IF_FAILED(_env, status, Object());
2640
+
2641
+ napi_valuetype type;
2642
+ status = napi_typeof(_env, refValue, &type);
2643
+ NAPI_THROW_IF_FAILED(_env, status, Object());
2644
+
2645
+ // If refValue isn't a symbol, then we proceed to whether the refValue has the
2646
+ // wrapped error flag
2647
+ if (type != napi_symbol) {
2648
+ // We are checking if the object is wrapped
2649
+ bool isWrappedObject = false;
2650
+
2651
+ status = napi_has_property(
2652
+ _env, refValue, String::From(_env, ERROR_WRAP_VALUE), &isWrappedObject);
2653
+
2654
+ // Don't care about status
2655
+ if (isWrappedObject) {
2656
+ napi_value unwrappedValue;
2657
+ status = napi_get_property(_env,
2658
+ refValue,
2659
+ String::From(_env, ERROR_WRAP_VALUE),
2660
+ &unwrappedValue);
2661
+ NAPI_THROW_IF_FAILED(_env, status, Object());
2662
+
2663
+ return Object(_env, unwrappedValue);
2664
+ }
2665
+ }
2666
+
2667
+ return Object(_env, refValue);
2668
+ }
2669
+
2507
2670
  inline Error::Error(Error&& other) : ObjectReference(std::move(other)) {
2508
2671
  }
2509
2672
 
@@ -2554,6 +2717,7 @@ inline const std::string& Error::Message() const NAPI_NOEXCEPT {
2554
2717
  return _message;
2555
2718
  }
2556
2719
 
2720
+ // we created an object on the &_ref
2557
2721
  inline void Error::ThrowAsJavaScriptException() const {
2558
2722
  HandleScope scope(_env);
2559
2723
  if (!IsEmpty()) {
package/napi.h CHANGED
@@ -741,6 +741,14 @@ namespace Napi {
741
741
  uint32_t index /// Property / element index
742
742
  );
743
743
 
744
+ /// Gets or sets an indexed property or array element.
745
+ PropertyLValue<Value> operator[](Value index /// Property / element index
746
+ );
747
+
748
+ /// Gets or sets an indexed property or array element.
749
+ PropertyLValue<Value> operator[](Value index /// Property / element index
750
+ ) const;
751
+
744
752
  /// Gets a named property.
745
753
  MaybeOrValue<Value> operator[](
746
754
  const char* utf8name ///< UTF-8 encoded null-terminated property name
@@ -928,6 +936,21 @@ namespace Napi {
928
936
  inline void AddFinalizer(Finalizer finalizeCallback,
929
937
  T* data,
930
938
  Hint* finalizeHint);
939
+
940
+ #ifdef NAPI_CPP_EXCEPTIONS
941
+ class const_iterator;
942
+
943
+ inline const_iterator begin() const;
944
+
945
+ inline const_iterator end() const;
946
+
947
+ class iterator;
948
+
949
+ inline iterator begin();
950
+
951
+ inline iterator end();
952
+ #endif // NAPI_CPP_EXCEPTIONS
953
+
931
954
  #if NAPI_VERSION >= 8
932
955
  /// This operation can fail in case of Proxy.[[GetPrototypeOf]] calling into
933
956
  /// JavaScript.
@@ -976,6 +999,55 @@ namespace Napi {
976
999
  uint32_t Length() const;
977
1000
  };
978
1001
 
1002
+ #ifdef NAPI_CPP_EXCEPTIONS
1003
+ class Object::const_iterator {
1004
+ private:
1005
+ enum class Type { BEGIN, END };
1006
+
1007
+ inline const_iterator(const Object* object, const Type type);
1008
+
1009
+ public:
1010
+ inline const_iterator& operator++();
1011
+
1012
+ inline bool operator==(const const_iterator& other) const;
1013
+
1014
+ inline bool operator!=(const const_iterator& other) const;
1015
+
1016
+ inline const std::pair<Value, Object::PropertyLValue<Value>> operator*()
1017
+ const;
1018
+
1019
+ private:
1020
+ const Napi::Object* _object;
1021
+ Array _keys;
1022
+ uint32_t _index;
1023
+
1024
+ friend class Object;
1025
+ };
1026
+
1027
+ class Object::iterator {
1028
+ private:
1029
+ enum class Type { BEGIN, END };
1030
+
1031
+ inline iterator(Object* object, const Type type);
1032
+
1033
+ public:
1034
+ inline iterator& operator++();
1035
+
1036
+ inline bool operator==(const iterator& other) const;
1037
+
1038
+ inline bool operator!=(const iterator& other) const;
1039
+
1040
+ inline std::pair<Value, Object::PropertyLValue<Value>> operator*();
1041
+
1042
+ private:
1043
+ Napi::Object* _object;
1044
+ Array _keys;
1045
+ uint32_t _index;
1046
+
1047
+ friend class Object;
1048
+ };
1049
+ #endif // NAPI_CPP_EXCEPTIONS
1050
+
979
1051
  /// A JavaScript array buffer value.
980
1052
  class ArrayBuffer : public Object {
981
1053
  public:
@@ -1627,6 +1699,8 @@ namespace Napi {
1627
1699
  const std::string& Message() const NAPI_NOEXCEPT;
1628
1700
  void ThrowAsJavaScriptException() const;
1629
1701
 
1702
+ Object Value() const;
1703
+
1630
1704
  #ifdef NAPI_CPP_EXCEPTIONS
1631
1705
  const char* what() const NAPI_NOEXCEPT override;
1632
1706
  #endif // NAPI_CPP_EXCEPTIONS
@@ -1646,7 +1720,9 @@ namespace Napi {
1646
1720
  /// !endcond
1647
1721
 
1648
1722
  private:
1649
- mutable std::string _message;
1723
+ const char* ERROR_WRAP_VALUE =
1724
+ "4bda9e7e-4913-4dbc-95de-891cbf66598e-errorVal";
1725
+ mutable std::string _message;
1650
1726
  };
1651
1727
 
1652
1728
  class TypeError : public Error {
package/package.json CHANGED
@@ -11,6 +11,10 @@
11
11
  "name": "Alba Mendez",
12
12
  "url": "https://github.com/jmendeth"
13
13
  },
14
+ {
15
+ "name": "Alexander Floh",
16
+ "url": "https://github.com/alexanderfloh"
17
+ },
14
18
  {
15
19
  "name": "András Timár, Dr",
16
20
  "url": "https://github.com/timarandras"
@@ -87,6 +91,10 @@
87
91
  "name": "Dongjin Na",
88
92
  "url": "https://github.com/nadongguri"
89
93
  },
94
+ {
95
+ "name": "Doni Rubiagatra",
96
+ "url": "https://github.com/rubiagatra"
97
+ },
90
98
  {
91
99
  "name": "Ferdinand Holzer",
92
100
  "url": "https://github.com/fholzer"
@@ -311,6 +319,11 @@
311
319
  "name": "Vlad Velmisov",
312
320
  "url": "https://github.com/Velmisov"
313
321
  },
322
+ {
323
+ "name": "WenheLI",
324
+ "url": "https://github.com/WenheLI"
325
+ },
326
+
314
327
  {
315
328
  "name": "Yohei Kishimoto",
316
329
  "url": "https://github.com/morokosi"
@@ -329,6 +342,12 @@
329
342
  "benchmark": "^2.1.4",
330
343
  "bindings": "^1.5.0",
331
344
  "clang-format": "^1.4.0",
345
+ "eslint": "^7.32.0",
346
+ "eslint-config-semistandard": "^16.0.0",
347
+ "eslint-config-standard": "^16.0.3",
348
+ "eslint-plugin-import": "^2.24.2",
349
+ "eslint-plugin-node": "^11.1.0",
350
+ "eslint-plugin-promise": "^5.1.0",
332
351
  "fs-extra": "^9.0.1",
333
352
  "path": "^0.12.7",
334
353
  "pre-commit": "^1.2.2",
@@ -351,7 +370,6 @@
351
370
  "license": "MIT",
352
371
  "main": "index.js",
353
372
  "name": "node-addon-api",
354
- "optionalDependencies": {},
355
373
  "readme": "README.md",
356
374
  "repository": {
357
375
  "type": "git",
@@ -372,10 +390,10 @@
372
390
  "predev:incremental": "node-gyp configure build -C test --debug",
373
391
  "dev:incremental": "node test",
374
392
  "doc": "doxygen doc/Doxyfile",
375
- "lint": "node tools/clang-format",
376
- "lint:fix": "node tools/clang-format --fix"
393
+ "lint": "node tools/eslint-format && node tools/clang-format",
394
+ "lint:fix": "node tools/clang-format --fix && node tools/eslint-format --fix"
377
395
  },
378
396
  "pre-commit": "lint",
379
- "version": "4.2.0",
397
+ "version": "4.3.0",
380
398
  "support": true
381
399
  }
@@ -4,36 +4,35 @@ const spawn = require('child_process').spawnSync;
4
4
  const path = require('path');
5
5
 
6
6
  const filesToCheck = ['*.h', '*.cc'];
7
- const CLANG_FORMAT_START = process.env.CLANG_FORMAT_START || 'main';
7
+ const FORMAT_START = process.env.FORMAT_START || 'main';
8
8
 
9
- function main(args) {
9
+ function main (args) {
10
10
  let fix = false;
11
11
  while (args.length > 0) {
12
12
  switch (args[0]) {
13
13
  case '-f':
14
14
  case '--fix':
15
15
  fix = true;
16
+ break;
16
17
  default:
17
18
  }
18
19
  args.shift();
19
20
  }
20
21
 
21
- let clangFormatPath = path.dirname(require.resolve('clang-format'));
22
+ const clangFormatPath = path.dirname(require.resolve('clang-format'));
22
23
  const options = ['--binary=node_modules/.bin/clang-format', '--style=file'];
23
24
  if (fix) {
24
- options.push(CLANG_FORMAT_START);
25
+ options.push(FORMAT_START);
25
26
  } else {
26
- options.push('--diff', CLANG_FORMAT_START);
27
+ options.push('--diff', FORMAT_START);
27
28
  }
28
29
 
29
- const gitClangFormatPath = path.join(clangFormatPath,
30
- 'bin/git-clang-format');
31
- const result = spawn('python', [
32
- gitClangFormatPath,
33
- ...options,
34
- '--',
35
- ...filesToCheck
36
- ], { encoding: 'utf-8' });
30
+ const gitClangFormatPath = path.join(clangFormatPath, 'bin/git-clang-format');
31
+ const result = spawn(
32
+ 'python',
33
+ [gitClangFormatPath, ...options, '--', ...filesToCheck],
34
+ { encoding: 'utf-8' }
35
+ );
37
36
 
38
37
  if (result.stderr) {
39
38
  console.error('Error running git-clang-format:', result.stderr);
@@ -47,9 +46,11 @@ function main(args) {
47
46
  return 0;
48
47
  }
49
48
  // Detect if there is any complains from clang-format
50
- if (clangFormatOutput !== '' &&
51
- clangFormatOutput !== ('no modified files to format') &&
52
- clangFormatOutput !== ('clang-format did not modify any files')) {
49
+ if (
50
+ clangFormatOutput !== '' &&
51
+ clangFormatOutput !== 'no modified files to format' &&
52
+ clangFormatOutput !== 'clang-format did not modify any files'
53
+ ) {
53
54
  console.error(clangFormatOutput);
54
55
  const fixCmd = 'npm run lint:fix';
55
56
  console.error(`
@@ -57,7 +58,7 @@ function main(args) {
57
58
  Note that when running the command locally, please keep your local
58
59
  main branch and working branch up to date with nodejs/node-addon-api
59
60
  to exclude un-related complains.
60
- Or you can run "env CLANG_FORMAT_START=upstream/main ${fixCmd}".`);
61
+ Or you can run "env FORMAT_START=upstream/main ${fixCmd}".`);
61
62
  return 1;
62
63
  }
63
64
  }
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+
3
+ const spawn = require('child_process').spawnSync;
4
+
5
+ const filesToCheck = '*.js';
6
+ const FORMAT_START = process.env.FORMAT_START || 'main';
7
+
8
+ function main (args) {
9
+ let fix = false;
10
+ while (args.length > 0) {
11
+ switch (args[0]) {
12
+ case '-f':
13
+ case '--fix':
14
+ fix = true;
15
+ break;
16
+ default:
17
+ }
18
+ args.shift();
19
+ }
20
+
21
+ // Check js files that change on unstaged file
22
+ const fileUnStaged = spawn(
23
+ 'git',
24
+ ['diff', '--name-only', FORMAT_START, filesToCheck],
25
+ {
26
+ encoding: 'utf-8'
27
+ }
28
+ );
29
+
30
+ // Check js files that change on staged file
31
+ const fileStaged = spawn(
32
+ 'git',
33
+ ['diff', '--name-only', '--cached', FORMAT_START, filesToCheck],
34
+ {
35
+ encoding: 'utf-8'
36
+ }
37
+ );
38
+
39
+ const options = [
40
+ ...fileStaged.stdout.split('\n').filter((f) => f !== ''),
41
+ ...fileUnStaged.stdout.split('\n').filter((f) => f !== '')
42
+ ];
43
+
44
+ if (fix) {
45
+ options.push('--fix');
46
+ }
47
+ const result = spawn('node_modules/.bin/eslint', [...options], {
48
+ encoding: 'utf-8'
49
+ });
50
+
51
+ if (result.status === 1) {
52
+ console.error('Eslint error:', result.stdout);
53
+ const fixCmd = 'npm run lint:fix';
54
+ console.error(`ERROR: please run "${fixCmd}" to format changes in your commit
55
+ Note that when running the command locally, please keep your local
56
+ main branch and working branch up to date with nodejs/node-addon-api
57
+ to exclude un-related complains.
58
+ Or you can run "env FORMAT_START=upstream/main ${fixCmd}".
59
+ Also fix JS files by yourself if necessary.`);
60
+ return 1;
61
+ }
62
+
63
+ if (result.stderr) {
64
+ console.error('Error running eslint:', result.stderr);
65
+ return 2;
66
+ }
67
+ }
68
+
69
+ if (require.main === module) {
70
+ process.exitCode = main(process.argv.slice(2));
71
+ }