@@ -254,8 +254,76 @@ export class Parser {
254
254
this . shouldIncludeExpression = Boolean ( shouldIncludeExpression ) ;
255
255
}
256
256
257
- private getComponentFromExpression ( exp : ts . Symbol ) {
257
+ public getTypeSymbol ( exp : ts . Symbol ) {
258
258
const declaration = exp . valueDeclaration || exp . declarations ! [ 0 ] ;
259
+ const type = this . checker . getTypeOfSymbolAtLocation ( exp , declaration ) ;
260
+ const typeSymbol = type . symbol || type . aliasSymbol ;
261
+ return typeSymbol ;
262
+ }
263
+
264
+ public isPlainObjectType ( exp : ts . Symbol ) {
265
+ let targetSymbol = exp ;
266
+ if ( exp . flags & ts . SymbolFlags . Alias ) {
267
+ targetSymbol = this . checker . getAliasedSymbol ( exp ) ;
268
+ }
269
+ const declaration =
270
+ targetSymbol . valueDeclaration || targetSymbol . declarations ! [ 0 ] ;
271
+
272
+ if ( ts . isClassDeclaration ( declaration ) ) {
273
+ return false ;
274
+ }
275
+
276
+ const type = this . checker . getTypeOfSymbolAtLocation (
277
+ targetSymbol ,
278
+ declaration
279
+ ) ;
280
+ // Confirm it's an object type
281
+ if ( ! ( type . flags & ts . TypeFlags . Object ) ) {
282
+ return false ;
283
+ }
284
+ const objectType = type as ts . ObjectType ;
285
+ const isPlain = ! ! (
286
+ objectType . objectFlags &
287
+ ( ts . ObjectFlags . Anonymous | ts . ObjectFlags . ObjectLiteral )
288
+ ) ;
289
+ return isPlain ;
290
+ }
291
+
292
+ /**
293
+ * Attempts to gather a symbol's exports.
294
+ * Some symbol's like `default` exports are aliased, so we need to get the real symbol.
295
+ * @param exp symbol
296
+ */
297
+ public getComponentExports ( exp : ts . Symbol ) {
298
+ let targetSymbol = exp ;
299
+
300
+ if ( targetSymbol . exports ) {
301
+ return { symbol : targetSymbol , exports : targetSymbol . exports ! } ;
302
+ }
303
+
304
+ if ( exp . flags & ts . SymbolFlags . Alias ) {
305
+ targetSymbol = this . checker . getAliasedSymbol ( exp ) ;
306
+ }
307
+ if ( targetSymbol . exports ) {
308
+ return { symbol : targetSymbol , exports : targetSymbol . exports } ;
309
+ }
310
+ }
311
+
312
+ private getComponentFromExpression ( exp : ts . Symbol ) {
313
+ let declaration = exp . valueDeclaration || exp . declarations ! [ 0 ] ;
314
+ // Lookup component if it's a property assignment
315
+ if ( declaration && ts . isPropertyAssignment ( declaration ) ) {
316
+ if ( ts . isIdentifier ( declaration . initializer ) ) {
317
+ const newSymbol = this . checker . getSymbolAtLocation (
318
+ declaration . initializer
319
+ ) ;
320
+ if ( newSymbol ) {
321
+ exp = newSymbol ;
322
+ declaration = exp . valueDeclaration || exp . declarations ! [ 0 ] ;
323
+ }
324
+ }
325
+ }
326
+
259
327
const type = this . checker . getTypeOfSymbolAtLocation ( exp , declaration ) ;
260
328
const typeSymbol = type . symbol || type . aliasSymbol ;
261
329
@@ -264,7 +332,6 @@ export class Parser {
264
332
}
265
333
266
334
const symbolName = typeSymbol . getName ( ) ;
267
-
268
335
if (
269
336
( symbolName === 'MemoExoticComponent' ||
270
337
symbolName === 'ForwardRefExoticComponent' ) &&
@@ -1230,7 +1297,7 @@ function getTextValueOfFunctionProperty(
1230
1297
source : ts . SourceFile ,
1231
1298
propertyName : string
1232
1299
) {
1233
- const [ textValue ] = source . statements
1300
+ const identifierStatements : [ ts . __String , string ] [ ] = source . statements
1234
1301
. filter ( statement => ts . isExpressionStatement ( statement ) )
1235
1302
. filter ( statement => {
1236
1303
const expr = ( statement as ts . ExpressionStatement )
@@ -1280,11 +1347,25 @@ function getTextValueOfFunctionProperty(
1280
1347
) ;
1281
1348
} )
1282
1349
. map ( statement => {
1283
- return ( ( ( statement as ts . ExpressionStatement )
1284
- . expression as ts . BinaryExpression ) . right as ts . Identifier ) . text ;
1350
+ const expressionStatement = ( statement as ts . ExpressionStatement )
1351
+ . expression as ts . BinaryExpression ;
1352
+ const name = ( ( expressionStatement . left as ts . PropertyAccessExpression )
1353
+ . expression as ts . Identifier ) . escapedText ;
1354
+ const value = ( expressionStatement . right as ts . Identifier ) . text ;
1355
+ return [ name , value ] ;
1285
1356
} ) ;
1286
1357
1287
- return textValue || '' ;
1358
+ if ( identifierStatements . length > 0 ) {
1359
+ const locatedStatement = identifierStatements . find (
1360
+ statement => statement [ 0 ] === exp . escapedName
1361
+ ) ;
1362
+ if ( locatedStatement ) {
1363
+ return locatedStatement [ 1 ] ;
1364
+ }
1365
+ return identifierStatements [ 0 ] [ 1 ] || '' ;
1366
+ }
1367
+
1368
+ return '' ;
1288
1369
}
1289
1370
1290
1371
function computeComponentName (
@@ -1450,11 +1531,28 @@ function parseWithProgramProvider(
1450
1531
return docs ;
1451
1532
}
1452
1533
1453
- const components = checker . getExportsOfModule ( moduleSymbol ) ;
1534
+ const exports = checker . getExportsOfModule ( moduleSymbol ) ;
1454
1535
const componentDocs : ComponentDoc [ ] = [ ] ;
1536
+ const exportsAndMembers : ts . Symbol [ ] = [ ] ;
1537
+
1538
+ // Examine each export to determine if it's on object which may contain components
1539
+ exports . forEach ( exp => {
1540
+ // Push symbol for extraction to maintain existing behavior
1541
+ exportsAndMembers . push ( exp ) ;
1542
+ // Determine if the export symbol is an object
1543
+ if ( ! parser . isPlainObjectType ( exp ) ) {
1544
+ return ;
1545
+ }
1546
+ const typeSymbol = parser . getTypeSymbol ( exp ) ;
1547
+ if ( typeSymbol ?. members ) {
1548
+ typeSymbol . members . forEach ( member => {
1549
+ exportsAndMembers . push ( member ) ;
1550
+ } ) ;
1551
+ }
1552
+ } ) ;
1455
1553
1456
1554
// First document all components
1457
- components . forEach ( exp => {
1555
+ exportsAndMembers . forEach ( exp => {
1458
1556
const doc = parser . getComponentInfo (
1459
1557
exp ,
1460
1558
sourceFile ,
@@ -1466,12 +1564,13 @@ function parseWithProgramProvider(
1466
1564
componentDocs . push ( doc ) ;
1467
1565
}
1468
1566
1469
- if ( ! exp . exports ) {
1567
+ const componentExports = parser . getComponentExports ( exp ) ;
1568
+ if ( ! componentExports ) {
1470
1569
return ;
1471
1570
}
1472
1571
1473
1572
// Then document any static sub-components
1474
- exp . exports . forEach ( symbol => {
1573
+ componentExports . exports . forEach ( symbol => {
1475
1574
if ( symbol . flags & ts . SymbolFlags . Prototype ) {
1476
1575
return ;
1477
1576
}
@@ -1494,7 +1593,9 @@ function parseWithProgramProvider(
1494
1593
1495
1594
if ( doc ) {
1496
1595
const prefix =
1497
- exp . escapedName === 'default' ? '' : `${ exp . escapedName } .` ;
1596
+ componentExports . symbol . escapedName === 'default'
1597
+ ? ''
1598
+ : `${ componentExports . symbol . escapedName } .` ;
1498
1599
1499
1600
componentDocs . push ( {
1500
1601
...doc ,
0 commit comments