]> git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-underscore-dangle.js
eb3e404a66d70d9f48ce56b9611415d563b9de29
[pve-eslint.git] / eslint / lib / rules / no-underscore-dangle.js
1 /**
2 * @fileoverview Rule to flag dangling underscores in variable declarations.
3 * @author Matt DuVall <http://www.mattduvall.com>
4 */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Rule Definition
10 //------------------------------------------------------------------------------
11
12 /** @type {import('../shared/types').Rule} */
13 module.exports = {
14 meta: {
15 type: "suggestion",
16
17 docs: {
18 description: "Disallow dangling underscores in identifiers",
19 recommended: false,
20 url: "https://eslint.org/docs/rules/no-underscore-dangle"
21 },
22
23 schema: [
24 {
25 type: "object",
26 properties: {
27 allow: {
28 type: "array",
29 items: {
30 type: "string"
31 }
32 },
33 allowAfterThis: {
34 type: "boolean",
35 default: false
36 },
37 allowAfterSuper: {
38 type: "boolean",
39 default: false
40 },
41 allowAfterThisConstructor: {
42 type: "boolean",
43 default: false
44 },
45 enforceInMethodNames: {
46 type: "boolean",
47 default: false
48 },
49 allowFunctionParams: {
50 type: "boolean",
51 default: true
52 },
53 enforceInClassFields: {
54 type: "boolean",
55 default: false
56 }
57 },
58 additionalProperties: false
59 }
60 ],
61
62 messages: {
63 unexpectedUnderscore: "Unexpected dangling '_' in '{{identifier}}'."
64 }
65 },
66
67 create(context) {
68
69 const options = context.options[0] || {};
70 const ALLOWED_VARIABLES = options.allow ? options.allow : [];
71 const allowAfterThis = typeof options.allowAfterThis !== "undefined" ? options.allowAfterThis : false;
72 const allowAfterSuper = typeof options.allowAfterSuper !== "undefined" ? options.allowAfterSuper : false;
73 const allowAfterThisConstructor = typeof options.allowAfterThisConstructor !== "undefined" ? options.allowAfterThisConstructor : false;
74 const enforceInMethodNames = typeof options.enforceInMethodNames !== "undefined" ? options.enforceInMethodNames : false;
75 const enforceInClassFields = typeof options.enforceInClassFields !== "undefined" ? options.enforceInClassFields : false;
76 const allowFunctionParams = typeof options.allowFunctionParams !== "undefined" ? options.allowFunctionParams : true;
77
78 //-------------------------------------------------------------------------
79 // Helpers
80 //-------------------------------------------------------------------------
81
82 /**
83 * Check if identifier is present inside the allowed option
84 * @param {string} identifier name of the node
85 * @returns {boolean} true if its is present
86 * @private
87 */
88 function isAllowed(identifier) {
89 return ALLOWED_VARIABLES.includes(identifier);
90 }
91
92 /**
93 * Check if identifier has a dangling underscore
94 * @param {string} identifier name of the node
95 * @returns {boolean} true if its is present
96 * @private
97 */
98 function hasDanglingUnderscore(identifier) {
99 const len = identifier.length;
100
101 return identifier !== "_" && (identifier[0] === "_" || identifier[len - 1] === "_");
102 }
103
104 /**
105 * Check if identifier is a special case member expression
106 * @param {string} identifier name of the node
107 * @returns {boolean} true if its is a special case
108 * @private
109 */
110 function isSpecialCaseIdentifierForMemberExpression(identifier) {
111 return identifier === "__proto__";
112 }
113
114 /**
115 * Check if identifier is a special case variable expression
116 * @param {string} identifier name of the node
117 * @returns {boolean} true if its is a special case
118 * @private
119 */
120 function isSpecialCaseIdentifierInVariableExpression(identifier) {
121
122 // Checks for the underscore library usage here
123 return identifier === "_";
124 }
125
126 /**
127 * Check if a node is a member reference of this.constructor
128 * @param {ASTNode} node node to evaluate
129 * @returns {boolean} true if it is a reference on this.constructor
130 * @private
131 */
132 function isThisConstructorReference(node) {
133 return node.object.type === "MemberExpression" &&
134 node.object.property.name === "constructor" &&
135 node.object.object.type === "ThisExpression";
136 }
137
138 /**
139 * Check if function parameter has a dangling underscore.
140 * @param {ASTNode} node function node to evaluate
141 * @returns {void}
142 * @private
143 */
144 function checkForDanglingUnderscoreInFunctionParameters(node) {
145 if (!allowFunctionParams) {
146 node.params.forEach(param => {
147 const { type } = param;
148 let nodeToCheck;
149
150 if (type === "RestElement") {
151 nodeToCheck = param.argument;
152 } else if (type === "AssignmentPattern") {
153 nodeToCheck = param.left;
154 } else {
155 nodeToCheck = param;
156 }
157
158 if (nodeToCheck.type === "Identifier") {
159 const identifier = nodeToCheck.name;
160
161 if (hasDanglingUnderscore(identifier) && !isAllowed(identifier)) {
162 context.report({
163 node: param,
164 messageId: "unexpectedUnderscore",
165 data: {
166 identifier
167 }
168 });
169 }
170 }
171 });
172 }
173 }
174
175 /**
176 * Check if function has a dangling underscore
177 * @param {ASTNode} node node to evaluate
178 * @returns {void}
179 * @private
180 */
181 function checkForDanglingUnderscoreInFunction(node) {
182 if (node.type === "FunctionDeclaration" && node.id) {
183 const identifier = node.id.name;
184
185 if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) && !isAllowed(identifier)) {
186 context.report({
187 node,
188 messageId: "unexpectedUnderscore",
189 data: {
190 identifier
191 }
192 });
193 }
194 }
195 checkForDanglingUnderscoreInFunctionParameters(node);
196 }
197
198 /**
199 * Check if variable expression has a dangling underscore
200 * @param {ASTNode} node node to evaluate
201 * @returns {void}
202 * @private
203 */
204 function checkForDanglingUnderscoreInVariableExpression(node) {
205 const identifier = node.id.name;
206
207 if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
208 !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) {
209 context.report({
210 node,
211 messageId: "unexpectedUnderscore",
212 data: {
213 identifier
214 }
215 });
216 }
217 }
218
219 /**
220 * Check if member expression has a dangling underscore
221 * @param {ASTNode} node node to evaluate
222 * @returns {void}
223 * @private
224 */
225 function checkForDanglingUnderscoreInMemberExpression(node) {
226 const identifier = node.property.name,
227 isMemberOfThis = node.object.type === "ThisExpression",
228 isMemberOfSuper = node.object.type === "Super",
229 isMemberOfThisConstructor = isThisConstructorReference(node);
230
231 if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
232 !(isMemberOfThis && allowAfterThis) &&
233 !(isMemberOfSuper && allowAfterSuper) &&
234 !(isMemberOfThisConstructor && allowAfterThisConstructor) &&
235 !isSpecialCaseIdentifierForMemberExpression(identifier) && !isAllowed(identifier)) {
236 context.report({
237 node,
238 messageId: "unexpectedUnderscore",
239 data: {
240 identifier
241 }
242 });
243 }
244 }
245
246 /**
247 * Check if method declaration or method property has a dangling underscore
248 * @param {ASTNode} node node to evaluate
249 * @returns {void}
250 * @private
251 */
252 function checkForDanglingUnderscoreInMethod(node) {
253 const identifier = node.key.name;
254 const isMethod = node.type === "MethodDefinition" || node.type === "Property" && node.method;
255
256 if (typeof identifier !== "undefined" && enforceInMethodNames && isMethod && hasDanglingUnderscore(identifier) && !isAllowed(identifier)) {
257 context.report({
258 node,
259 messageId: "unexpectedUnderscore",
260 data: {
261 identifier: node.key.type === "PrivateIdentifier"
262 ? `#${identifier}`
263 : identifier
264 }
265 });
266 }
267 }
268
269 /**
270 * Check if a class field has a dangling underscore
271 * @param {ASTNode} node node to evaluate
272 * @returns {void}
273 * @private
274 */
275 function checkForDanglingUnderscoreInClassField(node) {
276 const identifier = node.key.name;
277
278 if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
279 enforceInClassFields &&
280 !isAllowed(identifier)) {
281 context.report({
282 node,
283 messageId: "unexpectedUnderscore",
284 data: {
285 identifier: node.key.type === "PrivateIdentifier"
286 ? `#${identifier}`
287 : identifier
288 }
289 });
290 }
291 }
292
293 //--------------------------------------------------------------------------
294 // Public API
295 //--------------------------------------------------------------------------
296
297 return {
298 FunctionDeclaration: checkForDanglingUnderscoreInFunction,
299 VariableDeclarator: checkForDanglingUnderscoreInVariableExpression,
300 MemberExpression: checkForDanglingUnderscoreInMemberExpression,
301 MethodDefinition: checkForDanglingUnderscoreInMethod,
302 PropertyDefinition: checkForDanglingUnderscoreInClassField,
303 Property: checkForDanglingUnderscoreInMethod,
304 FunctionExpression: checkForDanglingUnderscoreInFunction,
305 ArrowFunctionExpression: checkForDanglingUnderscoreInFunction
306 };
307
308 }
309 };