Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(defaultPropsHandler): Fully support forwardRef #350

Merged
merged 2 commits into from May 3, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -226,6 +226,28 @@ Object {
}
`;

exports[`defaultPropsHandler forwardRef resolves default props in the parameters 1`] = `
Object {
"foo": Object {
"defaultValue": Object {
"computed": false,
"value": "'bar'",
},
},
}
`;

exports[`defaultPropsHandler forwardRef resolves defaultProps 1`] = `
Object {
"foo": Object {
"defaultValue": Object {
"computed": false,
"value": "'baz'",
},
},
}
`;

exports[`defaultPropsHandler should only consider Property nodes, not e.g. spread properties 1`] = `
Object {
"bar": Object {
Expand Down
24 changes: 24 additions & 0 deletions src/handlers/__tests__/defaultPropsHandler-test.js
Expand Up @@ -219,4 +219,28 @@ describe('defaultPropsHandler', () => {
expect(documentation.descriptors).toMatchSnapshot();
});
});

describe('forwardRef', () => {
it('resolves default props in the parameters', () => {
const src = `
import React from 'react';
React.forwardRef(({ foo = 'bar' }, ref) => <div ref={ref}>{foo}</div>);
`;
defaultPropsHandler(
documentation,
parse(src).get('body', 1, 'expression'),
);
expect(documentation.descriptors).toMatchSnapshot();
});

it('resolves defaultProps', () => {
const src = `
import React from 'react';
const Component = React.forwardRef(({ foo }, ref) => <div ref={ref}>{foo}</div>);
Component.defaultProps = { foo: 'baz' };
`;
defaultPropsHandler(documentation, parse(src).get('body', 1));
expect(documentation.descriptors).toMatchSnapshot();
});
});
});
15 changes: 12 additions & 3 deletions src/handlers/defaultPropsHandler.js
Expand Up @@ -15,7 +15,8 @@ import printValue from '../utils/printValue';
import recast from 'recast';
import resolveToValue from '../utils/resolveToValue';
import resolveFunctionDefinitionToReturnValue from '../utils/resolveFunctionDefinitionToReturnValue';
import isStatelessComponent from '../utils/isStatelessComponent';
import isReactComponentClass from '../utils/isReactComponentClass';
import isReactForwardRefCall from '../utils/isReactForwardRefCall';

const {
types: { namedTypes: types },
Expand Down Expand Up @@ -53,7 +54,12 @@ function getDefaultValue(path: NodePath) {
}

function getStatelessPropsPath(componentDefinition): NodePath {
return resolveToValue(componentDefinition).get('params', 0);
const value = resolveToValue(componentDefinition);
if (isReactForwardRefCall(value)) {
const inner = value.get('arguments', 0);
return inner.get('params', 0);
}
return value.get('params', 0);
}

function getDefaultPropsPath(componentDefinition: NodePath): ?NodePath {
Expand Down Expand Up @@ -118,7 +124,10 @@ export default function defaultPropsHandler(
) {
let statelessProps = null;
const defaultPropsPath = getDefaultPropsPath(componentDefinition);
if (isStatelessComponent(componentDefinition)) {
/**
* function, lazy, memo, forwardRef etc components can resolve default props as well
*/
if (!isReactComponentClass(componentDefinition)) {
statelessProps = getStatelessPropsPath(componentDefinition);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to change that too. This was always a bit misleading and with hooks it is definitely wrong.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are you referring here? Changing the name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming yes. Doesn't matter really since it's internals only. This should probably be handled in a different PR and applied consistently. But I don't know if this would change some react-docgen/utils API so I guess this is fine.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would you rename it to?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know. Probably just getFunctionPropsPath or just getPropsPath. Naming is hard but I don't think this discussion serves any purpose.

}

Expand Down