Skip to content

Commit

Permalink
New: no-restricted-properties rule (fixes eslint#3218)
Browse files Browse the repository at this point in the history
  • Loading branch information
willklein committed Apr 15, 2016
1 parent 9f7c21e commit 3f62847
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 0 deletions.
1 change: 1 addition & 0 deletions conf/eslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
"no-restricted-globals": "off",
"no-restricted-imports": "off",
"no-restricted-modules": "off",
"no-restricted-properties": "off",
"no-restricted-syntax": "off",
"no-return-assign": "off",
"no-script-url": "off",
Expand Down
1 change: 1 addition & 0 deletions docs/rules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ These rules are purely matters of style and are quite subjective.
* [no-nested-ternary](no-nested-ternary.md): disallow nested ternary expressions
* [no-new-object](no-new-object.md): disallow `Object` constructors
* [no-plusplus](no-plusplus.md): disallow the unary operators `++` and `--`
* [no-restricted-properties](no-restricted-properties.md) - disallow use of specified object properties
* [no-restricted-syntax](no-restricted-syntax.md): disallow specified syntax
* [no-spaced-func](no-spaced-func.md): disallow spacing between `function` identifiers and their applications (fixable)
* [no-ternary](no-ternary.md): disallow ternary operators
Expand Down
73 changes: 73 additions & 0 deletions docs/rules/no-restricted-properties.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# 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. 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.

## Rule Details

This rule is aimed at disallowing certain object properties from your code.

### 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."
}]]
}
}
```

The following patterns are considered problems:

```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.*/
```

The following patterns are not considered problems:

```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)
72 changes: 72 additions & 0 deletions lib/rules/no-restricted-properties.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* @fileoverview Rule to disallow specified object methods
* @author Will Klein
* @copyright 2016 Will Klein. All rights reserved.
*/

"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function(context) {
if (context.options.length === 0) {
return {};
}

var restrictedProperties = context.options.reduce(function(restrictions, option) {
var objectName = option.object;
var propertyName = option.property;

restrictions[objectName] = restrictions[objectName] || {};
restrictions[objectName][propertyName] = {
message: option.message
};

return restrictions;
}, {});

return {
"MemberExpression": function(node) {
var objectName = node.object && node.object.name;
var propertyName = node.property && node.property.name;
var matchedObject = restrictedProperties[objectName];
var matchedObjectProperty = matchedObject && matchedObject[propertyName];

if (matchedObjectProperty) {
var message = matchedObjectProperty.message ? " " + matchedObjectProperty.message : "";

context.report(node, "'{{objectName}}.{{propertyName}}' is restricted from being used.{{message}}", {
objectName: objectName,
propertyName: propertyName,
message: message
});
}
}
};
};

module.exports.schema = {
"type": "array",
"items": {
"type": "object",
"properties": {
"object": {
"type": "string"
},
"property": {
"type": "string"
},
"message": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"object",
"property"
]
},
"uniqueItems": true
};
94 changes: 94 additions & 0 deletions tests/lib/rules/no-restricted-properties.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* @fileoverview Tests for no-restricted-properties rule.
* @author Will Klein
* @copyright 2015 Will Klein. All rights reserved.
*/

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

var rule = require("../../../lib/rules/no-restricted-properties");
var RuleTester = require("../../../lib/testers/rule-tester");

var 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."
}]
}
],

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"
}]
}
]
});

0 comments on commit 3f62847

Please sign in to comment.