Skip to content

Commit 631c884

Browse files
authored
fix: extract display name correctly even if components are wrapped (#277)
This happens when for example using React.forwardRef()
1 parent 35babf2 commit 631c884

File tree

5 files changed

+85
-13
lines changed

5 files changed

+85
-13
lines changed

src/__tests__/__snapshots__/main-test.js.snap

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,3 +613,21 @@ Object {
613613
},
614614
}
615615
`;
616+
617+
exports[`main fixtures processes component "component_14.js" without errors 1`] = `
618+
Object {
619+
"description": "",
620+
"displayName": "UncoloredView",
621+
"methods": Array [],
622+
"props": Object {
623+
"color": Object {
624+
"description": "",
625+
"flowType": Object {
626+
"name": "string",
627+
"nullable": true,
628+
},
629+
"required": false,
630+
},
631+
},
632+
}
633+
`;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
type Props = $ReadOnly<{|
2+
color?: ?string,
3+
|}>;
4+
5+
const ColoredView = React.forwardRef((props: Props, ref) => (
6+
<View style={{backgroundColor: props.color}} />
7+
));
8+
9+
ColoredView.displayName = 'UncoloredView';
10+
11+
module.exports = ColoredView;

src/handlers/__tests__/displayNameHandler-test.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,18 @@ describe('defaultPropsHandler', () => {
174174
expect(documentation.displayName).toBe('Foo');
175175
});
176176

177+
it('considers the variable name even if wrapped', () => {
178+
const definition = statement('var Foo = React.forwardRef(() => {});').get(
179+
'declarations',
180+
0,
181+
'init',
182+
'arguments',
183+
0,
184+
);
185+
expect(() => displayNameHandler(documentation, definition)).not.toThrow();
186+
expect(documentation.displayName).toBe('Foo');
187+
});
188+
177189
it('considers the variable name on assign', () => {
178190
const definition = statement('Foo = () => {};').get(
179191
'expression',
@@ -183,6 +195,17 @@ describe('defaultPropsHandler', () => {
183195
expect(documentation.displayName).toBe('Foo');
184196
});
185197

198+
it('considers the variable name on assign even if wrapped', () => {
199+
const definition = statement('Foo = React.forwardRef(() => {});').get(
200+
'expression',
201+
'right',
202+
'arguments',
203+
0,
204+
);
205+
expect(() => displayNameHandler(documentation, definition)).not.toThrow();
206+
expect(documentation.displayName).toBe('Foo');
207+
});
208+
186209
it('considers a static displayName object property over variable name', () => {
187210
const definition = statement(`
188211
var Foo = () => {};
@@ -191,5 +214,14 @@ describe('defaultPropsHandler', () => {
191214
expect(() => displayNameHandler(documentation, definition)).not.toThrow();
192215
expect(documentation.displayName).toBe('Bar');
193216
});
217+
218+
it('considers a static displayName object property over variable name even if wrapped', () => {
219+
const definition = statement(`
220+
var Foo = React.forwardRef(() => {});
221+
Foo.displayName = 'Bar';
222+
`);
223+
expect(() => displayNameHandler(documentation, definition)).not.toThrow();
224+
expect(documentation.displayName).toBe('Bar');
225+
});
194226
});
195227
});

src/handlers/displayNameHandler.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,22 @@ export default function displayNameHandler(
3939
types.ArrowFunctionExpression.check(path.node) ||
4040
types.FunctionExpression.check(path.node)
4141
) {
42-
if (types.VariableDeclarator.check(path.parentPath.node)) {
43-
documentation.set(
44-
'displayName',
45-
getNameOrValue(path.parentPath.get('id')),
46-
);
47-
} else if (types.AssignmentExpression.check(path.parentPath.node)) {
48-
documentation.set(
49-
'displayName',
50-
getNameOrValue(path.parentPath.get('left')),
51-
);
42+
let currentPath = path;
43+
while (currentPath.parent) {
44+
if (types.VariableDeclarator.check(currentPath.parent.node)) {
45+
documentation.set(
46+
'displayName',
47+
getNameOrValue(currentPath.parent.get('id')),
48+
);
49+
return;
50+
} else if (types.AssignmentExpression.check(currentPath.parent.node)) {
51+
documentation.set(
52+
'displayName',
53+
getNameOrValue(currentPath.parent.get('left')),
54+
);
55+
return;
56+
}
57+
currentPath = currentPath.parent;
5258
}
5359
}
5460
return;

src/utils/getMemberExpressionValuePath.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,16 @@ function resolveName(path) {
4242
types.ArrowFunctionExpression.check(path.node) ||
4343
types.TaggedTemplateExpression.check(path.node)
4444
) {
45-
if (!types.VariableDeclarator.check(path.parent.node)) {
46-
return;
45+
let currentPath = path;
46+
while (currentPath.parent) {
47+
if (types.VariableDeclarator.check(currentPath.parent.node)) {
48+
return currentPath.parent.get('id', 'name').value;
49+
}
50+
51+
currentPath = currentPath.parent;
4752
}
4853

49-
return path.parent.get('id', 'name').value;
54+
return;
5055
}
5156

5257
throw new TypeError(

0 commit comments

Comments
 (0)