@@ -31,6 +31,8 @@ const fs = require('fs');
31
31
const loader = require ( '../lib/interface_loader.js' ) ;
32
32
const pkgFilters = require ( '../rosidl_gen/filter.js' ) ;
33
33
34
+ const descriptorInterfaceNamespace = 'descriptor' ;
35
+
34
36
async function generateAll ( ) {
35
37
// load pkg and interface info (msgs and srvs)
36
38
const generatedPath = path . join ( __dirname , '../generated/' ) ;
@@ -119,47 +121,30 @@ function savePkgInfoAsTSD(pkgInfos, fd) {
119
121
for ( const subfolder of pkgInfo . subfolders . keys ( ) ) {
120
122
fs . writeSync ( fd , ` namespace ${ subfolder } {\n` ) ;
121
123
122
- for ( const rosInterface of pkgInfo . subfolders . get ( subfolder ) ) {
123
- const type = rosInterface . type ( ) ;
124
- const fullInterfaceName = `${ type . pkgName } /${ type . subFolder } /${ type . interfaceName } ` ;
125
- const fullInterfacePath = `${ type . pkgName } .${ type . subFolder } .${ type . interfaceName } ` ;
126
- const fullInterfaceConstructor = fullInterfacePath + 'Constructor' ;
127
-
128
- if ( isMsgInterface ( rosInterface ) ) {
129
- // create message interface
130
- saveMsgAsTSD ( rosInterface , fd ) ;
131
- saveMsgConstructorAsTSD ( rosInterface , fd ) ;
132
- messagesMap [ fullInterfaceName ] = fullInterfacePath ;
133
- } else if ( isSrvInterface ( rosInterface ) ) {
134
- if (
135
- ! isValidService ( rosInterface , pkgInfo . subfolders . get ( subfolder ) )
136
- ) {
137
- let type = rosInterface . type ( ) ;
138
- console . log (
139
- `Incomplete service: ${ type . pkgName } .${ type . subFolder } .${ type . interfaceName } .`
140
- ) ;
141
- continue ;
142
- }
143
-
144
- // create service interface
145
- saveSrvAsTSD ( rosInterface , fd ) ;
146
- if ( ! isInternalActionSrvInterface ( rosInterface ) ) {
147
- servicesMap [ fullInterfaceName ] = fullInterfaceConstructor ;
148
- }
149
- } else if ( isActionInterface ( rosInterface ) ) {
150
- if ( ! isValidAction ( rosInterface , pkgInfo . subfolders . get ( subfolder ) ) ) {
151
- let type = rosInterface . type ( ) ;
152
- console . log (
153
- `Incomplete action: ${ type . pkgName } .${ type . subFolder } .${ type . interfaceName } .`
154
- ) ;
155
- continue ;
156
- }
157
-
158
- // create action interface
159
- saveActionAsTSD ( rosInterface , fd ) ;
160
- actionsMap [ fullInterfaceName ] = fullInterfaceConstructor ;
161
- }
162
- }
124
+ // generate real msg/srv/action interfaces
125
+ generateRosMsgInterfaces (
126
+ pkgInfo ,
127
+ subfolder ,
128
+ messagesMap ,
129
+ servicesMap ,
130
+ actionsMap ,
131
+ fd
132
+ ) ;
133
+
134
+ // generate descriptor msg/srv/action interfaces
135
+ fs . writeSync ( fd , ` namespace ${ descriptorInterfaceNamespace } {\n` ) ;
136
+ const willGenerateDescriptorInterface = true ;
137
+ generateRosMsgInterfaces (
138
+ pkgInfo ,
139
+ subfolder ,
140
+ messagesMap ,
141
+ servicesMap ,
142
+ actionsMap ,
143
+ fd ,
144
+ willGenerateDescriptorInterface
145
+ ) ;
146
+ // close namespace descriptor declare
147
+ fs . writeSync ( fd , ' }\n' ) ;
163
148
164
149
// close namespace declare
165
150
fs . writeSync ( fd , ' }\n' ) ;
@@ -238,16 +223,96 @@ function savePkgInfoAsTSD(pkgInfos, fd) {
238
223
fs . writeSync ( fd , '}\n' ) ;
239
224
}
240
225
241
- function saveMsgAsTSD ( rosMsgInterface , fd ) {
242
- fs . writeSync (
243
- fd ,
244
- ` export interface ${ rosMsgInterface . type ( ) . interfaceName } {\n`
226
+ function generateRosMsgInterfaces (
227
+ pkgInfo ,
228
+ subfolder ,
229
+ messagesMap ,
230
+ servicesMap ,
231
+ actionsMap ,
232
+ fd ,
233
+ willGenerateDescriptorInterface = false
234
+ ) {
235
+ const descriptorNamespaceName = willGenerateDescriptorInterface
236
+ ? `${ descriptorInterfaceNamespace } /`
237
+ : '' ;
238
+ const descriptorNamespacePath = willGenerateDescriptorInterface
239
+ ? `${ descriptorInterfaceNamespace } .`
240
+ : '' ;
241
+ for ( const rosInterface of pkgInfo . subfolders . get ( subfolder ) ) {
242
+ const type = rosInterface . type ( ) ;
243
+ const fullInterfaceName = `${ type . pkgName } /${ type . subFolder } /${ descriptorNamespaceName } ${ type . interfaceName } ` ;
244
+ const fullInterfacePath = `${ type . pkgName } .${ type . subFolder } .${ descriptorNamespacePath } ${ type . interfaceName } ` ;
245
+ const fullInterfaceConstructor = fullInterfacePath + 'Constructor' ;
246
+
247
+ const indentStartLevel = willGenerateDescriptorInterface ? 4 : 3 ;
248
+ if ( isMsgInterface ( rosInterface ) ) {
249
+ // create message interface
250
+ saveMsgAsTSD (
251
+ rosInterface ,
252
+ fd ,
253
+ indentStartLevel ,
254
+ willGenerateDescriptorInterface
255
+ ) ;
256
+ saveMsgConstructorAsTSD ( rosInterface , fd , indentStartLevel ) ;
257
+ messagesMap [ fullInterfaceName ] = fullInterfacePath ;
258
+ } else if ( isSrvInterface ( rosInterface ) ) {
259
+ if ( ! isValidService ( rosInterface , pkgInfo . subfolders . get ( subfolder ) ) ) {
260
+ let type = rosInterface . type ( ) ;
261
+ console . log (
262
+ `Incomplete service: ${ type . pkgName } .${ type . subFolder } .${ type . interfaceName } .`
263
+ ) ;
264
+ continue ;
265
+ }
266
+
267
+ // create service interface
268
+ saveSrvAsTSD ( rosInterface , fd , indentStartLevel ) ;
269
+ if ( ! isInternalActionSrvInterface ( rosInterface ) ) {
270
+ servicesMap [ fullInterfaceName ] = fullInterfaceConstructor ;
271
+ }
272
+ } else if ( isActionInterface ( rosInterface ) ) {
273
+ if ( ! isValidAction ( rosInterface , pkgInfo . subfolders . get ( subfolder ) ) ) {
274
+ let type = rosInterface . type ( ) ;
275
+ console . log (
276
+ `Incomplete action: ${ type . pkgName } .${ type . subFolder } .${ type . interfaceName } .`
277
+ ) ;
278
+ continue ;
279
+ }
280
+
281
+ // create action interface
282
+ saveActionAsTSD ( rosInterface , fd , indentStartLevel ) ;
283
+ actionsMap [ fullInterfaceName ] = fullInterfaceConstructor ;
284
+ }
285
+ }
286
+ }
287
+
288
+ function saveMsgAsTSD (
289
+ rosMsgInterface ,
290
+ fd ,
291
+ indentLevel = 3 ,
292
+ willGenerateDescriptorInterface = false
293
+ ) {
294
+ const outerIndentSpacing = getIndentSpacing ( indentLevel ) ;
295
+ const tmpl = indentString (
296
+ `export interface ${ rosMsgInterface . type ( ) . interfaceName } {\n` ,
297
+ outerIndentSpacing
245
298
) ;
299
+ fs . writeSync ( fd , tmpl ) ;
246
300
const useSamePkg =
247
301
isInternalActionMsgInterface ( rosMsgInterface ) ||
248
302
isInternalServiceEventMsgInterface ( rosMsgInterface ) ;
249
- saveMsgFieldsAsTSD ( rosMsgInterface , fd , 8 , ';' , '' , useSamePkg ) ;
250
- fs . writeSync ( fd , ' }\n' ) ;
303
+ const innerIndentLevel = indentLevel + 1 ;
304
+ const innerIndentSpacing = getIndentSpacing ( innerIndentLevel ) ;
305
+ saveMsgFieldsAsTSD (
306
+ rosMsgInterface ,
307
+ fd ,
308
+ innerIndentSpacing ,
309
+ ';' ,
310
+ '' ,
311
+ useSamePkg ,
312
+ willGenerateDescriptorInterface
313
+ ) ;
314
+ const tmplEnd = indentString ( '}\n' , outerIndentSpacing ) ;
315
+ fs . writeSync ( fd , tmplEnd ) ;
251
316
}
252
317
253
318
/**
@@ -261,6 +326,7 @@ function saveMsgAsTSD(rosMsgInterface, fd) {
261
326
* @param {string } typePrefix The prefix to put before the type name for
262
327
* non-primitive types
263
328
* @param {boolean } useSamePackageSubFolder Indicates if the sub folder name should be taken from the message
329
+ * @param {boolean } willGenerateDescriptorInterface Indicates if descriptor interface is being generated
264
330
* when the field type comes from the same package. This is needed for action interfaces. Defaults to false.
265
331
* @returns {undefined }
266
332
*/
@@ -270,7 +336,8 @@ function saveMsgFieldsAsTSD(
270
336
indent = 0 ,
271
337
lineEnd = ',' ,
272
338
typePrefix = '' ,
273
- useSamePackageSubFolder = false
339
+ useSamePackageSubFolder = false ,
340
+ willGenerateDescriptorInterface = false
274
341
) {
275
342
let type = rosMsgInterface . type ( ) ;
276
343
let fields = rosMsgInterface . ROSMessageDef . fields ;
@@ -280,49 +347,62 @@ function saveMsgFieldsAsTSD(
280
347
useSamePackageSubFolder && field . type . pkgName === type . pkgName
281
348
? type . subFolder
282
349
: 'msg' ;
283
- let fieldType = fieldType2JSName ( field , subFolder ) ;
350
+ let fieldType = fieldType2JSName (
351
+ field ,
352
+ subFolder ,
353
+ willGenerateDescriptorInterface
354
+ ) ;
284
355
let tp = field . type . isPrimitiveType ? '' : typePrefix ;
285
356
if ( typePrefix === 'rclnodejs.' ) {
286
357
fieldType = 'any' ;
287
358
tp = '' ;
288
359
}
289
360
290
- const tmpl = indentString ( `${ field . name } : ${ tp } ${ fieldType } ` , indent ) ;
291
- fs . writeSync ( fd , tmpl ) ;
361
+ let arrayString = '' ;
292
362
if ( field . type . isArray ) {
293
- fs . writeSync ( fd , '[]' ) ;
363
+ arrayString = '[]' ;
364
+
365
+ if ( field . type . isFixedSizeArray && willGenerateDescriptorInterface ) {
366
+ arrayString = `[${ field . type . arraySize } ]` ;
367
+ }
294
368
295
- if ( fieldType === 'number' ) {
369
+ if ( fieldType === 'number' && ! willGenerateDescriptorInterface ) {
296
370
// for number[] include alternate typed-array types, e.g., number[] | uint8[]
297
371
let jsTypedArrayName = fieldTypeArray2JSTypedArrayName ( field . type . type ) ;
298
372
299
373
if ( jsTypedArrayName ) {
300
- fs . writeSync ( fd , ` | ${ jsTypedArrayName } ` ) ;
374
+ arrayString += ` | ${ jsTypedArrayName } ` ;
301
375
}
302
376
}
303
377
}
378
+ const fieldString = willGenerateDescriptorInterface
379
+ ? `${ field . name } : '${ tp } ${ fieldType } ${ arrayString } '`
380
+ : `${ field . name } : ${ tp } ${ fieldType } ${ arrayString } ` ;
381
+ const tmpl = indentString ( fieldString , indent ) ;
382
+ fs . writeSync ( fd , tmpl ) ;
304
383
305
384
fs . writeSync ( fd , lineEnd ) ;
306
385
fs . writeSync ( fd , '\n' ) ;
307
386
}
308
387
}
309
388
310
- function saveMsgConstructorAsTSD ( rosMsgInterface , fd ) {
389
+ function saveMsgConstructorAsTSD ( rosMsgInterface , fd , indentLevel = 3 ) {
311
390
const type = rosMsgInterface . type ( ) ;
312
391
const msgName = type . interfaceName ;
313
-
314
- fs . writeSync ( fd , ` export interface ${ msgName } Constructor {\n` ) ;
392
+ let interfaceTmpl = [ `export interface ${ msgName } Constructor {` ] ;
315
393
316
394
for ( const constant of rosMsgInterface . ROSMessageDef . constants ) {
317
395
const constantType = primitiveType2JSName ( constant . type ) ;
318
- fs . writeSync ( fd , ` readonly ${ constant . name } : ${ constantType } ;\n ` ) ;
396
+ interfaceTmpl . push ( ` readonly ${ constant . name } : ${ constantType } ;` ) ;
319
397
}
320
-
321
- fs . writeSync ( fd , ` new(other?: ${ msgName } ): ${ msgName } ;\n` ) ;
322
- fs . writeSync ( fd , ' }\n' ) ;
398
+ interfaceTmpl . push ( ` new(other?: ${ msgName } ): ${ msgName } ;` ) ;
399
+ interfaceTmpl . push ( '}' ) ;
400
+ interfaceTmpl . push ( '' ) ;
401
+ const indentSpacing = getIndentSpacing ( indentLevel ) ;
402
+ fs . writeSync ( fd , indentLines ( interfaceTmpl , indentSpacing ) . join ( '\n' ) ) ;
323
403
}
324
404
325
- function saveSrvAsTSD ( rosSrvInterface , fd ) {
405
+ function saveSrvAsTSD ( rosSrvInterface , fd , indentLevel = 3 ) {
326
406
const serviceName = rosSrvInterface . type ( ) . interfaceName ;
327
407
328
408
const interfaceTemplate = [
@@ -332,11 +412,11 @@ function saveSrvAsTSD(rosSrvInterface, fd) {
332
412
'}' ,
333
413
'' ,
334
414
] ;
335
-
336
- fs . writeSync ( fd , indentLines ( interfaceTemplate , 6 ) . join ( '\n' ) ) ;
415
+ const indentSpacing = getIndentSpacing ( indentLevel ) ;
416
+ fs . writeSync ( fd , indentLines ( interfaceTemplate , indentSpacing ) . join ( '\n' ) ) ;
337
417
}
338
418
339
- function saveActionAsTSD ( rosActionInterface , fd ) {
419
+ function saveActionAsTSD ( rosActionInterface , fd , indentLevel = 3 ) {
340
420
const actionName = rosActionInterface . type ( ) . interfaceName ;
341
421
342
422
const interfaceTemplate = [
@@ -347,8 +427,19 @@ function saveActionAsTSD(rosActionInterface, fd) {
347
427
'}' ,
348
428
'' ,
349
429
] ;
430
+ const indentSpacing = getIndentSpacing ( indentLevel ) ;
431
+ fs . writeSync ( fd , indentLines ( interfaceTemplate , indentSpacing ) . join ( '\n' ) ) ;
432
+ }
350
433
351
- fs . writeSync ( fd , indentLines ( interfaceTemplate , 6 ) . join ( '\n' ) ) ;
434
+ /**
435
+ * Get number of indent spaces for given level
436
+ *
437
+ * @param {* } indentLevel Indention level
438
+ * @param {* } spacesPerLevel Number of spaces per level
439
+ * @returns Total number of space
440
+ */
441
+ function getIndentSpacing ( indentLevel , spacesPerLevel = 2 ) {
442
+ return indentLevel * spacesPerLevel ;
352
443
}
353
444
354
445
function isMsgInterface ( rosInterface ) {
@@ -451,7 +542,16 @@ function isValidAction(rosActionInterface, infos) {
451
542
return matches === SUCCESS_MATCH_COUNT ;
452
543
}
453
544
454
- function fieldType2JSName ( fieldInfo , subFolder = 'msg' ) {
545
+ function fieldType2JSName (
546
+ fieldInfo ,
547
+ subFolder = 'msg' ,
548
+ willGenerateDescriptorInterface = false
549
+ ) {
550
+ if ( willGenerateDescriptorInterface ) {
551
+ return fieldInfo . type . isPrimitiveType
552
+ ? `${ fieldInfo . type . type } `
553
+ : `${ fieldInfo . type . pkgName } /${ subFolder } /${ fieldInfo . type . type } ` ;
554
+ }
455
555
return fieldInfo . type . isPrimitiveType
456
556
? primitiveType2JSName ( fieldInfo . type . type )
457
557
: `${ fieldInfo . type . pkgName } .${ subFolder } .${ fieldInfo . type . type } ` ;
0 commit comments