rclnodejs 0.28.1 → 0.30.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
@@ -45,7 +45,7 @@ npm i rclnodejs@x.y.z
45
45
 
46
46
  | RCLNODEJS Version | Compatible ROS 2 LTS |
47
47
  | :------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: |
48
- | latest version (currently [v0.28.1](https://github.com/RobotWebTools/rclnodejs/tree/0.28.1)) | [Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy) |
48
+ | latest version (currently [v0.30.0](https://github.com/RobotWebTools/rclnodejs/tree/0.30.0)) | [Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy) |
49
49
 
50
50
  ## Documentation
51
51
 
package/binding.gyp CHANGED
@@ -10,6 +10,8 @@
10
10
  'variables': {
11
11
  'ros_version': '<!(node scripts/ros_distro.js)',
12
12
  'runtime%': 'node',
13
+ 'ros_lib_dir': "<!(node -p \"require('./scripts/config.js').getROSLibPath()\")",
14
+ 'ros_include_root': "<!(node -p \"require('./scripts/config.js').getROSIncludeRootPath()\")",
13
15
  },
14
16
  'targets': [
15
17
  {
@@ -28,6 +30,7 @@
28
30
  'include_dirs': [
29
31
  '.',
30
32
  "<!(node -e \"require('nan')\")",
33
+ '<(ros_include_root)',
31
34
  ],
32
35
  'cflags!': [
33
36
  '-fno-exceptions'
@@ -61,45 +64,11 @@
61
64
  ],
62
65
  'cflags_cc': [
63
66
  '-std=c++20'
64
- ],
65
- 'include_dirs':
66
- [
67
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/ ') + '/include/')\")",
68
- ],
69
- 'library_dirs': [
70
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/lib/ ') + '/lib/')\")",
71
- ],
72
- 'conditions': [
73
- [
74
- 'ros_version > 2105', # Humble, Rolling, ...
75
- {
76
- 'include_dirs':
77
- [
78
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/ ') + '/include/')\")",
79
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/rcl/ ') + '/include/rcl')\")",
80
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/rcutils/ ') + '/include/rcutils/')\")",
81
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/rmw/ ') + '/include/rmw/')\")",
82
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/rcl_yaml_param_parser/ ') + '/include/rcl_yaml_param_parser/')\")",
83
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/rosidl_typesupport_interface/ ') + '/include/rosidl_typesupport_interface/')\")",
84
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/rcl_action/ ') + '/include/rcl_action/')\")",
85
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/action_msgs/ ') + '/include/action_msgs/')\")",
86
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/service_msgs/ ') + '/include/service_msgs/')\")",
87
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/unique_identifier_msgs/ ') + '/include/unique_identifier_msgs/')\")",
88
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/builtin_interfaces/ ') + '/include/builtin_interfaces/')\")",
89
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/rcl_lifecycle/ ') + '/include/rcl_lifecycle/')\")",
90
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/lifecycle_msgs/ ') + '/include/lifecycle_msgs/')\")",
91
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/rosidl_runtime_c/ ') + '/include/rosidl_runtime_c/')\")",
92
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/rosidl_dynamic_typesupport/ ') + '/include/rosidl_dynamic_typesupport/')\")",
93
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/type_description_interfaces/ ') + '/include/type_description_interfaces/')\")",
94
- ],
95
- }
96
- ],
97
- ],
67
+ ]
98
68
  }
99
69
  ],
100
70
  [
101
- 'OS=="win"',
102
- {
71
+ 'OS=="win"', {
103
72
  'defines': [
104
73
  'OS_WINDOWS'
105
74
  ],
@@ -108,7 +77,6 @@
108
77
  ],
109
78
  'include_dirs': [
110
79
  './src/third_party/dlfcn-win32/',
111
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include ').replace(/\\\/g, '/') + '/include')\")",
112
80
  ],
113
81
  'msvs_settings': {
114
82
  'VCCLCompilerTool': {
@@ -116,49 +84,17 @@
116
84
  },
117
85
  'VCLinkerTool': {
118
86
  'AdditionalDependencies': ['psapi.lib'],
119
- 'AdditionalLibraryDirectories': ["<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '\\\lib ').replace(/\\\/g, '/') + '/lib')\")",],
87
+ 'AdditionalLibraryDirectories': ['<(ros_lib_dir)'],
120
88
  }
121
- },
122
- 'conditions': [
123
- [
124
- 'ros_version > 2105', # Humble, Rolling, ... TODO - not tested due to broken setup_ros v3.3 action on windows
125
- {
126
- 'include_dirs':
127
- [
128
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rcl ').replace(/\\\/g, '/') + '/include/rcl')\")",
129
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rcutils ').replace(/\\\/g, '/') + '/include/rcutils')\")",
130
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rmw ').replace(/\\\/g, '/') + '/include/rmw')\")",
131
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rcl_yaml_param_parser ').replace(/\\\/g, '/') + '/include/rcl_yaml_param_parser')\")",
132
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rosidl_runtime_c ').replace(/\\\/g, '/') + '/include/rosidl_runtime_c')\")",
133
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rosidl_typesupport_interface ').replace(/\\\/g, '/') + '/include/rosidl_typesupport_interface')\")",
134
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rcl_action ').replace(/\\\/g, '/') + '/include/rcl_action')\")",
135
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/action_msgs ').replace(/\\\/g, '/') + '/include/action_msgs')\")",
136
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/service_msgs ').replace(/\\\/g, '/') + '/include/service_msgs')\")",
137
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/unique_identifier_msgs ').replace(/\\\/g, '/') + '/include/unique_identifier_msgs')\")",
138
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/builtin_interfaces ').replace(/\\\/g, '/') + '/include/builtin_interfaces')\")",
139
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rcl_lifecycle ').replace(/\\\/g, '/') + '/include/rcl_lifecycle')\")",
140
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/lifecycle_msgs ').replace(/\\\/g, '/') + '/include/lifecycle_msgs')\")",
141
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rosidl_dynamic_typesupport ').replace(/\\\/g, '/') + '/include/rosidl_dynamic_typesupport')\")",
142
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/type_description_interfaces/ ').replace(/\\\/g, '/') + '/include/type_description_interfaces/')\")",
143
- ],
144
- }
145
- ]
146
- ]
89
+ }
147
90
  }
148
91
  ],
149
92
  [
150
- 'OS=="mac"',
151
93
  # TODO - macos is no longer a tier-1 ROS platform and we have no binary ROS builds to test for Humble & Rolling
152
- {
94
+ 'OS=="mac"', {
153
95
  'defines': [
154
96
  'OS_MACOS'
155
97
  ],
156
- 'include_dirs': [
157
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/ ') + '/include/')\")",
158
- ],
159
- 'library_dirs': [
160
- "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/lib/ ') + '/lib/')\")",
161
- ],
162
98
  'xcode_settings': {
163
99
  'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
164
100
  'CLANG_CXX_LIBRARY': 'libc++',
@@ -168,8 +104,7 @@
168
104
  }
169
105
  ],
170
106
  [
171
- 'ros_version<=1911',
172
- {
107
+ 'ros_version <= 1911', {
173
108
  'libraries': [
174
109
  '-lrosidl_generator_c'
175
110
  ],
@@ -178,9 +113,22 @@
178
113
  ]
179
114
  }
180
115
  ],
181
- ['runtime=="electron"', {
182
- "defines": ["NODE_RUNTIME_ELECTRON=1"]
183
- }],
116
+ [
117
+ # After Galactic, e.g., Humble, Jazzy, Rolling.
118
+ 'ros_version > 2105', {
119
+ 'include_dirs': [
120
+ "<!@(node -p \"require('./scripts/config.js').getIncludePaths().forEach(p => console.log(JSON.stringify(p)))\")"
121
+ ],
122
+ 'library_dirs': [
123
+ '<(ros_lib_dir)',
124
+ ]
125
+ }
126
+ ],
127
+ [
128
+ 'runtime=="electron"', {
129
+ "defines": ["NODE_RUNTIME_ELECTRON=1"]
130
+ }
131
+ ],
184
132
  ]
185
133
  }
186
134
  ]
package/lib/node.js CHANGED
@@ -1273,6 +1273,26 @@ class Node extends rclnodejs.ShadowNode {
1273
1273
  return params;
1274
1274
  }
1275
1275
 
1276
+ /**
1277
+ * Get the types of given parameters.
1278
+ *
1279
+ * Return the types of given parameters.
1280
+ *
1281
+ * @param {string[]} [names] - The names of the declared parameters.
1282
+ * @return {Uint8Array} - The types.
1283
+ */
1284
+ getParameterTypes(names = []) {
1285
+ let types = [];
1286
+
1287
+ for (const name of names) {
1288
+ const descriptor = this._parameterDescriptors.get(name);
1289
+ if (descriptor) {
1290
+ types.push(descriptor.type);
1291
+ }
1292
+ }
1293
+ return types;
1294
+ }
1295
+
1276
1296
  /**
1277
1297
  * Get the names of all declared parameters.
1278
1298
  *
package/lib/parameter.js CHANGED
@@ -34,6 +34,7 @@ const rclnodejs = require('bindings')('rclnodejs');
34
34
  const DEFAULT_NUMERIC_RANGE_TOLERANCE = 1e-6;
35
35
 
36
36
  const PARAMETER_SEPARATOR = '.';
37
+ const PARAMETER_BYTE = 10;
37
38
 
38
39
  /**
39
40
  * Enum for ParameterType
@@ -125,7 +126,9 @@ class Parameter {
125
126
  constructor(name, type, value) {
126
127
  this._name = name;
127
128
  this._type = type;
128
- this._value = value;
129
+ // Convert to bigint if it's type of `PARAMETER_INTEGER`.
130
+ this._value =
131
+ this._type == ParameterType.PARAMETER_INTEGER ? BigInt(value) : value;
129
132
  this._isDirty = true;
130
133
 
131
134
  this.validate();
@@ -240,10 +243,10 @@ class Parameter {
240
243
  msg.double_array_value = this.value;
241
244
  break;
242
245
  case ParameterType.PARAMETER_INTEGER:
243
- msg.integer_value = Math.trunc(this.value);
246
+ msg.integer_value = this.value;
244
247
  break;
245
248
  case ParameterType.PARAMETER_INTEGER_ARRAY:
246
- msg.integer_array_value = this.value.map((val) => Math.trunc(val));
249
+ msg.integer_array_value = this.value;
247
250
  break;
248
251
  case ParameterType.PARAMETER_STRING:
249
252
  msg.string_value = this.value;
@@ -537,10 +540,10 @@ class Range {
537
540
 
538
541
  /**
539
542
  * Determine if a value is within this range.
540
- * A TypeError is thrown when value is not a number.
543
+ * A TypeError is thrown when value is not a number or bigint.
541
544
  * Subclasses should override and call this method for basic type checking.
542
545
  *
543
- * @param {number} value - The number to check.
546
+ * @param {number|bigint} value - The number or bigint to check.
544
547
  * @return {boolean} - True if value satisfies the range; false otherwise.
545
548
  */
546
549
  inRange(value) {
@@ -550,8 +553,8 @@ class Range {
550
553
  (inRange, val) => inRange && this.inRange(val),
551
554
  true
552
555
  );
553
- } else if (typeof value !== 'number') {
554
- throw new TypeError('Value must be a number');
556
+ } else if (typeof value !== 'number' && typeof value !== 'bigint') {
557
+ throw new TypeError('Value must be a number or bigint');
555
558
  }
556
559
 
557
560
  return true;
@@ -652,27 +655,16 @@ class FloatingPointRange extends Range {
652
655
  * Defines a range for integer values.
653
656
  * @class
654
657
  */
655
- class IntegerRange extends FloatingPointRange {
658
+ class IntegerRange extends Range {
656
659
  /**
657
660
  * Create a new instance.
658
661
  * @constructor
659
- * @param {number} fromValue - The lowest inclusive value in range
660
- * @param {number} toValue - The highest inclusive value in range
661
- * @param {number} step - The internal unit size.
662
- * @param {number} tolerance - The plus/minus tolerance for number equivalence.
662
+ * @param {bigint} fromValue - The lowest inclusive value in range
663
+ * @param {bigint} toValue - The highest inclusive value in range
664
+ * @param {bigint} step - The internal unit size.
663
665
  */
664
- constructor(
665
- fromValue,
666
- toValue,
667
- step = 1,
668
- tolerance = DEFAULT_NUMERIC_RANGE_TOLERANCE
669
- ) {
670
- super(
671
- Math.trunc(fromValue),
672
- Math.trunc(toValue),
673
- Math.trunc(step),
674
- tolerance
675
- );
666
+ constructor(fromValue, toValue, step = 1n) {
667
+ super(fromValue, toValue, step);
676
668
  }
677
669
 
678
670
  /**
@@ -683,12 +675,23 @@ class IntegerRange extends FloatingPointRange {
683
675
  */
684
676
  isValidType(parameterType) {
685
677
  const result =
686
- parameterType === ParameterType.PARAMETER_BYTE ||
687
- parameterType === ParameterType.PARAMETER_BYTE_ARRAY ||
688
678
  parameterType === ParameterType.PARAMETER_INTEGER ||
689
679
  parameterType === ParameterType.PARAMETER_INTEGER_ARRAY;
690
680
  return result;
691
681
  }
682
+
683
+ inRange(value) {
684
+ const min = this.fromValue;
685
+ const max = this.toValue;
686
+ if (value < min || value > max) {
687
+ return false;
688
+ }
689
+
690
+ if (this.step != 0n && (value - min) % this.step !== 0n) {
691
+ return false;
692
+ }
693
+ return true;
694
+ }
692
695
  }
693
696
 
694
697
  /**
@@ -763,10 +766,13 @@ function validValue(value, type) {
763
766
  case ParameterType.PARAMETER_STRING:
764
767
  result = typeof value === 'string';
765
768
  break;
766
- case ParameterType.PARAMETER_INTEGER:
767
769
  case ParameterType.PARAMETER_DOUBLE:
770
+ case PARAMETER_BYTE:
768
771
  result = typeof value === 'number';
769
772
  break;
773
+ case ParameterType.PARAMETER_INTEGER:
774
+ result = typeof value === 'bigint';
775
+ break;
770
776
  case ParameterType.PARAMETER_BOOL_ARRAY:
771
777
  case ParameterType.PARAMETER_BYTE_ARRAY:
772
778
  case ParameterType.PARAMETER_INTEGER_ARRAY:
@@ -789,7 +795,7 @@ function _validArray(values, type) {
789
795
  if (type === ParameterType.PARAMETER_BOOL_ARRAY) {
790
796
  arrayElementType = ParameterType.PARAMETER_BOOL;
791
797
  } else if (type === ParameterType.PARAMETER_BYTE_ARRAY) {
792
- arrayElementType = ParameterType.PARAMETER_INTEGER;
798
+ arrayElementType = PARAMETER_BYTE;
793
799
  }
794
800
  if (type === ParameterType.PARAMETER_INTEGER_ARRAY) {
795
801
  arrayElementType = ParameterType.PARAMETER_INTEGER;
@@ -110,6 +110,16 @@ class ParameterService {
110
110
  }
111
111
  );
112
112
 
113
+ // Create GetParameterTypes service.
114
+ const getParameterTypesServiceName = nodeName + '/get_parameter_types';
115
+ this._node.createService(
116
+ 'rcl_interfaces/srv/GetParameterTypes',
117
+ getParameterTypesServiceName,
118
+ (request, response) => {
119
+ this._handleGetParameterTypes(request, response);
120
+ }
121
+ );
122
+
113
123
  // create SetParametersAtomically service
114
124
  const setParametersAtomicallyServiceName =
115
125
  nodeName + '/set_parameters_atomically';
@@ -266,6 +276,23 @@ class ParameterService {
266
276
  response.send(msg);
267
277
  }
268
278
 
279
+ /**
280
+ * Get a list of parameter types.
281
+ *
282
+ * request.names identifies the parameter types to get.
283
+ *
284
+ * @param {GetParameterTypes_Request} request - The client request.
285
+ * @param {GetParameterTypes_Response} response - The service response with
286
+ * Uint8Array.
287
+ * @return {undefined} -
288
+ */
289
+ _handleGetParameterTypes(request, response) {
290
+ const types = this._node.getParameterTypes(request.names);
291
+ const msg = response.template;
292
+ msg.types = types;
293
+ response.send(msg);
294
+ }
295
+
269
296
  /**
270
297
  * Update a list of parameters atomically.
271
298
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rclnodejs",
3
- "version": "0.28.1",
3
+ "version": "0.30.0",
4
4
  "description": "ROS2.0 JavaScript client with Node.js",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
@@ -50,10 +50,10 @@
50
50
  "@typescript-eslint/parser": "^8.18.0",
51
51
  "babel-eslint": "^10.1.0",
52
52
  "clang-format": "^1.8.0",
53
- "commander": "^12.1.0",
53
+ "commander": "^13.1.0",
54
54
  "deep-equal": "^1.1.1",
55
55
  "eslint": "^9.16.0",
56
- "eslint-config-prettier": "^9.1.0",
56
+ "eslint-config-prettier": "^10.0.1",
57
57
  "eslint-plugin-prettier": "^5.2.1",
58
58
  "husky": "^9.1.7",
59
59
  "jsdoc": "^4.0.4",
@@ -75,6 +75,7 @@
75
75
  "dot": "^1.1.3",
76
76
  "dtslint": "^4.2.1",
77
77
  "fs-extra": "^11.2.0",
78
+ "json-bigint": "^1.0.0",
78
79
  "int64-napi": "^1.0.2",
79
80
  "is-close": "^1.3.3",
80
81
  "mkdirp": "^3.0.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rosidl-generator",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Generate JavaScript object from ROS IDL(.msg) files",
5
5
  "main": "index.js",
6
6
  "authors": [
@@ -27,7 +27,12 @@ function copyMsgObject(msg, obj) {
27
27
  for (let i in obj) {
28
28
  if (msg.hasMember(i)) {
29
29
  const type = typeof obj[i];
30
- if (type === 'string' || type === 'number' || type === 'boolean') {
30
+ if (
31
+ type === 'string' ||
32
+ type === 'number' ||
33
+ type === 'boolean' ||
34
+ type === 'bigint'
35
+ ) {
31
36
  // A primitive-type value
32
37
  msg[i] = obj[i];
33
38
  } else if (Array.isArray(obj[i]) || isTypedArray(obj[i])) {
@@ -80,17 +85,20 @@ function verifyMessage(message, obj) {
80
85
  case 'char':
81
86
  case 'int16':
82
87
  case 'int32':
83
- case 'int64':
84
88
  case 'byte':
85
89
  case 'uint16':
86
90
  case 'uint32':
87
- case 'uint64':
88
91
  case 'float32':
89
92
  case 'float64':
90
93
  if (typeof obj[name] != 'number') {
91
94
  return false;
92
95
  }
93
96
  break;
97
+ case 'int64':
98
+ case 'uint64':
99
+ if (typeof obj[name] != 'bigint') {
100
+ return false;
101
+ }
94
102
  case 'bool':
95
103
  if (typeof obj[name] != 'boolean') {
96
104
  return false;
@@ -171,7 +179,12 @@ function toROSMessage(TypeClass, obj) {
171
179
 
172
180
  function constructFromPlanObject(msg, obj) {
173
181
  const type = typeof obj;
174
- if (type === 'string' || type === 'number' || type === 'boolean') {
182
+ if (
183
+ type === 'string' ||
184
+ type === 'number' ||
185
+ type === 'boolean' ||
186
+ type === 'bigint'
187
+ ) {
175
188
  msg.data = obj;
176
189
  } else if (type === 'object') {
177
190
  copyMsgObject(msg, obj);
@@ -161,9 +161,7 @@ async function generateMsgForSrv(filePath, interfaceInfo, pkgMap) {
161
161
  async function addInterfaceInfos(filePath, dir, pkgMap) {
162
162
  const interfaceInfo = grabInterfaceInfo(filePath, true);
163
163
  const ignore = pkgFilters.matchesAny(interfaceInfo);
164
- if (ignore) {
165
- console.log('Omitting filtered interface: ', interfaceInfo);
166
- } else {
164
+ if (!ignore) {
167
165
  if (path.extname(filePath) === '.msg') {
168
166
  // Some .msg files were generated prior to 0.3.2 for .action files,
169
167
  // which has been disabled. So these files should be ignored here.
@@ -232,9 +230,7 @@ async function findPackagesInDirectory(dir) {
232
230
  amentExecuted
233
231
  );
234
232
  const ignore = pkgFilters.matchesAny(interfaceInfo);
235
- if (ignore) {
236
- console.log('Omitting filtered interface: ', interfaceInfo);
237
- } else {
233
+ if (!ignore) {
238
234
  if (path.extname(file.name) === '.msg') {
239
235
  // Some .msg files were generated prior to 0.3.2 for .action files,
240
236
  // which has been disabled. So these files should be ignored here.
@@ -157,6 +157,10 @@ function isTypedArrayType(type) {
157
157
  return typedArrayType.indexOf(type.type.toLowerCase()) !== -1;
158
158
  }
159
159
 
160
+ function isBigInt(type) {
161
+ return ['int64', 'uint64'].indexOf(type.type.toLowerCase()) !== -1;
162
+ }
163
+
160
164
  const willUseTypedArray = isTypedArrayType(it.spec.baseType);
161
165
  const currentTypedArray = getTypedArrayName(it.spec.baseType);
162
166
  const currentTypedArrayElementType = getTypedArrayElementName(it.spec.baseType);
@@ -303,7 +307,13 @@ class {{=objectWrapper}} {
303
307
  this._refObject.{{=field.name}} = {{=field.default_value}};
304
308
  {{?}}
305
309
  {{?? field.type.isPrimitiveType && !isTypedArrayType(field.type) && field.default_value}}
306
- this._{{=field.name}}Array = {{=JSON.stringify(field.default_value)}};
310
+ {{? isBigInt(field.type)}}
311
+ {{/* For non-TypedArray like int64/uint64. */}}
312
+ this._{{=field.name}}Array = {{=JSON.stringify(field.default_value)}}.map(num => BigInt(num));
313
+ {{??}}
314
+ {{/* For non-TypedArray like bool. */}}
315
+ this._{{=field.name}}Array = {{=JSON.stringify(field.default_value)}};
316
+ {{?}}
307
317
  {{?? field.type.isPrimitiveType && isTypedArrayType(field.type) && field.default_value}}
308
318
  this._wrapperFields.{{=field.name}}.fill({{=getTypedArrayName(field.type)}}.from({{=JSON.stringify(field.default_value)}}));
309
319
  {{?}}
@@ -376,8 +386,11 @@ class {{=objectWrapper}} {
376
386
  }
377
387
  }
378
388
  }
389
+ {{?? isBigInt(field.type)}}
390
+ {{/* For non-TypedArray like int64/uint64. */}}
391
+ this._refObject.{{=field.name}} = this._{{=field.name}}Array.map(num => num.toString());
379
392
  {{??}}
380
- {{/* For non-TypedArray like int64/uint64/bool. */}}
393
+ {{/* For non-TypedArray like bool. */}}
381
394
  this._refObject.{{=field.name}} = this._{{=field.name}}Array;
382
395
  {{?}}
383
396
  {{?? field.type.isArray && field.type.isPrimitiveType && isTypedArrayType(field.type) && field.type.isFixedSizeArray}}
@@ -527,6 +540,8 @@ class {{=objectWrapper}} {
527
540
  return this._wrapperFields.{{=field.name}};
528
541
  {{?? !field.type.isArray && field.type.type === 'string' && it.spec.msgName !== 'String'}}
529
542
  return this._wrapperFields.{{=field.name}}.data;
543
+ {{?? isBigInt(field.type)}}
544
+ return BigInt(this._refObject.{{=field.name}});
530
545
  {{??}}
531
546
  return this._refObject.{{=field.name}};
532
547
  {{?}}
@@ -559,6 +574,11 @@ class {{=objectWrapper}} {
559
574
  }
560
575
  {{?? !field.type.isArray && field.type.type === 'string' && it.spec.msgName !== 'String'}}
561
576
  this._wrapperFields.{{=field.name}}.data = value;
577
+ {{?? isBigInt(field.type)}}
578
+ if (typeof value !== "bigint") {
579
+ throw new TypeError('{{=field.name}} must be type of bigint');
580
+ }
581
+ this._refObject.{{=field.name}} = value.toString();
562
582
  {{??}}
563
583
  {{? it.spec.msgName === 'String'}}
564
584
  this._refObject.size = Buffer.byteLength(value);
@@ -14,11 +14,20 @@
14
14
 
15
15
  'use strict';
16
16
 
17
+ const compareVersions = require('compare-versions');
17
18
  const path = require('path');
18
19
  const execFile = require('child_process').execFile;
19
20
 
20
21
  const pythonExecutable = require('./py_utils').getPythonExecutable('python3');
21
22
 
23
+ const contextSupportedVersion = '21.0.0.0';
24
+ const currentVersion = process.version;
25
+ const isContextSupported = compareVersions.compare(
26
+ currentVersion.substring(1, currentVersion.length),
27
+ contextSupportedVersion,
28
+ '>='
29
+ );
30
+
22
31
  const rosidlParser = {
23
32
  parseMessageFile(packageName, filePath) {
24
33
  return this._parseFile('parse_message_file', packageName, filePath);
@@ -32,6 +41,25 @@ const rosidlParser = {
32
41
  return this._parseFile('parse_action_file', packageName, filePath);
33
42
  },
34
43
 
44
+ _parseJSONObject(str) {
45
+ // For nodejs >= `contextSupportedVersion`, we leverage context parameter to
46
+ // convert unsafe integer to string, otherwise, json-bigint is used.
47
+ // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
48
+ if (isContextSupported) {
49
+ return JSON.parse(str, (key, value, context) => {
50
+ if (
51
+ Number.isInteger(value) &&
52
+ !Number.isSafeInteger(Number(context.source))
53
+ ) {
54
+ return context.source;
55
+ }
56
+ return value;
57
+ });
58
+ }
59
+ const JSONbigString = require('json-bigint')({ storeAsString: true });
60
+ return JSONbigString.parse(str);
61
+ },
62
+
35
63
  _parseFile(command, packageName, filePath) {
36
64
  return new Promise((resolve, reject) => {
37
65
  const args = [
@@ -54,7 +82,7 @@ const rosidlParser = {
54
82
  )
55
83
  );
56
84
  } else {
57
- resolve(JSON.parse(stdout));
85
+ resolve(this._parseJSONObject(stdout));
58
86
  }
59
87
  }
60
88
  );
@@ -478,7 +478,6 @@ function primitiveType2JSName(type) {
478
478
  case 'int8':
479
479
  case 'int16':
480
480
  case 'int32':
481
- case 'int64':
482
481
 
483
482
  // signed explicit float types
484
483
  case 'float32':
@@ -488,7 +487,6 @@ function primitiveType2JSName(type) {
488
487
  case 'uint8':
489
488
  case 'uint16':
490
489
  case 'uint32':
491
- case 'uint64':
492
490
  jsName = 'number';
493
491
  break;
494
492
  case 'bool':
@@ -499,6 +497,10 @@ function primitiveType2JSName(type) {
499
497
  case 'wstring':
500
498
  jsName = 'string';
501
499
  break;
500
+ case 'int64':
501
+ case 'uint64':
502
+ jsName = 'bigint';
503
+ break;
502
504
  }
503
505
 
504
506
  return jsName;
@@ -0,0 +1,69 @@
1
+ // Licensed under the Apache License, Version 2.0 (the "License");
2
+ // you may not use this file except in compliance with the License.
3
+ // You may obtain a copy of the License at
4
+ //
5
+ // http://www.apache.org/licenses/LICENSE-2.0
6
+ //
7
+ // Unless required by applicable law or agreed to in writing, software
8
+ // distributed under the License is distributed on an "AS IS" BASIS,
9
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ // See the License for the specific language governing permissions and
11
+ // limitations under the License.
12
+
13
+ 'use strict';
14
+
15
+ const os = require('os');
16
+ const path = require('path');
17
+ const { execSync } = require('child_process');
18
+
19
+ const dependencies = [
20
+ 'rcl',
21
+ 'rcutils',
22
+ 'rmw',
23
+ 'rcl_yaml_param_parser',
24
+ 'rosidl_typesupport_interface',
25
+ 'rcl_action',
26
+ 'action_msgs',
27
+ 'service_msgs',
28
+ 'unique_identifier_msgs',
29
+ 'builtin_interfaces',
30
+ 'rcl_lifecycle',
31
+ 'lifecycle_msgs',
32
+ 'rosidl_runtime_c',
33
+ 'rosidl_dynamic_typesupport',
34
+ 'type_description_interfaces',
35
+ ];
36
+
37
+ const command = os.type() === 'Windows_NT' ? 'where ros2' : 'which ros2';
38
+
39
+ function getROSRootPath() {
40
+ try {
41
+ // Execute the command to find the ROS2 installation path.
42
+ let ros2Path = execSync(command).toString().trim();
43
+ return path.dirname(path.dirname(ros2Path));
44
+ } catch (error) {
45
+ console.error(`Error: ${error.message}`);
46
+ }
47
+ }
48
+
49
+ function getROSLibPath() {
50
+ return path.join(getROSRootPath(), 'lib');
51
+ }
52
+
53
+ function getROSIncludeRootPath() {
54
+ return path.join(getROSRootPath(), 'include');
55
+ }
56
+
57
+ function getIncludePaths() {
58
+ const includeRoot = getROSIncludeRootPath();
59
+ return dependencies.map((dependency) => {
60
+ return path.join(includeRoot, dependency);
61
+ });
62
+ }
63
+
64
+ module.exports = {
65
+ getROSRootPath,
66
+ getROSLibPath,
67
+ getROSIncludeRootPath,
68
+ getIncludePaths,
69
+ };
@@ -45,7 +45,7 @@ npm i rclnodejs@x.y.z
45
45
 
46
46
  | RCLNODEJS Version | Compatible ROS 2 LTS |
47
47
  | :------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: |
48
- | latest version (currently [v0.28.1](https://github.com/RobotWebTools/rclnodejs/tree/0.28.1)) | [Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy) |
48
+ | latest version (currently [v0.30.0](https://github.com/RobotWebTools/rclnodejs/tree/0.30.0)) | [Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy) |
49
49
 
50
50
  ## Documentation
51
51
 
package/types/index.d.ts CHANGED
@@ -144,6 +144,13 @@ declare module 'rclnodejs' {
144
144
  type: T
145
145
  ): MessageType<T>;
146
146
 
147
+ /**
148
+ * Removes the default signal handler installed by rclnodejs. After calling this, rclnodejs
149
+ * will no longer clean itself up when a SIGINT is received, it is the application's
150
+ * responsibility to properly shut down all nodes and contexts.
151
+ */
152
+ function removeSignalHandlers(): void;
153
+
147
154
  /**
148
155
  * Get a list of action names and types for action clients associated with a node.
149
156
  * @param node - The node used for discovery.
package/types/node.d.ts CHANGED
@@ -324,7 +324,7 @@ declare module 'rclnodejs' {
324
324
  typeClass: T,
325
325
  topic: string,
326
326
  options: Options,
327
- callback: SubscriptionCallback<T>
327
+ callback: SubscriptionCallback<T> | SubscriptionWithRawMessageCallback
328
328
  ): Subscription;
329
329
 
330
330
  /**
@@ -45,7 +45,7 @@ declare module 'rclnodejs' {
45
45
  *
46
46
  * @param name - The parameter name, must be a valid name.
47
47
  * @param type - The type identifier.
48
- * @param {value - The parameter value.
48
+ * @param value - The parameter value.
49
49
  */
50
50
  constructor(name: string, type: ParameterType, value?: any);
51
51
 
@@ -261,16 +261,15 @@ declare module 'rclnodejs' {
261
261
  /**
262
262
  *
263
263
  */
264
- class IntegerRange extends FloatingPointRange {
264
+ class IntegerRange extends Range {
265
265
  /**
266
266
  * Create a new instance.
267
267
  * @constructor
268
- * @param {number} fromValue - The lowest inclusive value in range
269
- * @param {number} toValue - The highest inclusive value in range
270
- * @param {number} step - The internal unit size.
271
- * @param {number} tolerance - The plus/minus tolerance for number equivalence.
268
+ * @param {bigint} fromValue - The lowest inclusive value in range
269
+ * @param {bigint} toValue - The highest inclusive value in range
270
+ * @param {bigint} step - The internal unit size.
272
271
  */
273
- constructor(from: number, to: number, step?: number, tolerance?: number);
272
+ constructor(from: bigint, to: bigint, step?: bigint);
274
273
 
275
274
  /**
276
275
  * Determine if a ParameterType is compatible.
@@ -13,7 +13,23 @@ declare module 'rclnodejs' {
13
13
  */
14
14
  type SubscriptionCallback<T extends TypeClass<MessageTypeClassName>> =
15
15
  // * @param message - The published message
16
- (message: MessageType<T> | Buffer) => void;
16
+ (message: MessageType<T>) => void;
17
+
18
+ /**
19
+ * A callback for receiving published raw messages.
20
+ *
21
+ * @param message - The published message.
22
+ *
23
+ * @remarks
24
+ * See {@link Node#createSubscription | Node.createSubscription}
25
+ * See {@link SubscriptionContentFilter}
26
+ * See {@link Node#createPublisher | Node.createPublisher}
27
+ * See {@link Publisher}
28
+ * See {@link Subscription}
29
+ */
30
+ type SubscriptionWithRawMessageCallback =
31
+ // * @param message - The published raw message
32
+ (message: Buffer) => void;
17
33
 
18
34
  /**
19
35
  * A ROS Subscription for published messages on a topic.