Skip to content

Commit

Permalink
Support switch statements in no-conditional-returns
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanberckmans committed Oct 13, 2023
1 parent 34c8179 commit e58481d
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
26 changes: 26 additions & 0 deletions packages/react-app/eslint-rules/no-conditional-returns.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@

// NB see noConditionalReturnsTestCases.ts

// This no-conditional-returns eslint rule ensures that if any branch of an
// if-statement or try/catch might return, then the whole statement always
// returns or throws, and control flow never continues in the same
Expand All @@ -16,6 +19,10 @@ module.exports = {
const ifHasReturn = hasAnyReturn(node.consequent);
const elseHasReturn = node.alternate && hasAnyReturn(node.alternate);
return ifHasReturn || elseHasReturn;
} else if (node.type === 'SwitchStatement') {
return node.cases.some((caseNode) => caseNode.consequent.some(hasAnyReturn));
} else if (node.type === 'SwitchCase') {
return node.consequent.some(hasAnyReturn);
} else if (node.type === 'TryStatement') {
const blockHasReturn = hasAnyReturn(node.block);
const handlerHasReturn = node.handler && hasAnyReturn(node.handler.body);
Expand All @@ -34,6 +41,10 @@ module.exports = {
const ifReturnsOrThrows = returnsOrThrowsUnconditionally(node.consequent);
const elseReturnsOrThrows = node.alternate && returnsOrThrowsUnconditionally(node.alternate);
return ifReturnsOrThrows && (elseReturnsOrThrows || node.alternate === null);
} else if (node.type === 'SwitchStatement') {
return node.cases.every((caseNode) => caseNode.consequent.some(returnsOrThrowsUnconditionally));
} else if (node.type === 'SwitchCase') {
return node.consequent.some(returnsOrThrowsUnconditionally);
} else if (node.type === 'TryStatement') {
const blockReturnsOrThrows = returnsOrThrowsUnconditionally(node.block);
const handlerReturnsOrThrows = node.handler && returnsOrThrowsUnconditionally(node.handler.body);
Expand Down Expand Up @@ -66,6 +77,20 @@ module.exports = {
}
}

function checkSwitchStatement(switchStatement) {
if (switchStatement.cases.length < 1) return;

const anyCaseHasAnyReturn = switchStatement.cases.some(caseNode => hasAnyReturn(caseNode));
const allCasesReturnOrThrowUnconditionally = switchStatement.cases.every(caseNode => returnsOrThrowsUnconditionally(caseNode));

if (anyCaseHasAnyReturn && !allCasesReturnOrThrowUnconditionally) {
context.report({
node: switchStatement,
message: 'Expected all cases in the "switch" statement to unconditionally return or throw when any case has a return.',
});
}
}

function checkTryCatch(tryStatement) {
const blockHasAnyReturn = hasAnyReturn(tryStatement.block);
const handlerExistsAndHasAnyReturn = tryStatement.handler && hasAnyReturn(tryStatement.handler.body);
Expand All @@ -88,6 +113,7 @@ module.exports = {

return {
IfStatement: checkConditional,
SwitchStatement: checkSwitchStatement,
TryStatement: checkTryCatch,
};
},
Expand Down
43 changes: 43 additions & 0 deletions packages/react-app/src/noConditionalReturnsTestCases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,22 @@
// }
// }

// export function testNonViolation26(s: 1 | 2 | 3): number {
// if (s === 1) return 5;
// else switch (s) {
// case 2: return 5;
// case 3: return 8;
// }
// }

// export function testNonViolation27(s: 1 | 2 | 3): number {
// switch (s) {
// case 1: if (s === 1) return 5; else return 9;
// case 2: return 5;
// case 3: return 8;
// }
// }

// // ********************************************************
// // no-conditional-returns: examples of rule violations

Expand Down Expand Up @@ -389,3 +405,30 @@
// }
// return 13;
// }

// export function testViolation18(s: 1 | 2 | 3): number {
// if (s === 1) return 5;
// else switch (s) {
// case 2: return 5;
// case 3: console.log("hi");
// }
// return 8;
// }

// export function testViolation19(s: 1 | 2 | 3): number {
// switch (s) {
// case 1: if (s === 1) return 5; else return 9;
// case 2: console.log("hey"); break;
// case 3: return 8;
// }
// return 5;
// }

// export function testViolation20(s: 1 | 2 | 3): number {
// switch (s) {
// case 1: if (s === 1) return; else console.log('hi'); break;
// case 2: return 4;
// case 3: return 8;
// }
// return 8;
// }

0 comments on commit e58481d

Please sign in to comment.