diff --git a/src/__tests__/data/SeparateDefaultProps.tsx b/src/__tests__/data/SeparateDefaultProps.tsx new file mode 100644 index 00000000..34910113 --- /dev/null +++ b/src/__tests__/data/SeparateDefaultProps.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; + +const defaultProps = { + id: 123, + disabled: false +}; + +interface SeparateDefaultPropsProps { + id: number; + disabled: boolean; +} + +/** SeparateDefaultProps description */ +export const SeparateDefaultProps = (props: SeparateDefaultPropsProps) => ( +
test
+); + +SeparateDefaultProps.defaultProps = defaultProps; diff --git a/src/__tests__/data/SeparateDefaultPropsIndividual.tsx b/src/__tests__/data/SeparateDefaultPropsIndividual.tsx new file mode 100644 index 00000000..db1031b6 --- /dev/null +++ b/src/__tests__/data/SeparateDefaultPropsIndividual.tsx @@ -0,0 +1,25 @@ +import * as React from 'react'; + +const defaultProps2 = { + id: 123 +}; + +const defaultProps = { + id: defaultProps2.id, + disabled: false +}; + +interface SeparateDefaultPropsIndividualProps { + id: number; + disabled: boolean; +} + +/** SeparateDefaultPropsIndividual description */ +export const SeparateDefaultPropsIndividual = ( + props: SeparateDefaultPropsIndividualProps +) =>
test
; + +SeparateDefaultPropsIndividual.defaultProps = { + id: defaultProps.id, + disabled: defaultProps.disabled +}; diff --git a/src/__tests__/parser.ts b/src/__tests__/parser.ts index 2216f4e4..1ad72a01 100644 --- a/src/__tests__/parser.ts +++ b/src/__tests__/parser.ts @@ -982,6 +982,44 @@ describe('parser', () => { }); }); + it('should defaultProps in variable', () => { + check('SeparateDefaultProps', { + SeparateDefaultProps: { + disabled: { + description: '', + required: false, + defaultValue: false, + type: 'boolean' + }, + id: { + description: '', + required: false, + defaultValue: 123, + type: 'number' + } + } + }); + }); + + it('should defaultProps accessed variable', () => { + check('SeparateDefaultPropsIndividual', { + SeparateDefaultPropsIndividual: { + disabled: { + description: '', + required: false, + defaultValue: false, + type: 'boolean' + }, + id: { + description: '', + required: false, + defaultValue: 123, + type: 'number' + } + } + }); + }); + describe('Extracting literal values from enums', () => { it('extracts literal values from enum', () => { check( diff --git a/src/parser.ts b/src/parser.ts index b732523d..d26f7d05 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -141,7 +141,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); } @@ -775,9 +777,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 { @@ -787,13 +789,29 @@ export class Parser { } else if (statementIsStatelessWithDefaultProps(statement)) { let propMap = {}; (statement as ts.ExpressionStatement).getChildren().forEach(child => { - const { right } = child as ts.BinaryExpression; + let { right } = child as ts.BinaryExpression; + + if (right && ts.isIdentifier(right)) { + const value = ((source as any).locals as ts.SymbolTable).get( + right.escapedText + ); + + if ( + value && + value.valueDeclaration && + ts.isVariableDeclaration(value.valueDeclaration) && + value.valueDeclaration.initializer + ) { + right = value.valueDeclaration.initializer; + } + } + 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 + >); } } }); @@ -867,7 +885,22 @@ export class Parser { return (initializer as ts.Identifier).text === 'undefined' ? 'undefined' : null; - case ts.SyntaxKind.PropertyAccessExpression: + case ts.SyntaxKind.PropertyAccessExpression: { + const symbol = this.checker.getSymbolAtLocation( + initializer as ts.PropertyAccessExpression + ); + + if (symbol && symbol.declarations.length) { + const declaration = symbol.declarations[0]; + + if ( + ts.isBindingElement(declaration) || + ts.isPropertyAssignment(declaration) + ) { + return this.getLiteralValueFromPropertyAssignment(declaration); + } + } + } case ts.SyntaxKind.ObjectLiteralExpression: default: try { @@ -881,26 +914,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 propMap = properties.reduce( + (acc, property) => { + if (ts.isSpreadAssignment(property) || !property.name) { + return acc; + } - const literalValue = this.getLiteralValueFromPropertyAssignment(property); - const propertyName = getPropertyName(property.name); + 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; - } + 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; }