|                                                                                                                                                     |  | /** * @fileoverview Rule to disallow unnecessary labels * @author Toru Nagashima */
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../shared/types').Rule} */module.exports = {    meta: {        type: "suggestion",
        docs: {            description: "Disallow unnecessary labels",            recommended: false,            url: "https://eslint.org/docs/latest/rules/no-extra-label"        },
        schema: [],        fixable: "code",
        messages: {            unexpected: "This label '{{name}}' is unnecessary."        }    },
    create(context) {        const sourceCode = context.sourceCode;        let scopeInfo = null;
        /**         * Creates a new scope with a breakable statement.         * @param {ASTNode} node A node to create. This is a BreakableStatement.         * @returns {void}         */        function enterBreakableStatement(node) {            scopeInfo = {                label: node.parent.type === "LabeledStatement" ? node.parent.label : null,                breakable: true,                upper: scopeInfo            };        }
        /**         * Removes the top scope of the stack.         * @returns {void}         */        function exitBreakableStatement() {            scopeInfo = scopeInfo.upper;        }
        /**         * Creates a new scope with a labeled statement.         *         * This ignores it if the body is a breakable statement.         * In this case it's handled in the `enterBreakableStatement` function.         * @param {ASTNode} node A node to create. This is a LabeledStatement.         * @returns {void}         */        function enterLabeledStatement(node) {            if (!astUtils.isBreakableStatement(node.body)) {                scopeInfo = {                    label: node.label,                    breakable: false,                    upper: scopeInfo                };            }        }
        /**         * Removes the top scope of the stack.         *         * This ignores it if the body is a breakable statement.         * In this case it's handled in the `exitBreakableStatement` function.         * @param {ASTNode} node A node. This is a LabeledStatement.         * @returns {void}         */        function exitLabeledStatement(node) {            if (!astUtils.isBreakableStatement(node.body)) {                scopeInfo = scopeInfo.upper;            }        }
        /**         * Reports a given control node if it's unnecessary.         * @param {ASTNode} node A node. This is a BreakStatement or a         *      ContinueStatement.         * @returns {void}         */        function reportIfUnnecessary(node) {            if (!node.label) {                return;            }
            const labelNode = node.label;
            for (let info = scopeInfo; info !== null; info = info.upper) {                if (info.breakable || info.label && info.label.name === labelNode.name) {                    if (info.breakable && info.label && info.label.name === labelNode.name) {                        context.report({                            node: labelNode,                            messageId: "unexpected",                            data: labelNode,                            fix(fixer) {                                const breakOrContinueToken = sourceCode.getFirstToken(node);
                                if (sourceCode.commentsExistBetween(breakOrContinueToken, labelNode)) {                                    return null;                                }
                                return fixer.removeRange([breakOrContinueToken.range[1], labelNode.range[1]]);                            }                        });                    }                    return;                }            }        }
        return {            WhileStatement: enterBreakableStatement,            "WhileStatement:exit": exitBreakableStatement,            DoWhileStatement: enterBreakableStatement,            "DoWhileStatement:exit": exitBreakableStatement,            ForStatement: enterBreakableStatement,            "ForStatement:exit": exitBreakableStatement,            ForInStatement: enterBreakableStatement,            "ForInStatement:exit": exitBreakableStatement,            ForOfStatement: enterBreakableStatement,            "ForOfStatement:exit": exitBreakableStatement,            SwitchStatement: enterBreakableStatement,            "SwitchStatement:exit": exitBreakableStatement,            LabeledStatement: enterLabeledStatement,            "LabeledStatement:exit": exitLabeledStatement,            BreakStatement: reportIfUnnecessary,            ContinueStatement: reportIfUnnecessary        };    }};
 |