@@ -71,10 +71,13 @@ export function createTypings(
7171 }
7272 } ) ;
7373 }
74+ const alreadyDefined : string [ ] = [ ] ;
75+
7476 componentNames . forEach ( ( componentName ) => {
7577 const exportType = getComponentExportType ( ast , componentName ) ;
7678 const propTypes = getPropTypes ( ast , componentName ) ;
7779 if ( exportType ) {
80+ alreadyDefined . push ( componentName ) ;
7881 createExportedTypes (
7982 m ,
8083 ast ,
@@ -88,6 +91,59 @@ export function createTypings(
8891 }
8992 } ) ;
9093
94+ // top level object variables
95+ const componentObject = getComponentNamesByObject ( ast , componentNames ) ;
96+
97+ componentObject . forEach ( ( { name, properties = { } } ) => {
98+ const obj = dom . create . objectType ( [ ] ) ;
99+ let hasType ;
100+
101+ Object . keys ( properties ) . forEach ( ( k ) => {
102+ const { key, value } = properties [ k ] ;
103+ componentNames . forEach ( ( componentName ) => {
104+ // if a property matches an existing component
105+ // add it to the object definition
106+ if ( value . type === 'Identifier' && value . name === componentName ) {
107+ const exportType = getComponentExportType ( ast , componentName ) ;
108+ const propTypes = getPropTypes ( ast , value . name ) ;
109+ // if it was exported individually, it will already have been typed earlier
110+ if ( ! alreadyDefined . includes ( componentName ) ) {
111+ createExportedTypes (
112+ m ,
113+ ast ,
114+ value . name ,
115+ reactComponentName ,
116+ propTypes ,
117+ importedPropTypes ,
118+ exportType ,
119+ options
120+ ) ;
121+ }
122+
123+ if ( propTypes ) {
124+ hasType = true ;
125+ const type1 = dom . create . namedTypeReference ( value . name ) ;
126+ const typeBase = dom . create . typeof ( type1 ) ;
127+ const b = dom . create . property ( key . name , typeBase ) ;
128+ obj . members . push ( b ) ;
129+ }
130+ }
131+ } ) ;
132+ } ) ;
133+ if ( hasType ) {
134+ const exportType = getComponentExportType ( ast , name ) ;
135+
136+ const objConst = dom . create . const ( name , obj ) ;
137+ m . members . push ( objConst ) ;
138+
139+ if ( exportType === dom . DeclarationFlags . ExportDefault ) {
140+ m . members . push ( dom . create . exportDefault ( name ) ) ;
141+ } else {
142+ objConst . flags = exportType ;
143+ }
144+ }
145+ } ) ;
146+
91147 if ( moduleName === null ) {
92148 return m . members . map ( ( member ) => dom . emit ( member ) ) . join ( '' ) ;
93149 } else {
@@ -102,7 +158,7 @@ function createExportedTypes(
102158 reactComponentName : string | undefined ,
103159 propTypes : any ,
104160 importedPropTypes : ImportedPropTypes ,
105- exportType : dom . DeclarationFlags ,
161+ exportType : dom . DeclarationFlags | undefined ,
106162 options : IOptions
107163) : void {
108164 const classComponent = isClassComponent (
@@ -123,13 +179,19 @@ function createExportedTypes(
123179 }
124180
125181 if ( classComponent ) {
126- createExportedClassComponent (
127- m ,
128- componentName ,
129- reactComponentName ,
130- exportType ,
131- interf
132- ) ;
182+ if ( ! exportType ) {
183+ createClassComponent ( m , componentName , reactComponentName , interf ) ;
184+ } else {
185+ createExportedClassComponent (
186+ m ,
187+ componentName ,
188+ reactComponentName ,
189+ exportType ,
190+ interf
191+ ) ;
192+ }
193+ } else if ( ! exportType ) {
194+ createFunctionalComponent ( m , componentName , propTypes , interf ) ;
133195 } else {
134196 createExportedFunctionalComponent (
135197 m ,
@@ -141,18 +203,16 @@ function createExportedTypes(
141203 }
142204}
143205
144- function createExportedClassComponent (
206+ function createClassComponent (
145207 m : dom . ModuleDeclaration ,
146208 componentName : string ,
147209 reactComponentName : string | undefined ,
148- exportType : dom . DeclarationFlags ,
149210 interf : dom . InterfaceDeclaration
150- ) : void {
211+ ) : dom . ClassDeclaration {
151212 const classDecl = dom . create . class ( componentName ) ;
152213 classDecl . baseType = dom . create . interface (
153214 `React.${ reactComponentName || 'Component' } <${ interf . name } , any>`
154215 ) ;
155- classDecl . flags = exportType ;
156216 classDecl . members . push (
157217 dom . create . method (
158218 'render' ,
@@ -161,21 +221,53 @@ function createExportedClassComponent(
161221 )
162222 ) ;
163223 m . members . push ( classDecl ) ;
224+ return classDecl ;
164225}
165226
166- function createExportedFunctionalComponent (
227+ function createExportedClassComponent (
167228 m : dom . ModuleDeclaration ,
168229 componentName : string ,
169- propTypes : any ,
230+ reactComponentName : string | undefined ,
170231 exportType : dom . DeclarationFlags ,
171232 interf : dom . InterfaceDeclaration
172233) : void {
234+ const classDecl = createClassComponent (
235+ m ,
236+ componentName ,
237+ reactComponentName ,
238+ interf
239+ ) ;
240+ classDecl . flags = exportType ;
241+ }
242+
243+ function createFunctionalComponent (
244+ m : dom . ModuleDeclaration ,
245+ componentName : string ,
246+ propTypes : any ,
247+ interf : dom . InterfaceDeclaration
248+ ) : dom . ConstDeclaration {
173249 const typeDecl = dom . create . namedTypeReference (
174250 `React.FC${ propTypes ? `<${ interf . name } >` : '' } `
175251 ) ;
176252 const constDecl = dom . create . const ( componentName , typeDecl ) ;
177253 m . members . push ( constDecl ) ;
178254
255+ return constDecl ;
256+ }
257+
258+ function createExportedFunctionalComponent (
259+ m : dom . ModuleDeclaration ,
260+ componentName : string ,
261+ propTypes : any ,
262+ exportType : dom . DeclarationFlags ,
263+ interf : dom . InterfaceDeclaration
264+ ) : void {
265+ const constDecl = createFunctionalComponent (
266+ m ,
267+ componentName ,
268+ propTypes ,
269+ interf
270+ ) ;
179271 if ( exportType === dom . DeclarationFlags . ExportDefault ) {
180272 m . members . push ( dom . create . exportDefault ( componentName ) ) ;
181273 } else {
@@ -488,6 +580,38 @@ function getComponentNamesByJsxInBody(ast: AstQuery): string[] {
488580 return [ ] ;
489581}
490582
583+ function getComponentNamesByObject (
584+ ast : AstQuery ,
585+ componentNames : string [ ]
586+ ) : { name : string ; properties : object | undefined } [ ] {
587+ const res = ast . query ( `
588+ /:program *
589+ / VariableDeclaration
590+ / VariableDeclarator[
591+ /:init ObjectExpression
592+ // ObjectProperty
593+ ],
594+ /:program *
595+ / ExportNamedDeclaration
596+ // VariableDeclarator[
597+ /:init ObjectExpression
598+ // ObjectProperty
599+ ]
600+ ` ) ;
601+ if ( res . length > 0 ) {
602+ return (
603+ res
604+ // only interested in components that exist
605+ . filter ( ( match ) => ! componentNames . includes ( match ) )
606+ . map ( ( match ) => ( {
607+ name : match . id ? match . id . name : '' ,
608+ properties : match . init ?. properties ,
609+ } ) )
610+ ) ;
611+ }
612+ return [ ] ;
613+ }
614+
491615function getPropTypes ( ast : AstQuery , componentName : string ) : any | undefined {
492616 const propTypes =
493617 getPropTypesFromAssignment ( ast , componentName ) ||
0 commit comments