Skip to content

Commit

Permalink
New: 'id-blacklist' rule (fixes #3358)
Browse files Browse the repository at this point in the history
  • Loading branch information
keithamus committed Jan 14, 2016
1 parent 2dba9c7 commit 5e4841e
Show file tree
Hide file tree
Showing 5 changed files with 496 additions and 0 deletions.
1 change: 1 addition & 0 deletions conf/eslint.json
Expand Up @@ -180,6 +180,7 @@
"quotes": 0,
"radix": 0,
"id-match": 0,
"id-blacklist": 0,
"require-jsdoc": 0,
"require-yield": 0,
"semi": 0,
Expand Down
1 change: 1 addition & 0 deletions docs/rules/README.md
Expand Up @@ -157,6 +157,7 @@ These rules are purely matters of style and are quite subjective.
* [func-style](func-style.md) - enforce use of function declarations or expressions
* [id-length](id-length.md) - this option enforces minimum and maximum identifier lengths (variable names, property names etc.)
* [id-match](id-match.md) - require identifiers to match the provided regular expression
* [id-blacklist](id-blacklist.md) - blacklist certain identifiers to prevent them being used
* [indent](indent.md) - specify tab or space width for your code (fixable)
* [jsx-quotes](jsx-quotes.md) - specify whether double or single quotes should be used in JSX attributes
* [key-spacing](key-spacing.md) - enforce spacing between keys and values in object literal properties
Expand Down
83 changes: 83 additions & 0 deletions docs/rules/id-blacklist.md
@@ -0,0 +1,83 @@
# Blacklist certain identifiers to prevent them being used (id-blacklist)

> "There are only two hard things in Computer Science: cache invalidation and naming things." — Phil Karlton
Bad names can lead to hard to decipher code. Using generic names, such as `data` don't infer much about the code and the values it receives. This rule allows you to configure a blacklist of bad identifier names, that you don't want to see in your code.

## Rule Details

This rule compares assignments and function definitions to a provided list of identifier names. If the identifier is present in the list, it will return an error.

This rule will catch blacklisted identifiers that are:

- variable declarations
- function declarations
- object properties

It will not catch blacklisted identifiers that are:

- function calls (so you can still use functions you do not have control over)
- object properties (so you can still use objects you do not have control over)


### Options

This rule needs a a set of identifier names to blacklist, like so:

```json
{
"rules": {
"id-blacklist": [2, "data", "err", "e", "cb", "callback"]
}
}
```

For the rule in this example, the following patterns are considered problems:

```js
/*eslint id-blacklist: [2, "data", "err", "e", "cb", "callback"] */

var data = {...}; /*error Identifier 'data' is blacklisted*/

function callback() { /*error Identifier 'callback' is blacklisted*/
// ...
}

element.callback = function() { /*error Identifier 'callback' is blacklisted*/
// ...
};

var itemSet = {
data: [...] /*error Identifier 'data' is blacklisted*/
};
```

The following patterns are not considered problems:

```js
/*eslint id-blacklist: [2, "data", "err", "e", "cb", "callback"] */

var encodingOptions = {...};

function processFileResult() {
// ...
}

element.successHandler = function() {
// ...
};

var itemSet = {
entities: [...]
};

callback() // all function calls are ignored

foo.callback() // all function calls are ignored

foo.data // all property names that are not assignments are ignored
```

## When Not To Use It

You can turn this rule off if you are happy for identifiers to be named freely.
110 changes: 110 additions & 0 deletions lib/rules/id-blacklist.js
@@ -0,0 +1,110 @@
/**
* @fileoverview Rule that warns when identifier names that are
blacklisted in the configuration are used.
* @author Keith Cirkel (http://keithcirkel.co.uk)
* Based on id-match rule:
* @author Matthieu Larcher
* @copyright 2015 Matthieu Larcher. All rights reserved.
* See LICENSE in root directory for full license.
*/

"use strict";

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

module.exports = function(context) {


//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------

var blacklist = context.options;


/**
* Checks if a string matches the provided pattern
* @param {String} name The string to check.
* @returns {boolean} if the string is a match
* @private
*/
function isInvalid(name) {
return blacklist.indexOf(name) !== -1;
}

/**
* Verifies if we should report an error or not based on the effective
* parent node and the identifier name.
* @param {ASTNode} effectiveParent The effective parent node of the node to be reported
* @param {String} name The identifier name of the identifier node
* @returns {boolean} whether an error should be reported or not
*/
function shouldReport(effectiveParent, name) {
return effectiveParent.type !== "CallExpression"
&& effectiveParent.type !== "NewExpression" &&
isInvalid(name);
}

/**
* Reports an AST node as a rule violation.
* @param {ASTNode} node The node to report.
* @returns {void}
* @private
*/
function report(node) {
context.report(node, "Identifier '{{name}}' is blacklisted", {
name: node.name
});
}

return {

"Identifier": function(node) {
var name = node.name,
effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent;

// MemberExpressions get special rules
if (node.parent.type === "MemberExpression") {

// Always check object names
if (node.parent.object.type === "Identifier" &&
node.parent.object.name === node.name) {
if (isInvalid(name)) {
report(node);
}

// Report AssignmentExpressions only if they are the left side of the assignment
} else if (effectiveParent.type === "AssignmentExpression" &&
(effectiveParent.right.type !== "MemberExpression" ||
effectiveParent.left.type === "MemberExpression" &&
effectiveParent.left.property.name === node.name)) {
if (isInvalid(name)) {
report(node);
}
}

// Properties have their own rules
} else if (node.parent.type === "Property") {

if (shouldReport(effectiveParent, name)) {
report(node);
}

// Report anything that is a match and not a CallExpression
} else if (shouldReport(effectiveParent, name)) {
report(node);
}
}

};

};
module.exports.schema = {
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true
};

0 comments on commit 5e4841e

Please sign in to comment.