@@ -31,6 +31,8 @@ const fs = require('fs');
3131const loader = require ( '../lib/interface_loader.js' ) ;
3232const pkgFilters = require ( '../rosidl_gen/filter.js' ) ;
3333
34+ const descriptorInterfaceNamespace = 'descriptor' ;
35+
3436async function generateAll ( ) {
3537 // load pkg and interface info (msgs and srvs)
3638 const generatedPath = path . join ( __dirname , '../generated/' ) ;
@@ -119,47 +121,30 @@ function savePkgInfoAsTSD(pkgInfos, fd) {
119121 for ( const subfolder of pkgInfo . subfolders . keys ( ) ) {
120122 fs . writeSync ( fd , ` namespace ${ subfolder } {\n` ) ;
121123
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' ) ;
163148
164149 // close namespace declare
165150 fs . writeSync ( fd , ' }\n' ) ;
@@ -238,16 +223,96 @@ function savePkgInfoAsTSD(pkgInfos, fd) {
238223 fs . writeSync ( fd , '}\n' ) ;
239224}
240225
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
245298 ) ;
299+ fs . writeSync ( fd , tmpl ) ;
246300 const useSamePkg =
247301 isInternalActionMsgInterface ( rosMsgInterface ) ||
248302 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 ) ;
251316}
252317
253318/**
@@ -261,6 +326,7 @@ function saveMsgAsTSD(rosMsgInterface, fd) {
261326 * @param {string } typePrefix The prefix to put before the type name for
262327 * non-primitive types
263328 * @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
264330 * when the field type comes from the same package. This is needed for action interfaces. Defaults to false.
265331 * @returns {undefined }
266332 */
@@ -270,7 +336,8 @@ function saveMsgFieldsAsTSD(
270336 indent = 0 ,
271337 lineEnd = ',' ,
272338 typePrefix = '' ,
273- useSamePackageSubFolder = false
339+ useSamePackageSubFolder = false ,
340+ willGenerateDescriptorInterface = false
274341) {
275342 let type = rosMsgInterface . type ( ) ;
276343 let fields = rosMsgInterface . ROSMessageDef . fields ;
@@ -280,49 +347,62 @@ function saveMsgFieldsAsTSD(
280347 useSamePackageSubFolder && field . type . pkgName === type . pkgName
281348 ? type . subFolder
282349 : 'msg' ;
283- let fieldType = fieldType2JSName ( field , subFolder ) ;
350+ let fieldType = fieldType2JSName (
351+ field ,
352+ subFolder ,
353+ willGenerateDescriptorInterface
354+ ) ;
284355 let tp = field . type . isPrimitiveType ? '' : typePrefix ;
285356 if ( typePrefix === 'rclnodejs.' ) {
286357 fieldType = 'any' ;
287358 tp = '' ;
288359 }
289360
290- const tmpl = indentString ( `${ field . name } : ${ tp } ${ fieldType } ` , indent ) ;
291- fs . writeSync ( fd , tmpl ) ;
361+ let arrayString = '' ;
292362 if ( field . type . isArray ) {
293- fs . writeSync ( fd , '[]' ) ;
363+ arrayString = '[]' ;
364+
365+ if ( field . type . isFixedSizeArray && willGenerateDescriptorInterface ) {
366+ arrayString = `[${ field . type . arraySize } ]` ;
367+ }
294368
295- if ( fieldType === 'number' ) {
369+ if ( fieldType === 'number' && ! willGenerateDescriptorInterface ) {
296370 // for number[] include alternate typed-array types, e.g., number[] | uint8[]
297371 let jsTypedArrayName = fieldTypeArray2JSTypedArrayName ( field . type . type ) ;
298372
299373 if ( jsTypedArrayName ) {
300- fs . writeSync ( fd , ` | ${ jsTypedArrayName } ` ) ;
374+ arrayString += ` | ${ jsTypedArrayName } ` ;
301375 }
302376 }
303377 }
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 ) ;
304383
305384 fs . writeSync ( fd , lineEnd ) ;
306385 fs . writeSync ( fd , '\n' ) ;
307386 }
308387}
309388
310- function saveMsgConstructorAsTSD ( rosMsgInterface , fd ) {
389+ function saveMsgConstructorAsTSD ( rosMsgInterface , fd , indentLevel = 3 ) {
311390 const type = rosMsgInterface . type ( ) ;
312391 const msgName = type . interfaceName ;
313-
314- fs . writeSync ( fd , ` export interface ${ msgName } Constructor {\n` ) ;
392+ let interfaceTmpl = [ `export interface ${ msgName } Constructor {` ] ;
315393
316394 for ( const constant of rosMsgInterface . ROSMessageDef . constants ) {
317395 const constantType = primitiveType2JSName ( constant . type ) ;
318- fs . writeSync ( fd , ` readonly ${ constant . name } : ${ constantType } ;\n ` ) ;
396+ interfaceTmpl . push ( ` readonly ${ constant . name } : ${ constantType } ;` ) ;
319397 }
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' ) ) ;
323403}
324404
325- function saveSrvAsTSD ( rosSrvInterface , fd ) {
405+ function saveSrvAsTSD ( rosSrvInterface , fd , indentLevel = 3 ) {
326406 const serviceName = rosSrvInterface . type ( ) . interfaceName ;
327407
328408 const interfaceTemplate = [
@@ -332,11 +412,11 @@ function saveSrvAsTSD(rosSrvInterface, fd) {
332412 '}' ,
333413 '' ,
334414 ] ;
335-
336- fs . writeSync ( fd , indentLines ( interfaceTemplate , 6 ) . join ( '\n' ) ) ;
415+ const indentSpacing = getIndentSpacing ( indentLevel ) ;
416+ fs . writeSync ( fd , indentLines ( interfaceTemplate , indentSpacing ) . join ( '\n' ) ) ;
337417}
338418
339- function saveActionAsTSD ( rosActionInterface , fd ) {
419+ function saveActionAsTSD ( rosActionInterface , fd , indentLevel = 3 ) {
340420 const actionName = rosActionInterface . type ( ) . interfaceName ;
341421
342422 const interfaceTemplate = [
@@ -347,8 +427,19 @@ function saveActionAsTSD(rosActionInterface, fd) {
347427 '}' ,
348428 '' ,
349429 ] ;
430+ const indentSpacing = getIndentSpacing ( indentLevel ) ;
431+ fs . writeSync ( fd , indentLines ( interfaceTemplate , indentSpacing ) . join ( '\n' ) ) ;
432+ }
350433
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 ;
352443}
353444
354445function isMsgInterface ( rosInterface ) {
@@ -451,7 +542,16 @@ function isValidAction(rosActionInterface, infos) {
451542 return matches === SUCCESS_MATCH_COUNT ;
452543}
453544
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+ }
455555 return fieldInfo . type . isPrimitiveType
456556 ? primitiveType2JSName ( fieldInfo . type . type )
457557 : `${ fieldInfo . type . pkgName } .${ subFolder } .${ fieldInfo . type . type } ` ;
0 commit comments