@@ -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 descriptorInterfaceType = true ;
137+ generateRosMsgInterfaces (
138+ pkgInfo ,
139+ subfolder ,
140+ messagesMap ,
141+ servicesMap ,
142+ actionsMap ,
143+ fd ,
144+ descriptorInterfaceType
145+ ) ;
146+ // close namespace descriptor declare
147+ fs . writeSync ( fd , ' }\n' ) ;
163148
164149 // close namespace declare
165150 fs . writeSync ( fd , ' }\n' ) ;
@@ -238,16 +223,78 @@ 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+ descriptorInterfaceType = false
234+ ) {
235+ for ( const rosInterface of pkgInfo . subfolders . get ( subfolder ) ) {
236+ const type = rosInterface . type ( ) ;
237+ const fullInterfaceName = `${ type . pkgName } /${ type . subFolder } /${ type . interfaceName } ` ;
238+ const fullInterfacePath = `${ type . pkgName } .${ type . subFolder } .${ type . interfaceName } ` ;
239+ const fullInterfaceConstructor = fullInterfacePath + 'Constructor' ;
240+
241+ if ( isMsgInterface ( rosInterface ) ) {
242+ // create message interface
243+ saveMsgAsTSD ( rosInterface , fd , descriptorInterfaceType ) ;
244+ saveMsgConstructorAsTSD ( rosInterface , fd , descriptorInterfaceType ) ;
245+ messagesMap [ fullInterfaceName ] = fullInterfacePath ;
246+ } else if ( isSrvInterface ( rosInterface ) ) {
247+ if ( ! isValidService ( rosInterface , pkgInfo . subfolders . get ( subfolder ) ) ) {
248+ let type = rosInterface . type ( ) ;
249+ console . log (
250+ `Incomplete service: ${ type . pkgName } .${ type . subFolder } .${ type . interfaceName } .`
251+ ) ;
252+ continue ;
253+ }
254+
255+ // create service interface
256+ saveSrvAsTSD ( rosInterface , fd , descriptorInterfaceType ) ;
257+ if ( ! isInternalActionSrvInterface ( rosInterface ) ) {
258+ servicesMap [ fullInterfaceName ] = fullInterfaceConstructor ;
259+ }
260+ } else if ( isActionInterface ( rosInterface ) ) {
261+ if ( ! isValidAction ( rosInterface , pkgInfo . subfolders . get ( subfolder ) ) ) {
262+ let type = rosInterface . type ( ) ;
263+ console . log (
264+ `Incomplete action: ${ type . pkgName } .${ type . subFolder } .${ type . interfaceName } .`
265+ ) ;
266+ continue ;
267+ }
268+
269+ // create action interface
270+ saveActionAsTSD ( rosInterface , fd , descriptorInterfaceType ) ;
271+ actionsMap [ fullInterfaceName ] = fullInterfaceConstructor ;
272+ }
273+ }
274+ }
275+
276+ function saveMsgAsTSD ( rosMsgInterface , fd , descriptorInterfaceType = false ) {
277+ const indentlevel = descriptorInterfaceType ? 8 : 6 ;
278+ const tmpl = indentString (
279+ `export interface ${ rosMsgInterface . type ( ) . interfaceName } {\n` ,
280+ indentlevel
245281 ) ;
282+ fs . writeSync ( fd , tmpl ) ;
246283 const useSamePkg =
247284 isInternalActionMsgInterface ( rosMsgInterface ) ||
248285 isInternalServiceEventMsgInterface ( rosMsgInterface ) ;
249- saveMsgFieldsAsTSD ( rosMsgInterface , fd , 8 , ';' , '' , useSamePkg ) ;
250- fs . writeSync ( fd , ' }\n' ) ;
286+ const indentLevel = descriptorInterfaceType ? 10 : 8 ;
287+ saveMsgFieldsAsTSD (
288+ rosMsgInterface ,
289+ fd ,
290+ indentLevel ,
291+ ';' ,
292+ '' ,
293+ useSamePkg ,
294+ descriptorInterfaceType
295+ ) ;
296+ const tmplEnd = indentString ( '}\n' , indentlevel ) ;
297+ fs . writeSync ( fd , tmplEnd ) ;
251298}
252299
253300/**
@@ -261,6 +308,7 @@ function saveMsgAsTSD(rosMsgInterface, fd) {
261308 * @param {string } typePrefix The prefix to put before the type name for
262309 * non-primitive types
263310 * @param {boolean } useSamePackageSubFolder Indicates if the sub folder name should be taken from the message
311+ * @param {boolean } descriptorInterfaceType Indicates if descriptor interface is being generated
264312 * when the field type comes from the same package. This is needed for action interfaces. Defaults to false.
265313 * @returns {undefined }
266314 */
@@ -270,7 +318,8 @@ function saveMsgFieldsAsTSD(
270318 indent = 0 ,
271319 lineEnd = ',' ,
272320 typePrefix = '' ,
273- useSamePackageSubFolder = false
321+ useSamePackageSubFolder = false ,
322+ descriptorInterfaceType = false
274323) {
275324 let type = rosMsgInterface . type ( ) ;
276325 let fields = rosMsgInterface . ROSMessageDef . fields ;
@@ -280,75 +329,96 @@ function saveMsgFieldsAsTSD(
280329 useSamePackageSubFolder && field . type . pkgName === type . pkgName
281330 ? type . subFolder
282331 : 'msg' ;
283- let fieldType = fieldType2JSName ( field , subFolder ) ;
332+ let fieldType = fieldType2JSName ( field , subFolder , descriptorInterfaceType ) ;
284333 let tp = field . type . isPrimitiveType ? '' : typePrefix ;
285334 if ( typePrefix === 'rclnodejs.' ) {
286335 fieldType = 'any' ;
287336 tp = '' ;
288337 }
289338
290- const tmpl = indentString ( `${ field . name } : ${ tp } ${ fieldType } ` , indent ) ;
291- fs . writeSync ( fd , tmpl ) ;
339+ let arrayString = '' ;
292340 if ( field . type . isArray ) {
293- fs . writeSync ( fd , '[]' ) ;
341+ arrayString = '[]' ;
294342
295- if ( fieldType === 'number' ) {
343+ if ( field . type . isFixedSizeArray && descriptorInterfaceType ) {
344+ arrayString = `[${ field . type . arraySize } ]` ;
345+ }
346+
347+ if ( fieldType === 'number' && ! descriptorInterfaceType ) {
296348 // for number[] include alternate typed-array types, e.g., number[] | uint8[]
297349 let jsTypedArrayName = fieldTypeArray2JSTypedArrayName ( field . type . type ) ;
298350
299351 if ( jsTypedArrayName ) {
300- fs . writeSync ( fd , ` | ${ jsTypedArrayName } ` ) ;
352+ arrayString += ` | ${ jsTypedArrayName } ` ;
301353 }
302354 }
303355 }
356+ const fieldString = descriptorInterfaceType
357+ ? `${ field . name } : '${ tp } ${ fieldType } ${ arrayString } '`
358+ : `${ field . name } : ${ tp } ${ fieldType } ${ arrayString } ` ;
359+ const tmpl = indentString ( fieldString , indent ) ;
360+ fs . writeSync ( fd , tmpl ) ;
304361
305362 fs . writeSync ( fd , lineEnd ) ;
306363 fs . writeSync ( fd , '\n' ) ;
307364 }
308365}
309366
310- function saveMsgConstructorAsTSD ( rosMsgInterface , fd ) {
367+ function saveMsgConstructorAsTSD (
368+ rosMsgInterface ,
369+ fd ,
370+ descriptorInterfaceType = false
371+ ) {
311372 const type = rosMsgInterface . type ( ) ;
312373 const msgName = type . interfaceName ;
374+ if ( ! descriptorInterfaceType ) {
375+ fs . writeSync ( fd , ` export interface ${ msgName } Constructor {\n` ) ;
313376
314- fs . writeSync ( fd , ` export interface ${ msgName } Constructor {\n` ) ;
377+ for ( const constant of rosMsgInterface . ROSMessageDef . constants ) {
378+ const constantType = primitiveType2JSName ( constant . type ) ;
379+ fs . writeSync ( fd , ` readonly ${ constant . name } : ${ constantType } ;\n` ) ;
380+ }
315381
316- for ( const constant of rosMsgInterface . ROSMessageDef . constants ) {
317- const constantType = primitiveType2JSName ( constant . type ) ;
318- fs . writeSync ( fd , ` readonly ${ constant . name } : ${ constantType } ;\n` ) ;
382+ fs . writeSync ( fd , ` new(other?: ${ msgName } ): ${ msgName } ;\n` ) ;
383+ fs . writeSync ( fd , ' }\n' ) ;
319384 }
320-
321- fs . writeSync ( fd , ` new(other?: ${ msgName } ): ${ msgName } ;\n` ) ;
322- fs . writeSync ( fd , ' }\n' ) ;
323385}
324386
325- function saveSrvAsTSD ( rosSrvInterface , fd ) {
326- const serviceName = rosSrvInterface . type ( ) . interfaceName ;
327-
328- const interfaceTemplate = [
329- `export interface ${ serviceName } Constructor extends ROSService {` ,
330- ` readonly Request: ${ serviceName } _RequestConstructor;` ,
331- ` readonly Response: ${ serviceName } _ResponseConstructor;` ,
332- '}' ,
333- '' ,
334- ] ;
335-
336- fs . writeSync ( fd , indentLines ( interfaceTemplate , 6 ) . join ( '\n' ) ) ;
387+ function saveSrvAsTSD ( rosSrvInterface , fd , descriptorInterfaceType = false ) {
388+ if ( ! descriptorInterfaceType ) {
389+ const serviceName = rosSrvInterface . type ( ) . interfaceName ;
390+
391+ const interfaceTemplate = [
392+ `export interface ${ serviceName } Constructor extends ROSService {` ,
393+ ` readonly Request: ${ serviceName } _RequestConstructor;` ,
394+ ` readonly Response: ${ serviceName } _ResponseConstructor;` ,
395+ '}' ,
396+ '' ,
397+ ] ;
398+ const indentLevel = 6 ;
399+ fs . writeSync ( fd , indentLines ( interfaceTemplate , indentLevel ) . join ( '\n' ) ) ;
400+ }
337401}
338402
339- function saveActionAsTSD ( rosActionInterface , fd ) {
340- const actionName = rosActionInterface . type ( ) . interfaceName ;
341-
342- const interfaceTemplate = [
343- `export interface ${ actionName } Constructor {` ,
344- ` readonly Goal: ${ actionName } _GoalConstructor;` ,
345- ` readonly Result: ${ actionName } _ResultConstructor;` ,
346- ` readonly Feedback: ${ actionName } _FeedbackConstructor;` ,
347- '}' ,
348- '' ,
349- ] ;
350-
351- fs . writeSync ( fd , indentLines ( interfaceTemplate , 6 ) . join ( '\n' ) ) ;
403+ function saveActionAsTSD (
404+ rosActionInterface ,
405+ fd ,
406+ descriptorInterfaceType = false
407+ ) {
408+ if ( ! descriptorInterfaceNamespace ) {
409+ const actionName = rosActionInterface . type ( ) . interfaceName ;
410+
411+ const interfaceTemplate = [
412+ `export interface ${ actionName } Constructor {` ,
413+ ` readonly Goal: ${ actionName } _GoalConstructor;` ,
414+ ` readonly Result: ${ actionName } _ResultConstructor;` ,
415+ ` readonly Feedback: ${ actionName } _FeedbackConstructor;` ,
416+ '}' ,
417+ '' ,
418+ ] ;
419+ const indentLevel = 6 ;
420+ fs . writeSync ( fd , indentLines ( interfaceTemplate , indentLevel ) . join ( '\n' ) ) ;
421+ }
352422}
353423
354424function isMsgInterface ( rosInterface ) {
@@ -451,7 +521,16 @@ function isValidAction(rosActionInterface, infos) {
451521 return matches === SUCCESS_MATCH_COUNT ;
452522}
453523
454- function fieldType2JSName ( fieldInfo , subFolder = 'msg' ) {
524+ function fieldType2JSName (
525+ fieldInfo ,
526+ subFolder = 'msg' ,
527+ descriptorInterfaceType = false
528+ ) {
529+ if ( descriptorInterfaceType ) {
530+ return fieldInfo . type . isPrimitiveType
531+ ? `${ fieldInfo . type . type } `
532+ : `${ fieldInfo . type . pkgName } /${ subFolder } /${ fieldInfo . type . type } ` ;
533+ }
455534 return fieldInfo . type . isPrimitiveType
456535 ? primitiveType2JSName ( fieldInfo . type . type )
457536 : `${ fieldInfo . type . pkgName } .${ subFolder } .${ fieldInfo . type . type } ` ;
0 commit comments