Skip to content

Commit 56e7436

Browse files
committed
chore: handle returning call expressions
1 parent 34b6a94 commit 56e7436

File tree

2 files changed

+230
-28
lines changed

2 files changed

+230
-28
lines changed

lib/rules/no-render-return-undefined.js

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,44 +28,68 @@ module.exports = {
2828
},
2929

3030
create(context) {
31-
const isReturningUndefined = (returnStatement) => {
31+
function getReturnValue(returnNode) {
3232
const variables = variableUtil.variablesInScope(context);
33-
const returnNode = returnStatement && returnStatement.argument;
3433
const returnIdentifierName = returnNode && returnNode.name;
3534
const returnIdentifierVar = variableUtil.getVariable(
3635
variables,
3736
returnIdentifierName
3837
);
39-
const returnIdentifierValue = (() => {
40-
if (!returnNode) return undefined;
38+
39+
if (!returnNode) return undefined;
40+
41+
if (
42+
returnIdentifierVar
43+
&& returnIdentifierVar.defs
44+
&& returnIdentifierVar.defs[0]
45+
) {
46+
const value = returnIdentifierVar.defs[0].node.init;
4147
if (
42-
returnIdentifierVar
43-
&& returnIdentifierVar.defs
44-
&& returnIdentifierVar.defs[0]
48+
returnIdentifierVar.defs[0].node
49+
&& returnIdentifierVar.defs[0].node.type === 'VariableDeclarator'
50+
&& value === null
4551
) {
46-
const value = returnIdentifierVar.defs[0].node.init;
47-
if (
48-
returnIdentifierVar.defs[0].node.type === 'VariableDeclarator'
49-
&& value === null
50-
) {
51-
return undefined;
52-
}
53-
return value;
52+
return undefined;
5453
}
54+
return value;
55+
}
5556

56-
if (returnNode.type === 'ArrayExpression') {
57-
return returnNode.elements;
58-
}
57+
if (returnNode.type === 'ConditionalExpression') {
58+
const possibleReturnValue = [getReturnValue(returnNode.consequent), getReturnValue(returnNode.alternate)];
59+
const returnsUndefined = possibleReturnValue.some((val) => val === undefined);
60+
if (returnsUndefined) return undefined;
61+
return possibleReturnValue;
62+
}
5963

60-
if (returnNode.type === 'JSXElement') {
61-
return returnNode;
62-
}
64+
if (returnNode.type === 'CallExpression') {
65+
const calleeName = returnNode.callee.name;
66+
const calleeNode = variableUtil.variablesInScope(context).find((item) => item.name === calleeName);
67+
const calleeDefinitionNode = calleeNode && calleeNode.defs && calleeNode.defs[0] && calleeNode.defs[0].node;
68+
const calleeReturnStatement = astUtil.findReturnStatement(calleeDefinitionNode);
69+
const calleeReturnNode = (calleeReturnStatement && calleeReturnStatement.argument)
70+
|| (calleeDefinitionNode.init && calleeDefinitionNode.init.body);
71+
return getReturnValue(calleeReturnNode);
72+
}
73+
74+
if (returnNode.type === 'ArrayExpression') {
75+
return returnNode.elements;
76+
}
77+
78+
if (returnNode.type === 'JSXElement') {
79+
return returnNode;
80+
}
81+
82+
return returnNode.value;
83+
}
84+
85+
const isReturningUndefined = (returnStatement) => {
86+
const returnNode = returnStatement && returnStatement.argument;
87+
const returnIdentifierName = returnNode && returnNode.name;
6388

64-
return returnNode.value;
65-
})();
89+
const returnIdentifierValue = getReturnValue(returnNode);
6690

6791
const returnsArrayHavingUndefined = Array.isArray(returnIdentifierValue)
68-
&& returnIdentifierValue.some((el) => el.type === 'Identifier' && el.name === 'undefined');
92+
&& returnIdentifierValue.some((el) => el && el.type === 'Identifier' && el.name === 'undefined');
6993

7094
return !returnStatement
7195
|| returnIdentifierName === 'undefined'

tests/lib/rules/no-render-return-undefined.js

Lines changed: 182 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,112 @@ ruleTester.run('no-render-return-undefined', rule, {
126126
}
127127
`,
128128
},
129+
{
130+
code: `
131+
function App() {
132+
function getUI() {
133+
return 1;
134+
}
135+
return getUI();
136+
}
137+
`,
138+
},
139+
{
140+
code: `
141+
function getFoo() {
142+
return 1;
143+
}
144+
145+
function App() {
146+
function getUI() {
147+
return getFoo();
148+
}
149+
return getUI();
150+
}
151+
`,
152+
},
153+
{
154+
code: `
155+
const getFoo = () => 1;
156+
157+
function App() {
158+
function getUI() {
159+
return getFoo();
160+
}
161+
return getUI();
162+
}
163+
`,
164+
},
165+
{
166+
code: `
167+
function getFoo() {
168+
return 1;
169+
};
170+
171+
function App() {
172+
function getUI() {
173+
return getFoo();
174+
}
175+
return getUI();
176+
}
177+
`,
178+
},
179+
{
180+
code: `
181+
function getA() {
182+
return <A />;
183+
};
184+
function getB() {
185+
return <B />;
186+
};
187+
188+
function App() {
189+
function getUI() {
190+
return condition ? getA() : getB();
191+
}
192+
return getUI();
193+
}
194+
`,
195+
},
196+
{
197+
code: `
198+
const getA = () => <A />;
199+
const getB = () => <B />;
200+
201+
function App() {
202+
function getUI() {
203+
return condition ? getA() : getB();
204+
}
205+
return getUI();
206+
}
207+
`,
208+
},
209+
{
210+
code: `
211+
const getNum = () => 123;
212+
const getString = () => "ABC";
213+
214+
function App() {
215+
function getUI() {
216+
return condition ? getNum() : getString();
217+
}
218+
return getUI();
219+
}
220+
`,
221+
},
222+
{
223+
code: `
224+
const getA = () => null;
225+
const getB = () => [12, "Hello"];
226+
227+
function App() {
228+
function getUI() {
229+
return condition ? getA() : getB();
230+
}
231+
return getUI();
232+
}
233+
`,
234+
},
129235

130236
// Class Components
131237
{
@@ -143,7 +249,7 @@ ruleTester.run('no-render-return-undefined', rule, {
143249
render() {
144250
return 1;
145251
}
146-
}
252+
}
147253
`,
148254
},
149255
{
@@ -170,7 +276,7 @@ ruleTester.run('no-render-return-undefined', rule, {
170276
render() {
171277
return "Hello World";
172278
}
173-
}
279+
}
174280
`,
175281
},
176282
{
@@ -197,7 +303,7 @@ ruleTester.run('no-render-return-undefined', rule, {
197303
render() {
198304
return <div />;
199305
}
200-
}
306+
}
201307
`,
202308
},
203309
{
@@ -407,6 +513,78 @@ ruleTester.run('no-render-return-undefined', rule, {
407513
`,
408514
errors: [{ messageId: 'returnsUndefined' }],
409515
},
516+
{
517+
code: `
518+
function App() {
519+
function getUI() {
520+
return undefined;
521+
}
522+
return getUI();
523+
}
524+
`,
525+
errors: [{ messageId: 'returnsUndefined' }],
526+
},
527+
{
528+
code: `
529+
function getFoo() {
530+
return undefined;
531+
}
532+
533+
function App() {
534+
function getUI() {
535+
return getFoo();
536+
}
537+
return getUI();
538+
}
539+
`,
540+
errors: [{ messageId: 'returnsUndefined' }],
541+
},
542+
{
543+
code: `
544+
const getFoo = () => undefined;
545+
546+
function App() {
547+
function getUI() {
548+
return getFoo();
549+
}
550+
return getUI();
551+
}
552+
`,
553+
errors: [{ messageId: 'returnsUndefined' }],
554+
},
555+
{
556+
code: `
557+
function getA() {
558+
return undefined;
559+
};
560+
function getB() {
561+
return <B />;
562+
};
563+
564+
function App() {
565+
function getUI() {
566+
return condition ? getA() : getB();
567+
}
568+
return getUI();
569+
}
570+
`,
571+
errors: [{ messageId: 'returnsUndefined' }],
572+
},
573+
{
574+
code: `
575+
const getA = () => undefined;
576+
const getB = () => <B />;
577+
578+
function App() {
579+
function getUI() {
580+
return condition ? getA() : getB();
581+
}
582+
return getUI();
583+
}
584+
`,
585+
errors: [{ messageId: 'returnsUndefined' }],
586+
},
587+
410588
// Class Components
411589
{
412590
code: `
@@ -430,7 +608,7 @@ ruleTester.run('no-render-return-undefined', rule, {
430608
code: `
431609
const App = class {
432610
render() {}
433-
}
611+
}
434612
`,
435613
errors: [{ messageId: 'returnsUndefined' }],
436614
},

0 commit comments

Comments
 (0)