Skip to content

Commit 0f3ba92

Browse files
committed
Support 'memo(forwardRef(...'
1 parent 641b271 commit 0f3ba92

File tree

4 files changed

+56
-6
lines changed

4 files changed

+56
-6
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,17 @@ Object {
561561
}
562562
`;
563563

564+
exports[`defaultPropsHandler forwardRef resolves default props when memo used 1`] = `
565+
Object {
566+
"foo": Object {
567+
"defaultValue": Object {
568+
"computed": false,
569+
"value": "'bar'",
570+
},
571+
},
572+
}
573+
`;
574+
564575
exports[`defaultPropsHandler forwardRef resolves defaultProps 1`] = `
565576
Object {
566577
"foo": Object {

src/handlers/__tests__/componentDocblockHandler-test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,22 @@ describe('componentDocblockHandler', () => {
320320
);
321321
});
322322

323+
describe('inline implementation with memo', () => {
324+
test(`
325+
React.memo(React.forwardRef((props, ref) => {}));
326+
import React from "react";`, src =>
327+
beforeLastStatement(src).get('expression'));
328+
329+
testImports(
330+
`
331+
export default React.memo(React.forwardRef((props, ref) => {}));
332+
import React from 'react';`,
333+
src => beforeLastStatement(src).get('declaration'),
334+
'RefComponent',
335+
useDefault,
336+
);
337+
});
338+
323339
describe('out of line implementation', () => {
324340
test(`let Component = (props, ref) => {};
325341
React.forwardRef(Component);

src/handlers/__tests__/defaultPropsHandler-test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,19 @@ describe('defaultPropsHandler', () => {
573573
expect(documentation.descriptors).toMatchSnapshot();
574574
});
575575

576+
it('resolves default props when memo used', () => {
577+
const src = `
578+
import React, {memo, forwardRef} from 'react';
579+
memo(forwardRef(({ foo = 'bar' }, ref) => <div ref={ref}>{foo}</div>));
580+
`;
581+
defaultPropsHandler(
582+
documentation,
583+
parse(src).get('body', 1, 'expression'),
584+
noopImporter,
585+
);
586+
expect(documentation.descriptors).toMatchSnapshot();
587+
});
588+
576589
it('resolves imported default props in the parameters', () => {
577590
const src = `
578591
import baz from 'baz';

src/handlers/defaultPropsHandler.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import isReactForwardRefCall from '../utils/isReactForwardRefCall';
99
import type Documentation from '../Documentation';
1010
import type { Importer } from '../parse';
1111
import type { NodePath } from 'ast-types/lib/node-path';
12+
import isReactBuiltinCall from '../utils/isReactBuiltinCall';
1213

1314
function getDefaultValue(path: NodePath, importer: Importer) {
1415
let node = path.node;
@@ -46,12 +47,21 @@ function getStatelessPropsPath(
4647
componentDefinition: NodePath,
4748
importer: Importer,
4849
): NodePath {
49-
const value = resolveToValue(componentDefinition, importer);
50-
if (isReactForwardRefCall(value, importer)) {
51-
const inner = resolveToValue(value.get('arguments', 0), importer);
52-
return inner.get('params', 0);
53-
}
54-
return value.get('params', 0);
50+
let actPath = componentDefinition;
51+
let changed = false;
52+
do {
53+
changed = false;
54+
const value = resolveToValue(actPath, importer);
55+
if (
56+
isReactBuiltinCall(value, 'memo', importer) ||
57+
isReactForwardRefCall(value, importer)
58+
) {
59+
actPath = resolveToValue(actPath.get('arguments', 0), importer);
60+
changed = true;
61+
}
62+
} while (changed);
63+
64+
return actPath.get('params', 0);
5565
}
5666

5767
function getDefaultPropsPath(

0 commit comments

Comments
 (0)