diff --git a/src/__tests__/data/FunctionDeclarationDefaultProps.tsx b/src/__tests__/data/FunctionDeclarationDefaultProps.tsx new file mode 100644 index 00000000..65d71321 --- /dev/null +++ b/src/__tests__/data/FunctionDeclarationDefaultProps.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; + +interface FunctionDeclarationDefaultPropsProps { + id?: number; +} + +/** FunctionDeclarationDefaultProps description */ +export const FunctionDeclarationDefaultProps = ( + props: FunctionDeclarationDefaultPropsProps +) => { + return
Hello World
; +}; + +FunctionDeclarationDefaultProps.defaultProps = { + id: 1 +}; diff --git a/src/__tests__/parser.ts b/src/__tests__/parser.ts index cd93c394..1dd6aa4a 100644 --- a/src/__tests__/parser.ts +++ b/src/__tests__/parser.ts @@ -350,6 +350,19 @@ describe('parser', () => { }); }); + it('should parse react stateless component default props when declared as a normal function', () => { + check('FunctionDeclarationDefaultProps', { + FunctionDeclarationDefaultProps: { + id: { + defaultValue: 1, + description: '', + required: false, + type: 'number' + } + } + }); + }); + it('should parse react stateless component with external intersection props', () => { check('StatelessIntersectionExternalProps', { StatelessIntersectionExternalProps: { diff --git a/src/parser.ts b/src/parser.ts index 0e39d1a9..fe0948fb 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -137,7 +137,9 @@ export function withCustomConfig( if (error !== undefined) { // tslint:disable-next-line: max-line-length - const errorText = `Cannot load custom tsconfig.json from provided path: ${tsconfigPath}, with error code: ${error.code}, message: ${error.messageText}`; + const errorText = `Cannot load custom tsconfig.json from provided path: ${tsconfigPath}, with error code: ${ + error.code + }, message: ${error.messageText}`; throw new Error(errorText); } @@ -631,23 +633,20 @@ export class Parser { symbol: ts.Symbol, source: ts.SourceFile ) { - let possibleStatements = source.statements - // ensure that name property is available - .filter(stmt => !!(stmt as ts.ClassDeclaration).name) - .filter( - stmt => - this.checker.getSymbolAtLocation( - (stmt as ts.ClassDeclaration).name! - ) === symbol - ); - - if (!possibleStatements.length) { - // if no class declaration is found, try to find a - // expression statement used in a React.StatelessComponent - possibleStatements = source.statements.filter( + let possibleStatements = [ + ...source.statements + // ensure that name property is available + .filter(stmt => !!(stmt as ts.ClassDeclaration).name) + .filter( + stmt => + this.checker.getSymbolAtLocation( + (stmt as ts.ClassDeclaration).name! + ) === symbol + ), + ...source.statements.filter( stmt => ts.isExpressionStatement(stmt) || ts.isVariableStatement(stmt) - ); - } + ) + ]; return possibleStatements.reduce((res, statement) => { if (statementIsClassDeclaration(statement) && statement.members.length) { @@ -683,9 +682,9 @@ export class Parser { let propMap = {}; if (properties) { - propMap = this.getPropMap( - properties as ts.NodeArray - ); + propMap = this.getPropMap(properties as ts.NodeArray< + ts.PropertyAssignment + >); } return { @@ -699,9 +698,9 @@ export class Parser { if (right) { const { properties } = right as ts.ObjectLiteralExpression; if (properties) { - propMap = this.getPropMap( - properties as ts.NodeArray - ); + propMap = this.getPropMap(properties as ts.NodeArray< + ts.PropertyAssignment + >); } } }); @@ -709,6 +708,7 @@ export class Parser { ...res, ...propMap }; + } else { } const functionStatement = this.getFunctionStatement(statement); @@ -788,26 +788,31 @@ export class Parser { public getPropMap( properties: ts.NodeArray ): StringIndexedObject { - const propMap = properties.reduce((acc, property) => { - if (ts.isSpreadAssignment(property) || !property.name) { - return acc; - } - - const literalValue = this.getLiteralValueFromPropertyAssignment(property); - const propertyName = getPropertyName(property.name); + const propMap = properties.reduce( + (acc, property) => { + if (ts.isSpreadAssignment(property) || !property.name) { + return acc; + } - if ( - (typeof literalValue === 'string' || - typeof literalValue === 'number' || - typeof literalValue === 'boolean' || - literalValue === null) && - propertyName !== null - ) { - acc[propertyName] = literalValue; - } + const literalValue = this.getLiteralValueFromPropertyAssignment( + property + ); + const propertyName = getPropertyName(property.name); + + if ( + (typeof literalValue === 'string' || + typeof literalValue === 'number' || + typeof literalValue === 'boolean' || + literalValue === null) && + propertyName !== null + ) { + acc[propertyName] = literalValue; + } - return acc; - }, {} as StringIndexedObject); + return acc; + }, + {} as StringIndexedObject + ); return propMap; }