source: imaps-frontend/node_modules/eslint/lib/rules/camelcase.js@ d565449

main
Last change on this file since d565449 was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 13.7 KB
RevLine 
[d565449]1/**
2 * @fileoverview Rule to flag non-camelcased identifiers
3 * @author Nicholas C. Zakas
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Requirements
10//------------------------------------------------------------------------------
11
12const astUtils = require("./utils/ast-utils");
13
14//------------------------------------------------------------------------------
15// Rule Definition
16//------------------------------------------------------------------------------
17
18/** @type {import('../shared/types').Rule} */
19module.exports = {
20 meta: {
21 type: "suggestion",
22
23 docs: {
24 description: "Enforce camelcase naming convention",
25 recommended: false,
26 url: "https://eslint.org/docs/latest/rules/camelcase"
27 },
28
29 schema: [
30 {
31 type: "object",
32 properties: {
33 ignoreDestructuring: {
34 type: "boolean",
35 default: false
36 },
37 ignoreImports: {
38 type: "boolean",
39 default: false
40 },
41 ignoreGlobals: {
42 type: "boolean",
43 default: false
44 },
45 properties: {
46 enum: ["always", "never"]
47 },
48 allow: {
49 type: "array",
50 items: [
51 {
52 type: "string"
53 }
54 ],
55 minItems: 0,
56 uniqueItems: true
57 }
58 },
59 additionalProperties: false
60 }
61 ],
62
63 messages: {
64 notCamelCase: "Identifier '{{name}}' is not in camel case.",
65 notCamelCasePrivate: "#{{name}} is not in camel case."
66 }
67 },
68
69 create(context) {
70 const options = context.options[0] || {};
71 const properties = options.properties === "never" ? "never" : "always";
72 const ignoreDestructuring = options.ignoreDestructuring;
73 const ignoreImports = options.ignoreImports;
74 const ignoreGlobals = options.ignoreGlobals;
75 const allow = options.allow || [];
76 const sourceCode = context.sourceCode;
77
78 //--------------------------------------------------------------------------
79 // Helpers
80 //--------------------------------------------------------------------------
81
82 // contains reported nodes to avoid reporting twice on destructuring with shorthand notation
83 const reported = new Set();
84
85 /**
86 * Checks if a string contains an underscore and isn't all upper-case
87 * @param {string} name The string to check.
88 * @returns {boolean} if the string is underscored
89 * @private
90 */
91 function isUnderscored(name) {
92 const nameBody = name.replace(/^_+|_+$/gu, "");
93
94 // if there's an underscore, it might be A_CONSTANT, which is okay
95 return nameBody.includes("_") && nameBody !== nameBody.toUpperCase();
96 }
97
98 /**
99 * Checks if a string match the ignore list
100 * @param {string} name The string to check.
101 * @returns {boolean} if the string is ignored
102 * @private
103 */
104 function isAllowed(name) {
105 return allow.some(
106 entry => name === entry || name.match(new RegExp(entry, "u"))
107 );
108 }
109
110 /**
111 * Checks if a given name is good or not.
112 * @param {string} name The name to check.
113 * @returns {boolean} `true` if the name is good.
114 * @private
115 */
116 function isGoodName(name) {
117 return !isUnderscored(name) || isAllowed(name);
118 }
119
120 /**
121 * Checks if a given identifier reference or member expression is an assignment
122 * target.
123 * @param {ASTNode} node The node to check.
124 * @returns {boolean} `true` if the node is an assignment target.
125 */
126 function isAssignmentTarget(node) {
127 const parent = node.parent;
128
129 switch (parent.type) {
130 case "AssignmentExpression":
131 case "AssignmentPattern":
132 return parent.left === node;
133
134 case "Property":
135 return (
136 parent.parent.type === "ObjectPattern" &&
137 parent.value === node
138 );
139 case "ArrayPattern":
140 case "RestElement":
141 return true;
142
143 default:
144 return false;
145 }
146 }
147
148 /**
149 * Checks if a given binding identifier uses the original name as-is.
150 * - If it's in object destructuring or object expression, the original name is its property name.
151 * - If it's in import declaration, the original name is its exported name.
152 * @param {ASTNode} node The `Identifier` node to check.
153 * @returns {boolean} `true` if the identifier uses the original name as-is.
154 */
155 function equalsToOriginalName(node) {
156 const localName = node.name;
157 const valueNode = node.parent.type === "AssignmentPattern"
158 ? node.parent
159 : node;
160 const parent = valueNode.parent;
161
162 switch (parent.type) {
163 case "Property":
164 return (
165 (parent.parent.type === "ObjectPattern" || parent.parent.type === "ObjectExpression") &&
166 parent.value === valueNode &&
167 !parent.computed &&
168 parent.key.type === "Identifier" &&
169 parent.key.name === localName
170 );
171
172 case "ImportSpecifier":
173 return (
174 parent.local === node &&
175 astUtils.getModuleExportName(parent.imported) === localName
176 );
177
178 default:
179 return false;
180 }
181 }
182
183 /**
184 * Reports an AST node as a rule violation.
185 * @param {ASTNode} node The node to report.
186 * @returns {void}
187 * @private
188 */
189 function report(node) {
190 if (reported.has(node.range[0])) {
191 return;
192 }
193 reported.add(node.range[0]);
194
195 // Report it.
196 context.report({
197 node,
198 messageId: node.type === "PrivateIdentifier"
199 ? "notCamelCasePrivate"
200 : "notCamelCase",
201 data: { name: node.name }
202 });
203 }
204
205 /**
206 * Reports an identifier reference or a binding identifier.
207 * @param {ASTNode} node The `Identifier` node to report.
208 * @returns {void}
209 */
210 function reportReferenceId(node) {
211
212 /*
213 * For backward compatibility, if it's in callings then ignore it.
214 * Not sure why it is.
215 */
216 if (
217 node.parent.type === "CallExpression" ||
218 node.parent.type === "NewExpression"
219 ) {
220 return;
221 }
222
223 /*
224 * For backward compatibility, if it's a default value of
225 * destructuring/parameters then ignore it.
226 * Not sure why it is.
227 */
228 if (
229 node.parent.type === "AssignmentPattern" &&
230 node.parent.right === node
231 ) {
232 return;
233 }
234
235 /*
236 * The `ignoreDestructuring` flag skips the identifiers that uses
237 * the property name as-is.
238 */
239 if (ignoreDestructuring && equalsToOriginalName(node)) {
240 return;
241 }
242
243 report(node);
244 }
245
246 return {
247
248 // Report camelcase of global variable references ------------------
249 Program(node) {
250 const scope = sourceCode.getScope(node);
251
252 if (!ignoreGlobals) {
253
254 // Defined globals in config files or directive comments.
255 for (const variable of scope.variables) {
256 if (
257 variable.identifiers.length > 0 ||
258 isGoodName(variable.name)
259 ) {
260 continue;
261 }
262 for (const reference of variable.references) {
263
264 /*
265 * For backward compatibility, this rule reports read-only
266 * references as well.
267 */
268 reportReferenceId(reference.identifier);
269 }
270 }
271 }
272
273 // Undefined globals.
274 for (const reference of scope.through) {
275 const id = reference.identifier;
276
277 if (isGoodName(id.name)) {
278 continue;
279 }
280
281 /*
282 * For backward compatibility, this rule reports read-only
283 * references as well.
284 */
285 reportReferenceId(id);
286 }
287 },
288
289 // Report camelcase of declared variables --------------------------
290 [[
291 "VariableDeclaration",
292 "FunctionDeclaration",
293 "FunctionExpression",
294 "ArrowFunctionExpression",
295 "ClassDeclaration",
296 "ClassExpression",
297 "CatchClause"
298 ]](node) {
299 for (const variable of sourceCode.getDeclaredVariables(node)) {
300 if (isGoodName(variable.name)) {
301 continue;
302 }
303 const id = variable.identifiers[0];
304
305 // Report declaration.
306 if (!(ignoreDestructuring && equalsToOriginalName(id))) {
307 report(id);
308 }
309
310 /*
311 * For backward compatibility, report references as well.
312 * It looks unnecessary because declarations are reported.
313 */
314 for (const reference of variable.references) {
315 if (reference.init) {
316 continue; // Skip the write references of initializers.
317 }
318 reportReferenceId(reference.identifier);
319 }
320 }
321 },
322
323 // Report camelcase in properties ----------------------------------
324 [[
325 "ObjectExpression > Property[computed!=true] > Identifier.key",
326 "MethodDefinition[computed!=true] > Identifier.key",
327 "PropertyDefinition[computed!=true] > Identifier.key",
328 "MethodDefinition > PrivateIdentifier.key",
329 "PropertyDefinition > PrivateIdentifier.key"
330 ]](node) {
331 if (properties === "never" || isGoodName(node.name)) {
332 return;
333 }
334 report(node);
335 },
336 "MemberExpression[computed!=true] > Identifier.property"(node) {
337 if (
338 properties === "never" ||
339 !isAssignmentTarget(node.parent) || // ← ignore read-only references.
340 isGoodName(node.name)
341 ) {
342 return;
343 }
344 report(node);
345 },
346
347 // Report camelcase in import --------------------------------------
348 ImportDeclaration(node) {
349 for (const variable of sourceCode.getDeclaredVariables(node)) {
350 if (isGoodName(variable.name)) {
351 continue;
352 }
353 const id = variable.identifiers[0];
354
355 // Report declaration.
356 if (!(ignoreImports && equalsToOriginalName(id))) {
357 report(id);
358 }
359
360 /*
361 * For backward compatibility, report references as well.
362 * It looks unnecessary because declarations are reported.
363 */
364 for (const reference of variable.references) {
365 reportReferenceId(reference.identifier);
366 }
367 }
368 },
369
370 // Report camelcase in re-export -----------------------------------
371 [[
372 "ExportAllDeclaration > Identifier.exported",
373 "ExportSpecifier > Identifier.exported"
374 ]](node) {
375 if (isGoodName(node.name)) {
376 return;
377 }
378 report(node);
379 },
380
381 // Report camelcase in labels --------------------------------------
382 [[
383 "LabeledStatement > Identifier.label",
384
385 /*
386 * For backward compatibility, report references as well.
387 * It looks unnecessary because declarations are reported.
388 */
389 "BreakStatement > Identifier.label",
390 "ContinueStatement > Identifier.label"
391 ]](node) {
392 if (isGoodName(node.name)) {
393 return;
394 }
395 report(node);
396 }
397 };
398 }
399};
Note: See TracBrowser for help on using the repository browser.