From 3bb2146b7b2fd3016821ccd9417baf925e4d66a2 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Sat, 4 May 2019 01:40:33 +0200 Subject: [PATCH] feat(defaultPropsHandler): Fully support forwardRef (#350) * test(failing): defaultPropsHandler and forwardRef * feat(defaultPropsHandler): support forwardRef # Conflicts: # src/handlers/__tests__/__snapshots__/defaultPropsHandler-test.js.snap --- .../defaultPropsHandler-test.js.snap | 23 ++++++++++++++++++ .../__tests__/defaultPropsHandler-test.js | 24 +++++++++++++++++++ src/handlers/defaultPropsHandler.js | 15 +++++++++--- 3 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 src/handlers/__tests__/__snapshots__/defaultPropsHandler-test.js.snap diff --git a/src/handlers/__tests__/__snapshots__/defaultPropsHandler-test.js.snap b/src/handlers/__tests__/__snapshots__/defaultPropsHandler-test.js.snap new file mode 100644 index 00000000000..55d0ce0852f --- /dev/null +++ b/src/handlers/__tests__/__snapshots__/defaultPropsHandler-test.js.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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'", + }, + }, +} +`; diff --git a/src/handlers/__tests__/defaultPropsHandler-test.js b/src/handlers/__tests__/defaultPropsHandler-test.js index a97a32e6de7..ba8752ce41f 100644 --- a/src/handlers/__tests__/defaultPropsHandler-test.js +++ b/src/handlers/__tests__/defaultPropsHandler-test.js @@ -219,4 +219,28 @@ describe('defaultPropsHandler', () => { expect(documentation.descriptors).toEqual({}); }); }); + + describe('forwardRef', () => { + it('resolves default props in the parameters', () => { + const src = ` + import React from 'react'; + React.forwardRef(({ foo = 'bar' }, ref) =>
{foo}
); + `; + 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) =>
{foo}
); + Component.defaultProps = { foo: 'baz' }; + `; + defaultPropsHandler(documentation, parse(src).get('body', 1)); + expect(documentation.descriptors).toMatchSnapshot(); + }); + }); }); diff --git a/src/handlers/defaultPropsHandler.js b/src/handlers/defaultPropsHandler.js index 7d410323265..3753a95d1f6 100644 --- a/src/handlers/defaultPropsHandler.js +++ b/src/handlers/defaultPropsHandler.js @@ -18,7 +18,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 }, @@ -56,7 +57,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 { @@ -120,7 +126,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); }