Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/__tests__/data/ComponentWithReferencedDefaultProps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as React from 'react';

/** IComponentWithDefaultPropsProps props */
export interface IComponentWithDefaultPropsProps {
/**
* sample with default value
* @default hello
*/
sampleDefaultFromJSDoc: 'hello' | 'goodbye';
/** sampleTrue description */
sampleTrue?: boolean;
/** sampleFalse description */
sampleFalse?: boolean;
/** sampleString description */
sampleString?: string;
/** sampleObject description */
sampleObject?: { [key: string]: any };
/** sampleNull description */
sampleNull?: null;
/** sampleUndefined description */
sampleUndefined?: any;
/** sampleNumber description */
sampleNumber?: number;
}

const defaultProps: Partial<IComponentWithDefaultPropsProps> = {
sampleFalse: false,
sampleNull: null,
sampleNumber: -1,
// prettier-ignore
sampleObject: { a: '1', b: 2, c: true, d: false, e: undefined, f: null, g: { a: '1' } },
sampleString: 'hello',
sampleTrue: true,
sampleUndefined: undefined
};

const defaultPropsReference = defaultProps;

/** ComponentWithDefaultProps description */
export class ComponentWithDefaultProps extends React.Component<
IComponentWithDefaultPropsProps,
{}
> {
static defaultProps: Partial<
IComponentWithDefaultPropsProps
> = defaultPropsReference;

public render() {
return <div>test</div>;
}
}
12 changes: 10 additions & 2 deletions src/__tests__/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ describe('parser', () => {
});
});

it('should parse react component with default props', () => {
check('ComponentWithDefaultProps', {
describe('component with default props', () => {
const expectation = {
ComponentWithDefaultProps: {
sampleDefaultFromJSDoc: {
defaultValue: 'hello',
Expand Down Expand Up @@ -209,6 +209,14 @@ describe('parser', () => {
type: 'any'
}
}
};

it('should parse defined props', () => {
check('ComponentWithDefaultProps', expectation);
});

it('should parse referenced props', () => {
check('ComponentWithReferencedDefaultProps', expectation);
});
});

Expand Down
25 changes: 23 additions & 2 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,20 +408,41 @@ class Parser {
if (!possibleStatements.length) {
return {};
}

const statement = possibleStatements[0];

if (statementIsClassDeclaration(statement) && statement.members.length) {
const possibleDefaultProps = statement.members.filter(
member => member.name && getPropertyName(member.name) === 'defaultProps'
);

if (!possibleDefaultProps.length) {
return {};
}

const defaultProps = possibleDefaultProps[0];
const { initializer } = defaultProps as ts.PropertyDeclaration;
const { properties } = initializer as ts.ObjectLiteralExpression;
let initializer = (defaultProps as ts.PropertyDeclaration).initializer;
let properties = (initializer as ts.ObjectLiteralExpression).properties;

while (ts.isIdentifier(initializer as ts.Identifier)) {
const defaultPropsReference = this.checker.getSymbolAtLocation(
initializer as ts.Node
);
if (defaultPropsReference) {
const declarations = defaultPropsReference.getDeclarations();

if (declarations) {
initializer = (declarations[0] as ts.VariableDeclaration)
.initializer;
properties = (initializer as ts.ObjectLiteralExpression).properties;
}
}
}

const propMap = getPropMap(properties as ts.NodeArray<
ts.PropertyAssignment
>);

return propMap;
} else if (statementIsStateless(statement)) {
let propMap = {};
Expand Down