.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / id-blacklist.js
1 /**
2  * @fileoverview Rule that warns when identifier names that are
3  * specified in the configuration are used.
4  * @author Keith Cirkel (http://keithcirkel.co.uk)
5  */
6
7 "use strict";
8
9 //------------------------------------------------------------------------------
10 // Helpers
11 //------------------------------------------------------------------------------
12
13 /**
14  * Checks whether the given node represents assignment target in a normal assignment or destructuring.
15  * @param {ASTNode} node The node to check.
16  * @returns {boolean} `true` if the node is assignment target.
17  */
18 function isAssignmentTarget(node) {
19     const parent = node.parent;
20
21     return (
22
23         // normal assignment
24         (
25             parent.type === "AssignmentExpression" &&
26             parent.left === node
27         ) ||
28
29         // destructuring
30         parent.type === "ArrayPattern" ||
31         parent.type === "RestElement" ||
32         (
33             parent.type === "Property" &&
34             parent.value === node &&
35             parent.parent.type === "ObjectPattern"
36         ) ||
37         (
38             parent.type === "AssignmentPattern" &&
39             parent.left === node
40         )
41     );
42 }
43
44 /**
45  * Checks whether the given node represents an imported name that is renamed in the same import/export specifier.
46  *
47  * Examples:
48  * import { a as b } from 'mod'; // node `a` is renamed import
49  * export { a as b } from 'mod'; // node `a` is renamed import
50  * @param {ASTNode} node `Identifier` node to check.
51  * @returns {boolean} `true` if the node is a renamed import.
52  */
53 function isRenamedImport(node) {
54     const parent = node.parent;
55
56     return (
57         (
58             parent.type === "ImportSpecifier" &&
59             parent.imported !== parent.local &&
60             parent.imported === node
61         ) ||
62         (
63             parent.type === "ExportSpecifier" &&
64             parent.parent.source && // re-export
65             parent.local !== parent.exported &&
66             parent.local === node
67         )
68     );
69 }
70
71 /**
72  * Checks whether the given node is a renamed identifier node in an ObjectPattern destructuring.
73  *
74  * Examples:
75  * const { a : b } = foo; // node `a` is renamed node.
76  * @param {ASTNode} node `Identifier` node to check.
77  * @returns {boolean} `true` if the node is a renamed node in an ObjectPattern destructuring.
78  */
79 function isRenamedInDestructuring(node) {
80     const parent = node.parent;
81
82     return (
83         (
84             !parent.computed &&
85             parent.type === "Property" &&
86             parent.parent.type === "ObjectPattern" &&
87             parent.value !== node &&
88             parent.key === node
89         )
90     );
91 }
92
93 /**
94  * Checks whether the given node represents shorthand definition of a property in an object literal.
95  * @param {ASTNode} node `Identifier` node to check.
96  * @returns {boolean} `true` if the node is a shorthand property definition.
97  */
98 function isShorthandPropertyDefinition(node) {
99     const parent = node.parent;
100
101     return (
102         parent.type === "Property" &&
103         parent.parent.type === "ObjectExpression" &&
104         parent.shorthand
105     );
106 }
107
108 //------------------------------------------------------------------------------
109 // Rule Definition
110 //------------------------------------------------------------------------------
111
112 module.exports = {
113     meta: {
114         deprecated: true,
115         replacedBy: ["id-denylist"],
116
117         type: "suggestion",
118
119         docs: {
120             description: "disallow specified identifiers",
121             category: "Stylistic Issues",
122             recommended: false,
123             url: "https://eslint.org/docs/rules/id-blacklist"
124         },
125
126         schema: {
127             type: "array",
128             items: {
129                 type: "string"
130             },
131             uniqueItems: true
132         },
133         messages: {
134             restricted: "Identifier '{{name}}' is restricted."
135         }
136     },
137
138     create(context) {
139
140         const denyList = new Set(context.options);
141         const reportedNodes = new Set();
142
143         let globalScope;
144
145         /**
146          * Checks whether the given name is restricted.
147          * @param {string} name The name to check.
148          * @returns {boolean} `true` if the name is restricted.
149          * @private
150          */
151         function isRestricted(name) {
152             return denyList.has(name);
153         }
154
155         /**
156          * Checks whether the given node represents a reference to a global variable that is not declared in the source code.
157          * These identifiers will be allowed, as it is assumed that user has no control over the names of external global variables.
158          * @param {ASTNode} node `Identifier` node to check.
159          * @returns {boolean} `true` if the node is a reference to a global variable.
160          */
161         function isReferenceToGlobalVariable(node) {
162             const variable = globalScope.set.get(node.name);
163
164             return variable && variable.defs.length === 0 &&
165                 variable.references.some(ref => ref.identifier === node);
166         }
167
168         /**
169          * Determines whether the given node should be checked.
170          * @param {ASTNode} node `Identifier` node.
171          * @returns {boolean} `true` if the node should be checked.
172          */
173         function shouldCheck(node) {
174             const parent = node.parent;
175
176             /*
177              * Member access has special rules for checking property names.
178              * Read access to a property with a restricted name is allowed, because it can be on an object that user has no control over.
179              * Write access isn't allowed, because it potentially creates a new property with a restricted name.
180              */
181             if (
182                 parent.type === "MemberExpression" &&
183                 parent.property === node &&
184                 !parent.computed
185             ) {
186                 return isAssignmentTarget(parent);
187             }
188
189             return (
190                 parent.type !== "CallExpression" &&
191                 parent.type !== "NewExpression" &&
192                 !isRenamedImport(node) &&
193                 !isRenamedInDestructuring(node) &&
194                 !(
195                     isReferenceToGlobalVariable(node) &&
196                     !isShorthandPropertyDefinition(node)
197                 )
198             );
199         }
200
201         /**
202          * Reports an AST node as a rule violation.
203          * @param {ASTNode} node The node to report.
204          * @returns {void}
205          * @private
206          */
207         function report(node) {
208             if (!reportedNodes.has(node)) {
209                 context.report({
210                     node,
211                     messageId: "restricted",
212                     data: {
213                         name: node.name
214                     }
215                 });
216                 reportedNodes.add(node);
217             }
218         }
219
220         return {
221
222             Program() {
223                 globalScope = context.getScope();
224             },
225
226             Identifier(node) {
227                 if (isRestricted(node.name) && shouldCheck(node)) {
228                     report(node);
229                 }
230             }
231         };
232     }
233 };