Repository: eslint/eslint (JavaScript)

Issue:
`id-length` does not check identifier in array pattern
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).

    This template is for bug reports. If you are here for another reason, please see below:

    1. To propose a new rule: https://eslint.org/docs/developer-guide/contributing/new-rules
    2. To request a rule change: https://eslint.org/docs/developer-guide/contributing/rule-changes
    3. To request a change that is not a bug fix, rule change, or new rule: https://eslint.org/docs/developer-guide/contributing/changes
    4. If you have any questions, please stop by our chatroom: https://gitter.im/eslint/eslint

    Note that leaving sections blank will make it difficult for us to troubleshoot and we may have to close the issue.
-->

**Tell us about your environment**

<!--
    If you are using ESLint v6.5.0 or later, you can run ESLint with the `--env-info` flag and paste the output here.
-->

* **ESLint Version:** 6.8.0
* **Node Version:** 12.13.0
* **npm Version:** 6.12.0

**What parser (default, Babel-ESLint, etc.) are you using?**

default

**Please show your full configuration:**

<details>
<summary>Configuration</summary>

<!-- Paste your configuration below: -->
```js

```

</details>

**What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.**

[Online demo](https://eslint.org/demo#eyJ0ZXh0IjoiLyplc2xpbnQgaWQtbGVuZ3RoOiBcImVycm9yXCIqLyAgICAgLy8gZGVmYXVsdCBpcyBtaW5pbXVtIDItY2hhcnMgKHsgXCJtaW5cIjogMiB9KVxuLyplc2xpbnQtZW52IGVzNiovXG5jb25zdCBbYV0gPSBmb287Iiwib3B0aW9ucyI6eyJwYXJzZXJPcHRpb25zIjp7ImVjbWFWZXJzaW9uIjoxMSwic291cmNlVHlwZSI6Im1vZHVsZSIsImVjbWFGZWF0dXJlcyI6eyJqc3giOnRydWV9fSwicnVsZXMiOnt9LCJlbnYiOnsiYnJvd3NlciI6ZmFsc2V9fX0=)
<!-- Paste the source code below: -->
```js
/*eslint id-length: "error"*/     // default is minimum 2-chars ({ "min": 2 })
/*eslint-env es6*/
const [a] = foo;
```


**What did you expect to happen?**

Warn about short named identifier `a`;

**What actually happened? Please include the actual, raw output from ESLint.**

No error.

**Are you willing to submit a pull request to fix this bug?**

Yes. I already finished the implementation.(locally)

But, I have a question before pull request.

> Examples of correct code for this rule with the default options:
> ...
> var { prop: [x] } = {};
> ...

By the [docs in id-length](https://eslint.org/docs/rules/id-length), there is an example in the correct example section showing the array pattern with the short identifier `x`.
In my understanding, the `x` is an identifier created by array destructuring so it should be checked by this rule.

Am I missing something? Is it intended behavior?



Discussion:
Thanks for reporting this! Agreed that this is a bug. The rule already warns for this alternative equivalent:

```js
const a = foo[0];
```
See demo [here](https://eslint.org/demo#eyJ0ZXh0IjoiLyplc2xpbnQgaWQtbGVuZ3RoOiBcImVycm9yXCIqLyAgICAgLy8gZGVmYXVsdCBpcyBtaW5pbXVtIDItY2hhcnMgKHsgXCJtaW5cIjogMiB9KVxuLyplc2xpbnQtZW52IGVzNiovXG5cbmNvbnN0IGEgPSBmb29bMF07Iiwib3B0aW9ucyI6eyJwYXJzZXJPcHRpb25zIjp7ImVjbWFWZXJzaW9uIjoxMSwic291cmNlVHlwZSI6Im1vZHVsZSIsImVjbWFGZWF0dXJlcyI6eyJqc3giOnRydWV9fSwicnVsZXMiOnt9LCJlbnYiOnsiYnJvd3NlciI6ZmFsc2V9fX0=).
## To note
After #12881 merged, there are false negative examples in the `id-length.md`:

At Examples of correct code...
```js
/*eslint id-length: "error"*/     // default is minimum 2-chars ({ "min": 2 })
/*eslint-env es6*/
// ...
var { prop: [x] } = {}; // false negative, It should be placed in an incorrect example
// ...
```

This will be fixed in #12839.




Patch:
diff --git a/docs/rules/id-length.md b/docs/rules/id-length.md
index 081784bbebcf..f9f6de100805 100644
--- a/docs/rules/id-length.md
+++ b/docs/rules/id-length.md
@@ -31,6 +31,9 @@ var myObj = { a: 1 };
 class x { }
 class Foo { x() {} }
 function foo(...x) { }
+function foo([x]) { }
+var [x] = arr;
+var { prop: [x]} = {};
 function foo({x}) { }
 var { x } = {};
 var { prop: a} = {};
@@ -59,71 +62,19 @@ function foo(num = 0) { }
 class MyClass { }
 class Foo { method() {} }
 function foo(...args) { }
+function foo([longName]) { }
+var { prop } = {};
+var { prop: [longName] } = {};
+var [longName] = arr;
 function foo({ prop }) { }
 function foo({ a: prop }) { }
 var { prop } = {};
 var { a: prop } = {};
-var { prop: [x] } = {};
 ({ prop: obj.longName } = {});
 var data = { "x": 1 };  // excused because of quotes
 data["y"] = 3;  // excused because of calculated property access
 ```
 
-This rule has a shorthand integer option for the `"min"` object property.
-
-Examples of **incorrect** code for this rule with a minimum of 4:
-
-```js
-/*eslint id-length: ["error", { "min": 4 }]*/
-/*eslint-env es6*/
-
-var val = 5;
-obj.e = document.body;
-function foo (e) { };
-try {
-    dangerousStuff();
-} catch (e) {
-    // ignore as many do
-}
-var myObj = { a: 1 };
-(val) => { val * val };
-class x { }
-class Foo { x() {} }
-function foo(...x) { }
-var { x } = {};
-var { prop: x} = {};
-({ prop: obj.x } = {});
-```
-
-Examples of **correct** code for this rule with a minimum of 4:
-
-```js
-/*eslint id-length: ["error", { "min": 4 }]*/
-/*eslint-env es6*/
-
-var value = 5;
-function func() { return 42; }
-obj.element = document.body;
-var foobar = function (event) { /* do stuff */ };
-try {
-    dangerousStuff();
-} catch (error) {
-    // ignore as many do
-}
-var myObj = { apple: 1 };
-(value) => { value * value };
-function foobar(value = 0) { }
-class MyClass { }
-class Foobar { method() {} }
-function foobar(...args) { }
-var { prop } = {};
-var { a: longName } = {};
-var { prop: [x] } = {};
-({ prop: obj.name } = {});
-var data = { "x": 1 };  // excused because of quotes
-data["y"] = 3;  // excused because of calculated property access
-```
-
 This rule has an object option:
 
 * `"min"` (default: 2) enforces a minimum identifier length
@@ -155,6 +106,8 @@ class Foo { x() {} }
 function foo(...x) { }
 var { x } = {};
 var { prop: a} = {};
+var [x] = arr;
+var { prop: [x]} = {};
 ({ prop: obj.x } = {});
 ```
 
@@ -180,8 +133,9 @@ class MyClass { }
 class Foobar { method() {} }
 function foobar(...args) { }
 var { prop } = {};
+var [longName] = foo;
+var { a: [prop] } = {};
 var { a: longName } = {};
-var { prop: [x] } = {};
 ({ prop: obj.name } = {});
 var data = { "x": 1 };  // excused because of quotes
 data["y"] = 3;  // excused because of calculated property access
@@ -205,6 +159,7 @@ try {
     // ignore as many do
 }
 (reallyLongArgName) => { return !reallyLongArgName; };
+var [reallyLongFirstElementName] = arr;
 ```
 
 Examples of **correct** code for this rule with the `{ "max": 10 }` option:
@@ -223,6 +178,7 @@ try {
     // ignore as many do
 }
 (arg) => { return !arg; };
+var [first] = arr;
 ```
 
 ### properties
@@ -256,6 +212,7 @@ try {
     // ignore as many do
 }
 (x) => { return x * x; };
+var [x] = arr;
 const { x } = foo;
 const { a: x } = foo;
 ```
diff --git a/lib/rules/id-length.js b/lib/rules/id-length.js
index 5509a486aff4..a68873ac0628 100644
--- a/lib/rules/id-length.js
+++ b/lib/rules/id-length.js
@@ -100,7 +100,8 @@ module.exports = {
             ClassDeclaration: true,
             FunctionDeclaration: true,
             MethodDefinition: true,
-            CatchClause: true
+            CatchClause: true,
+            ArrayPattern: true
         };
 
         return {


Test patch:
diff --git a/tests/lib/rules/id-length.js b/tests/lib/rules/id-length.js
index 69ea8670abb8..a63ae1be99c9 100644
--- a/tests/lib/rules/id-length.js
+++ b/tests/lib/rules/id-length.js
@@ -72,6 +72,8 @@ ruleTester.run("id-length", rule, {
         { code: "var obj = {}; obj.aaaaa = 1;", options: [{ max: 4, properties: "never" }] },
         { code: "({ a: obj.x.y.z } = {});", options: [{ max: 4, properties: "never" }], parserOptions: { ecmaVersion: 6 } },
         { code: "({ prop: obj.xxxxx } = {});", options: [{ max: 4, properties: "never" }], parserOptions: { ecmaVersion: 6 } },
+        { code: "var arr = [i,j,f,b]", parserOptions: { ecmaVersion: 6 } },
+        { code: "function foo([arr]) {}", parserOptions: { ecmaVersion: 6 } },
         { code: "var {x} = foo;", options: [{ properties: "never" }], parserOptions: { ecmaVersion: 6 } },
         { code: "var {x, y: {z}} = foo;", options: [{ properties: "never" }], parserOptions: { ecmaVersion: 6 } },
         { code: "let foo = { [a]: 1 };", options: [{ properties: "always" }], parserOptions: { ecmaVersion: 6 } },
@@ -88,6 +90,9 @@ ruleTester.run("id-length", rule, {
         { code: "var handler = function (e) {};", errors: [tooShortError] },
         { code: "for (var i=0; i < 10; i++) { console.log(i); }", errors: [tooShortError] },
         { code: "var j=0; while (j > -10) { console.log(--j); }", errors: [tooShortError] },
+        { code: "var [i] = arr;", parserOptions: { ecmaVersion: 6 }, errors: [tooShortError] },
+        { code: "var [,i,a] = arr;", parserOptions: { ecmaVersion: 6 }, errors: [tooShortError, tooShortError] },
+        { code: "function foo([a]) {}", parserOptions: { ecmaVersion: 6 }, errors: [tooShortError] },
         {
             code: "var _$xt_$ = Foo(42)",
             options: [{ min: 2, max: 4 }],
@@ -252,6 +257,20 @@ ruleTester.run("id-length", rule, {
                 tooShortError
             ]
         },
+        {
+            code: "var { prop: [x] } = {};",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                tooShortError
+            ]
+        },
+        {
+            code: "var { prop: [[x]] } = {};",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                tooShortError
+            ]
+        },
         {
             code: "var { prop: longName } = {};",
             options: [{ min: 3, max: 5 }],