From 2f679bb0280abfc99c88b1f5f83a8ef7515a1c1d Mon Sep 17 00:00:00 2001 From: yassin-kammoun-sonarsource Date: Wed, 23 Mar 2022 10:02:34 +0100 Subject: [PATCH] Add suggestion for 'prefer-single-boolean-return' --- README.md | 2 +- docs/rules/prefer-single-boolean-return.md | 2 + src/rules/prefer-single-boolean-return.ts | 23 ++++++++ .../prefer-single-boolean-return.test.ts | 59 +++++++++++++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 48013251..d81c03b0 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Code Smells, or maintainability issues, are raised for places of code which migh * "catch" clauses should do more than rethrow ([`no-useless-catch`]) * Local variables should not be declared and then immediately returned or thrown ([`prefer-immediate-return`]) (:wrench: *fixable*) * Object literal syntax should be used ([`prefer-object-literal`]) -* Return of boolean expressions should not be wrapped into an "if-then-else" statement ([`prefer-single-boolean-return`]) +* Return of boolean expressions should not be wrapped into an "if-then-else" statement ([`prefer-single-boolean-return`]) (:wrench: *fixable*) * A "while" loop should be used instead of a "for" loop ([`prefer-while`]) (:wrench: *fixable*) [`cognitive-complexity`]: ./docs/rules/cognitive-complexity.md diff --git a/docs/rules/prefer-single-boolean-return.md b/docs/rules/prefer-single-boolean-return.md index 8848f27c..786bebd6 100644 --- a/docs/rules/prefer-single-boolean-return.md +++ b/docs/rules/prefer-single-boolean-return.md @@ -1,5 +1,7 @@ # prefer-single-boolean-return +:wrench: *fixable* + Return of boolean literal statements wrapped into `if-then-else` flow should be simplified. ## Noncompliant Code Example diff --git a/src/rules/prefer-single-boolean-return.ts b/src/rules/prefer-single-boolean-return.ts index 9c8128e9..7a7a5062 100644 --- a/src/rules/prefer-single-boolean-return.ts +++ b/src/rules/prefer-single-boolean-return.ts @@ -31,9 +31,11 @@ const rule: TSESLint.RuleModule = { meta: { messages: { replaceIfThenElseByReturn: 'Replace this if-then-else flow by a single return statement.', + suggestIfThenElseReplacement: 'Replace with single return statement', }, schema: [], type: 'suggestion', + hasSuggestions: true, docs: { description: 'Return of boolean expressions should not be wrapped into an "if-then-else" statement', @@ -53,6 +55,7 @@ const rule: TSESLint.RuleModule = { context.report({ messageId: 'replaceIfThenElseByReturn', node, + suggest: getSuggestion(node), }); } }, @@ -91,6 +94,26 @@ const rule: TSESLint.RuleModule = { // `statement.argument` can be `null`, replace it with `undefined` in this case return isReturnStatement(statement) && isBooleanLiteral(statement.argument || undefined); } + + function getSuggestion(ifStmt: TSESTree.IfStatement): TSESLint.ReportSuggestionArray { + return [ + { + messageId: 'suggestIfThenElseReplacement', + fix: fixer => { + const singleReturn = `return ${context.getSourceCode().getText(ifStmt.test)};`; + if (ifStmt.alternate) { + return fixer.replaceText(ifStmt, singleReturn); + } else { + const parent = ifStmt.parent as TSESTree.BlockStatement; + const ifStmtIndex = parent.body.findIndex(stmt => stmt === ifStmt); + const returnStmt = parent.body[ifStmtIndex + 1]; + const range: [number, number] = [ifStmt.range[0], returnStmt.range[1]]; + return fixer.replaceTextRange(range, singleReturn); + } + }, + }, + ]; + } }, }; diff --git a/tests/rules/prefer-single-boolean-return.test.ts b/tests/rules/prefer-single-boolean-return.test.ts index d661016d..c6b7aa60 100644 --- a/tests/rules/prefer-single-boolean-return.test.ts +++ b/tests/rules/prefer-single-boolean-return.test.ts @@ -227,5 +227,64 @@ ruleTester.run('prefer-single-boolean-return', rule, { }, ], }, + { + code: ` +function foo() { + if (bar()) { + if (baz()) { + return true; + } else { + return false; + } + } + return qux(); +}`, + errors: [ + { + messageId: 'replaceIfThenElseByReturn', + suggestions: [ + { + messageId: 'suggestIfThenElseReplacement', + output: ` +function foo() { + if (bar()) { + return baz(); + } + return qux(); +}`, + }, + ], + }, + ], + }, + { + code: ` +function foo() { + if (bar()) { + if (baz()) { + return true; + } + return false; + } + return qux(); +}`, + errors: [ + { + messageId: 'replaceIfThenElseByReturn', + suggestions: [ + { + messageId: 'suggestIfThenElseReplacement', + output: ` +function foo() { + if (bar()) { + return baz(); + } + return qux(); +}`, + }, + ], + }, + ], + }, ], });