Skip to content

Commit

Permalink
Fix: id-length does not work for most of the new ES6 patterns (fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
BYK committed Aug 8, 2015
1 parent a222f54 commit 6db92d6
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 30 deletions.
50 changes: 50 additions & 0 deletions docs/rules/id-length.md
Expand Up @@ -31,6 +31,32 @@ try {
}

var myObj = { a: 1 }; // Identifier 'a' is too short. (< 2)

(a) => { a * a }; // Identifier name 'a' is too short. (< 2)

function foo(x = 0) { } // Identifier name 'x' is too short. (< 2)

class x { } // Identifier name 'x' is too short. (< 2)

class Foo { x() {} } // Identifier name 'x' is too short. (< 2)

function foo(...x) { } // Identifier name 'x' is too short. (< 2)

var { x} = {}; // Identifier name 'x' is too short. (< 2)

var { x: a} = {}; // Identifier name 'x' is too short. (< 2)

var { a: [x]} = {}; // Identifier name 'a' is too short. (< 2)

import x from 'y'; // Identifier name 'x' is too short. (< 2)

export var x = 0; // Identifier name 'x' is too short. (< 2)

({ a: obj.x.y.z }) = {}; // Identifier name 'a' is too short. (< 2)
// Identifier name 'x' is too short. (< 2)

({ prop: obj.x }) = {}; // Identifier name 'x' is too short. (< 2)

```

The following patterns are not considered warnings:
Expand All @@ -56,6 +82,30 @@ try {

var myObj = { apple: 1 };

(num) => { num * num };

function foo(num = 0) { }

class MyClass { }

class Foo { method() {} }

function foo(...args) { }

var { prop } = {};

var { prop: a } = {};

var { prop: [x] } = {};

import something from "y";

export var num = 0;

({ prop: obj.x.y.something }) = {};

({ prop: obj.longName }) = {};

var data = { "x": 1 }; // excused because of quotes

data["y"] = 3; // excused because of calculated property access
Expand Down
30 changes: 21 additions & 9 deletions lib/rules/id-length.js
Expand Up @@ -23,37 +23,49 @@ module.exports = function(context) {
}, {});

var SUPPORTED_EXPRESSIONS = {
"AssignmentExpression": function(parent, node) {
return parent.left.type === "MemberExpression" &&
!parent.left.computed && parent.left.property === node;
"MemberExpression": function(parent) {
return !parent.computed && (
// regular property assignment
parent.parent.left === parent || (
// or the last identifier in an ObjectPattern destructuring
parent.parent.type === "Property" && parent.parent.value === parent &&
parent.parent.parent.type === "ObjectPattern" && parent.parent.parent.parent.left === parent.parent.parent
)
);
},
"AssignmentPattern": function(parent, node) {
return parent.left === node;
},
"VariableDeclarator": function(parent, node) {
return parent.id === node;
},
"ObjectExpression": function(parent, node) {
return node.parent.key === node;
"Property": function(parent, node) {
return parent.key === node;
},
"ImportDefaultSpecifier": true,
"RestElement": true,
"FunctionExpression": true,
"ArrowFunctionExpression": true,
"ClassDeclaration": true,
"FunctionDeclaration": true,
"MethodDefinition": 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 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];
var isValidExpression = SUPPORTED_EXPRESSIONS[parent.type];

if (isValidExpression && (isValidExpression === true || isValidExpression(effectiveParent, node))) {
if (isValidExpression && (isValidExpression === true || isValidExpression(parent, node))) {
context.report(
node,
isShort ?
Expand Down
88 changes: 67 additions & 21 deletions tests/lib/rules/id-length.js
Expand Up @@ -34,31 +34,77 @@ ruleTester.run("id-length", rule, {
"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"]}] },
{ code: "(num) => { num * num };", ecmaFeatures: { arrowFunctions: true } }
{ 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"] }] },
{ code: "(num) => { num * num };", ecmaFeatures: { arrowFunctions: true } },
{ code: "function foo(num = 0) { }", ecmaFeatures: { defaultParams: true } },
{ code: "class MyClass { }", ecmaFeatures: { classes: true } },
{ code: "class Foo { method() {} }", ecmaFeatures: { classes: true } },
{ code: "function foo(...args) { }", ecmaFeatures: { restParams: true } },
{ code: "var { prop } = {};", ecmaFeatures: { destructuring: true } },
{ code: "var { prop: a } = {};", ecmaFeatures: { destructuring: true } },
{ code: "var { prop: [x] } = {};", ecmaFeatures: { destructuring: true } },
{ code: "import something from 'y';", ecmaFeatures: { modules: true } },
{ code: "export var num = 0;", ecmaFeatures: { modules: true } },
{ code: "({ prop: obj.x.y.something }) = {};", ecmaFeatures: { destructuring: true } },
{ code: "({ prop: obj.longName }) = {};", ecmaFeatures: { destructuring: true } }
],
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 = 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"}
{ code: "var _$x$_t$ = Foo(42)", options: [{ "min": 2, "max": 4 }], errors: [
{ message: "Identifier name '_$x$_t$' is too long. (> 4)", type: "Identifier" }
]},
{ code: "(a) => { a * a };", ecmaFeatures: { arrowFunctions: true}, errors: [
{ message: "Identifier name 'a' is too short. (< 2)", type: "Identifier"}
{ code: "(a) => { a * a };", ecmaFeatures: { arrowFunctions: true }, errors: [
{ message: "Identifier name 'a' is too short. (< 2)", type: "Identifier" }
]},
{ code: "function foo(x = 0) { }", ecmaFeatures: { defaultParams: true }, errors: [
{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier" }
]},
{ code: "class x { }", ecmaFeatures: { classes: true }, errors: [
{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier" }
]},
{ code: "class Foo { x() {} }", ecmaFeatures: { classes: true }, errors: [
{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier" }
]},
{ code: "function foo(...x) { }", ecmaFeatures: { restParams: true}, errors: [
{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier" }
]},
{ code: "var { x} = {};", ecmaFeatures: { destructuring: true}, errors: [
{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier" },
{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier" }
]},
{ code: "var { x: a} = {};", ecmaFeatures: { destructuring: true}, errors: [
{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier" }
]},
{ code: "var { a: [x]} = {};", ecmaFeatures: { destructuring: true }, errors: [
{ message: "Identifier name 'a' is too short. (< 2)", type: "Identifier" }
]},
{ code: "import x from 'y';", ecmaFeatures: { modules: true }, errors: [
{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier" }
]},
{ code: "export var x = 0;", ecmaFeatures: { modules: true }, errors: [
{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier" }
]},
{ code: "({ a: obj.x.y.z }) = {};", ecmaFeatures: { destructuring: true }, errors: [
{ message: "Identifier name 'a' is too short. (< 2)", type: "Identifier" },
{ message: "Identifier name 'z' is too short. (< 2)", type: "Identifier" }
]},
{ code: "({ prop: obj.x }) = {};", ecmaFeatures: { destructuring: true }, errors: [
{ message: "Identifier name 'x' is too short. (< 2)", type: "Identifier" }
]}
]
});

0 comments on commit 6db92d6

Please sign in to comment.