minor adjustment to readme
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / id-match.js
1 /**
2  * @fileoverview Rule to flag non-matching identifiers
3  * @author Matthieu Larcher
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Rule Definition
10 //------------------------------------------------------------------------------
11
12 module.exports = {
13     meta: {
14         type: "suggestion",
15
16         docs: {
17             description: "require identifiers to match a specified regular expression",
18             category: "Stylistic Issues",
19             recommended: false,
20             url: "https://eslint.org/docs/rules/id-match"
21         },
22
23         schema: [
24             {
25                 type: "string"
26             },
27             {
28                 type: "object",
29                 properties: {
30                     properties: {
31                         type: "boolean",
32                         default: false
33                     },
34                     onlyDeclarations: {
35                         type: "boolean",
36                         default: false
37                     },
38                     ignoreDestructuring: {
39                         type: "boolean",
40                         default: false
41                     }
42                 }
43             }
44         ],
45         messages: {
46             notMatch: "Identifier '{{name}}' does not match the pattern '{{pattern}}'."
47         }
48     },
49
50     create(context) {
51
52         //--------------------------------------------------------------------------
53         // Options
54         //--------------------------------------------------------------------------
55         const pattern = context.options[0] || "^.+$",
56             regexp = new RegExp(pattern, "u");
57
58         const options = context.options[1] || {},
59             properties = !!options.properties,
60             onlyDeclarations = !!options.onlyDeclarations,
61             ignoreDestructuring = !!options.ignoreDestructuring;
62
63         //--------------------------------------------------------------------------
64         // Helpers
65         //--------------------------------------------------------------------------
66
67         // contains reported nodes to avoid reporting twice on destructuring with shorthand notation
68         const reported = new Map();
69         const ALLOWED_PARENT_TYPES = new Set(["CallExpression", "NewExpression"]);
70         const DECLARATION_TYPES = new Set(["FunctionDeclaration", "VariableDeclarator"]);
71         const IMPORT_TYPES = new Set(["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"]);
72
73         /**
74          * Checks if a string matches the provided pattern
75          * @param {string} name The string to check.
76          * @returns {boolean} if the string is a match
77          * @private
78          */
79         function isInvalid(name) {
80             return !regexp.test(name);
81         }
82
83         /**
84          * Checks if a parent of a node is an ObjectPattern.
85          * @param {ASTNode} node The node to check.
86          * @returns {boolean} if the node is inside an ObjectPattern
87          * @private
88          */
89         function isInsideObjectPattern(node) {
90             let { parent } = node;
91
92             while (parent) {
93                 if (parent.type === "ObjectPattern") {
94                     return true;
95                 }
96
97                 parent = parent.parent;
98             }
99
100             return false;
101         }
102
103         /**
104          * Verifies if we should report an error or not based on the effective
105          * parent node and the identifier name.
106          * @param {ASTNode} effectiveParent The effective parent node of the node to be reported
107          * @param {string} name The identifier name of the identifier node
108          * @returns {boolean} whether an error should be reported or not
109          */
110         function shouldReport(effectiveParent, name) {
111             return (!onlyDeclarations || DECLARATION_TYPES.has(effectiveParent.type)) &&
112                 !ALLOWED_PARENT_TYPES.has(effectiveParent.type) && isInvalid(name);
113         }
114
115         /**
116          * Reports an AST node as a rule violation.
117          * @param {ASTNode} node The node to report.
118          * @returns {void}
119          * @private
120          */
121         function report(node) {
122             if (!reported.has(node)) {
123                 context.report({
124                     node,
125                     messageId: "notMatch",
126                     data: {
127                         name: node.name,
128                         pattern
129                     }
130                 });
131                 reported.set(node, true);
132             }
133         }
134
135         return {
136
137             Identifier(node) {
138                 const name = node.name,
139                     parent = node.parent,
140                     effectiveParent = (parent.type === "MemberExpression") ? parent.parent : parent;
141
142                 if (parent.type === "MemberExpression") {
143
144                     if (!properties) {
145                         return;
146                     }
147
148                     // Always check object names
149                     if (parent.object.type === "Identifier" &&
150                         parent.object.name === name) {
151                         if (isInvalid(name)) {
152                             report(node);
153                         }
154
155                     // Report AssignmentExpressions left side's assigned variable id
156                     } else if (effectiveParent.type === "AssignmentExpression" &&
157                         effectiveParent.left.type === "MemberExpression" &&
158                         effectiveParent.left.property.name === node.name) {
159                         if (isInvalid(name)) {
160                             report(node);
161                         }
162
163                     // Report AssignmentExpressions only if they are the left side of the assignment
164                     } else if (effectiveParent.type === "AssignmentExpression" && effectiveParent.right.type !== "MemberExpression") {
165                         if (isInvalid(name)) {
166                             report(node);
167                         }
168                     }
169
170                 /*
171                  * Properties have their own rules, and
172                  * AssignmentPattern nodes can be treated like Properties:
173                  * e.g.: const { no_camelcased = false } = bar;
174                  */
175                 } else if (parent.type === "Property" || parent.type === "AssignmentPattern") {
176
177                     if (parent.parent && parent.parent.type === "ObjectPattern") {
178                         if (parent.shorthand && parent.value.left && isInvalid(name)) {
179
180                             report(node);
181                         }
182
183                         const assignmentKeyEqualsValue = parent.key.name === parent.value.name;
184
185                         // prevent checking righthand side of destructured object
186                         if (!assignmentKeyEqualsValue && parent.key === node) {
187                             return;
188                         }
189
190                         const valueIsInvalid = parent.value.name && isInvalid(name);
191
192                         // ignore destructuring if the option is set, unless a new identifier is created
193                         if (valueIsInvalid && !(assignmentKeyEqualsValue && ignoreDestructuring)) {
194                             report(node);
195                         }
196                     }
197
198                     // never check properties or always ignore destructuring
199                     if (!properties || (ignoreDestructuring && isInsideObjectPattern(node))) {
200                         return;
201                     }
202
203                     // don't check right hand side of AssignmentExpression to prevent duplicate warnings
204                     if (parent.right !== node && shouldReport(effectiveParent, name)) {
205                         report(node);
206                     }
207
208                 // Check if it's an import specifier
209                 } else if (IMPORT_TYPES.has(parent.type)) {
210
211                     // Report only if the local imported identifier is invalid
212                     if (parent.local && parent.local.name === node.name && isInvalid(name)) {
213                         report(node);
214                     }
215
216                 // Report anything that is invalid that isn't a CallExpression
217                 } else if (shouldReport(effectiveParent, name)) {
218                     report(node);
219                 }
220             }
221
222         };
223
224     }
225 };