/**
							 | 
						|
								 * @fileoverview Rule to flag fall-through cases in switch statements.
							 | 
						|
								 * @author Matt DuVall <http://mattduvall.com/>
							 | 
						|
								 */
							 | 
						|
								"use strict";
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								// Requirements
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								const { directivesPattern } = require("../shared/directives");
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								// Helpers
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								const DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/iu;
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Checks all segments in a set and returns true if any are reachable.
							 | 
						|
								 * @param {Set<CodePathSegment>} segments The segments to check.
							 | 
						|
								 * @returns {boolean} True if any segment is reachable; false otherwise.
							 | 
						|
								 */
							 | 
						|
								function isAnySegmentReachable(segments) {
							 | 
						|
								
							 | 
						|
								    for (const segment of segments) {
							 | 
						|
								        if (segment.reachable) {
							 | 
						|
								            return true;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return false;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Checks whether or not a given comment string is really a fallthrough comment and not an ESLint directive.
							 | 
						|
								 * @param {string} comment The comment string to check.
							 | 
						|
								 * @param {RegExp} fallthroughCommentPattern The regular expression used for checking for fallthrough comments.
							 | 
						|
								 * @returns {boolean} `true` if the comment string is truly a fallthrough comment.
							 | 
						|
								 */
							 | 
						|
								function isFallThroughComment(comment, fallthroughCommentPattern) {
							 | 
						|
								    return fallthroughCommentPattern.test(comment) && !directivesPattern.test(comment.trim());
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Checks whether or not a given case has a fallthrough comment.
							 | 
						|
								 * @param {ASTNode} caseWhichFallsThrough SwitchCase node which falls through.
							 | 
						|
								 * @param {ASTNode} subsequentCase The case after caseWhichFallsThrough.
							 | 
						|
								 * @param {RuleContext} context A rule context which stores comments.
							 | 
						|
								 * @param {RegExp} fallthroughCommentPattern A pattern to match comment to.
							 | 
						|
								 * @returns {boolean} `true` if the case has a valid fallthrough comment.
							 | 
						|
								 */
							 | 
						|
								function hasFallthroughComment(caseWhichFallsThrough, subsequentCase, context, fallthroughCommentPattern) {
							 | 
						|
								    const sourceCode = context.sourceCode;
							 | 
						|
								
							 | 
						|
								    if (caseWhichFallsThrough.consequent.length === 1 && caseWhichFallsThrough.consequent[0].type === "BlockStatement") {
							 | 
						|
								        const trailingCloseBrace = sourceCode.getLastToken(caseWhichFallsThrough.consequent[0]);
							 | 
						|
								        const commentInBlock = sourceCode.getCommentsBefore(trailingCloseBrace).pop();
							 | 
						|
								
							 | 
						|
								        if (commentInBlock && isFallThroughComment(commentInBlock.value, fallthroughCommentPattern)) {
							 | 
						|
								            return true;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    const comment = sourceCode.getCommentsBefore(subsequentCase).pop();
							 | 
						|
								
							 | 
						|
								    return Boolean(comment && isFallThroughComment(comment.value, fallthroughCommentPattern));
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Checks whether a node and a token are separated by blank lines
							 | 
						|
								 * @param {ASTNode} node The node to check
							 | 
						|
								 * @param {Token} token The token to compare against
							 | 
						|
								 * @returns {boolean} `true` if there are blank lines between node and token
							 | 
						|
								 */
							 | 
						|
								function hasBlankLinesBetween(node, token) {
							 | 
						|
								    return token.loc.start.line > node.loc.end.line + 1;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								// Rule Definition
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								/** @type {import('../shared/types').Rule} */
							 | 
						|
								module.exports = {
							 | 
						|
								    meta: {
							 | 
						|
								        type: "problem",
							 | 
						|
								
							 | 
						|
								        docs: {
							 | 
						|
								            description: "Disallow fallthrough of `case` statements",
							 | 
						|
								            recommended: true,
							 | 
						|
								            url: "https://eslint.org/docs/latest/rules/no-fallthrough"
							 | 
						|
								        },
							 | 
						|
								
							 | 
						|
								        schema: [
							 | 
						|
								            {
							 | 
						|
								                type: "object",
							 | 
						|
								                properties: {
							 | 
						|
								                    commentPattern: {
							 | 
						|
								                        type: "string",
							 | 
						|
								                        default: ""
							 | 
						|
								                    },
							 | 
						|
								                    allowEmptyCase: {
							 | 
						|
								                        type: "boolean",
							 | 
						|
								                        default: false
							 | 
						|
								                    }
							 | 
						|
								                },
							 | 
						|
								                additionalProperties: false
							 | 
						|
								            }
							 | 
						|
								        ],
							 | 
						|
								        messages: {
							 | 
						|
								            case: "Expected a 'break' statement before 'case'.",
							 | 
						|
								            default: "Expected a 'break' statement before 'default'."
							 | 
						|
								        }
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    create(context) {
							 | 
						|
								        const options = context.options[0] || {};
							 | 
						|
								        const codePathSegments = [];
							 | 
						|
								        let currentCodePathSegments = new Set();
							 | 
						|
								        const sourceCode = context.sourceCode;
							 | 
						|
								        const allowEmptyCase = options.allowEmptyCase || false;
							 | 
						|
								
							 | 
						|
								        /*
							 | 
						|
								         * We need to use leading comments of the next SwitchCase node because
							 | 
						|
								         * trailing comments is wrong if semicolons are omitted.
							 | 
						|
								         */
							 | 
						|
								        let fallthroughCase = null;
							 | 
						|
								        let fallthroughCommentPattern = null;
							 | 
						|
								
							 | 
						|
								        if (options.commentPattern) {
							 | 
						|
								            fallthroughCommentPattern = new RegExp(options.commentPattern, "u");
							 | 
						|
								        } else {
							 | 
						|
								            fallthroughCommentPattern = DEFAULT_FALLTHROUGH_COMMENT;
							 | 
						|
								        }
							 | 
						|
								        return {
							 | 
						|
								
							 | 
						|
								            onCodePathStart() {
							 | 
						|
								                codePathSegments.push(currentCodePathSegments);
							 | 
						|
								                currentCodePathSegments = new Set();
							 | 
						|
								            },
							 | 
						|
								
							 | 
						|
								            onCodePathEnd() {
							 | 
						|
								                currentCodePathSegments = codePathSegments.pop();
							 | 
						|
								            },
							 | 
						|
								
							 | 
						|
								            onUnreachableCodePathSegmentStart(segment) {
							 | 
						|
								                currentCodePathSegments.add(segment);
							 | 
						|
								            },
							 | 
						|
								
							 | 
						|
								            onUnreachableCodePathSegmentEnd(segment) {
							 | 
						|
								                currentCodePathSegments.delete(segment);
							 | 
						|
								            },
							 | 
						|
								
							 | 
						|
								            onCodePathSegmentStart(segment) {
							 | 
						|
								                currentCodePathSegments.add(segment);
							 | 
						|
								            },
							 | 
						|
								
							 | 
						|
								            onCodePathSegmentEnd(segment) {
							 | 
						|
								                currentCodePathSegments.delete(segment);
							 | 
						|
								            },
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								            SwitchCase(node) {
							 | 
						|
								
							 | 
						|
								                /*
							 | 
						|
								                 * 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))) {
							 | 
						|
								                    context.report({
							 | 
						|
								                        messageId: node.test ? "case" : "default",
							 | 
						|
								                        node
							 | 
						|
								                    });
							 | 
						|
								                }
							 | 
						|
								                fallthroughCase = null;
							 | 
						|
								            },
							 | 
						|
								
							 | 
						|
								            "SwitchCase:exit"(node) {
							 | 
						|
								                const nextToken = sourceCode.getTokenAfter(node);
							 | 
						|
								
							 | 
						|
								                /*
							 | 
						|
								                 * `reachable` meant fall through because statements preceded by
							 | 
						|
								                 * `break`, `return`, or `throw` are unreachable.
							 | 
						|
								                 * And allows empty cases and the last case.
							 | 
						|
								                 */
							 | 
						|
								                if (isAnySegmentReachable(currentCodePathSegments) &&
							 | 
						|
								                    (node.consequent.length > 0 || (!allowEmptyCase && hasBlankLinesBetween(node, nextToken))) &&
							 | 
						|
								                    node.parent.cases[node.parent.cases.length - 1] !== node) {
							 | 
						|
								                    fallthroughCase = node;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        };
							 | 
						|
								    }
							 | 
						|
								};
							 |