]> git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-extra-label.js
import 8.3.0 source
[pve-eslint.git] / eslint / lib / rules / no-extra-label.js
1 /**
2 * @fileoverview Rule to disallow unnecessary labels
3 * @author Toru Nagashima
4 */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const astUtils = require("./utils/ast-utils");
13
14 //------------------------------------------------------------------------------
15 // Rule Definition
16 //------------------------------------------------------------------------------
17
18 module.exports = {
19 meta: {
20 type: "suggestion",
21
22 docs: {
23 description: "disallow unnecessary labels",
24 recommended: false,
25 url: "https://eslint.org/docs/rules/no-extra-label"
26 },
27
28 schema: [],
29 fixable: "code",
30
31 messages: {
32 unexpected: "This label '{{name}}' is unnecessary."
33 }
34 },
35
36 create(context) {
37 const sourceCode = context.getSourceCode();
38 let scopeInfo = null;
39
40 /**
41 * Creates a new scope with a breakable statement.
42 * @param {ASTNode} node A node to create. This is a BreakableStatement.
43 * @returns {void}
44 */
45 function enterBreakableStatement(node) {
46 scopeInfo = {
47 label: node.parent.type === "LabeledStatement" ? node.parent.label : null,
48 breakable: true,
49 upper: scopeInfo
50 };
51 }
52
53 /**
54 * Removes the top scope of the stack.
55 * @returns {void}
56 */
57 function exitBreakableStatement() {
58 scopeInfo = scopeInfo.upper;
59 }
60
61 /**
62 * Creates a new scope with a labeled statement.
63 *
64 * This ignores it if the body is a breakable statement.
65 * In this case it's handled in the `enterBreakableStatement` function.
66 * @param {ASTNode} node A node to create. This is a LabeledStatement.
67 * @returns {void}
68 */
69 function enterLabeledStatement(node) {
70 if (!astUtils.isBreakableStatement(node.body)) {
71 scopeInfo = {
72 label: node.label,
73 breakable: false,
74 upper: scopeInfo
75 };
76 }
77 }
78
79 /**
80 * Removes the top scope of the stack.
81 *
82 * This ignores it if the body is a breakable statement.
83 * In this case it's handled in the `exitBreakableStatement` function.
84 * @param {ASTNode} node A node. This is a LabeledStatement.
85 * @returns {void}
86 */
87 function exitLabeledStatement(node) {
88 if (!astUtils.isBreakableStatement(node.body)) {
89 scopeInfo = scopeInfo.upper;
90 }
91 }
92
93 /**
94 * Reports a given control node if it's unnecessary.
95 * @param {ASTNode} node A node. This is a BreakStatement or a
96 * ContinueStatement.
97 * @returns {void}
98 */
99 function reportIfUnnecessary(node) {
100 if (!node.label) {
101 return;
102 }
103
104 const labelNode = node.label;
105
106 for (let info = scopeInfo; info !== null; info = info.upper) {
107 if (info.breakable || info.label && info.label.name === labelNode.name) {
108 if (info.breakable && info.label && info.label.name === labelNode.name) {
109 context.report({
110 node: labelNode,
111 messageId: "unexpected",
112 data: labelNode,
113 fix(fixer) {
114 const breakOrContinueToken = sourceCode.getFirstToken(node);
115
116 if (sourceCode.commentsExistBetween(breakOrContinueToken, labelNode)) {
117 return null;
118 }
119
120 return fixer.removeRange([breakOrContinueToken.range[1], labelNode.range[1]]);
121 }
122 });
123 }
124 return;
125 }
126 }
127 }
128
129 return {
130 WhileStatement: enterBreakableStatement,
131 "WhileStatement:exit": exitBreakableStatement,
132 DoWhileStatement: enterBreakableStatement,
133 "DoWhileStatement:exit": exitBreakableStatement,
134 ForStatement: enterBreakableStatement,
135 "ForStatement:exit": exitBreakableStatement,
136 ForInStatement: enterBreakableStatement,
137 "ForInStatement:exit": exitBreakableStatement,
138 ForOfStatement: enterBreakableStatement,
139 "ForOfStatement:exit": exitBreakableStatement,
140 SwitchStatement: enterBreakableStatement,
141 "SwitchStatement:exit": exitBreakableStatement,
142 LabeledStatement: enterLabeledStatement,
143 "LabeledStatement:exit": exitLabeledStatement,
144 BreakStatement: reportIfUnnecessary,
145 ContinueStatement: reportIfUnnecessary
146 };
147 }
148 };