-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2799 from BYK/id-length
New: Add id-length rule (fixes #2784)
- Loading branch information
Showing
5 changed files
with
234 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
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,84 @@ | ||
# Limit minimum and maximum length for identifiers (id-length) | ||
|
||
Very short identifier names like `e`, `x`, `_t` or very long ones like `hashGeneratorResultOutputContainerObject` usually make the code harder to read and potentially less maintainable. To prevent this, one may enforce a minimum and/or maximum identifier length. (usually min 2-chars) | ||
|
||
```js | ||
// id-length: 1 // default is minimum 2-chars ({ min: 2}) | ||
var x = 5; // too short | ||
``` | ||
|
||
## Rule Details | ||
|
||
This rule is aimed at increasing code readability and maintainability by enforcing an identifier length convention. It will warn on any type of identifier which doesn't conform to length limits (upper and lower). | ||
|
||
It allows the programmers to silently by-pass this check by using "quoted" property names or calculated property access to allow potential server-side data requirements. | ||
|
||
The following patterns are considered warnings: | ||
|
||
```js | ||
// id-length: 1 // default is minimum 2-chars ({ min: 2}) | ||
|
||
var x = 5; | ||
|
||
obj.e = document.body; | ||
|
||
var handler = function (e) { /* do stuff */ }; | ||
|
||
try { | ||
dangerousStuff(); | ||
} catch (e) { // Identifier 'e' is too short. (< 2) | ||
// ignore as many do | ||
} | ||
|
||
var myObj = { a: 1 }; // Identifier 'a' is too short. (< 2) | ||
``` | ||
|
||
The following patterns are not considered warnings: | ||
|
||
```js | ||
// id-length: 1 // default is minimum 2-chars ({ min: 2}) | ||
|
||
var num = 5; | ||
|
||
function _f() { return 42; } | ||
|
||
function _func() { return 42; } | ||
|
||
obj.el = document.body; | ||
|
||
var handler = function (evt) { /* do stuff */ }; | ||
|
||
try { | ||
dangerousStuff(); | ||
} catch (error) { // Identifier 'e' is too short. (< 2) | ||
// ignore as many do | ||
} | ||
|
||
var myObj = { apple: 1 }; | ||
|
||
var data = { "x": 1 }; // excused because of quotes | ||
|
||
data["y"] = 3; // excused because of calculated property access | ||
``` | ||
|
||
### Options | ||
|
||
The `id-length` rule has no required options and has 4 optional ones that needs to be passed in a single options object: | ||
|
||
* **min** *(default: 2)*: The minimum number of characters an identifier name should be, after it is stripped from it is prefixes and suffixes | ||
* **max** *(default: Infinity)*: The maximum number of characters an identifier name should be, after it is stripped from it is prefixes and suffixes | ||
* **exceptions**: An array of identifier names that the rule should not apply to | ||
|
||
For example, to specify a minimum identifier length of 3 and maximum of 10 and add `x` to exception list, use the following configuration: | ||
|
||
```json | ||
"id-length": [2, {"min": 3, "max": 10, "exceptions": ["x"]}] | ||
``` | ||
|
||
|
||
## Related Rules | ||
|
||
* [max-len](max-len.md) | ||
* [new-cap](new-cap.md) | ||
* [func-names](func-names.md) | ||
* [camelcase](camelcase.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 that warns when identifier names are shorter or longer | ||
* than the values provided in configuration. | ||
* @author Burak Yigit Kaya aka BYK | ||
* @copyright 2015 Burak Yigit Kaya. All rights reserved. | ||
*/ | ||
|
||
"use strict"; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Rule Definition | ||
//------------------------------------------------------------------------------ | ||
|
||
module.exports = function(context) { | ||
var options = context.options[0] || {}; | ||
var minLength = typeof options.min !== "undefined" ? options.min : 2; | ||
var maxLength = typeof options.max !== "undefined" ? options.max : Infinity; | ||
var exceptions = (options.exceptions ? options.exceptions : []) | ||
.reduce(function(obj, item) { | ||
obj[item] = true; | ||
|
||
return obj; | ||
}, {}); | ||
|
||
var SUPPORTED_EXPRESSIONS = { | ||
"AssignmentExpression": function(parent, node) { | ||
return parent.left.type === "MemberExpression" && | ||
!parent.left.computed && parent.left.property === node; | ||
}, | ||
"VariableDeclarator": function(parent, node) { | ||
return parent.id === node; | ||
}, | ||
"ObjectExpression": function(parent, node) { | ||
return node.parent.key === node; | ||
}, | ||
"FunctionExpression": true, | ||
"FunctionDeclaration": true, | ||
"CatchClause": true | ||
}; | ||
|
||
return { | ||
Identifier: function(node) { | ||
var name = node.name; | ||
var effectiveParent = (node.parent.type === "MemberExpression" || node.parent.type === "Property") ? | ||
node.parent.parent : node.parent; | ||
|
||
var isShort = name.length < minLength; | ||
var isLong = name.length > maxLength; | ||
if (!(isShort || isLong) || exceptions[name]) { | ||
return; // Nothing to report | ||
} | ||
|
||
var isValidExpression = SUPPORTED_EXPRESSIONS[effectiveParent.type]; | ||
|
||
if (isValidExpression && (isValidExpression === true || isValidExpression(effectiveParent, node))) { | ||
context.report( | ||
node, | ||
isShort ? | ||
"Identifier name '{{name}}' is too short. (< {{min}})" : | ||
"Identifier name '{{name}}' is too long. (> {{max}})", | ||
{ name: name, min: minLength, max: maxLength } | ||
); | ||
} | ||
} | ||
}; | ||
}; | ||
|
||
module.exports.schema = [ | ||
{ | ||
"type": "object", | ||
"properties": { | ||
"min": { | ||
"type": "number" | ||
}, | ||
"max": { | ||
"type": "number" | ||
}, | ||
"exceptions": { | ||
"type": "array", | ||
"uniqueItems": true, | ||
"items": { | ||
"type": "string" | ||
} | ||
} | ||
}, | ||
"additionalProperties": false | ||
} | ||
]; |
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,60 @@ | ||
/** | ||
* @fileoverview Tests for id-length rule. | ||
* @author Burak Yigit Kaya | ||
*/ | ||
|
||
"use strict"; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Requirements | ||
//------------------------------------------------------------------------------ | ||
|
||
var eslint = require("../../../lib/eslint"), | ||
ESLintTester = require("../../../lib/testers/eslint-tester"); | ||
|
||
//------------------------------------------------------------------------------ | ||
// Tests | ||
//------------------------------------------------------------------------------ | ||
|
||
var eslintTester = new ESLintTester(eslint); | ||
eslintTester.addRuleTest("lib/rules/id-length", { | ||
valid: [ | ||
"var xyz;", | ||
"var xy = 1;", | ||
"function xyz() {};", | ||
"function xyz(abc, de) {};", | ||
"var obj = { abc: 1, de: 2 };", | ||
"var obj = { 'a': 1, bc: 2 };", | ||
"var obj = {}; obj['a'] = 2;", | ||
"abc = d;", | ||
"try { blah(); } catch (err) { /* pass */ }", | ||
"var handler = function ($e) {};", | ||
"var _a = 2", | ||
"var _ad$$ = new $;", | ||
"var xyz = new ΣΣ();", | ||
"unrelatedExpressionThatNeedsToBeIgnored();", | ||
"var obj = { 'a': 1, bc: 2 }; obj.tk = obj.a;", | ||
{ code: "var x = Foo(42)", options: [{"min": 1}] }, | ||
{ code: "var x = Foo(42)", options: [{"min": 0}] }, | ||
{ code: "foo.$x = Foo(42)", options: [{"min": 1}] }, | ||
{ code: "var lalala = Foo(42)", options: [{"max": 6}] }, | ||
{ code: "for (var q, h=0; h < 10; h++) { console.log(h); q++;}", options: [{exceptions: ["h", "q"]}] } | ||
], | ||
invalid: [ | ||
{ code: "var x = 1;", errors: [{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier"}] }, | ||
{ code: "var x;", errors: [{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier"}] }, | ||
{ code: "function x() {};", errors: [{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier"}] }, | ||
{ code: "function xyz(a) {};", errors: [{ message: "Identifier name 'a' is too short. (< 2)", type: "Identifier"}] }, | ||
{ code: "var obj = {a: 1, bc: 2};", errors: [{ message: "Identifier name 'a' is too short. (< 2)", type: "Identifier"}] }, | ||
{ code: "try { blah(); } catch (e) { /* pass */ }", errors: [{ message: "Identifier name 'e' is too short. (< 2)", type: "Identifier"}] }, | ||
{ code: "var handler = function (e) {};", errors: [{ message: "Identifier name 'e' is too short. (< 2)", type: "Identifier"}] }, | ||
{ code: "for (var i=0; i < 10; i++) { console.log(i); }", errors: [{ message: "Identifier name 'i' is too short. (< 2)", type: "Identifier"}] }, | ||
{ code: "var j=0; while (j > -10) { console.log(--j); }", errors: [{ message: "Identifier name 'j' is too short. (< 2)", type: "Identifier"}] }, | ||
{ code: "var _$xt_$ = Foo(42)", options: [{"min": 2, "max": 4}], errors: [ | ||
{ message: "Identifier name '_$xt_$' is too long. (> 4)", type: "Identifier"} | ||
]}, | ||
{ code: "var _$x$_t$ = Foo(42)", options: [{"min": 2, "max": 4}], errors: [ | ||
{ message: "Identifier name '_$x$_t$' is too long. (> 4)", type: "Identifier"} | ||
] } | ||
] | ||
}); |