Skip to content

Commit c9a1556

Browse files
eps1londanez
authored andcommitted
feat(defaultPropsHandler): Fully support forwardRef (#350)
* test(failing): defaultPropsHandler and forwardRef * feat(defaultPropsHandler): support forwardRef
1 parent a33c430 commit c9a1556

File tree

3 files changed

+58
-3
lines changed

3 files changed

+58
-3
lines changed

src/handlers/__tests__/__snapshots__/defaultPropsHandler-test.js.snap

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,28 @@ Object {
226226
}
227227
`;
228228

229+
exports[`defaultPropsHandler forwardRef resolves default props in the parameters 1`] = `
230+
Object {
231+
"foo": Object {
232+
"defaultValue": Object {
233+
"computed": false,
234+
"value": "'bar'",
235+
},
236+
},
237+
}
238+
`;
239+
240+
exports[`defaultPropsHandler forwardRef resolves defaultProps 1`] = `
241+
Object {
242+
"foo": Object {
243+
"defaultValue": Object {
244+
"computed": false,
245+
"value": "'baz'",
246+
},
247+
},
248+
}
249+
`;
250+
229251
exports[`defaultPropsHandler should only consider Property nodes, not e.g. spread properties 1`] = `
230252
Object {
231253
"bar": Object {

src/handlers/__tests__/defaultPropsHandler-test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,4 +219,28 @@ describe('defaultPropsHandler', () => {
219219
expect(documentation.descriptors).toMatchSnapshot();
220220
});
221221
});
222+
223+
describe('forwardRef', () => {
224+
it('resolves default props in the parameters', () => {
225+
const src = `
226+
import React from 'react';
227+
React.forwardRef(({ foo = 'bar' }, ref) => <div ref={ref}>{foo}</div>);
228+
`;
229+
defaultPropsHandler(
230+
documentation,
231+
parse(src).get('body', 1, 'expression'),
232+
);
233+
expect(documentation.descriptors).toMatchSnapshot();
234+
});
235+
236+
it('resolves defaultProps', () => {
237+
const src = `
238+
import React from 'react';
239+
const Component = React.forwardRef(({ foo }, ref) => <div ref={ref}>{foo}</div>);
240+
Component.defaultProps = { foo: 'baz' };
241+
`;
242+
defaultPropsHandler(documentation, parse(src).get('body', 1));
243+
expect(documentation.descriptors).toMatchSnapshot();
244+
});
245+
});
222246
});

src/handlers/defaultPropsHandler.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import printValue from '../utils/printValue';
1515
import recast from 'recast';
1616
import resolveToValue from '../utils/resolveToValue';
1717
import resolveFunctionDefinitionToReturnValue from '../utils/resolveFunctionDefinitionToReturnValue';
18-
import isStatelessComponent from '../utils/isStatelessComponent';
18+
import isReactComponentClass from '../utils/isReactComponentClass';
19+
import isReactForwardRefCall from '../utils/isReactForwardRefCall';
1920

2021
const {
2122
types: { namedTypes: types },
@@ -53,7 +54,12 @@ function getDefaultValue(path: NodePath) {
5354
}
5455

5556
function getStatelessPropsPath(componentDefinition): NodePath {
56-
return resolveToValue(componentDefinition).get('params', 0);
57+
const value = resolveToValue(componentDefinition);
58+
if (isReactForwardRefCall(value)) {
59+
const inner = value.get('arguments', 0);
60+
return inner.get('params', 0);
61+
}
62+
return value.get('params', 0);
5763
}
5864

5965
function getDefaultPropsPath(componentDefinition: NodePath): ?NodePath {
@@ -118,7 +124,10 @@ export default function defaultPropsHandler(
118124
) {
119125
let statelessProps = null;
120126
const defaultPropsPath = getDefaultPropsPath(componentDefinition);
121-
if (isStatelessComponent(componentDefinition)) {
127+
/**
128+
* function, lazy, memo, forwardRef etc components can resolve default props as well
129+
*/
130+
if (!isReactComponentClass(componentDefinition)) {
122131
statelessProps = getStatelessPropsPath(componentDefinition);
123132
}
124133

0 commit comments

Comments
 (0)