]> git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-labels.js
import 8.3.0 source
[pve-eslint.git] / eslint / lib / rules / no-labels.js
1 /**
2 * @fileoverview Disallow Labeled Statements
3 * @author Nicholas C. Zakas
4 */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Requirements
9 //------------------------------------------------------------------------------
10
11 const astUtils = require("./utils/ast-utils");
12
13 //------------------------------------------------------------------------------
14 // Rule Definition
15 //------------------------------------------------------------------------------
16
17 module.exports = {
18 meta: {
19 type: "suggestion",
20
21 docs: {
22 description: "disallow labeled statements",
23 recommended: false,
24 url: "https://eslint.org/docs/rules/no-labels"
25 },
26
27 schema: [
28 {
29 type: "object",
30 properties: {
31 allowLoop: {
32 type: "boolean",
33 default: false
34 },
35 allowSwitch: {
36 type: "boolean",
37 default: false
38 }
39 },
40 additionalProperties: false
41 }
42 ],
43
44 messages: {
45 unexpectedLabel: "Unexpected labeled statement.",
46 unexpectedLabelInBreak: "Unexpected label in break statement.",
47 unexpectedLabelInContinue: "Unexpected label in continue statement."
48 }
49 },
50
51 create(context) {
52 const options = context.options[0];
53 const allowLoop = options && options.allowLoop;
54 const allowSwitch = options && options.allowSwitch;
55 let scopeInfo = null;
56
57 /**
58 * Gets the kind of a given node.
59 * @param {ASTNode} node A node to get.
60 * @returns {string} The kind of the node.
61 */
62 function getBodyKind(node) {
63 if (astUtils.isLoop(node)) {
64 return "loop";
65 }
66 if (node.type === "SwitchStatement") {
67 return "switch";
68 }
69 return "other";
70 }
71
72 /**
73 * Checks whether the label of a given kind is allowed or not.
74 * @param {string} kind A kind to check.
75 * @returns {boolean} `true` if the kind is allowed.
76 */
77 function isAllowed(kind) {
78 switch (kind) {
79 case "loop": return allowLoop;
80 case "switch": return allowSwitch;
81 default: return false;
82 }
83 }
84
85 /**
86 * Checks whether a given name is a label of a loop or not.
87 * @param {string} label A name of a label to check.
88 * @returns {boolean} `true` if the name is a label of a loop.
89 */
90 function getKind(label) {
91 let info = scopeInfo;
92
93 while (info) {
94 if (info.label === label) {
95 return info.kind;
96 }
97 info = info.upper;
98 }
99
100 /* istanbul ignore next: syntax error */
101 return "other";
102 }
103
104 //--------------------------------------------------------------------------
105 // Public
106 //--------------------------------------------------------------------------
107
108 return {
109 LabeledStatement(node) {
110 scopeInfo = {
111 label: node.label.name,
112 kind: getBodyKind(node.body),
113 upper: scopeInfo
114 };
115 },
116
117 "LabeledStatement:exit"(node) {
118 if (!isAllowed(scopeInfo.kind)) {
119 context.report({
120 node,
121 messageId: "unexpectedLabel"
122 });
123 }
124
125 scopeInfo = scopeInfo.upper;
126 },
127
128 BreakStatement(node) {
129 if (node.label && !isAllowed(getKind(node.label.name))) {
130 context.report({
131 node,
132 messageId: "unexpectedLabelInBreak"
133 });
134 }
135 },
136
137 ContinueStatement(node) {
138 if (node.label && !isAllowed(getKind(node.label.name))) {
139 context.report({
140 node,
141 messageId: "unexpectedLabelInContinue"
142 });
143 }
144 }
145 };
146
147 }
148 };