Skip to content

Commit 34b6a94

Browse files
committed
chore: add tc for class components
1 parent 61981c7 commit 34b6a94

File tree

2 files changed

+261
-15
lines changed

2 files changed

+261
-15
lines changed

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

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,7 @@ module.exports = {
2828
},
2929

3030
create(context) {
31-
const handleFunctionalComponents = (node) => {
32-
const fnName = (node.id && node.id.name) || node.parent.id.name;
33-
const isReactComponent = fnName[0] === fnName[0].toUpperCase();
34-
const returnStatement = astUtil.findReturnStatement(node);
35-
36-
if (!isReactComponent) return;
37-
31+
const isReturningUndefined = (returnStatement) => {
3832
const variables = variableUtil.variablesInScope(context);
3933
const returnNode = returnStatement && returnStatement.argument;
4034
const returnIdentifierName = returnNode && returnNode.name;
@@ -73,13 +67,35 @@ module.exports = {
7367
const returnsArrayHavingUndefined = Array.isArray(returnIdentifierValue)
7468
&& returnIdentifierValue.some((el) => el.type === 'Identifier' && el.name === 'undefined');
7569

76-
if (
77-
!returnStatement
78-
|| returnIdentifierName === 'undefined'
79-
|| returnIdentifierValue === undefined
80-
|| (returnIdentifierValue && returnIdentifierValue.name === 'undefined')
81-
|| returnsArrayHavingUndefined
82-
) {
70+
return !returnStatement
71+
|| returnIdentifierName === 'undefined'
72+
|| returnIdentifierValue === undefined
73+
|| (returnIdentifierValue && returnIdentifierValue.name === 'undefined')
74+
|| returnsArrayHavingUndefined;
75+
};
76+
77+
const handleFunctionalComponents = (node) => {
78+
const fnName = (node.id && node.id.name) || node.parent.id.name;
79+
80+
// Considering functions starting with Uppercase letters are react components
81+
const isReactComponent = fnName[0] === fnName[0].toUpperCase();
82+
const returnStatement = astUtil.findReturnStatement(node);
83+
84+
if (!isReactComponent) return;
85+
86+
if (isReturningUndefined(returnStatement)) {
87+
report(context, messages.returnsUndefined, 'returnsUndefined', {
88+
node,
89+
});
90+
}
91+
};
92+
93+
const handleClassComponents = (node) => {
94+
const componentProperties = astUtil.getComponentProperties(node);
95+
const renderFnNode = componentProperties.find((prop) => prop.key.name === 'render');
96+
const returnStatement = astUtil.findReturnStatement(renderFnNode);
97+
98+
if (isReturningUndefined(returnStatement)) {
8399
report(context, messages.returnsUndefined, 'returnsUndefined', {
84100
node,
85101
});
@@ -89,6 +105,8 @@ module.exports = {
89105
return {
90106
FunctionDeclaration: handleFunctionalComponents,
91107
ArrowFunctionExpression: handleFunctionalComponents,
108+
ClassDeclaration: handleClassComponents,
109+
ClassExpression: handleClassComponents,
92110
};
93111
},
94112
};

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

Lines changed: 229 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const parserOptions = {
2828

2929
const ruleTester = new RuleTester({ parserOptions });
3030
ruleTester.run('no-render-return-undefined', rule, {
31+
// Valid Cases
3132
valid: parsers.all([
3233
{
3334
code: `
@@ -125,7 +126,128 @@ ruleTester.run('no-render-return-undefined', rule, {
125126
}
126127
`,
127128
},
129+
130+
// Class Components
131+
{
132+
code: `
133+
class App {
134+
render() {
135+
return 1;
136+
}
137+
}
138+
`,
139+
},
140+
{
141+
code: `
142+
const App = class {
143+
render() {
144+
return 1;
145+
}
146+
}
147+
`,
148+
},
149+
{
150+
code: `
151+
class App extends React.Component {
152+
render() {
153+
return 1;
154+
}
155+
}
156+
`,
157+
},
158+
{
159+
code: `
160+
class App {
161+
render() {
162+
return "Hello World";
163+
}
164+
}
165+
`,
166+
},
167+
{
168+
code: `
169+
const App = class {
170+
render() {
171+
return "Hello World";
172+
}
173+
}
174+
`,
175+
},
176+
{
177+
code: `
178+
class App extends React.Component {
179+
render() {
180+
return "Hello World";
181+
}
182+
}
183+
`,
184+
},
185+
{
186+
code: `
187+
class App {
188+
render() {
189+
return <div />;
190+
}
191+
}
192+
`,
193+
},
194+
{
195+
code: `
196+
const App = class {
197+
render() {
198+
return <div />;
199+
}
200+
}
201+
`,
202+
},
203+
{
204+
code: `
205+
class App extends React.Component {
206+
render() {
207+
return <div />;
208+
}
209+
}
210+
`,
211+
},
212+
{
213+
code: `
214+
class App {
215+
render() {
216+
return [1, "Hello", <div />];
217+
}
218+
}
219+
`,
220+
},
221+
{
222+
code: `
223+
class App extends React.Component {
224+
render() {
225+
return [1, "Hello", <div />];
226+
}
227+
}
228+
`,
229+
},
230+
{
231+
code: `
232+
class App {
233+
render() {
234+
return null;
235+
}
236+
}
237+
`,
238+
},
239+
{
240+
code: `
241+
class App extends React.Component {
242+
render() {
243+
return null;
244+
}
245+
}
246+
`,
247+
},
128248
]),
249+
250+
// Invalid Cases
129251
invalid: parsers.all([
130252
{
131253
code: `
@@ -235,7 +357,6 @@ ruleTester.run('no-render-return-undefined', rule, {
235357
{
236358
code: `
237359
function foo() {}
238-
239360
function App() {
240361
return foo();
241362
}
@@ -286,5 +407,112 @@ ruleTester.run('no-render-return-undefined', rule, {
286407
`,
287408
errors: [{ messageId: 'returnsUndefined' }],
288409
},
410+
// Class Components
411+
{
412+
code: `
413+
class App {
414+
render() {
415+
}
416+
}
417+
`,
418+
errors: [{ messageId: 'returnsUndefined' }],
419+
},
420+
{
421+
code: `
422+
class App extends React.Component {
423+
render() {
424+
}
425+
}
426+
`,
427+
errors: [{ messageId: 'returnsUndefined' }],
428+
},
429+
{
430+
code: `
431+
const App = class {
432+
render() {}
433+
}
434+
`,
435+
errors: [{ messageId: 'returnsUndefined' }],
436+
},
437+
{
438+
code: `
439+
class App {
440+
render() {
441+
return;
442+
}
443+
}
444+
`,
445+
errors: [{ messageId: 'returnsUndefined' }],
446+
},
447+
{
448+
code: `
449+
class App extends React.Component {
450+
render() {
451+
return;
452+
}
453+
}
454+
`,
455+
errors: [{ messageId: 'returnsUndefined' }],
456+
},
457+
{
458+
code: `
459+
class App {
460+
render() {
461+
return undefined;
462+
}
463+
}
464+
`,
465+
errors: [{ messageId: 'returnsUndefined' }],
466+
},
467+
{
468+
code: `
469+
class App extends React.Component {
470+
render() {
471+
return undefined;
472+
}
473+
}
474+
`,
475+
errors: [{ messageId: 'returnsUndefined' }],
476+
},
477+
{
478+
code: `
479+
class App {
480+
render() {
481+
return [undefined];
482+
}
483+
}
484+
`,
485+
errors: [{ messageId: 'returnsUndefined' }],
486+
},
487+
{
488+
code: `
489+
class App extends React.Component {
490+
render() {
491+
return [undefined];
492+
}
493+
}
494+
`,
495+
errors: [{ messageId: 'returnsUndefined' }],
496+
},
497+
{
498+
code: `
499+
class App {
500+
render() {
501+
return [1, undefined];
502+
}
503+
}
504+
`,
505+
errors: [{ messageId: 'returnsUndefined' }],
506+
},
507+
{
508+
code: `
509+
class App extends React.Component {
510+
render() {
511+
return [1, undefined];
512+
}
513+
}
514+
`,
515+
errors: [{ messageId: 'returnsUndefined' }],
516+
},
289517
]),
290518
});

0 commit comments

Comments
 (0)