@@ -38,7 +38,7 @@ function generateAll() {
3838 // load pkg and interface info (msgs and srvs)
3939 const generatedPath = path . join ( __dirname , '../generated/' ) ;
4040 const pkgInfos = getPkgInfos ( generatedPath ) ;
41-
41+
4242 // write message.d.ts file
4343 const messagesFilePath = path . join ( __dirname , '../types/interfaces.d.ts' ) ;
4444 const fd = fs . openSync ( messagesFilePath , 'w' ) ;
@@ -56,17 +56,19 @@ function getPkgInfos(generatedRoot) {
5656
5757 const pkgInfo = {
5858 name : pkg ,
59- messages : [ ]
59+ messages : [ ] ,
60+ services : [ ]
6061 } ;
6162
6263 const pkgPath = path . join ( rootDir , pkg ) ;
63- const files = fs . readdirSync ( pkgPath ) ;
64+ const files = fs . readdirSync ( pkgPath ) . filter ( fn => fn . endsWith ( '.js' ) ) ;
6465
6566 for ( let filename of files ) {
6667 const typeClass = fileName2Typeclass ( filename ) ;
6768
6869 if ( typeClass . type === 'srv' ) { // skip __srv__<action>
6970 if ( ! typeClass . name . endsWith ( 'Request' ) && ! typeClass . name . endsWith ( 'Response' ) ) {
71+ pkgInfo . services . push ( typeClass ) ;
7072 continue ;
7173 }
7274 }
@@ -93,10 +95,12 @@ function getPkgInfos(generatedRoot) {
9395
9496
9597function savePkgInfoAsTSD ( pkgInfos , fd ) {
96-
97- let fullMessageNames = [ 'string' ] ;
98+ let messagesMap = {
99+ string : 'string' ,
100+ } ;
98101
99102 fs . writeSync ( fd , '/* eslint-disable camelcase */\n' ) ;
103+ fs . writeSync ( fd , '/* eslint-disable max-len */\n' ) ;
100104 fs . writeSync ( fd , '// DO NOT EDIT\n' ) ;
101105 fs . writeSync ( fd , '// This file is generated by the rostsd_gen script\n\n' ) ;
102106
@@ -115,7 +119,7 @@ function savePkgInfoAsTSD(pkgInfos, fd) {
115119 for ( const msgInfo of pkgInfo . messages ) {
116120
117121 if ( msgInfo . typeClass . type != curNS ) {
118- if ( curNS ) { // close current ns
122+ if ( curNS ) { // close current ns
119123 fs . writeSync ( fd , ' }\n' ) ;
120124 }
121125
@@ -129,10 +133,11 @@ function savePkgInfoAsTSD(pkgInfos, fd) {
129133 }
130134
131135 saveMsgInfoAsTSD ( msgInfo , fd ) ;
136+ saveMsgWrapperAsTSD ( msgInfo , fd ) ;
132137
133138 // full path to this msg
134- const fullMessageName = `${ pkgInfo . name } . ${ msgInfo . typeClass . type } . ${ msgInfo . typeClass . name } ` ;
135- fullMessageNames . push ( fullMessageName ) ;
139+ const fullMessageName = `${ pkgInfo . name } / ${ msgInfo . typeClass . type } / ${ msgInfo . typeClass . name } ` ;
140+ messagesMap [ fullMessageName ] = ` ${ pkgInfo . name } . ${ msgInfo . typeClass . type } . ${ msgInfo . typeClass . name } ` ;
136141 }
137142
138143 if ( curNS ) {
@@ -144,66 +149,112 @@ function savePkgInfoAsTSD(pkgInfos, fd) {
144149 fs . writeSync ( fd , ' }\n\n' ) ;
145150 }
146151
147- // write type alias for Message
148- // e.g. type Message =
149- // string |
150- // std_msgs.msg.Bool |
151- // std_msgs.msg.Byte |
152- // ...
153- fs . writeSync ( fd , ' type Message = \n' ) ;
154- for ( let i = 0 ; i < fullMessageNames . length ; i ++ ) {
155- fs . writeSync ( fd , ' ' + fullMessageNames [ i ] ) ;
156- if ( i != fullMessageNames . length - 1 ) {
157- fs . writeSync ( fd , ' |\n' ) ;
158- }
152+ // write messages type mappings
153+ fs . writeSync ( fd , ' type MessagesMap = {\n' ) ;
154+ for ( const key in messagesMap ) {
155+ fs . writeSync ( fd , ` '${ key } ': ${ messagesMap [ key ] } ,\n` ) ;
156+ }
157+ fs . writeSync ( fd , ' };\n' ) ;
158+ fs . writeSync ( fd , ' type MessageTypeClassName = keyof MessagesMap;\n' ) ;
159+ fs . writeSync ( fd , ' type Message = MessagesMap[MessageTypeClassName];\n' ) ;
160+ fs . writeSync ( fd , ' type MessageType<T> = T extends MessageTypeClassName ? MessagesMap[T] : object;\n\n' ) ;
161+
162+ // write message wrappers mappings
163+ fs . writeSync ( fd , ' type MessageTypeClassWrappersMap = {\n' ) ;
164+ for ( const key in messagesMap ) {
165+ if ( key === 'string' ) {
166+ fs . writeSync ( fd , " 'string': never,\n" ) ;
167+ continue ;
168+ }
169+ fs . writeSync ( fd , ` '${ key } ': ${ messagesMap [ key ] } _WrapperType,\n` ) ;
170+ }
171+ fs . writeSync ( fd , ' };\n' ) ;
172+ fs . writeSync ( fd , ' type MessageWrapperType<T> = T extends MessageTypeClassName ? MessageTypeClassWrappersMap[T] : object;\n\n' ) ;
173+
174+ // write service type class string
175+ const services = [ ] ;
176+ for ( const pkg of pkgInfos ) {
177+ services . push ( ...pkg . services ) ;
178+ }
179+ if ( ! services . length ) {
180+ fs . writeSync ( fd , ' type ServiceTypeClassName = never;\n\n' ) ;
181+ } else {
182+ fs . writeSync ( fd , ' type ServiceTypeClassName = \n' ) ;
183+ for ( let i = 0 ; i < services . length ; i ++ ) {
184+ const srv = services [ i ] ;
185+ const srvTypeClassStr = `${ srv . package } /${ srv . type } /${ srv . name } ` ;
186+ fs . writeSync ( fd , ` '${ srvTypeClassStr } '` ) ;
187+
188+ if ( i !== services . length - 1 ) {
189+ fs . writeSync ( fd , ' |\n' ) ;
190+ }
191+ }
192+ fs . writeSync ( fd , ';\n\n' ) ;
159193 }
160-
161- fs . writeSync ( fd , ';\n' ) ;
194+
195+ fs . writeSync ( fd , ' type TypeClassName = MessageTypeClassName | ServiceTypeClassName ;\n' ) ;
162196
163197 // close module declare
164198 fs . writeSync ( fd , '}\n' ) ;
199+
165200 fs . closeSync ( fd ) ;
166201}
167202
168203
169- function saveMsgInfoAsTSD ( msgInfo , fd ) {
170-
171- // write type = xxxx {
172- const typeTemplate =
173- ` export type ${ msgInfo . typeClass . name } = {\n` ;
174-
175- fs . writeSync ( fd , typeTemplate ) ;
176-
177- // write constant definitions
178- for ( let i = 0 ; i < msgInfo . def . constants . length ; i ++ ) {
179- const constant = msgInfo . def . constants [ i ] ;
204+ function saveMsgWrapperAsTSD ( msgInfo , fd ) {
205+ const msgName = msgInfo . typeClass . name ;
206+ fs . writeSync ( fd , ` export type ${ msgName } _WrapperType = {\n` ) ;
207+ for ( const constant of msgInfo . def . constants ) {
180208 const constantType = primitiveType2JSName ( constant . type ) ;
181- const tmpl = ( constantType == 'string' ) ?
182- ` ${ constant . name } : '${ constant . value } '` :
183- ` ${ constant . name } : ${ constant . value } ` ;
184- fs . writeSync ( fd , tmpl ) ;
185-
186- if ( i != msgInfo . def . constants . length - 1 ) {
187- fs . writeSync ( fd , ',\n' ) ;
188- } else if ( msgInfo . def . fields . length > 0 ) {
189- fs . writeSync ( fd , ',\n' ) ;
190- }
209+ fs . writeSync ( fd , ` readonly ${ constant . name } : ${ constantType } ,\n` ) ;
191210 }
211+ fs . writeSync ( fd , ` new(other?: ${ msgName } ): ${ msgName } ,\n` ) ;
212+ fs . writeSync ( fd , ' }\n' ) ;
213+ }
192214
193- // write field definitions
215+
216+ /**
217+ * Writes the message fields as typescript definitions.
218+ *
219+ * @param {* } msgInfo ros message info
220+ * @param {* } fd file descriptor
221+ * @param {string } indent The amount of indent, in spaces
222+ * @param {string } lineEnd The character to put at the end of each line, usually ','
223+ * or ';'
224+ * @param {string } typePrefix The prefix to put before the type name for
225+ * non-primitive types
226+ * @returns {undefined }
227+ */
228+ function saveMsgFieldsAsTSD ( msgInfo , fd , indent = 0 , lineEnd = ',' , typePrefix = '' ) {
229+ const indentStr = ' ' . repeat ( indent ) ;
194230 for ( let i = 0 ; i < msgInfo . def . fields . length ; i ++ ) {
195231 const field = msgInfo . def . fields [ i ] ;
196- const fieldType = fieldType2JSName ( field ) ;
197- const tmpl = ` ${ field . name } : ${ fieldType } ` ;
232+ let fieldType = fieldType2JSName ( field ) ;
233+ let tp = field . type . isPrimitiveType ? '' : typePrefix ;
234+ if ( typePrefix === 'rclnodejs.' ) {
235+ fieldType = 'any' ;
236+ tp = '' ;
237+ }
238+ const tmpl = `${ indentStr } ${ field . name } : ${ tp } ${ fieldType } ` ;
198239 fs . writeSync ( fd , tmpl ) ;
199240 if ( field . type . isArray ) {
200241 fs . writeSync ( fd , '[]' ) ;
201242 }
202- if ( i != msgInfo . def . fields . length - 1 ) {
203- fs . writeSync ( fd , ',' ) ;
204- }
243+ fs . writeSync ( fd , lineEnd ) ;
205244 fs . writeSync ( fd , '\n' ) ;
206245 }
246+ }
247+
248+
249+ function saveMsgInfoAsTSD ( msgInfo , fd ) {
250+ // write type = xxxx {
251+ const typeTemplate =
252+ ` export type ${ msgInfo . typeClass . name } = {\n` ;
253+
254+ fs . writeSync ( fd , typeTemplate ) ;
255+
256+ // write field definitions
257+ saveMsgFieldsAsTSD ( msgInfo , fd , 8 ) ;
207258
208259 // end of def
209260 fs . writeSync ( fd , ' };\n' ) ;
@@ -223,7 +274,7 @@ function primitiveType2JSName(type) {
223274 switch ( type ) {
224275 case 'char' :
225276 case 'byte' :
226- case 'uin8 ' :
277+ case 'uint8 ' :
227278 case 'int8' :
228279 case 'int16' :
229280 case 'uint16' :
@@ -256,7 +307,7 @@ function fileName2Typeclass(filename) {
256307 const array = filename . split ( regex ) . filter ( Boolean ) ;
257308
258309 if ( ! array || array . length != 3 ) {
259- // todo: throw error
310+ // todo: throw error
260311 console . log ( 'ERRORRROOROR' , array ) ;
261312 return ;
262313 }
0 commit comments