Skip to content

Commit 30d6da5

Browse files
committed
Small tweaks to components-return-once
1 parent 063e63c commit 30d6da5

File tree

2 files changed

+50
-13
lines changed

2 files changed

+50
-13
lines changed

src/rules/components-return-once.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const isNothing = (node?: T.Node): boolean => {
1515
}
1616
};
1717

18-
const getLocLength = (loc: T.SourceLocation) => loc.end.line - loc.start.line + 1;
18+
const getLineLength = (loc: T.SourceLocation) => loc.end.line - loc.start.line + 1;
1919

2020
const rule: TSESLint.RuleModule<"noEarlyReturn" | "noConditionalReturn", []> = {
2121
meta: {
@@ -48,24 +48,26 @@ const rule: TSESLint.RuleModule<"noEarlyReturn" | "noConditionalReturn", []> = {
4848
};
4949
const currentFunction = () => functionStack[functionStack.length - 1];
5050
const onFunctionEnter = (node: FunctionNode) => {
51-
const getLastReturn = () => {
52-
if (node.body.type === "BlockStatement") {
53-
const { length } = node.body.body;
54-
const last = length && node.body.body[length - 1];
55-
if (last && last.type === "ReturnStatement") {
56-
return last;
57-
}
51+
let lastReturn: T.ReturnStatement | undefined;
52+
if (node.body.type === "BlockStatement") {
53+
const { length } = node.body.body;
54+
const last = length && node.body.body[length - 1];
55+
if (last && last.type === "ReturnStatement") {
56+
lastReturn = last;
5857
}
59-
};
60-
functionStack.push({ isComponent: false, lastReturn: getLastReturn(), earlyReturns: [] });
58+
}
59+
functionStack.push({ isComponent: false, lastReturn, earlyReturns: [] });
6160
};
61+
6262
const onFunctionExit = (node: FunctionNode) => {
6363
if (
64+
(node.type === "FunctionDeclaration" && node.id?.name?.match(/^[a-z]/)) ||
6465
node.parent?.type === "JSXExpressionContainer" // "render props" aren't components
6566
) {
6667
currentFunction().isComponent = false;
6768
}
6869
if (currentFunction().isComponent) {
70+
// Warn on each early return
6971
currentFunction().earlyReturns.forEach((earlyReturn) => {
7072
context.report({
7173
node: earlyReturn,
@@ -115,7 +117,7 @@ const rule: TSESLint.RuleModule<"noEarlyReturn" | "noConditionalReturn", []> = {
115117
}
116118
if (
117119
isNothing(fallback) ||
118-
getLocLength(consequent.loc) >= getLocLength(alternate.loc) * 1.5
120+
getLineLength(consequent.loc) >= getLineLength(alternate.loc) * 1.5
119121
) {
120122
// we have a standard ternary, and the alternate is a bit shorter in LOC than the consequent, which
121123
// should be enough to tell that it's logically a fallback instead of an equal branch.

test/rules/components-return-once.test.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,28 @@ import { run } from "../ruleTester";
22
import rule from "../../src/rules/components-return-once";
33

44
export const cases = run("components-return-once", rule, {
5-
valid: [],
5+
valid: [
6+
`function Component() {
7+
return <div />;
8+
}`,
9+
`function someFunc() {
10+
if (condition) {
11+
return 5;
12+
}
13+
return 10;
14+
}`,
15+
`function notAComponent() {
16+
if (condition) {
17+
return <div />;
18+
}
19+
return <div />;
20+
}`,
21+
],
622
invalid: [
723
// Early returns
824
{
925
code: `function Component() {
10-
if (true) {
26+
if (condition) {
1127
return <div />;
1228
};
1329
return <span />;
@@ -49,6 +65,25 @@ export const cases = run("components-return-once", rule, {
4965
Big!
5066
No, really big!
5167
</div></Show>;
68+
}`,
69+
},
70+
// Switch/Match
71+
{
72+
code: `function Component(props) {
73+
return props.cond1 ? (
74+
<div>Condition 1</div>
75+
) : Boolean(props.cond2) ? (
76+
<div>Not condition 1, but condition 2</div>
77+
) : (
78+
<div>Neither condition 1 or 2</div>
79+
);
80+
}`,
81+
errors: [{ messageId: "noConditionalReturn" }],
82+
output: `function Component(props) {
83+
return <Switch fallback={<div>Neither condition 1 or 2</div>}>
84+
<Match when={props.cond1}><div>Condition 1</div></Match>
85+
<Match when={Boolean(props.cond2)}><div>Not condition 1, but condition 2</div></Match>
86+
</Switch>;
5287
}`,
5388
},
5489
],

0 commit comments

Comments
 (0)