@@ -32,6 +32,10 @@ module.exports = {
32
32
type : "boolean" ,
33
33
default : false
34
34
} ,
35
+ ignoreGlobals : {
36
+ type : "boolean" ,
37
+ default : false
38
+ } ,
35
39
properties : {
36
40
enum : [ "always" , "never" ]
37
41
} ,
@@ -61,8 +65,11 @@ module.exports = {
61
65
let properties = options . properties || "" ;
62
66
const ignoreDestructuring = options . ignoreDestructuring ;
63
67
const ignoreImports = options . ignoreImports ;
68
+ const ignoreGlobals = options . ignoreGlobals ;
64
69
const allow = options . allow || [ ] ;
65
70
71
+ let globalScope ;
72
+
66
73
if ( properties !== "always" && properties !== "never" ) {
67
74
properties = "always" ;
68
75
}
@@ -159,6 +166,37 @@ module.exports = {
159
166
return false ;
160
167
}
161
168
169
+ /**
170
+ * Checks whether the given node represents a reference to a global variable that is not declared in the source code.
171
+ * These identifiers will be allowed, as it is assumed that user has no control over the names of external global variables.
172
+ * @param {ASTNode } node `Identifier` node to check.
173
+ * @returns {boolean } `true` if the node is a reference to a global variable.
174
+ */
175
+ function isReferenceToGlobalVariable ( node ) {
176
+ const variable = globalScope . set . get ( node . name ) ;
177
+
178
+ return variable && variable . defs . length === 0 &&
179
+ variable . references . some ( ref => ref . identifier === node ) ;
180
+ }
181
+
182
+ /**
183
+ * Checks whether the given node represents a reference to a property of an object in an object literal expression.
184
+ * This allows to differentiate between a global variable that is allowed to be used as a reference, and the key
185
+ * of the expressed object (which shouldn't be allowed).
186
+ * @param {ASTNode } node `Identifier` node to check.
187
+ * @returns {boolean } `true` if the node is a property name of an object literal expression
188
+ */
189
+ function isPropertyNameInObjectLiteral ( node ) {
190
+ const parent = node . parent ;
191
+
192
+ return (
193
+ parent . type === "Property" &&
194
+ parent . parent . type === "ObjectExpression" &&
195
+ ! parent . computed &&
196
+ parent . key === node
197
+ ) ;
198
+ }
199
+
162
200
/**
163
201
* Reports an AST node as a rule violation.
164
202
* @param {ASTNode } node The node to report.
@@ -174,6 +212,10 @@ module.exports = {
174
212
175
213
return {
176
214
215
+ Program ( ) {
216
+ globalScope = context . getScope ( ) ;
217
+ } ,
218
+
177
219
Identifier ( node ) {
178
220
179
221
/*
@@ -189,6 +231,11 @@ module.exports = {
189
231
return ;
190
232
}
191
233
234
+ // Check if it's a global variable
235
+ if ( ignoreGlobals && isReferenceToGlobalVariable ( node ) && ! isPropertyNameInObjectLiteral ( node ) ) {
236
+ return ;
237
+ }
238
+
192
239
// MemberExpressions get special rules
193
240
if ( node . parent . type === "MemberExpression" ) {
194
241
0 commit comments