@@ -71,10 +71,13 @@ export function createTypings(
71
71
}
72
72
} ) ;
73
73
}
74
+ const alreadyDefined : string [ ] = [ ] ;
75
+
74
76
componentNames . forEach ( ( componentName ) => {
75
77
const exportType = getComponentExportType ( ast , componentName ) ;
76
78
const propTypes = getPropTypes ( ast , componentName ) ;
77
79
if ( exportType ) {
80
+ alreadyDefined . push ( componentName ) ;
78
81
createExportedTypes (
79
82
m ,
80
83
ast ,
@@ -88,6 +91,59 @@ export function createTypings(
88
91
}
89
92
} ) ;
90
93
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
+
91
147
if ( moduleName === null ) {
92
148
return m . members . map ( ( member ) => dom . emit ( member ) ) . join ( '' ) ;
93
149
} else {
@@ -102,7 +158,7 @@ function createExportedTypes(
102
158
reactComponentName : string | undefined ,
103
159
propTypes : any ,
104
160
importedPropTypes : ImportedPropTypes ,
105
- exportType : dom . DeclarationFlags ,
161
+ exportType : dom . DeclarationFlags | undefined ,
106
162
options : IOptions
107
163
) : void {
108
164
const classComponent = isClassComponent (
@@ -123,13 +179,19 @@ function createExportedTypes(
123
179
}
124
180
125
181
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 ) ;
133
195
} else {
134
196
createExportedFunctionalComponent (
135
197
m ,
@@ -141,18 +203,16 @@ function createExportedTypes(
141
203
}
142
204
}
143
205
144
- function createExportedClassComponent (
206
+ function createClassComponent (
145
207
m : dom . ModuleDeclaration ,
146
208
componentName : string ,
147
209
reactComponentName : string | undefined ,
148
- exportType : dom . DeclarationFlags ,
149
210
interf : dom . InterfaceDeclaration
150
- ) : void {
211
+ ) : dom . ClassDeclaration {
151
212
const classDecl = dom . create . class ( componentName ) ;
152
213
classDecl . baseType = dom . create . interface (
153
214
`React.${ reactComponentName || 'Component' } <${ interf . name } , any>`
154
215
) ;
155
- classDecl . flags = exportType ;
156
216
classDecl . members . push (
157
217
dom . create . method (
158
218
'render' ,
@@ -161,21 +221,53 @@ function createExportedClassComponent(
161
221
)
162
222
) ;
163
223
m . members . push ( classDecl ) ;
224
+ return classDecl ;
164
225
}
165
226
166
- function createExportedFunctionalComponent (
227
+ function createExportedClassComponent (
167
228
m : dom . ModuleDeclaration ,
168
229
componentName : string ,
169
- propTypes : any ,
230
+ reactComponentName : string | undefined ,
170
231
exportType : dom . DeclarationFlags ,
171
232
interf : dom . InterfaceDeclaration
172
233
) : 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 {
173
249
const typeDecl = dom . create . namedTypeReference (
174
250
`React.FC${ propTypes ? `<${ interf . name } >` : '' } `
175
251
) ;
176
252
const constDecl = dom . create . const ( componentName , typeDecl ) ;
177
253
m . members . push ( constDecl ) ;
178
254
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
+ ) ;
179
271
if ( exportType === dom . DeclarationFlags . ExportDefault ) {
180
272
m . members . push ( dom . create . exportDefault ( componentName ) ) ;
181
273
} else {
@@ -488,6 +580,38 @@ function getComponentNamesByJsxInBody(ast: AstQuery): string[] {
488
580
return [ ] ;
489
581
}
490
582
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
+
491
615
function getPropTypes ( ast : AstQuery , componentName : string ) : any | undefined {
492
616
const propTypes =
493
617
getPropTypesFromAssignment ( ast , componentName ) ||
0 commit comments