UNPKG

3.21 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to disallow unused labels.
3 * @author Toru Nagashima
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Rule Definition
10//------------------------------------------------------------------------------
11
12module.exports = {
13 meta: {
14 docs: {
15 description: "disallow unused labels",
16 category: "Best Practices",
17 recommended: true,
18 url: "https://eslint.org/docs/rules/no-unused-labels"
19 },
20
21 schema: [],
22
23 fixable: "code"
24 },
25
26 create(context) {
27 const sourceCode = context.getSourceCode();
28 let scopeInfo = null;
29
30 /**
31 * Adds a scope info to the stack.
32 *
33 * @param {ASTNode} node - A node to add. This is a LabeledStatement.
34 * @returns {void}
35 */
36 function enterLabeledScope(node) {
37 scopeInfo = {
38 label: node.label.name,
39 used: false,
40 upper: scopeInfo
41 };
42 }
43
44 /**
45 * Removes the top of the stack.
46 * At the same time, this reports the label if it's never used.
47 *
48 * @param {ASTNode} node - A node to report. This is a LabeledStatement.
49 * @returns {void}
50 */
51 function exitLabeledScope(node) {
52 if (!scopeInfo.used) {
53 context.report({
54 node: node.label,
55 message: "'{{name}}:' is defined but never used.",
56 data: node.label,
57 fix(fixer) {
58
59 /*
60 * Only perform a fix if there are no comments between the label and the body. This will be the case
61 * when there is exactly one token/comment (the ":") between the label and the body.
62 */
63 if (sourceCode.getTokenAfter(node.label, { includeComments: true }) ===
64 sourceCode.getTokenBefore(node.body, { includeComments: true })) {
65 return fixer.removeRange([node.range[0], node.body.range[0]]);
66 }
67
68 return null;
69 }
70 });
71 }
72
73 scopeInfo = scopeInfo.upper;
74 }
75
76 /**
77 * Marks the label of a given node as used.
78 *
79 * @param {ASTNode} node - A node to mark. This is a BreakStatement or
80 * ContinueStatement.
81 * @returns {void}
82 */
83 function markAsUsed(node) {
84 if (!node.label) {
85 return;
86 }
87
88 const label = node.label.name;
89 let info = scopeInfo;
90
91 while (info) {
92 if (info.label === label) {
93 info.used = true;
94 break;
95 }
96 info = info.upper;
97 }
98 }
99
100 return {
101 LabeledStatement: enterLabeledScope,
102 "LabeledStatement:exit": exitLabeledScope,
103 BreakStatement: markAsUsed,
104 ContinueStatement: markAsUsed
105 };
106 }
107};