UNPKG

3.08 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to flag fall-through cases in switch statements.
3 * @author Matt DuVall <http://mattduvall.com/>
4 */
5"use strict";
6
7//------------------------------------------------------------------------------
8// Requirements
9//------------------------------------------------------------------------------
10
11var getLast = require("../util").getLast;
12
13//------------------------------------------------------------------------------
14// Helpers
15//------------------------------------------------------------------------------
16
17var FALLTHROUGH_COMMENT = /falls?\s?through/i;
18
19/**
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 * @returns {boolean} `true` if the node has a fallthrough comment.
24 */
25function hasFallthroughComment(node, context) {
26 var sourceCode = context.getSourceCode();
27 var comment = getLast(sourceCode.getComments(node).leading);
28
29 return Boolean(comment && FALLTHROUGH_COMMENT.test(comment.value));
30}
31
32/**
33 * Checks whether or not a given code path segment is reachable.
34 * @param {CodePathSegment} segment - A CodePathSegment to check.
35 * @returns {boolean} `true` if the segment is reachable.
36 */
37function isReachable(segment) {
38 return segment.reachable;
39}
40
41//------------------------------------------------------------------------------
42// Rule Definition
43//------------------------------------------------------------------------------
44
45module.exports = function(context) {
46 var currentCodePath = null;
47
48 // We need to use leading comments of the next SwitchCase node because
49 // trailing comments is wrong if semicolons are omitted.
50 var fallthroughCase = null;
51
52 return {
53 "onCodePathStart": function(codePath) {
54 currentCodePath = codePath;
55 },
56 "onCodePathEnd": function() {
57 currentCodePath = currentCodePath.upper;
58 },
59
60 "SwitchCase": function(node) {
61 // Checks whether or not there is a fallthrough comment.
62 // And reports the previous fallthrough node if that does not exist.
63 if (fallthroughCase && !hasFallthroughComment(node, context)) {
64 context.report({
65 message: "Expected a 'break' statement before '{{type}}'.",
66 data: {type: node.test ? "case" : "default"},
67 node: node
68 });
69 }
70 fallthroughCase = null;
71 },
72
73 "SwitchCase:exit": function(node) {
74 // `reachable` meant fall through because statements preceded by
75 // `break`, `return`, or `throw` are unreachable.
76 // And allows empty cases and the last case.
77 if (currentCodePath.currentSegments.some(isReachable) &&
78 node.consequent.length > 0 &&
79 getLast(node.parent.cases) !== node
80 ) {
81 fallthroughCase = node;
82 }
83 }
84 };
85};
86
87module.exports.schema = [];