/** * @fileoverview Rule to flag fall-through cases in switch statements. * @author Matt DuVall */ "use strict"; var FALLTHROUGH_COMMENT = /falls\sthrough/; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { var switches = []; return { "SwitchCase": function(node) { var consequent = node.consequent, switchData = switches[switches.length - 1], i, comments, comment; /* * Some developers wrap case bodies in blocks, so if there is just one * node and it's a block statement, check inside. */ if (consequent.length === 1 && consequent[0].type === "BlockStatement") { consequent = consequent[0]; } // checking on previous case if (!switchData.lastCaseClosed) { // a fall through comment will be the last trailing comment of the last case comments = context.getComments(switchData.lastCase).trailing; comment = comments[comments.length - 1]; // unless the user doesn't like semicolons, in which case it's first leading comment of this case if (!comment) { comments = context.getComments(node).leading; comment = comments[comments.length - 1]; } // check for comment if (!comment || !FALLTHROUGH_COMMENT.test(comment.value)) { context.report(switchData.lastCase, "Expected a \"break\" statement before \"{{code}}\".", { code: node.test ? "case" : "default" }); } } // now dealing with the current case switchData.lastCaseClosed = false; switchData.lastCase = node; // try to verify using statements - go backwards as a fast path for the search if (consequent.length) { for (i = consequent.length - 1; i >= 0; i--) { if (/(?:Break|Continue|Return|Throw)Statement/.test(consequent[i].type)) { switchData.lastCaseClosed = true; break; } } } else { // the case statement has no statements, so it must logically fall through switchData.lastCaseClosed = true; } /* * Any warnings are triggered when the next SwitchCase occurs. * There is no need to warn on the last SwitchCase, since it can't * fall through to anything. */ }, "SwitchStatement": function(node) { switches.push({ node: node, lastCaseClosed: true, lastCase: null }); }, "SwitchStatement:exit": function() { switches.pop(); } }; };