Skip to content

Commit 86211ec

Browse files
committed
Support 'memo(forwardRef(...'
1 parent 641b271 commit 86211ec

File tree

4 files changed

+58
-10
lines changed

4 files changed

+58
-10
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__/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 from 'react';
579+
React.memo(React.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/componentDocblockHandler.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,29 @@ import isReactForwardRefCall from '../utils/isReactForwardRefCall';
55
import resolveToValue from '../utils/resolveToValue';
66
import type { Importer } from '../parse';
77
import type { NodePath } from 'ast-types/lib/node-path';
8+
import isReactBuiltinCall from '../utils/isReactBuiltinCall';
89

910
function isClassDefinition(nodePath: NodePath): boolean {
1011
const node = nodePath.node;
1112
return t.ClassDeclaration.check(node) || t.ClassExpression.check(node);
1213
}
1314

15+
function resolveReactHOCs(path: NodePath, importer: Importer) {
16+
let actPath = path;
17+
let changed = false;
18+
do {
19+
changed = false;
20+
if (isReactForwardRefCall(path, importer)) {
21+
actPath = path.get('arguments', 0);
22+
changed = true;
23+
} else if (isReactBuiltinCall(path, 'memo', importer)) {
24+
actPath = path.get('arguments', 0);
25+
changed = true;
26+
}
27+
} while (changed);
28+
return actPath;
29+
}
30+
1431
function getDocblockFromComponent(
1532
path: NodePath,
1633
importer: Importer,
@@ -45,10 +62,7 @@ function getDocblockFromComponent(
4562
}
4663
}
4764
if (!description) {
48-
const searchPath = isReactForwardRefCall(path, importer)
49-
? path.get('arguments', 0)
50-
: path;
51-
const inner = resolveToValue(searchPath, importer);
65+
const inner = resolveToValue(resolveReactHOCs(path, importer), importer);
5266
if (inner.node !== path.node) {
5367
return getDocblockFromComponent(inner, importer);
5468
}

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)