From 30b1a2dac9060673101485841c4c7521675bf917 Mon Sep 17 00:00:00 2001 From: Amaresh S M Date: Fri, 26 Aug 2022 23:28:56 +0530 Subject: [PATCH] feat: add `allowEmptyCase` option to no-fallthrough rule (#15887) * feat: allow empty case in switch * feat: add test case with semicolon * docs:add allow emtpy case option in docs * feat: disallow switch case with ; * feat: disallow empty statement * chore: lint .md file * remove redundant logic --- docs/src/rules/no-fallthrough.md | 33 +++++++++++- lib/rules/no-fallthrough.js | 11 ++-- tests/lib/rules/no-fallthrough.js | 83 +++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 5 deletions(-) diff --git a/docs/src/rules/no-fallthrough.md b/docs/src/rules/no-fallthrough.md index bb97a402954..7986b8109d0 100644 --- a/docs/src/rules/no-fallthrough.md +++ b/docs/src/rules/no-fallthrough.md @@ -168,9 +168,11 @@ Note that the last `case` statement in these examples does not cause a warning b ## Options -This rule accepts a single options argument: +This rule has an object option: -* Set the `commentPattern` option to a regular expression string to change the test for intentional fallthrough comment +* Set the `commentPattern` option to a regular expression string to change the test for intentional fallthrough comment. + +* Set the `allowEmptyCase` option to `true` to allow empty cases regardless of the layout. By default, this rule does not require a fallthrough comment after an empty `case` only if the empty `case` and the next `case` are on the same line or on consecutive lines. ### commentPattern @@ -202,6 +204,33 @@ switch(foo) { ::: +### allowEmptyCase + +Examples of **correct** code for the `{ "allowEmptyCase": true }` option: + +::: correct + +```js +/* eslint no-fallthrough: ["error", { "allowEmptyCase": true }] */ + +switch(foo){ + case 1: + + case 2: doSomething(); +} + +switch(foo){ + case 1: + /* + Put a message here + */ + case 2: doSomething(); +} + +``` + +::: + ## When Not To Use It If you don't want to enforce that each `case` statement should end with a `throw`, `return`, `break`, or comment, then you can safely turn this rule off. diff --git a/lib/rules/no-fallthrough.js b/lib/rules/no-fallthrough.js index b51faa87bae..536aa213f8a 100644 --- a/lib/rules/no-fallthrough.js +++ b/lib/rules/no-fallthrough.js @@ -76,6 +76,10 @@ module.exports = { commentPattern: { type: "string", default: "" + }, + allowEmptyCase: { + type: "boolean", + default: false } }, additionalProperties: false @@ -91,6 +95,7 @@ module.exports = { const options = context.options[0] || {}; let currentCodePath = null; const sourceCode = context.getSourceCode(); + const allowEmptyCase = options.allowEmptyCase || false; /* * We need to use leading comments of the next SwitchCase node because @@ -104,7 +109,6 @@ module.exports = { } else { fallthroughCommentPattern = DEFAULT_FALLTHROUGH_COMMENT; } - return { onCodePathStart(codePath) { currentCodePath = codePath; @@ -119,7 +123,8 @@ module.exports = { * Checks whether or not there is a fallthrough comment. * And reports the previous fallthrough node if that does not exist. */ - if (fallthroughCase && !hasFallthroughComment(fallthroughCase, node, context, fallthroughCommentPattern)) { + + if (fallthroughCase && (!hasFallthroughComment(fallthroughCase, node, context, fallthroughCommentPattern))) { context.report({ messageId: node.test ? "case" : "default", node @@ -137,7 +142,7 @@ module.exports = { * And allows empty cases and the last case. */ if (currentCodePath.currentSegments.some(isReachable) && - (node.consequent.length > 0 || hasBlankLinesBetween(node, nextToken)) && + (node.consequent.length > 0 || (!allowEmptyCase && hasBlankLinesBetween(node, nextToken))) && node.parent.cases[node.parent.cases.length - 1] !== node) { fallthroughCase = node; } diff --git a/tests/lib/rules/no-fallthrough.js b/tests/lib/rules/no-fallthrough.js index 0b98d3293e9..d6f6c6f93f2 100644 --- a/tests/lib/rules/no-fallthrough.js +++ b/tests/lib/rules/no-fallthrough.js @@ -92,6 +92,22 @@ ruleTester.run("no-fallthrough", rule, { options: [{ commentPattern: "break[\\s\\w]+omitted" }] + }, + { + code: "switch(foo) { case 0: \n\n\n case 1: b(); }", + options: [{ allowEmptyCase: true }] + }, + { + code: "switch(foo) { case 0: \n /* with comments */ \n case 1: b(); }", + options: [{ allowEmptyCase: true }] + }, + { + code: "switch (a) {\n case 1: ; break; \n case 3: }", + options: [{ allowEmptyCase: true }] + }, + { + code: "switch (a) {\n case 1: ; break; \n case 3: }", + options: [{ allowEmptyCase: false }] } ], invalid: [ @@ -214,6 +230,73 @@ ruleTester.run("no-fallthrough", rule, { column: 1 } ] + }, + { + code: "switch(foo) { case 0: \n /* with comments */ \ncase 1: b(); }", + errors: [ + { + messageId: "case", + type: "SwitchCase", + line: 3, + column: 1 + } + ] + }, + { + code: "switch(foo) { case 0:\n\ncase 1: b(); }", + options: [{ + allowEmptyCase: false + }], + errors: [ + { + messageId: "case", + type: "SwitchCase", + line: 3, + column: 1 + } + ] + }, + { + code: "switch(foo) { case 0:\n\ncase 1: b(); }", + options: [{}], + errors: [ + { + messageId: "case", + type: "SwitchCase", + line: 3, + column: 1 + } + ] + }, + { + code: "switch (a) { case 1: \n ; case 2: }", + options: [{ allowEmptyCase: false }], + errors: [ + { + messageId: "case", + type: "SwitchCase", + line: 2, + column: 4 + } + ] + }, + { + code: "switch (a) { case 1: ; case 2: ; case 3: }", + options: [{ allowEmptyCase: true }], + errors: [ + { + messageId: "case", + type: "SwitchCase", + line: 1, + column: 24 + }, + { + messageId: "case", + type: "SwitchCase", + line: 1, + column: 34 + } + ] } ] });