123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- /**
- * @fileoverview Rule to disallow unnecessary labels
- * @author Toru Nagashima
- */
- "use strict";
- //------------------------------------------------------------------------------
- // Requirements
- //------------------------------------------------------------------------------
- const astUtils = require("./utils/ast-utils");
- //------------------------------------------------------------------------------
- // Rule Definition
- //------------------------------------------------------------------------------
- module.exports = {
- meta: {
- type: "suggestion",
- docs: {
- description: "disallow unnecessary labels",
- category: "Best Practices",
- recommended: false,
- url: "https://eslint.org/docs/rules/no-extra-label"
- },
- schema: [],
- fixable: "code",
- messages: {
- unexpected: "This label '{{name}}' is unnecessary."
- }
- },
- create(context) {
- const sourceCode = context.getSourceCode();
- 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
- };
- }
- };
|