rclnodejs 1.6.0 → 1.8.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/binding.gyp +2 -0
- package/index.js +152 -0
- package/lib/action/client.js +109 -10
- package/lib/action/deferred.js +8 -2
- package/lib/action/server.js +10 -1
- package/lib/action/uuid.js +4 -1
- package/lib/client.js +218 -4
- package/lib/clock.js +182 -1
- package/lib/clock_change.js +49 -0
- package/lib/clock_event.js +88 -0
- package/lib/context.js +12 -2
- package/lib/duration.js +37 -12
- package/lib/errors.js +621 -0
- package/lib/event_handler.js +21 -4
- package/lib/interface_loader.js +52 -12
- package/lib/lifecycle.js +8 -2
- package/lib/logging.js +90 -3
- package/lib/message_introspector.js +123 -0
- package/lib/message_serialization.js +10 -2
- package/lib/message_validation.js +512 -0
- package/lib/native_loader.js +9 -4
- package/lib/node.js +403 -50
- package/lib/node_options.js +40 -1
- package/lib/observable_subscription.js +105 -0
- package/lib/parameter.js +172 -35
- package/lib/parameter_client.js +506 -0
- package/lib/parameter_watcher.js +309 -0
- package/lib/publisher.js +56 -1
- package/lib/qos.js +79 -5
- package/lib/rate.js +6 -1
- package/lib/serialization.js +7 -2
- package/lib/subscription.js +8 -0
- package/lib/time.js +136 -21
- package/lib/time_source.js +13 -4
- package/lib/timer.js +42 -0
- package/lib/utils.js +27 -1
- package/lib/validator.js +74 -19
- package/package.json +4 -2
- package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
- package/rosidl_gen/message_translator.js +0 -61
- package/scripts/config.js +1 -0
- package/src/addon.cpp +2 -0
- package/src/clock_event.cpp +268 -0
- package/src/clock_event.hpp +62 -0
- package/src/macros.h +2 -4
- package/src/rcl_action_server_bindings.cpp +21 -3
- package/src/rcl_bindings.cpp +59 -0
- package/src/rcl_context_bindings.cpp +5 -0
- package/src/rcl_graph_bindings.cpp +73 -0
- package/src/rcl_logging_bindings.cpp +158 -0
- package/src/rcl_node_bindings.cpp +14 -2
- package/src/rcl_publisher_bindings.cpp +12 -0
- package/src/rcl_service_bindings.cpp +7 -6
- package/src/rcl_subscription_bindings.cpp +51 -14
- package/src/rcl_time_point_bindings.cpp +135 -0
- package/src/rcl_timer_bindings.cpp +140 -0
- package/src/rcl_utilities.cpp +103 -2
- package/src/rcl_utilities.h +7 -1
- package/types/action_client.d.ts +27 -2
- package/types/base.d.ts +6 -0
- package/types/client.d.ts +65 -1
- package/types/clock.d.ts +86 -0
- package/types/clock_change.d.ts +27 -0
- package/types/clock_event.d.ts +51 -0
- package/types/errors.d.ts +496 -0
- package/types/index.d.ts +10 -0
- package/types/logging.d.ts +32 -0
- package/types/message_introspector.d.ts +75 -0
- package/types/message_validation.d.ts +183 -0
- package/types/node.d.ts +107 -0
- package/types/node_options.d.ts +13 -0
- package/types/observable_subscription.d.ts +39 -0
- package/types/parameter_client.d.ts +252 -0
- package/types/parameter_watcher.d.ts +104 -0
- package/types/publisher.d.ts +28 -1
- package/types/qos.d.ts +18 -0
- package/types/subscription.d.ts +6 -0
- package/types/timer.d.ts +18 -0
- package/types/validator.d.ts +86 -0
package/lib/time.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
const rclnodejs = require('./native_loader.js');
|
|
18
18
|
const Duration = require('./duration.js');
|
|
19
19
|
const ClockType = require('./clock_type.js');
|
|
20
|
+
const { TypeValidationError, RangeValidationError } = require('./errors.js');
|
|
20
21
|
const S_TO_NS = 10n ** 9n;
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -36,29 +37,49 @@ class Time {
|
|
|
36
37
|
clockType = ClockType.SYSTEM_TIME
|
|
37
38
|
) {
|
|
38
39
|
if (typeof seconds !== 'bigint') {
|
|
39
|
-
throw new
|
|
40
|
+
throw new TypeValidationError('seconds', seconds, 'bigint', {
|
|
41
|
+
entityType: 'time',
|
|
42
|
+
});
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
if (typeof nanoseconds !== 'bigint') {
|
|
43
|
-
throw new
|
|
46
|
+
throw new TypeValidationError('nanoseconds', nanoseconds, 'bigint', {
|
|
47
|
+
entityType: 'time',
|
|
48
|
+
});
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
if (typeof clockType !== 'number') {
|
|
47
|
-
throw new
|
|
52
|
+
throw new TypeValidationError('clockType', clockType, 'number', {
|
|
53
|
+
entityType: 'time',
|
|
54
|
+
});
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
if (seconds < 0n) {
|
|
51
|
-
throw new
|
|
58
|
+
throw new RangeValidationError('seconds', seconds, '>= 0', {
|
|
59
|
+
entityType: 'time',
|
|
60
|
+
});
|
|
52
61
|
}
|
|
53
62
|
|
|
54
63
|
if (nanoseconds < 0n) {
|
|
55
|
-
throw new
|
|
64
|
+
throw new RangeValidationError('nanoseconds', nanoseconds, '>= 0', {
|
|
65
|
+
entityType: 'time',
|
|
66
|
+
});
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
const total = seconds * S_TO_NS + nanoseconds;
|
|
59
70
|
if (total >= 2n ** 63n) {
|
|
60
|
-
throw new
|
|
61
|
-
'
|
|
71
|
+
throw new RangeValidationError(
|
|
72
|
+
'total nanoseconds',
|
|
73
|
+
total,
|
|
74
|
+
'< 2^63 (max C time point)',
|
|
75
|
+
{
|
|
76
|
+
entityType: 'time',
|
|
77
|
+
details: {
|
|
78
|
+
seconds: seconds,
|
|
79
|
+
nanoseconds: nanoseconds,
|
|
80
|
+
total: total,
|
|
81
|
+
},
|
|
82
|
+
}
|
|
62
83
|
);
|
|
63
84
|
}
|
|
64
85
|
this._nanoseconds = total;
|
|
@@ -116,7 +137,9 @@ class Time {
|
|
|
116
137
|
this._clockType
|
|
117
138
|
);
|
|
118
139
|
}
|
|
119
|
-
throw new
|
|
140
|
+
throw new TypeValidationError('other', other, 'Duration', {
|
|
141
|
+
entityType: 'time',
|
|
142
|
+
});
|
|
120
143
|
}
|
|
121
144
|
|
|
122
145
|
/**
|
|
@@ -127,7 +150,18 @@ class Time {
|
|
|
127
150
|
sub(other) {
|
|
128
151
|
if (other instanceof Time) {
|
|
129
152
|
if (other._clockType !== this._clockType) {
|
|
130
|
-
throw new
|
|
153
|
+
throw new TypeValidationError(
|
|
154
|
+
'other',
|
|
155
|
+
other,
|
|
156
|
+
`Time with clock type ${this._clockType}`,
|
|
157
|
+
{
|
|
158
|
+
entityType: 'time',
|
|
159
|
+
details: {
|
|
160
|
+
expectedClockType: this._clockType,
|
|
161
|
+
providedClockType: other._clockType,
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
);
|
|
131
165
|
}
|
|
132
166
|
return new Duration(0n, this._nanoseconds - other._nanoseconds);
|
|
133
167
|
} else if (other instanceof Duration) {
|
|
@@ -137,7 +171,9 @@ class Time {
|
|
|
137
171
|
this._clockType
|
|
138
172
|
);
|
|
139
173
|
}
|
|
140
|
-
throw new
|
|
174
|
+
throw new TypeValidationError('other', other, 'Time or Duration', {
|
|
175
|
+
entityType: 'time',
|
|
176
|
+
});
|
|
141
177
|
}
|
|
142
178
|
|
|
143
179
|
/**
|
|
@@ -148,11 +184,24 @@ class Time {
|
|
|
148
184
|
eq(other) {
|
|
149
185
|
if (other instanceof Time) {
|
|
150
186
|
if (other._clockType !== this._clockType) {
|
|
151
|
-
throw new
|
|
187
|
+
throw new TypeValidationError(
|
|
188
|
+
'other',
|
|
189
|
+
other,
|
|
190
|
+
`Time with clock type ${this._clockType}`,
|
|
191
|
+
{
|
|
192
|
+
entityType: 'time',
|
|
193
|
+
details: {
|
|
194
|
+
expectedClockType: this._clockType,
|
|
195
|
+
providedClockType: other._clockType,
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
);
|
|
152
199
|
}
|
|
153
200
|
return this._nanoseconds === other.nanoseconds;
|
|
154
201
|
}
|
|
155
|
-
throw new
|
|
202
|
+
throw new TypeValidationError('other', other, 'Time', {
|
|
203
|
+
entityType: 'time',
|
|
204
|
+
});
|
|
156
205
|
}
|
|
157
206
|
|
|
158
207
|
/**
|
|
@@ -163,10 +212,24 @@ class Time {
|
|
|
163
212
|
ne(other) {
|
|
164
213
|
if (other instanceof Time) {
|
|
165
214
|
if (other._clockType !== this._clockType) {
|
|
166
|
-
throw new
|
|
215
|
+
throw new TypeValidationError(
|
|
216
|
+
'other',
|
|
217
|
+
other,
|
|
218
|
+
`Time with clock type ${this._clockType}`,
|
|
219
|
+
{
|
|
220
|
+
entityType: 'time',
|
|
221
|
+
details: {
|
|
222
|
+
expectedClockType: this._clockType,
|
|
223
|
+
providedClockType: other._clockType,
|
|
224
|
+
},
|
|
225
|
+
}
|
|
226
|
+
);
|
|
167
227
|
}
|
|
168
228
|
return this._nanoseconds !== other.nanoseconds;
|
|
169
229
|
}
|
|
230
|
+
throw new TypeValidationError('other', other, 'Time', {
|
|
231
|
+
entityType: 'time',
|
|
232
|
+
});
|
|
170
233
|
}
|
|
171
234
|
|
|
172
235
|
/**
|
|
@@ -177,11 +240,24 @@ class Time {
|
|
|
177
240
|
lt(other) {
|
|
178
241
|
if (other instanceof Time) {
|
|
179
242
|
if (other._clockType !== this._clockType) {
|
|
180
|
-
throw new
|
|
243
|
+
throw new TypeValidationError(
|
|
244
|
+
'other',
|
|
245
|
+
other,
|
|
246
|
+
`Time with clock type ${this._clockType}`,
|
|
247
|
+
{
|
|
248
|
+
entityType: 'time',
|
|
249
|
+
details: {
|
|
250
|
+
expectedClockType: this._clockType,
|
|
251
|
+
providedClockType: other._clockType,
|
|
252
|
+
},
|
|
253
|
+
}
|
|
254
|
+
);
|
|
181
255
|
}
|
|
182
256
|
return this._nanoseconds < other.nanoseconds;
|
|
183
257
|
}
|
|
184
|
-
throw new
|
|
258
|
+
throw new TypeValidationError('other', other, 'Time', {
|
|
259
|
+
entityType: 'time',
|
|
260
|
+
});
|
|
185
261
|
}
|
|
186
262
|
|
|
187
263
|
/**
|
|
@@ -192,11 +268,24 @@ class Time {
|
|
|
192
268
|
lte(other) {
|
|
193
269
|
if (other instanceof Time) {
|
|
194
270
|
if (other._clockType !== this._clockType) {
|
|
195
|
-
throw new
|
|
271
|
+
throw new TypeValidationError(
|
|
272
|
+
'other',
|
|
273
|
+
other,
|
|
274
|
+
`Time with clock type ${this._clockType}`,
|
|
275
|
+
{
|
|
276
|
+
entityType: 'time',
|
|
277
|
+
details: {
|
|
278
|
+
expectedClockType: this._clockType,
|
|
279
|
+
providedClockType: other._clockType,
|
|
280
|
+
},
|
|
281
|
+
}
|
|
282
|
+
);
|
|
196
283
|
}
|
|
197
284
|
return this._nanoseconds <= other.nanoseconds;
|
|
198
285
|
}
|
|
199
|
-
throw new
|
|
286
|
+
throw new TypeValidationError('other', other, 'Time', {
|
|
287
|
+
entityType: 'time',
|
|
288
|
+
});
|
|
200
289
|
}
|
|
201
290
|
|
|
202
291
|
/**
|
|
@@ -207,11 +296,24 @@ class Time {
|
|
|
207
296
|
gt(other) {
|
|
208
297
|
if (other instanceof Time) {
|
|
209
298
|
if (other._clockType !== this._clockType) {
|
|
210
|
-
throw new
|
|
299
|
+
throw new TypeValidationError(
|
|
300
|
+
'other',
|
|
301
|
+
other,
|
|
302
|
+
`Time with clock type ${this._clockType}`,
|
|
303
|
+
{
|
|
304
|
+
entityType: 'time',
|
|
305
|
+
details: {
|
|
306
|
+
expectedClockType: this._clockType,
|
|
307
|
+
providedClockType: other._clockType,
|
|
308
|
+
},
|
|
309
|
+
}
|
|
310
|
+
);
|
|
211
311
|
}
|
|
212
312
|
return this._nanoseconds > other.nanoseconds;
|
|
213
313
|
}
|
|
214
|
-
throw new
|
|
314
|
+
throw new TypeValidationError('other', other, 'Time', {
|
|
315
|
+
entityType: 'time',
|
|
316
|
+
});
|
|
215
317
|
}
|
|
216
318
|
|
|
217
319
|
/**
|
|
@@ -222,11 +324,24 @@ class Time {
|
|
|
222
324
|
gte(other) {
|
|
223
325
|
if (other instanceof Time) {
|
|
224
326
|
if (other._clockType !== this._clockType) {
|
|
225
|
-
throw new
|
|
327
|
+
throw new TypeValidationError(
|
|
328
|
+
'other',
|
|
329
|
+
other,
|
|
330
|
+
`Time with clock type ${this._clockType}`,
|
|
331
|
+
{
|
|
332
|
+
entityType: 'time',
|
|
333
|
+
details: {
|
|
334
|
+
expectedClockType: this._clockType,
|
|
335
|
+
providedClockType: other._clockType,
|
|
336
|
+
},
|
|
337
|
+
}
|
|
338
|
+
);
|
|
226
339
|
}
|
|
227
340
|
return this._nanoseconds >= other.nanoseconds;
|
|
228
341
|
}
|
|
229
|
-
throw new
|
|
342
|
+
throw new TypeValidationError('other', other, 'Time', {
|
|
343
|
+
entityType: 'time',
|
|
344
|
+
});
|
|
230
345
|
}
|
|
231
346
|
|
|
232
347
|
/**
|
package/lib/time_source.js
CHANGED
|
@@ -19,6 +19,7 @@ const { Clock, ROSClock } = require('./clock.js');
|
|
|
19
19
|
const { ClockType } = Clock;
|
|
20
20
|
const { Parameter, ParameterType } = require('./parameter.js');
|
|
21
21
|
const Time = require('./time.js');
|
|
22
|
+
const { TypeValidationError, OperationError } = require('./errors.js');
|
|
22
23
|
|
|
23
24
|
const USE_SIM_TIME_PARAM = 'use_sim_time';
|
|
24
25
|
const CLOCK_TOPIC = '/clock';
|
|
@@ -102,7 +103,9 @@ class TimeSource {
|
|
|
102
103
|
*/
|
|
103
104
|
attachNode(node) {
|
|
104
105
|
if ((!node) instanceof rclnodejs.ShadowNode) {
|
|
105
|
-
throw new
|
|
106
|
+
throw new TypeValidationError('node', node, 'Node', {
|
|
107
|
+
entityType: 'time source',
|
|
108
|
+
});
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
if (this._node) {
|
|
@@ -150,8 +153,12 @@ class TimeSource {
|
|
|
150
153
|
detachNode() {
|
|
151
154
|
if (this._clockSubscription) {
|
|
152
155
|
if (!this._node) {
|
|
153
|
-
throw new
|
|
154
|
-
'Unable to destroy previously created clock subscription'
|
|
156
|
+
throw new OperationError(
|
|
157
|
+
'Unable to destroy previously created clock subscription',
|
|
158
|
+
{
|
|
159
|
+
code: 'NO_NODE_ATTACHED',
|
|
160
|
+
entityType: 'time source',
|
|
161
|
+
}
|
|
155
162
|
);
|
|
156
163
|
}
|
|
157
164
|
this._node.destroySubscription(this._clockSubscription);
|
|
@@ -167,7 +174,9 @@ class TimeSource {
|
|
|
167
174
|
*/
|
|
168
175
|
attachClock(clock) {
|
|
169
176
|
if (!(clock instanceof ROSClock)) {
|
|
170
|
-
throw new
|
|
177
|
+
throw new TypeValidationError('clock', clock, 'ROSClock', {
|
|
178
|
+
entityType: 'time source',
|
|
179
|
+
});
|
|
171
180
|
}
|
|
172
181
|
clock.rosTimeOverride = this._lastTimeSet;
|
|
173
182
|
clock.isRosTimeActive = this._isRosTimeActive;
|
package/lib/timer.js
CHANGED
|
@@ -88,6 +88,19 @@ class Timer {
|
|
|
88
88
|
return rclnodejs.timerGetTimeUntilNextCall(this._handle);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Get the absolute time in nanoseconds when the next callback is due.
|
|
93
|
+
* Note: Only available on ROS2 distributions after Humble.
|
|
94
|
+
* @return {bigint | null} - The next call time in nanoseconds, or null if the timer is canceled.
|
|
95
|
+
* Returns undefined if not supported on current ROS2 distribution.
|
|
96
|
+
*/
|
|
97
|
+
getNextCallTime() {
|
|
98
|
+
if (typeof rclnodejs.getTimerNextCallTime !== 'function') {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
return rclnodejs.getTimerNextCallTime(this._handle);
|
|
102
|
+
}
|
|
103
|
+
|
|
91
104
|
/**
|
|
92
105
|
* Change the timer period.
|
|
93
106
|
* @param {bigint} period - The new period in nanoseconds.
|
|
@@ -105,6 +118,35 @@ class Timer {
|
|
|
105
118
|
return rclnodejs.getTimerPeriod(this._handle);
|
|
106
119
|
}
|
|
107
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Set the on reset callback.
|
|
123
|
+
* @param {function} callback - The callback to be called when the timer is reset.
|
|
124
|
+
* @return {undefined}
|
|
125
|
+
*/
|
|
126
|
+
setOnResetCallback(callback) {
|
|
127
|
+
if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')) {
|
|
128
|
+
console.warn(
|
|
129
|
+
'setOnResetCallback is not supported by this version of ROS 2'
|
|
130
|
+
);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
rclnodejs.setTimerOnResetCallback(this._handle, callback);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Clear the on reset callback.
|
|
138
|
+
* @return {undefined}
|
|
139
|
+
*/
|
|
140
|
+
clearOnResetCallback() {
|
|
141
|
+
if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')) {
|
|
142
|
+
console.warn(
|
|
143
|
+
'clearOnResetCallback is not supported by this version of ROS 2'
|
|
144
|
+
);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
rclnodejs.clearTimerOnResetCallback(this._handle);
|
|
148
|
+
}
|
|
149
|
+
|
|
108
150
|
/**
|
|
109
151
|
* Call a timer and starts counting again, retrieves actual and expected call time.
|
|
110
152
|
* @return {object} - The timer information.
|
package/lib/utils.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
const fs = require('fs');
|
|
16
16
|
const fsPromises = require('fs/promises');
|
|
17
17
|
const path = require('path');
|
|
18
|
+
const { ValidationError } = require('./errors.js');
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Ensure directory exists, create recursively if needed (async)
|
|
@@ -182,6 +183,25 @@ function detectUbuntuCodename() {
|
|
|
182
183
|
}
|
|
183
184
|
}
|
|
184
185
|
|
|
186
|
+
/**
|
|
187
|
+
* Normalize a ROS 2 node name by removing the leading slash if present.
|
|
188
|
+
*
|
|
189
|
+
* ROS 2 node names may be specified with or without a leading slash depending
|
|
190
|
+
* on the context. This utility ensures consistent representation without the
|
|
191
|
+
* leading slash, which is the standard format for most ROS 2 APIs.
|
|
192
|
+
*
|
|
193
|
+
* @param {string} nodeName - The node name to normalize
|
|
194
|
+
* @returns {string} The normalized node name without leading slash
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* normalizeNodeName('my_node') // 'my_node'
|
|
198
|
+
* normalizeNodeName('/my_node') // 'my_node'
|
|
199
|
+
* normalizeNodeName('/ns/my_node') // 'ns/my_node'
|
|
200
|
+
*/
|
|
201
|
+
function normalizeNodeName(nodeName) {
|
|
202
|
+
return nodeName.startsWith('/') ? nodeName.substring(1) : nodeName;
|
|
203
|
+
}
|
|
204
|
+
|
|
185
205
|
/**
|
|
186
206
|
* Check if two numbers are equal within a given tolerance.
|
|
187
207
|
*
|
|
@@ -294,7 +314,12 @@ function compareVersions(version1, version2, operator) {
|
|
|
294
314
|
case '!==':
|
|
295
315
|
return cmp !== 0;
|
|
296
316
|
default:
|
|
297
|
-
throw new
|
|
317
|
+
throw new ValidationError(`Invalid operator: ${operator}`, {
|
|
318
|
+
code: 'INVALID_OPERATOR',
|
|
319
|
+
argumentName: 'operator',
|
|
320
|
+
providedValue: operator,
|
|
321
|
+
expectedType: "'eq' | 'ne' | 'lt' | 'lte' | 'gt' | 'gte'",
|
|
322
|
+
});
|
|
298
323
|
}
|
|
299
324
|
}
|
|
300
325
|
|
|
@@ -302,6 +327,7 @@ module.exports = {
|
|
|
302
327
|
// General utilities
|
|
303
328
|
detectUbuntuCodename,
|
|
304
329
|
isClose,
|
|
330
|
+
normalizeNodeName,
|
|
305
331
|
|
|
306
332
|
// File system utilities (async)
|
|
307
333
|
ensureDir,
|
package/lib/validator.js
CHANGED
|
@@ -15,84 +15,139 @@
|
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
17
|
const rclnodejs = require('./native_loader.js');
|
|
18
|
+
const { TypeValidationError, NameValidationError } = require('./errors.js');
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* An object - Representing a validator in ROS.
|
|
21
22
|
* @exports validator
|
|
22
23
|
*/
|
|
23
24
|
let validator = {
|
|
24
|
-
_createErrorFromValidation: function (result) {
|
|
25
|
-
|
|
26
|
-
err.invalidIndex = result[1];
|
|
27
|
-
return err;
|
|
25
|
+
_createErrorFromValidation: function (result, nameValue, nameType) {
|
|
26
|
+
return new NameValidationError(nameValue, nameType, result[0], result[1]);
|
|
28
27
|
},
|
|
29
28
|
|
|
30
29
|
/**
|
|
31
30
|
* Validate a given topic or service name, and throw an error if invalid.
|
|
32
|
-
* @param {string} topic - The name of topic/service.
|
|
33
|
-
* @
|
|
31
|
+
* @param {string} topic - The name of topic/service. Must be fully-qualified and already expanded.
|
|
32
|
+
* @returns {true} Always returns true if valid.
|
|
33
|
+
* @throws {TypeValidationError} If topic is not a string.
|
|
34
|
+
* @throws {NameValidationError} If the topic name is invalid.
|
|
34
35
|
*/
|
|
35
36
|
validateFullTopicName(topic) {
|
|
36
37
|
if (typeof topic !== 'string') {
|
|
37
|
-
throw new
|
|
38
|
+
throw new TypeValidationError('topic', topic, 'string');
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
let result = rclnodejs.validateFullTopicName(topic);
|
|
41
42
|
if (result === null) {
|
|
42
43
|
return true;
|
|
43
44
|
}
|
|
44
|
-
throw this._createErrorFromValidation(result);
|
|
45
|
+
throw this._createErrorFromValidation(result, topic, 'topic');
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check if a fully-qualified topic name is valid without throwing.
|
|
50
|
+
* @param {string} topic - The name of topic/service. Must be fully-qualified and already expanded.
|
|
51
|
+
* @returns {boolean} True if valid, false otherwise.
|
|
52
|
+
*/
|
|
53
|
+
isValidFullTopicName(topic) {
|
|
54
|
+
if (typeof topic !== 'string') {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return rclnodejs.validateFullTopicName(topic) === null;
|
|
45
58
|
},
|
|
46
59
|
|
|
47
60
|
/**
|
|
48
61
|
* Validate a given node name, and throw an error if invalid.
|
|
49
62
|
* @param {string} name - The name of node.
|
|
50
|
-
* @
|
|
63
|
+
* @returns {true} Always returns true if valid.
|
|
64
|
+
* @throws {TypeValidationError} If name is not a string.
|
|
65
|
+
* @throws {NameValidationError} If the node name is invalid.
|
|
51
66
|
*/
|
|
52
67
|
validateNodeName(name) {
|
|
53
68
|
if (typeof name !== 'string') {
|
|
54
|
-
throw new
|
|
69
|
+
throw new TypeValidationError('name', name, 'string');
|
|
55
70
|
}
|
|
56
71
|
|
|
57
72
|
let result = rclnodejs.validateNodeName(name);
|
|
58
73
|
if (result === null) {
|
|
59
74
|
return true;
|
|
60
75
|
}
|
|
61
|
-
throw this._createErrorFromValidation(result);
|
|
76
|
+
throw this._createErrorFromValidation(result, name, 'node');
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Check if a node name is valid without throwing.
|
|
81
|
+
* @param {string} name - The name of node.
|
|
82
|
+
* @returns {boolean} True if valid, false otherwise.
|
|
83
|
+
*/
|
|
84
|
+
isValidNodeName(name) {
|
|
85
|
+
if (typeof name !== 'string') {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
return rclnodejs.validateNodeName(name) === null;
|
|
62
89
|
},
|
|
63
90
|
|
|
64
91
|
/**
|
|
65
92
|
* Validate a given topic or service name, and throw an error if invalid.
|
|
66
|
-
* @param {string} topic - The name of topic/service
|
|
67
|
-
* @
|
|
93
|
+
* @param {string} topic - The name of topic/service. Does not have to be fully-qualified.
|
|
94
|
+
* @returns {true} Always returns true if valid.
|
|
95
|
+
* @throws {TypeValidationError} If topic is not a string.
|
|
96
|
+
* @throws {NameValidationError} If the topic name is invalid.
|
|
68
97
|
*/
|
|
69
98
|
validateTopicName(topic) {
|
|
70
99
|
if (typeof topic !== 'string') {
|
|
71
|
-
throw new
|
|
100
|
+
throw new TypeValidationError('topic', topic, 'string');
|
|
72
101
|
}
|
|
73
102
|
|
|
74
103
|
let result = rclnodejs.validateTopicName(topic);
|
|
75
104
|
if (result === null) {
|
|
76
105
|
return true;
|
|
77
106
|
}
|
|
78
|
-
throw this._createErrorFromValidation(result);
|
|
107
|
+
throw this._createErrorFromValidation(result, topic, 'topic');
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Check if a topic name is valid without throwing.
|
|
112
|
+
* @param {string} topic - The name of topic/service. Does not have to be fully-qualified.
|
|
113
|
+
* @returns {boolean} True if valid, false otherwise.
|
|
114
|
+
*/
|
|
115
|
+
isValidTopicName(topic) {
|
|
116
|
+
if (typeof topic !== 'string') {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
return rclnodejs.validateTopicName(topic) === null;
|
|
79
120
|
},
|
|
80
121
|
|
|
81
122
|
/**
|
|
82
123
|
* Validate a given namespace, and throw an error if invalid.
|
|
83
|
-
* @param {string} namespace - The namespace to be validated
|
|
84
|
-
* @
|
|
124
|
+
* @param {string} namespace - The namespace to be validated.
|
|
125
|
+
* @returns {true} Always returns true if valid.
|
|
126
|
+
* @throws {TypeValidationError} If namespace is not a string.
|
|
127
|
+
* @throws {NameValidationError} If the namespace is invalid.
|
|
85
128
|
*/
|
|
86
129
|
validateNamespace(namespace) {
|
|
87
130
|
if (typeof namespace !== 'string') {
|
|
88
|
-
throw new
|
|
131
|
+
throw new TypeValidationError('namespace', namespace, 'string');
|
|
89
132
|
}
|
|
90
133
|
|
|
91
134
|
let result = rclnodejs.validateNamespace(namespace);
|
|
92
135
|
if (result === null) {
|
|
93
136
|
return true;
|
|
94
137
|
}
|
|
95
|
-
throw this._createErrorFromValidation(result);
|
|
138
|
+
throw this._createErrorFromValidation(result, namespace, 'namespace');
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Check if a namespace is valid without throwing.
|
|
143
|
+
* @param {string} namespace - The namespace to be validated.
|
|
144
|
+
* @returns {boolean} True if valid, false otherwise.
|
|
145
|
+
*/
|
|
146
|
+
isValidNamespace(namespace) {
|
|
147
|
+
if (typeof namespace !== 'string') {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
return rclnodejs.validateNamespace(namespace) === null;
|
|
96
151
|
},
|
|
97
152
|
};
|
|
98
153
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rclnodejs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "ROS2.0 JavaScript client with Node.js",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@eslint/js": "^9.36.0",
|
|
52
|
-
"@types/node": "^
|
|
52
|
+
"@types/node": "^25.0.2",
|
|
53
53
|
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
54
54
|
"@typescript-eslint/parser": "^8.18.0",
|
|
55
55
|
"clang-format": "^1.8.0",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"jsdoc": "^4.0.4",
|
|
65
65
|
"lint-staged": "^16.2.0",
|
|
66
66
|
"mocha": "^11.0.2",
|
|
67
|
+
"node-gyp": "^12.1.0",
|
|
67
68
|
"nyc": "^17.1.0",
|
|
68
69
|
"prebuildify": "^6.0.1",
|
|
69
70
|
"rimraf": "^6.0.1",
|
|
@@ -79,6 +80,7 @@
|
|
|
79
80
|
"debug": "^4.4.0",
|
|
80
81
|
"json-bigint": "^1.0.0",
|
|
81
82
|
"node-addon-api": "^8.3.1",
|
|
83
|
+
"rxjs": "^7.8.1",
|
|
82
84
|
"walk": "^2.3.15"
|
|
83
85
|
},
|
|
84
86
|
"husky": {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|