Skip to content

Commit

Permalink
Add: Exception option for no-extend-native and no-native-reassign (
Browse files Browse the repository at this point in the history
…fixes #2355)
  • Loading branch information
gyandeeps committed Apr 26, 2015
1 parent 66eaade commit 8257b4f
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 9 deletions.
15 changes: 15 additions & 0 deletions docs/rules/no-extend-native.md
Expand Up @@ -36,6 +36,21 @@ It *does not* check for any of the following less obvious approaches:
* `with(Array) { prototype.thing = 'thing'; };`
* `window.Function.prototype.bind = 'tight';`

## Options

### exceptions

Array of native object names that are permitted to be extended.
If provided, it must be an `Array`.

```js
{
"rules": {
"no-extend-native": [2, {"exceptions": ["Object"]}]
}
}
```

## When Not To Use It

You may want to disable this rule when working with polyfills that try to patch older versions of JavaScript with the latest spec, such as those that might `Function.prototype.bind` or `Array.prototype.forEach` in a future-friendly way.
Expand Down
15 changes: 15 additions & 0 deletions docs/rules/no-native-reassign.md
Expand Up @@ -54,6 +54,21 @@ String = new Object();
var String;
```

## Options

### exceptions

Array of native object names that are permitted to be reassigned.
If provided, it must be an `Array`.

```js
{
"rules": {
"no-native-reassign": [2, {"exceptions": ["Object"]}]
}
}
```

## When Not To Use It

If you are trying to override one of the native objects.
Expand Down
14 changes: 12 additions & 2 deletions lib/rules/no-extend-native.js
Expand Up @@ -21,6 +21,16 @@ var BUILTINS = [

module.exports = function(context) {

var config = context.options[0] || {};
var exceptions = config.exceptions || [];
var modifiedBuiltins = BUILTINS;

if (exceptions.length) {
modifiedBuiltins = BUILTINS.filter(function(builtIn) {
return exceptions.indexOf(builtIn) === -1;
});
}

return {

// handle the Array.prototype.extra style case
Expand All @@ -39,7 +49,7 @@ module.exports = function(context) {
return;
}

BUILTINS.forEach(function(builtin) {
modifiedBuiltins.forEach(function(builtin) {
if (lhs.object.object.name === builtin) {
context.report(node, builtin + " prototype is read only, properties should not be added.");
}
Expand All @@ -64,7 +74,7 @@ module.exports = function(context) {

if (object &&
object.type === "Identifier" &&
(BUILTINS.indexOf(object.name) > -1) &&
(modifiedBuiltins.indexOf(object.name) > -1) &&
subject.property.name === "prototype") {

context.report(node, object.name + " prototype is read only, properties should not be added.");
Expand Down
15 changes: 12 additions & 3 deletions lib/rules/no-native-reassign.js
Expand Up @@ -11,24 +11,33 @@

module.exports = function(context) {

var nativeObjects = ["Array", "Boolean", "Date", "decodeURI",
var NATIVE_OBJECTS = ["Array", "Boolean", "Date", "decodeURI",
"decodeURIComponent", "encodeURI", "encodeURIComponent",
"Error", "eval", "EvalError", "Function", "isFinite",
"isNaN", "JSON", "Math", "Number", "Object", "parseInt",
"parseFloat", "RangeError", "ReferenceError", "RegExp",
"String", "SyntaxError", "TypeError", "URIError",
"Map", "NaN", "Set", "WeakMap", "Infinity", "undefined"];
var config = context.options[0] || {};
var exceptions = config.exceptions || [];
var modifiedNativeObjects = NATIVE_OBJECTS;

if (exceptions.length) {
modifiedNativeObjects = NATIVE_OBJECTS.filter(function(builtIn) {
return exceptions.indexOf(builtIn) === -1;
});
}

return {

"AssignmentExpression": function(node) {
if (nativeObjects.indexOf(node.left.name) >= 0) {
if (modifiedNativeObjects.indexOf(node.left.name) >= 0) {
context.report(node, node.left.name + " is a read-only native object.");
}
},

"VariableDeclarator": function(node) {
if (nativeObjects.indexOf(node.id.name) >= 0) {
if (modifiedNativeObjects.indexOf(node.id.name) >= 0) {
context.report(node, "Redefinition of '{{nativeObject}}'.", { nativeObject: node.id.name });
}
}
Expand Down
17 changes: 15 additions & 2 deletions tests/lib/rules/no-extend-native.js
Expand Up @@ -30,7 +30,11 @@ eslintTester.addRuleTest("lib/rules/no-extend-native", {
"this.Object.prototype.toString = 0",
"with(Object) { prototype.p = 0; }",
"o = Object; o.prototype.toString = 0",
"eval('Object.prototype.toString = 0')"
"eval('Object.prototype.toString = 0')",
{
code: "Object.prototype.g = 0",
options: [{exceptions: ["Object"]}]
}
],
invalid: [{
code: "Object.prototype.p = 0",
Expand Down Expand Up @@ -62,5 +66,14 @@ eslintTester.addRuleTest("lib/rules/no-extend-native", {
message: "Array prototype is read only, properties should not be added.",
type: "CallExpression"
}]
}]
},
{
code: "Number['prototype']['p'] = 0",
options: [{exceptions: ["Object"]}],
errors: [{
message: "Number prototype is read only, properties should not be added.",
type: "AssignmentExpression"
}]
}
]
});
13 changes: 11 additions & 2 deletions tests/lib/rules/no-native-reassign.js
Expand Up @@ -20,10 +20,19 @@ var eslintTester = new ESLintTester(eslint);
eslintTester.addRuleTest("lib/rules/no-native-reassign", {
valid: [
"string = 'hello world';",
"var string;"
"var string;",
{
code: "var Object = 0",
options: [{exceptions: ["Object"]}]
}
],
invalid: [
{ code: "String = 'hello world';", errors: [{ message: "String is a read-only native object.", type: "AssignmentExpression"}] },
{ code: "var String;", errors: [{ message: "Redefinition of 'String'.", type: "VariableDeclarator"}] }
{ code: "var String;", errors: [{ message: "Redefinition of 'String'.", type: "VariableDeclarator"}] },
{
code: "var Object = 0",
options: [{exceptions: ["Number"]}],
errors: [{ message: "Redefinition of 'Object'.", type: "VariableDeclarator"}]
}
]
});

0 comments on commit 8257b4f

Please sign in to comment.