rclnodejs 1.8.2 → 1.8.3

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 (41) hide show
  1. package/index.js +33 -23
  2. package/lib/action/client.js +6 -0
  3. package/lib/action/server.js +1 -3
  4. package/lib/distro.js +2 -1
  5. package/lib/lifecycle_publisher.js +2 -2
  6. package/lib/node.js +37 -11
  7. package/lib/parameter.js +5 -9
  8. package/lib/service.js +8 -4
  9. package/lib/time_source.js +3 -20
  10. package/package.json +2 -2
  11. package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
  12. package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
  13. package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
  14. package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
  15. package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
  16. package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
  17. package/rosidl_gen/generate_worker.js +3 -13
  18. package/rosidl_gen/idl_generator.js +210 -0
  19. package/rosidl_gen/index.js +3 -12
  20. package/rosidl_gen/packages.js +1 -3
  21. package/rosidl_gen/primitive_types.js +2 -2
  22. package/rosidl_parser/idl_parser.py +437 -0
  23. package/rosidl_parser/parser.py +2 -4
  24. package/rosidl_parser/rosidl_parser.js +27 -0
  25. package/src/executor.cpp +1 -0
  26. package/src/macros.h +2 -2
  27. package/src/rcl_action_client_bindings.cpp +18 -11
  28. package/src/rcl_action_server_bindings.cpp +24 -13
  29. package/src/rcl_client_bindings.cpp +13 -5
  30. package/src/rcl_context_bindings.cpp +7 -8
  31. package/src/rcl_guard_condition_bindings.cpp +12 -3
  32. package/src/rcl_lifecycle_bindings.cpp +34 -15
  33. package/src/rcl_node_bindings.cpp +11 -4
  34. package/src/rcl_publisher_bindings.cpp +12 -3
  35. package/src/rcl_service_bindings.cpp +12 -3
  36. package/src/rcl_subscription_bindings.cpp +24 -21
  37. package/src/rcl_timer_bindings.cpp +24 -9
  38. package/src/rcl_type_description_service_bindings.cpp +9 -1
  39. package/rosidl_convertor/README.md +0 -298
  40. package/rosidl_convertor/idl_convertor.js +0 -50
  41. package/rosidl_convertor/idl_convertor.py +0 -1250
package/index.js CHANGED
@@ -85,7 +85,7 @@ async function getCurrentGeneratorVersion() {
85
85
  const jsonFilePath = path.join(generator.generatedRoot, 'generator.json');
86
86
 
87
87
  return new Promise((resolve, reject) => {
88
- fs.open(jsonFilePath, 'r', (err) => {
88
+ fs.readFile(jsonFilePath, 'utf8', (err, data) => {
89
89
  if (err) {
90
90
  if (err.code === 'ENOENT') {
91
91
  resolve(null);
@@ -93,13 +93,11 @@ async function getCurrentGeneratorVersion() {
93
93
  reject(err);
94
94
  }
95
95
  } else {
96
- fs.readFile(jsonFilePath, 'utf8', (err, data) => {
97
- if (err) {
98
- reject(err);
99
- } else {
100
- resolve(JSON.parse(data).version);
101
- }
102
- });
96
+ try {
97
+ resolve(JSON.parse(data).version);
98
+ } catch (parseErr) {
99
+ reject(parseErr);
100
+ }
103
101
  }
104
102
  });
105
103
  });
@@ -389,23 +387,35 @@ let rcl = {
389
387
 
390
388
  rclnodejs.init(context.handle, argv, context._domainId);
391
389
 
392
- if (_rosVersionChecked) {
393
- // no further processing required
394
- return;
395
- }
390
+ try {
391
+ if (_rosVersionChecked) {
392
+ // no further processing required
393
+ return;
394
+ }
396
395
 
397
- const version = await getCurrentGeneratorVersion();
398
- const forced =
399
- version === null || compareVersions(version, generator.version(), '<');
400
- if (forced) {
401
- debug(
402
- 'The generator will begin to create JavaScript code from ROS IDL files...'
403
- );
404
- }
396
+ const version = await getCurrentGeneratorVersion();
397
+ const forced =
398
+ version === null || compareVersions(version, generator.version(), '<');
399
+ if (forced) {
400
+ debug(
401
+ 'The generator will begin to create JavaScript code from ROS IDL files...'
402
+ );
403
+ }
405
404
 
406
- await generator.generateAll(forced);
407
- // TODO determine if tsd generateAll() should be here
408
- _rosVersionChecked = true;
405
+ await generator.generateAll(forced);
406
+ // TODO determine if tsd generateAll() should be here
407
+ _rosVersionChecked = true;
408
+ } catch (error) {
409
+ try {
410
+ context.tryShutdown();
411
+ } catch (shutdownError) {
412
+ const initError =
413
+ error instanceof Error ? error : new Error(String(error));
414
+ initError.message += ` (rollback also failed: ${shutdownError.message})`;
415
+ throw initError;
416
+ }
417
+ throw error;
418
+ }
409
419
  },
410
420
 
411
421
  /**
@@ -126,6 +126,12 @@ class ActionClient extends Entity {
126
126
  }
127
127
 
128
128
  this._goalHandles.set(uuid, goalHandle);
129
+ } else {
130
+ // Clean up feedback callback for rejected goals
131
+ let uuid = ActionUuid.fromMessage(
132
+ this._sequenceNumberGoalIdMap.get(sequence)
133
+ ).toString();
134
+ this._feedbackCallbacks.delete(uuid);
129
135
  }
130
136
 
131
137
  this._pendingGoalRequests.get(sequence).setResult(goalHandle);
@@ -437,10 +437,8 @@ class ActionServer extends Entity {
437
437
 
438
438
  _executeExpiredGoals(result, count) {
439
439
  for (let i = 0; i < count; i++) {
440
- const goal = result.data[i];
441
-
442
440
  const goalInfo = new ActionInterfaces.GoalInfo();
443
- goalInfo.deserialize(goal.refObject);
441
+ goalInfo.deserialize(result._refArray[i]);
444
442
 
445
443
  let uuid = ActionUuid.fromBytes(goalInfo.goal_id.uuid).toString();
446
444
  this._goalHandles.delete(uuid);
package/lib/distro.js CHANGED
@@ -65,7 +65,8 @@ const DistroUtils = {
65
65
  return process.env.ROS_DISTRO;
66
66
  }
67
67
 
68
- return [...DistroNameIdMap].find(([, val]) => val == distroId)[0];
68
+ const result = [...DistroNameIdMap].find(([, val]) => val == distroId);
69
+ return result ? result[0] : undefined;
69
70
  },
70
71
 
71
72
  getKnownDistroNames: function () {
@@ -30,7 +30,7 @@ class LifecyclePublisher extends Publisher {
30
30
  super(handle, typeClass, /*topic=*/ '', options);
31
31
 
32
32
  this._enabled = false;
33
- this._loggger = Logging.getLogger('LifecyclePublisher');
33
+ this._logger = Logging.getLogger('LifecyclePublisher');
34
34
  }
35
35
 
36
36
  /**
@@ -42,7 +42,7 @@ class LifecyclePublisher extends Publisher {
42
42
  */
43
43
  publish(message) {
44
44
  if (!this._enabled) {
45
- this._loggger.warn(
45
+ this._logger.warn(
46
46
  `Trying to publish message on the topic ${this.topic}, but the publisher is not activated`
47
47
  );
48
48
 
package/lib/node.js CHANGED
@@ -97,7 +97,30 @@ class Node extends rclnodejs.ShadowNode {
97
97
  );
98
98
  }
99
99
 
100
+ static _normalizeOptions(options) {
101
+ if (options instanceof NodeOptions) {
102
+ return options;
103
+ }
104
+ const defaults = NodeOptions.defaultOptions;
105
+ return {
106
+ startParameterServices:
107
+ options.startParameterServices ?? defaults.startParameterServices,
108
+ parameterOverrides:
109
+ options.parameterOverrides ?? defaults.parameterOverrides,
110
+ automaticallyDeclareParametersFromOverrides:
111
+ options.automaticallyDeclareParametersFromOverrides ??
112
+ defaults.automaticallyDeclareParametersFromOverrides,
113
+ startTypeDescriptionService:
114
+ options.startTypeDescriptionService ??
115
+ defaults.startTypeDescriptionService,
116
+ enableRosout: options.enableRosout ?? defaults.enableRosout,
117
+ rosoutQos: options.rosoutQos ?? defaults.rosoutQos,
118
+ };
119
+ }
120
+
100
121
  _init(name, namespace, options, context, args, useGlobalArguments) {
122
+ options = Node._normalizeOptions(options);
123
+
101
124
  this.handle = rclnodejs.createNode(
102
125
  name,
103
126
  namespace,
@@ -151,7 +174,7 @@ class Node extends rclnodejs.ShadowNode {
151
174
  // override cli parameterOverrides with those specified in options
152
175
  if (options.parameterOverrides.length > 0) {
153
176
  for (const parameter of options.parameterOverrides) {
154
- if ((!parameter) instanceof Parameter) {
177
+ if (!(parameter instanceof Parameter)) {
155
178
  throw new TypeValidationError(
156
179
  'parameterOverride',
157
180
  parameter,
@@ -425,17 +448,20 @@ class Node extends rclnodejs.ShadowNode {
425
448
  }
426
449
 
427
450
  if (properties.isGoalExpired) {
428
- let GoalInfoArray = ActionInterfaces.GoalInfo.ArrayType;
429
- let message = new GoalInfoArray(actionServer._goalHandles.size);
430
- let count = rclnodejs.actionExpireGoals(
431
- actionServer.handle,
432
- actionServer._goalHandles.size,
433
- message._refArray.buffer
434
- );
435
- if (count > 0) {
436
- actionServer.processGoalExpired(message, count);
451
+ let numGoals = actionServer._goalHandles.size;
452
+ if (numGoals > 0) {
453
+ let GoalInfoArray = ActionInterfaces.GoalInfo.ArrayType;
454
+ let message = new GoalInfoArray(numGoals);
455
+ let count = rclnodejs.actionExpireGoals(
456
+ actionServer.handle,
457
+ numGoals,
458
+ message._refArray.buffer
459
+ );
460
+ if (count > 0) {
461
+ actionServer.processGoalExpired(message, count);
462
+ }
463
+ GoalInfoArray.freeArray(message);
437
464
  }
438
- GoalInfoArray.freeArray(message);
439
465
  }
440
466
  }
441
467
 
package/lib/parameter.js CHANGED
@@ -864,9 +864,8 @@ function parameterTypeFromValue(value) {
864
864
  function validType(parameterType) {
865
865
  let result =
866
866
  typeof parameterType === 'number' &&
867
- ParameterType.PARAMETER_NOT_SET <=
868
- parameterType <=
869
- ParameterType.PARAMETER_STRING_ARRAY;
867
+ parameterType >= ParameterType.PARAMETER_NOT_SET &&
868
+ parameterType <= ParameterType.PARAMETER_STRING_ARRAY;
870
869
 
871
870
  return result;
872
871
  }
@@ -923,14 +922,11 @@ function _validArray(values, type) {
923
922
  arrayElementType = ParameterType.PARAMETER_BOOL;
924
923
  } else if (type === ParameterType.PARAMETER_BYTE_ARRAY) {
925
924
  arrayElementType = PARAMETER_BYTE;
926
- }
927
- if (type === ParameterType.PARAMETER_INTEGER_ARRAY) {
925
+ } else if (type === ParameterType.PARAMETER_INTEGER_ARRAY) {
928
926
  arrayElementType = ParameterType.PARAMETER_INTEGER;
929
- }
930
- if (type === ParameterType.PARAMETER_DOUBLE_ARRAY) {
927
+ } else if (type === ParameterType.PARAMETER_DOUBLE_ARRAY) {
931
928
  arrayElementType = ParameterType.PARAMETER_DOUBLE;
932
- }
933
- if (type === ParameterType.PARAMETER_STRING_ARRAY) {
929
+ } else if (type === ParameterType.PARAMETER_STRING_ARRAY) {
934
930
  arrayElementType = ParameterType.PARAMETER_STRING;
935
931
  }
936
932
 
package/lib/service.js CHANGED
@@ -17,6 +17,7 @@
17
17
  const rclnodejs = require('./native_loader.js');
18
18
  const DistroUtils = require('./distro.js');
19
19
  const Entity = require('./entity.js');
20
+ const Logging = require('./logging.js');
20
21
  const debug = require('debug')('rclnodejs:service');
21
22
 
22
23
  /**
@@ -75,8 +76,8 @@ class Service extends Entity {
75
76
 
76
77
  const plainObj = request.toPlainObject(this.typedArrayEnabled);
77
78
  const response = new Response(this, headerHandle);
78
- Promise.resolve(this._callback(plainObj, response)).then(
79
- (responseToReturn) => {
79
+ Promise.resolve(this._callback(plainObj, response))
80
+ .then((responseToReturn) => {
80
81
  if (!response.sent && responseToReturn) {
81
82
  responseToReturn = new this._typeClass.Response(responseToReturn);
82
83
  const rawResponse = responseToReturn.serialize();
@@ -86,8 +87,11 @@ class Service extends Entity {
86
87
  debug(
87
88
  `Service has processed the ${this._serviceName} request and sent the response.`
88
89
  );
89
- }
90
- );
90
+ })
91
+ .catch((error) => {
92
+ const logger = Logging.getLogger('rclnodejs');
93
+ logger.error(`Error processing ${this._serviceName} request: ${error}`);
94
+ });
91
95
  }
92
96
 
93
97
  static createService(nodeHandle, serviceName, typeClass, options, callback) {
@@ -45,26 +45,6 @@ class TimeSource {
45
45
  }
46
46
  }
47
47
 
48
- get isRosTimeActive() {
49
- return this._isRosTimeActive;
50
- }
51
-
52
- set isRosTimeActive(enabled) {
53
- if (this.isRosTimeActive === enabled) return;
54
-
55
- this._isRosTimeActive = enabled;
56
- for (const clock in this._associatedClocks) {
57
- clock.isRosTimeActive = enabled;
58
- }
59
-
60
- if (enabled) {
61
- this._subscribeToClockTopic();
62
- } else if (this._node && this._clockSubscription) {
63
- this._node.destroySubscription(this._clockSubscription);
64
- this._node._clockSubscription = null;
65
- }
66
- }
67
-
68
48
  /**
69
49
  * Return status that whether the ROS time is active.
70
50
  * @name TimeSource#get:isRosTimeActive
@@ -93,6 +73,9 @@ class TimeSource {
93
73
  });
94
74
  if (enabled) {
95
75
  this._subscribeToClockTopic();
76
+ } else if (this._node && this._clockSubscription) {
77
+ this._node.destroySubscription(this._clockSubscription);
78
+ this._clockSubscription = undefined;
96
79
  }
97
80
  }
98
81
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rclnodejs",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "description": "ROS2.0 JavaScript client with Node.js",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
@@ -65,7 +65,7 @@
65
65
  "lint-staged": "^16.2.0",
66
66
  "mocha": "^11.0.2",
67
67
  "node-gyp": "^12.1.0",
68
- "nyc": "^17.1.0",
68
+ "nyc": "^18.0.0",
69
69
  "prebuildify": "^6.0.1",
70
70
  "rimraf": "^6.0.1",
71
71
  "sinon": "^21.0.0",
@@ -12,14 +12,11 @@
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
 
15
- const fse = require('../lib/utils.js');
16
15
  const generateJSStructFromIDL = require('./idl_generator.js');
17
16
  const packages = require('./packages.js');
18
17
  const path = require('path');
19
- const idlConvertor = require('../rosidl_convertor/idl_convertor.js');
20
18
 
21
19
  const generatedRoot = path.join(__dirname, '../generated/');
22
- const idlPath = path.join(generatedRoot, 'share');
23
20
  const useIDL = !!process.argv.find((arg) => arg === '--idl');
24
21
 
25
22
  // Get target path from environment variable instead of workerData
@@ -32,17 +29,10 @@ async function generateInPath(targetPath) {
32
29
  (await packages.findPackagesInDirectory(targetPath)).values()
33
30
  );
34
31
  } else {
32
+ // Direct IDL parsing: pass .idl files to the generator which uses
33
+ // rosidl_parser to parse them directly (no .msg/.srv/.action conversion).
35
34
  const idlPkgs = await packages.findPackagesInDirectory(targetPath, useIDL);
36
- await fse.ensureDir(idlPath);
37
- const promises = [];
38
- idlPkgs.forEach((pkg) => {
39
- pkg.idls.forEach((idl) => {
40
- promises.push(idlConvertor(idl.pkgName, idl.filePath, idlPath));
41
- });
42
- });
43
- await Promise.all(promises);
44
- const pkgsFromIdl = await packages.findPackagesInDirectory(idlPath, false);
45
- pkgsInfo = Array.from(pkgsFromIdl.values());
35
+ pkgsInfo = Array.from(idlPkgs.values());
46
36
  }
47
37
 
48
38
  await Promise.all(
@@ -305,7 +305,217 @@ async function generateJSStructFromIDL(pkg, dir) {
305
305
  pkg.actions.forEach((actionInfo) => {
306
306
  results.push(generateActionJSStruct(actionInfo, dir));
307
307
  });
308
+
309
+ // Handle .idl files directly (parsed via rosidl_parser, no .msg conversion)
310
+ if (pkg.idls) {
311
+ pkg.idls.forEach((idlInfo) => {
312
+ results.push(generateJSStructFromIdlFile(idlInfo, dir));
313
+ });
314
+ }
315
+
308
316
  await Promise.all(results);
309
317
  }
310
318
 
319
+ /**
320
+ * Parse an .idl file directly and generate the appropriate JS struct.
321
+ * This uses rosidl_parser to parse the IDL and produces the same JSON
322
+ * spec format, so the same templates can be used.
323
+ */
324
+ async function generateJSStructFromIdlFile(idlInfo, dir) {
325
+ const result = await parser.parseIdlFile(idlInfo.filePath);
326
+ const { type, spec } = result;
327
+
328
+ if (type === 'message') {
329
+ await generateMessageJSStructFromSpec(
330
+ {
331
+ pkgName: idlInfo.pkgName,
332
+ subFolder: idlInfo.subFolder,
333
+ interfaceName: idlInfo.interfaceName,
334
+ },
335
+ dir,
336
+ spec
337
+ );
338
+ } else if (type === 'service') {
339
+ // Generate request and response message JS structs
340
+ const requestMsg = generateMessageJSStructFromSpec(
341
+ {
342
+ pkgName: idlInfo.pkgName,
343
+ subFolder: idlInfo.subFolder,
344
+ interfaceName: `${idlInfo.interfaceName}_Request`,
345
+ },
346
+ dir,
347
+ spec.request
348
+ );
349
+
350
+ const responseMsg = generateMessageJSStructFromSpec(
351
+ {
352
+ pkgName: idlInfo.pkgName,
353
+ subFolder: idlInfo.subFolder,
354
+ interfaceName: `${idlInfo.interfaceName}_Response`,
355
+ },
356
+ dir,
357
+ spec.response
358
+ );
359
+
360
+ // Generate service JS struct
361
+ const serviceInfo = {
362
+ pkgName: idlInfo.pkgName,
363
+ subFolder: idlInfo.subFolder,
364
+ interfaceName: idlInfo.interfaceName,
365
+ };
366
+ const srv = generateServiceJSStruct(
367
+ serviceInfo,
368
+ dir,
369
+ /*isActionService=*/ false
370
+ );
371
+
372
+ await Promise.all([requestMsg, responseMsg, srv]);
373
+ } else if (type === 'action') {
374
+ // Generate goal, result, feedback message JS structs
375
+ const goalMsg = generateMessageJSStructFromSpec(
376
+ {
377
+ pkgName: idlInfo.pkgName,
378
+ subFolder: idlInfo.subFolder,
379
+ interfaceName: `${idlInfo.interfaceName}_Goal`,
380
+ },
381
+ dir,
382
+ spec.goal
383
+ );
384
+
385
+ const resultMsg = generateMessageJSStructFromSpec(
386
+ {
387
+ pkgName: idlInfo.pkgName,
388
+ subFolder: idlInfo.subFolder,
389
+ interfaceName: `${idlInfo.interfaceName}_Result`,
390
+ },
391
+ dir,
392
+ spec.result
393
+ );
394
+
395
+ const feedbackMsg = generateMessageJSStructFromSpec(
396
+ {
397
+ pkgName: idlInfo.pkgName,
398
+ subFolder: idlInfo.subFolder,
399
+ interfaceName: `${idlInfo.interfaceName}_Feedback`,
400
+ },
401
+ dir,
402
+ spec.feedback
403
+ );
404
+
405
+ // Generate derived action messages (SendGoal, GetResult, FeedbackMessage)
406
+ const sendGoalRequestSpec = actionMsgs.createSendGoalRequestSpec(
407
+ idlInfo.pkgName,
408
+ idlInfo.interfaceName
409
+ );
410
+ const sendGoalRequestMsg = generateMessageJSStructFromSpec(
411
+ {
412
+ pkgName: idlInfo.pkgName,
413
+ subFolder: idlInfo.subFolder,
414
+ interfaceName: `${idlInfo.interfaceName}_SendGoal_Request`,
415
+ },
416
+ dir,
417
+ sendGoalRequestSpec
418
+ );
419
+
420
+ const sendGoalResponseSpec = actionMsgs.createSendGoalResponseSpec(
421
+ idlInfo.pkgName,
422
+ idlInfo.interfaceName
423
+ );
424
+ const sendGoalResponseMsg = generateMessageJSStructFromSpec(
425
+ {
426
+ pkgName: idlInfo.pkgName,
427
+ subFolder: idlInfo.subFolder,
428
+ interfaceName: `${idlInfo.interfaceName}_SendGoal_Response`,
429
+ },
430
+ dir,
431
+ sendGoalResponseSpec
432
+ );
433
+
434
+ const sendGoalSrv = generateServiceJSStruct(
435
+ {
436
+ pkgName: idlInfo.pkgName,
437
+ subFolder: idlInfo.subFolder,
438
+ interfaceName: `${idlInfo.interfaceName}_SendGoal`,
439
+ },
440
+ dir
441
+ );
442
+
443
+ const getResultRequestSpec = actionMsgs.createGetResultRequestSpec(
444
+ idlInfo.pkgName,
445
+ idlInfo.interfaceName
446
+ );
447
+ const getResultRequestMsg = generateMessageJSStructFromSpec(
448
+ {
449
+ pkgName: idlInfo.pkgName,
450
+ subFolder: idlInfo.subFolder,
451
+ interfaceName: `${idlInfo.interfaceName}_GetResult_Request`,
452
+ },
453
+ dir,
454
+ getResultRequestSpec
455
+ );
456
+
457
+ const getResultResponseSpec = actionMsgs.createGetResultResponseSpec(
458
+ idlInfo.pkgName,
459
+ idlInfo.interfaceName
460
+ );
461
+ const getResultResponseMsg = generateMessageJSStructFromSpec(
462
+ {
463
+ pkgName: idlInfo.pkgName,
464
+ subFolder: idlInfo.subFolder,
465
+ interfaceName: `${idlInfo.interfaceName}_GetResult_Response`,
466
+ },
467
+ dir,
468
+ getResultResponseSpec
469
+ );
470
+
471
+ const getResultSrv = generateServiceJSStruct(
472
+ {
473
+ pkgName: idlInfo.pkgName,
474
+ subFolder: idlInfo.subFolder,
475
+ interfaceName: `${idlInfo.interfaceName}_GetResult`,
476
+ },
477
+ dir
478
+ );
479
+
480
+ const feedbackMessageSpec = actionMsgs.createFeedbackMessageSpec(
481
+ idlInfo.pkgName,
482
+ idlInfo.interfaceName
483
+ );
484
+ const feedbackMessageMsg = generateMessageJSStructFromSpec(
485
+ {
486
+ pkgName: idlInfo.pkgName,
487
+ subFolder: idlInfo.subFolder,
488
+ interfaceName: `${idlInfo.interfaceName}_FeedbackMessage`,
489
+ },
490
+ dir,
491
+ feedbackMessageSpec
492
+ );
493
+
494
+ const fileName =
495
+ idlInfo.pkgName +
496
+ '__' +
497
+ idlInfo.subFolder +
498
+ '__' +
499
+ idlInfo.interfaceName +
500
+ '.js';
501
+ const generatedCode = generateAction({ actionInfo: idlInfo });
502
+ const actionDir = path.join(dir, idlInfo.pkgName);
503
+ const action = writeGeneratedCode(actionDir, fileName, generatedCode);
504
+
505
+ await Promise.all([
506
+ goalMsg,
507
+ resultMsg,
508
+ feedbackMsg,
509
+ sendGoalRequestMsg,
510
+ sendGoalResponseMsg,
511
+ sendGoalSrv,
512
+ getResultRequestMsg,
513
+ getResultResponseMsg,
514
+ getResultSrv,
515
+ feedbackMessageMsg,
516
+ action,
517
+ ]);
518
+ }
519
+ }
520
+
311
521
  module.exports = generateJSStructFromIDL;
@@ -18,10 +18,8 @@ const fse = require('../lib/utils.js');
18
18
  const generateJSStructFromIDL = require('./idl_generator.js');
19
19
  const packages = require('./packages.js');
20
20
  const path = require('path');
21
- const idlConvertor = require('../rosidl_convertor/idl_convertor.js');
22
21
  const generatedRoot = path.join(__dirname, '../generated/');
23
22
  const serviceMsgPath = path.join(generatedRoot, 'srv_msg');
24
- const idlPath = path.join(generatedRoot, 'share');
25
23
  const useIDL = !!process.argv.find((arg) => arg === '--idl');
26
24
 
27
25
  function getInstalledPackagePaths() {
@@ -35,17 +33,10 @@ async function generateInPath(path) {
35
33
  (await packages.findPackagesInDirectory(path)).values()
36
34
  );
37
35
  } else {
36
+ // Direct IDL parsing: pass .idl files to the generator which uses
37
+ // rosidl_parser to parse them directly (no .msg/.srv/.action conversion).
38
38
  const idlPkgs = await packages.findPackagesInDirectory(path, useIDL);
39
- await fse.ensureDir(idlPath);
40
- const promises = [];
41
- idlPkgs.forEach((pkg) => {
42
- pkg.idls.forEach((idl) => {
43
- promises.push(idlConvertor(idl.pkgName, idl.filePath, idlPath));
44
- });
45
- });
46
- await Promise.all(promises);
47
- const pkgsFromIdl = await packages.findPackagesInDirectory(idlPath, false);
48
- pkgsInfo = Array.from(pkgsFromIdl.values());
39
+ pkgsInfo = Array.from(idlPkgs.values());
49
40
  }
50
41
 
51
42
  await Promise.all(
@@ -150,9 +150,7 @@ async function generateMsgForSrv(filePath, interfaceInfo, pkgMap) {
150
150
  const arr = data.split(/-{3,}/);
151
151
  if (arr.length == 2) {
152
152
  const packagePath = path.join(serviceMsgPath, interfaceInfo.pkgName);
153
- if (!fs.existsSync(packagePath)) {
154
- fs.mkdirSync(packagePath);
155
- }
153
+ fs.mkdirSync(packagePath, { recursive: true });
156
154
 
157
155
  await fsp.writeFile(path.join(packagePath, requestMsgName), arr[0]);
158
156
  await fsp.writeFile(path.join(packagePath, responseMsgName), arr[1]);
@@ -26,14 +26,14 @@ const StringRefStruct = StructType({
26
26
 
27
27
  function initString(str, own = false) {
28
28
  if (own) {
29
- if ((!str) instanceof Buffer) {
29
+ if (!(str instanceof Buffer)) {
30
30
  throw new TypeError(
31
31
  'Invalid argument: should provide a Node Buffer to bindingsStringInit()'
32
32
  );
33
33
  }
34
34
  rclnodejs.initString(str);
35
35
  } else {
36
- if ((!str) instanceof StringRefStruct) {
36
+ if (!(str instanceof StringRefStruct)) {
37
37
  throw new TypeError(
38
38
  'Invalid argument: should provide a type of StringRefStruct'
39
39
  );