@@ -165,12 +165,16 @@ class RosMsgSpec {
165165 fileContents = this . _loadMessageFile ( filePath ) ;
166166 }
167167 if ( fileContents !== null ) {
168- this . fileContents = this . _extractRelevantMessage ( fileContents ) ;
168+ this . fileContents = fileContents ;
169169
170- this . _extractFields ( this . fileContents ) ;
170+ this . _parseMessage ( fileContents ) ;
171171 }
172172 }
173173
174+ _parseMessage ( ) {
175+ throw new Error ( 'Unable to parse message file for base class RosMsgSpec' ) ;
176+ }
177+
174178 /**
175179 * Generates the file data for this class
176180 */
@@ -218,7 +222,89 @@ class RosMsgSpec {
218222 }
219223
220224 /**
221- * TODO: move this to MsgSpec? Really only makes sense there...
225+ * For this message spec, generates the text used to calculate the message's md5 sum
226+ * @returns {string }
227+ */
228+ getMd5text ( ) {
229+ return '' ;
230+ }
231+
232+ /**
233+ * Get the md5 sum of this message
234+ * @returns {string }
235+ */
236+ getMd5sum ( ) {
237+ return md5 ( this . getMd5text ( ) ) ;
238+ }
239+
240+ /**
241+ * Generates a depth-first list of all dependencies of this message in field order.
242+ * @param [deps] {Array}
243+ * @returns {Array }
244+ */
245+ getFullDependencies ( deps = [ ] ) {
246+ return [ ] ;
247+ }
248+
249+ /**
250+ * Computes the full text of a message/service.
251+ * Necessary for rosbags.
252+ * Mirrors gentools.
253+ * See compute_full_text() in
254+ * https://github.com/ros/ros/blob/kinetic-devel/core/roslib/src/roslib/gentools.py
255+ */
256+ computeFullText ( ) {
257+ const w = new IndentedWriter ( ) ;
258+
259+ const deps = this . getFullDependencies ( ) ;
260+ const sep = '=' . repeat ( 80 ) ;
261+ w . write ( this . fileContents . trim ( ) )
262+ . newline ( ) ;
263+
264+ deps . forEach ( ( dep ) => {
265+ w . write ( sep )
266+ . write ( `MSG: ${ dep . getFullMessageName ( ) } ` )
267+ . write ( dep . fileContents . trim ( ) )
268+ . newline ( ) ;
269+ } ) ;
270+
271+ return w . get ( ) . trim ( ) ;
272+ }
273+ }
274+
275+ /**
276+ * Subclass of RosMsgSpec
277+ * Implements logic for individual ros messages as well as separated parts of services and actions
278+ * (e.g. Request, Response, Goal, ActionResult, ...)
279+ * @class MsgSpec
280+ */
281+ class MsgSpec extends RosMsgSpec {
282+ constructor ( msgCache , packageName , messageName , type , filePath = null , fileContents = null ) {
283+ super ( msgCache , packageName , messageName , type , filePath ) ;
284+ this . constants = [ ] ;
285+ this . fields = [ ] ;
286+
287+ this . loadFile ( filePath , fileContents ) ;
288+ }
289+
290+ /**
291+ * Parses through message definition for fields and constants
292+ * @param content {string} relevant portion of message definition
293+ * @private
294+ */
295+ _parseMessage ( content ) {
296+ let lines = content . split ( '\n' ) . map ( ( line ) => line . trim ( ) ) ;
297+
298+ try {
299+ lines . forEach ( this . _parseLine . bind ( this ) ) ;
300+ }
301+ catch ( err ) {
302+ console . error ( 'Error while parsing message %s: %s' , this . getFullMessageName ( ) , err ) ;
303+ throw err ;
304+ }
305+ }
306+
307+ /**
222308 * Given a line from the message file, parse it for useful contents
223309 * @param line {string}
224310 * @private
@@ -284,135 +370,6 @@ class RosMsgSpec {
284370 this . fields . push ( f ) ;
285371 }
286372 }
287- } ;
288-
289- /**
290- * Takes a full definition and pulls out the piece relevant to this specific message spec
291- * (e.g. only the goal from the action message or only the request from the service message)
292- * @param fileContents string
293- * @returns {string }
294- * @private
295- */
296- _extractRelevantMessage ( fileContents ) {
297- let lines = fileContents . split ( '\n' ) . map ( ( line ) => line . trim ( ) ) ;
298-
299- switch ( this . type ) {
300- case SRV_REQUEST_TYPE : {
301- let divider = lines . indexOf ( MSG_DIVIDER ) ;
302- lines = lines . slice ( 0 , divider ) ;
303- break ;
304- }
305- case SRV_RESPONSE_TYPE : {
306- let divider = lines . indexOf ( MSG_DIVIDER ) ;
307- lines = lines . slice ( divider + 1 ) ;
308- break ;
309- }
310- case ACTION_GOAL_TYPE : {
311- let divider = lines . indexOf ( MSG_DIVIDER ) ;
312- lines = lines . slice ( 0 , divider ) ;
313- break ;
314- }
315- case ACTION_RESULT_TYPE : {
316- const divider1 = lines . indexOf ( MSG_DIVIDER ) + 1 ;
317- const divider2 = lines . indexOf ( MSG_DIVIDER , divider1 ) ;
318- lines = lines . slice ( divider1 , divider2 ) ;
319- break ;
320- }
321- case ACTION_FEEDBACK_TYPE : {
322- let divider = lines . indexOf ( MSG_DIVIDER ) ;
323- divider = lines . indexOf ( MSG_DIVIDER , divider + 1 ) ;
324- lines = lines . slice ( divider + 1 ) ;
325- break ;
326- }
327- default :
328- break ;
329- }
330-
331- return lines . join ( '\n' ) ;
332- }
333-
334- /**
335- * Parses through message definition for fields and constants
336- * Todo: move this to MsgSpec?
337- * @param content {string} raw message definition
338- * @private
339- */
340- _extractFields ( content ) {
341- let lines = content . split ( '\n' ) . map ( ( line ) => line . trim ( ) ) ;
342-
343- try {
344- lines . forEach ( this . _parseLine . bind ( this ) ) ;
345- }
346- catch ( err ) {
347- console . error ( 'Error while parsing message %s: %s' , this . getFullMessageName ( ) , err ) ;
348- throw err ;
349- }
350- }
351-
352- /**
353- * For this message spec, generates the text used to calculate the message's md5 sum
354- * @returns {string }
355- */
356- getMd5text ( ) {
357- return '' ;
358- }
359-
360- /**
361- * Get the md5 sum of this message
362- * @returns {string }
363- */
364- getMd5sum ( ) {
365- return md5 ( this . getMd5text ( ) ) ;
366- }
367-
368- /**
369- * Generates a depth-first list of all dependencies of this message in field order.
370- * @param [deps] {Array}
371- * @returns {Array }
372- */
373- getFullDependencies ( deps = [ ] ) {
374- return [ ] ;
375- }
376-
377- /**
378- * Computes the full text of a message/service.
379- * Necessary for rosbags.
380- * Mirrors gentools.
381- * See compute_full_text() in
382- * https://github.com/ros/ros/blob/kinetic-devel/core/roslib/src/roslib/gentools.py
383- */
384- computeFullText ( ) {
385- const w = new IndentedWriter ( ) ;
386-
387- const deps = this . getFullDependencies ( ) ;
388- const sep = '=' . repeat ( 80 ) ;
389- w . write ( this . fileContents . trim ( ) )
390- . newline ( ) ;
391-
392- deps . forEach ( ( dep ) => {
393- w . write ( sep )
394- . write ( `MSG: ${ dep . getFullMessageName ( ) } ` )
395- . write ( dep . fileContents . trim ( ) )
396- . newline ( ) ;
397- } ) ;
398-
399- return w . get ( ) . trim ( ) ;
400- }
401- }
402-
403- /**
404- * Subclass of RosMsgSpec
405- * Implements logic for individual ros messages as well as separated parts of services and actions
406- * (e.g. Request, Response, Goal, ActionResult, ...)
407- * @class MsgSpec
408- */
409- class MsgSpec extends RosMsgSpec {
410- constructor ( msgCache , packageName , messageName , type , filePath = null , fileContents = null ) {
411- super ( msgCache , packageName , messageName , type , filePath ) ;
412- this . constants = [ ] ;
413- this . fields = [ ] ;
414-
415- this . loadFile ( filePath , fileContents ) ;
416373 }
417374
418375 /**
@@ -558,9 +515,38 @@ class SrvSpec extends RosMsgSpec {
558515 super ( msgCache , packageName , messageName , type , filePath ) ;
559516
560517 this . fileContents = this . _loadMessageFile ( filePath ) ;
518+ const { req, resp} = this . _extractMessageSections ( this . fileContents ) ;
561519
562- this . request = new MsgSpec ( msgCache , packageName , messageName + 'Request' , SRV_REQUEST_TYPE , null , this . fileContents ) ;
563- this . response = new MsgSpec ( msgCache , packageName , messageName + 'Response' , SRV_RESPONSE_TYPE , null , this . fileContents ) ;
520+ this . request = new MsgSpec ( msgCache , packageName , messageName + 'Request' , SRV_REQUEST_TYPE , null , req ) ;
521+ this . response = new MsgSpec ( msgCache , packageName , messageName + 'Response' , SRV_RESPONSE_TYPE , null , resp ) ;
522+ }
523+
524+ /**
525+ * Takes a full service definition and pulls out the request and response sections
526+ * @param fileContents {string}
527+ * @returns {object }
528+ * @private
529+ */
530+ _extractMessageSections ( fileContents ) {
531+ let lines = fileContents . split ( '\n' ) . map ( ( line ) => line . trim ( ) ) ;
532+
533+ const sections = {
534+ req : '' ,
535+ resp : ''
536+ } ;
537+
538+ let currentSection = 'req' ;
539+
540+ lines . forEach ( ( line ) => {
541+ if ( line . startsWith ( MSG_DIVIDER ) ) {
542+ currentSection = 'resp' ;
543+ }
544+ else {
545+ sections [ currentSection ] += `\n${ line } ` ;
546+ }
547+ } ) ;
548+
549+ return sections ;
564550 }
565551
566552 getMd5text ( ) {
@@ -594,14 +580,47 @@ class ActionSpec extends RosMsgSpec {
594580 super ( msgCache , packageName , messageName , type , filePath ) ;
595581
596582 this . fileContents = this . _loadMessageFile ( filePath ) ;
583+ const { goal, result, feedback} = this . _extractMessageSections ( this . fileContents ) ;
597584
598585 // Parse the action definition into its 3 respective parts
599- this . goal = new MsgSpec ( msgCache , packageName , messageName + 'Goal' , ACTION_GOAL_TYPE , null , this . fileContents ) ;
600- this . result = new MsgSpec ( msgCache , packageName , messageName + 'Result' , ACTION_RESULT_TYPE , null , this . fileContents ) ;
601- this . feedback = new MsgSpec ( msgCache , packageName , messageName + 'Feedback' , ACTION_FEEDBACK_TYPE , null , this . fileContents ) ;
586+ this . goal = new MsgSpec ( msgCache , packageName , messageName + 'Goal' , ACTION_GOAL_TYPE , null , goal ) ;
587+ this . result = new MsgSpec ( msgCache , packageName , messageName + 'Result' , ACTION_RESULT_TYPE , null , result ) ;
588+ this . feedback = new MsgSpec ( msgCache , packageName , messageName + 'Feedback' , ACTION_FEEDBACK_TYPE , null , feedback ) ;
602589 this . generateActionMessages ( ) ;
603590 }
604591
592+ /**
593+ * Takes a full service definition and pulls out the request and response sections
594+ * @param fileContents {string}
595+ * @returns {object }
596+ * @private
597+ */
598+ _extractMessageSections ( fileContents ) {
599+ let lines = fileContents . split ( '\n' ) . map ( ( line ) => line . trim ( ) ) ;
600+
601+ const sections = {
602+ goal : '' ,
603+ result : '' ,
604+ feedback : ''
605+ } ;
606+
607+ let currentSection = 'goal' ;
608+
609+ lines . forEach ( ( line ) => {
610+ if ( line . startsWith ( MSG_DIVIDER ) ) {
611+ currentSection = {
612+ goal : 'result' ,
613+ result : 'feedback'
614+ } [ currentSection ] ;
615+ }
616+ else {
617+ sections [ currentSection ] += `\n${ line } ` ;
618+ }
619+ } ) ;
620+
621+ return sections ;
622+ }
623+
605624 /**
606625 * Get a list of all the message specs created by this ros action
607626 * @returns {MsgSpec[] }
@@ -670,4 +689,4 @@ RosMsgSpec.ACTION_ACTION_FEEDBACK_TYPE = ACTION_ACTION_FEEDBACK_TYPE;
670689RosMsgSpec . ACTION_ACTION_RESULT_TYPE = ACTION_ACTION_RESULT_TYPE ;
671690RosMsgSpec . ACTION_ACTION_TYPE = ACTION_ACTION_TYPE ;
672691
673- module . exports = RosMsgSpec ;
692+ module . exports = RosMsgSpec ;
0 commit comments