Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* New: no-restricted-properties rule (fixes #3218) * Updating to use the new format * Updating the docs * Fixing lint errors in the markdown * Force Build * Using Map instead of an object * Using the property name getter from astUtils
- Loading branch information
Showing
4 changed files
with
284 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
# disallow certain object properties (no-restricted-properties) | ||
|
||
Certain properties on objects may be disallowed in a codebase. This is useful for deprecating an API or restricting usage of a module's methods. For example, you may want to disallow using `describe.only` when using Mocha or telling people to use `Object.assign` instead of `_.extend`. | ||
|
||
|
||
## Rule Details | ||
|
||
This rule looks for accessing a given property key on a given object name, either when reading the property's value or invoking it as a function. You may specify an optional message to indicate an alternative API or a reason for the restriction. | ||
|
||
### Options | ||
|
||
This rule takes a list of objects, where the object name and property names are specified: | ||
|
||
```json | ||
{ | ||
"rules": { | ||
"no-restricted-properties": [2, [{ | ||
"object": "disallowedObjectName", | ||
"property": "disallowedPropertyName" | ||
}]] | ||
} | ||
} | ||
``` | ||
|
||
Multiple object/property values can be disallowed, and you can specify an optional message: | ||
|
||
```json | ||
{ | ||
"rules": { | ||
"no-restricted-properties": [2, [{ | ||
"object": "disallowedObjectName", | ||
"property": "disallowedPropertyName" | ||
}, { | ||
"object": "disallowedObjectName", | ||
"property": "anotherDisallowedPropertyName", | ||
"message": "Please use allowedObjectName.allowedPropertyName." | ||
}]] | ||
} | ||
} | ||
``` | ||
|
||
Examples of **incorrect** code for this rule: | ||
|
||
```js | ||
/* eslint no-restricted-properties: [2, { | ||
"object": "disallowedObjectName", | ||
"property": "disallowedPropertyName" | ||
}] */ | ||
|
||
var example = disallowedObjectName.disallowedPropertyName; /*error Disallowed object property: disallowedObjectName.disallowedPropertyName.*/ | ||
|
||
disallowedObjectName.disallowedPropertyName(); /*error Disallowed object property: disallowedObjectName.disallowedPropertyName.*/ | ||
``` | ||
|
||
Examples of **correct** code for this rule: | ||
|
||
```js | ||
/* eslint no-restricted-properties: [2, { | ||
"object": "disallowedObjectName", | ||
"property": "disallowedPropertyName" | ||
}] */ | ||
|
||
var example = disallowedObjectName.somePropertyName; | ||
|
||
allowedObjectName.disallowedPropertyName(); | ||
``` | ||
|
||
## When Not To Use It | ||
|
||
If you don't have any object/property combinations to restrict, you should not use this rule. | ||
|
||
## Related Rules | ||
|
||
* [no-restricted-syntax](no-restricted-syntax.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/** | ||
* @fileoverview Rule to disallow certain object properties | ||
* @author Will Klein & Eli White | ||
*/ | ||
|
||
"use strict"; | ||
|
||
const astUtils = require("../ast-utils"); | ||
|
||
//------------------------------------------------------------------------------ | ||
// Rule Definition | ||
//------------------------------------------------------------------------------ | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: "disallow certain properties on certain objects", | ||
category: "Node.js and CommonJS", | ||
recommended: false | ||
}, | ||
|
||
schema: { | ||
type: "array", | ||
items: { | ||
type: "object", | ||
properties: { | ||
object: { | ||
type: "string" | ||
}, | ||
property: { | ||
type: "string" | ||
}, | ||
message: { | ||
type: "string" | ||
} | ||
}, | ||
additionalProperties: false, | ||
required: [ | ||
"object", | ||
"property" | ||
] | ||
}, | ||
uniqueItems: true | ||
} | ||
}, | ||
|
||
create(context) { | ||
const restrictedCalls = context.options; | ||
|
||
if (restrictedCalls.length === 0) { | ||
return {}; | ||
} | ||
|
||
const restrictedProperties = restrictedCalls.reduce(function(restrictions, option) { | ||
const objectName = option.object; | ||
const propertyName = option.property; | ||
|
||
if (!restrictions.has(objectName)) { | ||
restrictions.set(objectName, new Map()); | ||
} | ||
|
||
restrictions.get(objectName).set(propertyName, { | ||
message: option.message | ||
}); | ||
|
||
return restrictions; | ||
}, new Map()); | ||
|
||
return { | ||
MemberExpression(node) { | ||
const objectName = node.object && node.object.name; | ||
const propertyName = astUtils.getStaticPropertyName(node); | ||
const matchedObject = restrictedProperties.get(objectName); | ||
const matchedObjectProperty = matchedObject && matchedObject.get(propertyName); | ||
|
||
if (matchedObjectProperty) { | ||
const message = matchedObjectProperty.message ? " " + matchedObjectProperty.message : ""; | ||
|
||
context.report(node, "'{{objectName}}.{{propertyName}}' is restricted from being used.{{message}}", { | ||
objectName, | ||
propertyName, | ||
message | ||
}); | ||
} | ||
} | ||
}; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/** | ||
* @fileoverview Tests for no-restricted-properties rule. | ||
* @author Will Klein & Eli White | ||
*/ | ||
|
||
"use strict"; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Requirements | ||
//------------------------------------------------------------------------------ | ||
|
||
const rule = require("../../../lib/rules/no-restricted-properties"), | ||
RuleTester = require("../../../lib/testers/rule-tester"); | ||
|
||
//------------------------------------------------------------------------------ | ||
// Tests | ||
//------------------------------------------------------------------------------ | ||
|
||
const ruleTester = new RuleTester(); | ||
|
||
ruleTester.run("no-restricted-properties", rule, { | ||
valid: [ | ||
{ | ||
code: "someObject.someProperty", | ||
options: [{ | ||
object: "someObject", | ||
property: "disallowedProperty" | ||
}] | ||
}, { | ||
code: "anotherObject.disallowedProperty", | ||
options: [{ | ||
object: "someObject", | ||
property: "disallowedProperty" | ||
}] | ||
}, { | ||
code: "someObject.someProperty()", | ||
options: [{ | ||
object: "someObject", | ||
property: "disallowedProperty" | ||
}] | ||
}, { | ||
code: "anotherObject.disallowedProperty()", | ||
options: [{ | ||
object: "someObject", | ||
property: "disallowedProperty" | ||
}] | ||
}, { | ||
code: "anotherObject.disallowedProperty()", | ||
options: [{ | ||
object: "someObject", | ||
property: "disallowedProperty", | ||
message: "Please use someObject.allowedProperty instead." | ||
}] | ||
}, { | ||
code: "anotherObject['disallowedProperty']()", | ||
options: [{ | ||
object: "someObject", | ||
property: "disallowedProperty" | ||
}] | ||
}, { | ||
code: "obj.toString", | ||
options: [{ | ||
object: "obj", | ||
property: "__proto__" | ||
}] | ||
}, { | ||
code: "toString.toString", | ||
options: [{ | ||
object: "obj", | ||
property: "foo" | ||
}] | ||
}, { | ||
code: "obj.toString", | ||
options: [{ | ||
object: "obj", | ||
property: "foo" | ||
}] | ||
} | ||
], | ||
|
||
invalid: [ | ||
{ | ||
code: "someObject.disallowedProperty", | ||
options: [{ | ||
object: "someObject", | ||
property: "disallowedProperty" | ||
}], | ||
errors: [{ | ||
message: "'someObject.disallowedProperty' is restricted from being used.", | ||
type: "MemberExpression" | ||
}] | ||
}, { | ||
code: "someObject.disallowedProperty", | ||
options: [{ | ||
object: "someObject", | ||
property: "disallowedProperty", | ||
message: "Please use someObject.allowedProperty instead." | ||
}], | ||
errors: [{ | ||
message: "'someObject.disallowedProperty' is restricted from being used. Please use someObject.allowedProperty instead.", | ||
type: "MemberExpression" | ||
}] | ||
}, { | ||
code: "someObject.disallowedProperty; anotherObject.anotherDisallowedProperty()", | ||
options: [{ | ||
object: "someObject", | ||
property: "disallowedProperty" | ||
}, { | ||
object: "anotherObject", | ||
property: "anotherDisallowedProperty" | ||
}], | ||
errors: [{ | ||
message: "'someObject.disallowedProperty' is restricted from being used.", | ||
type: "MemberExpression" | ||
}, { | ||
message: "'anotherObject.anotherDisallowedProperty' is restricted from being used.", | ||
type: "MemberExpression" | ||
}] | ||
} | ||
] | ||
}); |