2 * @fileoverview Rule to flag fall-through cases in switch statements.
3 * @author Matt DuVall <http://mattduvall.com/>
7 //------------------------------------------------------------------------------
9 //------------------------------------------------------------------------------
11 const lodash = require("lodash");
13 //------------------------------------------------------------------------------
15 //------------------------------------------------------------------------------
17 const DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/iu;
20 * Checks whether or not a given node has a fallthrough comment.
21 * @param {ASTNode} node A SwitchCase node to get comments.
22 * @param {RuleContext} context A rule context which stores comments.
23 * @param {RegExp} fallthroughCommentPattern A pattern to match comment to.
24 * @returns {boolean} `true` if the node has a valid fallthrough comment.
26 function hasFallthroughComment(node, context, fallthroughCommentPattern) {
27 const sourceCode = context.getSourceCode();
28 const comment = lodash.last(sourceCode.getCommentsBefore(node));
30 return Boolean(comment && fallthroughCommentPattern.test(comment.value));
34 * Checks whether or not a given code path segment is reachable.
35 * @param {CodePathSegment} segment A CodePathSegment to check.
36 * @returns {boolean} `true` if the segment is reachable.
38 function isReachable(segment) {
39 return segment.reachable;
43 * Checks whether a node and a token are separated by blank lines
44 * @param {ASTNode} node The node to check
45 * @param {Token} token The token to compare against
46 * @returns {boolean} `true` if there are blank lines between node and token
48 function hasBlankLinesBetween(node, token) {
49 return token.loc.start.line > node.loc.end.line + 1;
52 //------------------------------------------------------------------------------
54 //------------------------------------------------------------------------------
61 description: "disallow fallthrough of `case` statements",
62 category: "Best Practices",
64 url: "https://eslint.org/docs/rules/no-fallthrough"
76 additionalProperties: false
80 case: "Expected a 'break' statement before 'case'.",
81 default: "Expected a 'break' statement before 'default'."
86 const options = context.options[0] || {};
87 let currentCodePath = null;
88 const sourceCode = context.getSourceCode();
91 * We need to use leading comments of the next SwitchCase node because
92 * trailing comments is wrong if semicolons are omitted.
94 let fallthroughCase = null;
95 let fallthroughCommentPattern = null;
97 if (options.commentPattern) {
98 fallthroughCommentPattern = new RegExp(options.commentPattern, "u");
100 fallthroughCommentPattern = DEFAULT_FALLTHROUGH_COMMENT;
104 onCodePathStart(codePath) {
105 currentCodePath = codePath;
108 currentCodePath = currentCodePath.upper;
114 * Checks whether or not there is a fallthrough comment.
115 * And reports the previous fallthrough node if that does not exist.
117 if (fallthroughCase && !hasFallthroughComment(node, context, fallthroughCommentPattern)) {
119 messageId: node.test ? "case" : "default",
123 fallthroughCase = null;
126 "SwitchCase:exit"(node) {
127 const nextToken = sourceCode.getTokenAfter(node);
130 * `reachable` meant fall through because statements preceded by
131 * `break`, `return`, or `throw` are unreachable.
132 * And allows empty cases and the last case.
134 if (currentCodePath.currentSegments.some(isReachable) &&
135 (node.consequent.length > 0 || hasBlankLinesBetween(node, nextToken)) &&
136 lodash.last(node.parent.cases) !== node) {
137 fallthroughCase = node;