@@ -251,6 +251,61 @@ export class Parser {
251251 this . shouldIncludeExpression = Boolean ( shouldIncludeExpression ) ;
252252 }
253253
254+ public getTypeSymbol ( exp : ts . Symbol ) {
255+ const declaration = exp . valueDeclaration || exp . declarations ! [ 0 ] ;
256+ const type = this . checker . getTypeOfSymbolAtLocation ( exp , declaration ) ;
257+ const typeSymbol = type . symbol || type . aliasSymbol ;
258+ return typeSymbol ;
259+ }
260+
261+ public isPlainObjectType ( exp : ts . Symbol ) {
262+ let targetSymbol = exp ;
263+ if ( exp . flags & ts . SymbolFlags . Alias ) {
264+ targetSymbol = this . checker . getAliasedSymbol ( exp ) ;
265+ }
266+ const declaration =
267+ targetSymbol . valueDeclaration || targetSymbol . declarations ! [ 0 ] ;
268+
269+ if ( ts . isClassDeclaration ( declaration ) ) {
270+ return false ;
271+ }
272+
273+ const type = this . checker . getTypeOfSymbolAtLocation (
274+ targetSymbol ,
275+ declaration
276+ ) ;
277+ // Confirm it's an object type
278+ if ( ! ( type . flags & ts . TypeFlags . Object ) ) {
279+ return false ;
280+ }
281+ const objectType = type as ts . ObjectType ;
282+ const isPlain = ! ! (
283+ objectType . objectFlags &
284+ ( ts . ObjectFlags . Anonymous | ts . ObjectFlags . ObjectLiteral )
285+ ) ;
286+ return isPlain ;
287+ }
288+
289+ /**
290+ * Attempts to gather a symbol's exports.
291+ * Some symbol's like `default` exports are aliased, so we need to get the real symbol.
292+ * @param exp symbol
293+ */
294+ public getComponentExports ( exp : ts . Symbol ) {
295+ let targetSymbol = exp ;
296+
297+ if ( targetSymbol . exports ) {
298+ return { symbol : targetSymbol , exports : targetSymbol . exports ! } ;
299+ }
300+
301+ if ( exp . flags & ts . SymbolFlags . Alias ) {
302+ targetSymbol = this . checker . getAliasedSymbol ( exp ) ;
303+ }
304+ if ( targetSymbol . exports ) {
305+ return { symbol : targetSymbol , exports : targetSymbol . exports } ;
306+ }
307+ }
308+
254309 private getComponentFromExpression ( exp : ts . Symbol ) {
255310 const declaration = exp . valueDeclaration || exp . declarations ! [ 0 ] ;
256311 const type = this . checker . getTypeOfSymbolAtLocation ( exp , declaration ) ;
@@ -261,7 +316,6 @@ export class Parser {
261316 }
262317
263318 const symbolName = typeSymbol . getName ( ) ;
264-
265319 if (
266320 ( symbolName === 'MemoExoticComponent' ||
267321 symbolName === 'ForwardRefExoticComponent' ) &&
@@ -1238,7 +1292,6 @@ function computeComponentName(
12381292 customComponentTypes : ParserOptions [ 'customComponentTypes' ] = [ ]
12391293) {
12401294 const exportName = exp . getName ( ) ;
1241-
12421295 const statelessDisplayName = getTextValueOfFunctionProperty (
12431296 exp ,
12441297 source ,
@@ -1395,11 +1448,28 @@ function parseWithProgramProvider(
13951448 return docs ;
13961449 }
13971450
1398- const components = checker . getExportsOfModule ( moduleSymbol ) ;
1451+ const exports = checker . getExportsOfModule ( moduleSymbol ) ;
13991452 const componentDocs : ComponentDoc [ ] = [ ] ;
1453+ const exportsAndMembers : ts . Symbol [ ] = [ ] ;
1454+
1455+ // Examine each export to determine if it's on object which may contain components
1456+ exports . forEach ( exp => {
1457+ // Push symbol for extraction to maintain existing behavior
1458+ exportsAndMembers . push ( exp ) ;
1459+ // Determine if the export symbol is an object
1460+ if ( ! parser . isPlainObjectType ( exp ) ) {
1461+ return ;
1462+ }
1463+ const typeSymbol = parser . getTypeSymbol ( exp ) ;
1464+ if ( typeSymbol ?. members ) {
1465+ typeSymbol . members . forEach ( member => {
1466+ exportsAndMembers . push ( member ) ;
1467+ } ) ;
1468+ }
1469+ } ) ;
14001470
14011471 // First document all components
1402- components . forEach ( exp => {
1472+ exportsAndMembers . forEach ( exp => {
14031473 const doc = parser . getComponentInfo (
14041474 exp ,
14051475 sourceFile ,
@@ -1411,12 +1481,13 @@ function parseWithProgramProvider(
14111481 componentDocs . push ( doc ) ;
14121482 }
14131483
1414- if ( ! exp . exports ) {
1484+ const componentExports = parser . getComponentExports ( exp ) ;
1485+ if ( ! componentExports ) {
14151486 return ;
14161487 }
14171488
14181489 // Then document any static sub-components
1419- exp . exports . forEach ( symbol => {
1490+ componentExports . exports . forEach ( symbol => {
14201491 if ( symbol . flags & ts . SymbolFlags . Prototype ) {
14211492 return ;
14221493 }
@@ -1439,7 +1510,9 @@ function parseWithProgramProvider(
14391510
14401511 if ( doc ) {
14411512 const prefix =
1442- exp . escapedName === 'default' ? '' : `${ exp . escapedName } .` ;
1513+ componentExports . symbol . escapedName === 'default'
1514+ ? ''
1515+ : `${ componentExports . symbol . escapedName } .` ;
14431516
14441517 componentDocs . push ( {
14451518 ...doc ,
0 commit comments