Permalink
Browse files

New: no-restricted-globals rule implementation (fixes #3966)

  • Loading branch information...
BenoitZugmeyer committed Feb 24, 2016
1 parent 44ee913 commit 560c0d9e5ee948199c40e294c370b9d63704e8a0
View
@@ -81,6 +81,7 @@
"no-proto": 0,
"no-redeclare": 2,
"no-regex-spaces": 2,
"no-restricted-globals": 0,
"no-restricted-imports": 0,
"no-restricted-modules": 0,
"no-restricted-syntax": 0,
View
@@ -120,6 +120,7 @@ These rules have to do with variable declarations.
* [no-catch-shadow](no-catch-shadow.md) - disallow the catch clause parameter name being the same as a variable in the outer scope
* [no-delete-var](no-delete-var.md) - disallow deletion of variables (recommended)
* [no-label-var](no-label-var.md) - disallow labels that share a name with a variable
* [no-restricted-globals](no-restricted-globals.md) - restrict usage of specified global variables
* [no-shadow](no-shadow.md) - disallow declaration of variables already declared in the outer scope
* [no-shadow-restricted-names](no-shadow-restricted-names.md) - disallow shadowing of names such as `arguments`
* [no-undef](no-undef.md) - disallow use of undeclared variables unless mentioned in a `/*global */` block (recommended)
@@ -0,0 +1,50 @@
# Disallow specific global variables (no-restricted-globals)
Disallowing usage of specific global variables can be useful if you want to allow a set of global
variables by enabling an environment, but still want to disallow some of those.
For instance, early Internet Explorer versions exposed the current DOM event as a global variable
`event`, but using this variable has been considered as a bad practice for a long time. Restricting
this will make sure this variable isn't used in browser code.
## Rule Details
This rule allows you to specify global variable names that you don't want to use in your application.
## Options
This rule takes a list of strings where strings denote the global variable names:
```json
"no-restricted-globals": [2, "event", "fdescribe"]
```
The following patterns are considered problems:
```js
/*global event, fdescribe*/
/*eslint no-restricted-globals: [2, "event", "fdescribe"]*/
function onClick() {
console.log(event);
}
fdescribe("foo", function() {
});
```
The following patterns are not considered problems:
```js
/*global event*/
/*eslint no-restricted-globals: [2, "event"]*/
import event from "event-module";
```
```js
/*global event*/
/*eslint no-restricted-globals: [2, "event"]*/
var event = 1;
```
@@ -0,0 +1,72 @@
/**
* @fileoverview Restrict usage of specified globals.
* @author Benoît Zugmeyer
* @copyright 2016 Benoît Zugmeyer. All rights reserved.
* See LICENSE file in root directory for full license.
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = function(context) {
var restrictedGlobals = context.options;
// if no globals are restricted we don't need to check
if (restrictedGlobals.length === 0) {
return {};
}
/**
* Report a variable to be used as a restricted global.
* @param {Reference} reference the variable reference
* @returns {void}
* @private
*/
function reportReference(reference) {
context.report(reference.identifier, "Unexpected use of '{{name}}'", {
name: reference.identifier.name
});
}
/**
* Check if the given name is a restricted global name.
* @param {string} name name of a variable
* @returns {boolean} whether the variable is a restricted global or not
* @private
*/
function isRestricted(name) {
return restrictedGlobals.indexOf(name) >= 0;
}
return {
"Program": function() {
var scope = context.getScope();
// Report variables declared elsewhere (ex: variables defined as "global" by eslint)
scope.variables.forEach(function(variable) {
if (!variable.defs.length && isRestricted(variable.name)) {
variable.references.forEach(reportReference);
}
});
// Report variables not declared at all
scope.through.forEach(function(reference) {
if (isRestricted(reference.identifier.name)) {
reportReference(reference);
}
});
}
};
};
module.exports.schema = {
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true
};
@@ -0,0 +1,67 @@
/**
* @fileoverview Tests for no-restricted-globals.
* @author Benoît Zugmeyer
* @copyright 2016 Benoît Zugmeyer. All rights reserved.
* See LICENSE file in root directory for full license.
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
var rule = require("../../../lib/rules/no-restricted-globals"),
RuleTester = require("../../../lib/testers/rule-tester");
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
var ruleTester = new RuleTester();
ruleTester.run("no-restricted-globals", rule, {
valid: [
{ code: "foo" },
{ code: "foo", options: ["bar"] },
{ code: "var foo = 1;", options: ["foo"] },
{ code: "event", env: { browser: true }, options: ["bar"] },
{ code: "import foo from 'bar';", options: ["foo"], parserOptions: { ecmaVersion: 6, sourceType: "module" } },
{ code: "function foo() {}", options: ["foo"] },
{ code: "function fn() { var foo; }", options: ["foo"] },
{ code: "foo.bar", options: ["bar"] }
],
invalid: [
{
code: "foo", options: ["foo"],
errors: [{ message: "Unexpected use of 'foo'", type: "Identifier"}]
},
{
code: "function fn() { foo; }", options: ["foo"],
errors: [{ message: "Unexpected use of 'foo'", type: "Identifier"}]
},
{
code: "function fn() { foo; }", options: ["foo"],
globals: {foo: false},
errors: [{ message: "Unexpected use of 'foo'", type: "Identifier"}]
},
{
code: "event", options: ["foo", "event"],
env: { browser: true },
errors: [{ message: "Unexpected use of 'event'", type: "Identifier"}]
},
{
code: "foo", options: ["foo"],
globals: {foo: false},
errors: [{ message: "Unexpected use of 'foo'", type: "Identifier"}]
},
{
code: "foo()", options: ["foo"],
errors: [{ message: "Unexpected use of 'foo'", type: "Identifier"}]
},
{
code: "foo.bar()", options: ["foo"],
errors: [{ message: "Unexpected use of 'foo'", type: "Identifier"}]
}
]
});

0 comments on commit 560c0d9

Please sign in to comment.