Skip to content

Commit 27bc3c3

Browse files
authored
Add auto-fix for no-unreadable-array-destructuring (#1010)
1 parent 4c92d4c commit 27bc3c3

File tree

6 files changed

+247
-26
lines changed

6 files changed

+247
-26
lines changed

docs/rules/no-unreadable-array-destructuring.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,23 @@
22

33
Destructuring is very useful, but it can also make some code harder to read. This rule prevents ignoring consecutive values when destructuring from an array.
44

5+
This rule is partly fixable.
56

67
## Fail
78

89
```js
910
const [,, foo] = parts;
11+
```
12+
13+
```js
1014
const [,,, foo] = parts;
15+
```
16+
17+
```js
1118
const [,,,, foo] = parts;
19+
```
20+
21+
```js
1222
const [,,...rest] = parts;
1323
```
1424

@@ -17,11 +27,23 @@ const [,,...rest] = parts;
1727

1828
```js
1929
const [, foo] = parts;
30+
```
31+
32+
```js
2033
const [foo] = parts;
34+
```
35+
36+
```js
2137
const foo = parts[3];
38+
```
39+
40+
```js
2241
const [,...rest] = parts;
2342
```
2443

44+
```js
45+
const foo = parts.slice(3);
46+
```
2547

2648
## Note
2749

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ Configure it in `package.json`.
138138
- [no-null](docs/rules/no-null.md) - Disallow the use of the `null` literal.
139139
- [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) - Disallow the use of objects as default parameters.
140140
- [no-process-exit](docs/rules/no-process-exit.md) - Disallow `process.exit()`.
141-
- [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) - Disallow unreadable array destructuring.
141+
- [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) - Disallow unreadable array destructuring. *(partly fixable)*
142142
- [no-unsafe-regex](docs/rules/no-unsafe-regex.md) - Disallow unsafe regular expressions.
143143
- [no-unused-properties](docs/rules/no-unused-properties.md) - Disallow unused object properties.
144144
- [no-useless-undefined](docs/rules/no-useless-undefined.md) - Disallow useless `undefined`. *(fixable)*
Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
2+
const {isParenthesized} = require('eslint-utils');
23
const getDocumentationUrl = require('./utils/get-documentation-url');
4+
const shouldAddParenthesesToMemberExpressionObject = require('./utils/should-add-parentheses-to-member-expression-object');
35

46
const MESSAGE_ID = 'no-unreadable-array-destructuring';
57
const messages = {
@@ -10,14 +12,53 @@ const isCommaFollowedWithComma = (element, index, array) =>
1012
element === null && array[index + 1] === null;
1113

1214
const create = context => {
15+
const sourceCode = context.getSourceCode();
16+
1317
return {
14-
'ArrayPattern[elements.length>=3]': node => {
15-
if (node.elements.some((element, index, array) => isCommaFollowedWithComma(element, index, array))) {
16-
context.report({
17-
node,
18-
messageId: MESSAGE_ID
19-
});
18+
'ArrayPattern[elements.length>=3]'(node) {
19+
const {elements, parent} = node;
20+
21+
if (!elements.some((element, index, elements) => isCommaFollowedWithComma(element, index, elements))) {
22+
return;
2023
}
24+
25+
const problem = {
26+
node,
27+
messageId: MESSAGE_ID
28+
};
29+
30+
const nonNullElements = elements.filter(node => node !== null);
31+
if (
32+
parent.type === 'VariableDeclarator' &&
33+
parent.id === node &&
34+
nonNullElements.length === 1
35+
) {
36+
const [element] = nonNullElements;
37+
38+
if (element.type !== 'AssignmentPattern') {
39+
problem.fix = function * (fixer) {
40+
const index = elements.indexOf(element);
41+
const isSlice = element.type === 'RestElement';
42+
const variable = isSlice ? element.argument : element;
43+
44+
yield fixer.replaceText(node, sourceCode.getText(variable));
45+
46+
const code = isSlice ? `.slice(${index})` : `[${index}]`;
47+
const array = parent.init;
48+
if (
49+
!isParenthesized(array, sourceCode) &&
50+
shouldAddParenthesesToMemberExpressionObject(array, sourceCode)
51+
) {
52+
yield fixer.insertTextBefore(array, '(');
53+
yield fixer.insertTextAfter(parent, `)${code}`);
54+
} else {
55+
yield fixer.insertTextAfter(parent, code);
56+
}
57+
};
58+
}
59+
}
60+
61+
context.report(problem);
2162
}
2263
};
2364
};
@@ -29,6 +70,7 @@ module.exports = {
2970
docs: {
3071
url: getDocumentationUrl(__filename)
3172
},
32-
messages
73+
messages,
74+
fixable: 'code'
3375
}
3476
};

test/no-unreadable-array-destructuring.js

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {test} from './utils/test.js';
22

3-
test({
3+
test.visualize({
44
valid: [
55
'const [, foo] = parts;',
66
'const [foo] = parts;',
@@ -22,21 +22,31 @@ test({
2222
// This is stupid, but valid code
2323
'const [,,] = parts;'
2424
],
25-
invalid: []
25+
invalid: [
26+
'const [,, foo] = parts;',
27+
'const [foo,,, bar] = parts;',
28+
'const [foo,,,] = parts;',
29+
'const [foo, bar,, baz ,,, qux] = parts;',
30+
'[,, foo] = bar;',
31+
'({parts: [,, foo]} = bar);',
32+
'function foo([,, bar]) {}',
33+
'function foo([bar,,, baz]) {}',
34+
'function foo([bar,,,]) {}',
35+
'function foo([bar, baz,, qux ,,, quux]) {}',
36+
'const [,,...rest] = parts;',
37+
// This is stupid, but valid code
38+
'const [,,,] = parts;',
39+
// Should add parentheses to array
40+
'const [,,...rest] = new Array;',
41+
'const [,,...rest] = (0, foo);',
42+
'let [,,thirdElement] = new Array;',
43+
'var [,,thirdElement] = (((0, foo)));',
44+
// Variable is not `Identifier`
45+
'let [,,[,,thirdElementInThirdElement]] = foo',
46+
'let [,,{propertyOfThirdElement}] = foo',
47+
// Multiple declarations
48+
'let [,,thirdElement] = foo, anotherVariable = bar;',
49+
// Default value
50+
'let [,,thirdElement = {}] = foo;'
51+
]
2652
});
27-
28-
test.visualize([
29-
'const [,, foo] = parts;',
30-
'const [foo,,, bar] = parts;',
31-
'const [foo,,,] = parts;',
32-
'const [foo, bar,, baz ,,, qux] = parts;',
33-
'[,, foo] = bar;',
34-
'({parts: [,, foo]} = bar);',
35-
'function foo([,, bar]) {}',
36-
'function foo([bar,,, baz]) {}',
37-
'function foo([bar,,,]) {}',
38-
'function foo([bar, baz,, qux ,,, quux]) {}',
39-
'const [,,...rest] = parts;',
40-
// This is stupid, but valid code
41-
'const [,,,] = parts;'
42-
]);

test/snapshots/no-unreadable-array-destructuring.js.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ Generated by [AVA](https://avajs.dev).
77
## Invalid #1
88
1 | const [,, foo] = parts;
99

10+
> Output
11+
12+
`␊
13+
1 | const foo = parts[2];␊
14+
`
15+
1016
> Error 1/1
1117
1218
`␊
@@ -27,6 +33,12 @@ Generated by [AVA](https://avajs.dev).
2733
## Invalid #3
2834
1 | const [foo,,,] = parts;
2935

36+
> Output
37+
38+
`␊
39+
1 | const foo = parts[0];␊
40+
`
41+
3042
> Error 1/1
3143
3244
`␊
@@ -107,6 +119,12 @@ Generated by [AVA](https://avajs.dev).
107119
## Invalid #11
108120
1 | const [,,...rest] = parts;
109121

122+
> Output
123+
124+
`␊
125+
1 | const rest = parts.slice(2);␊
126+
`
127+
110128
> Error 1/1
111129
112130
`␊
@@ -123,3 +141,132 @@ Generated by [AVA](https://avajs.dev).
123141
> 1 | const [,,,] = parts;␊
124142
| ^^^^^ Array destructuring may not contain consecutive ignored values.␊
125143
`
144+
145+
## Invalid #13
146+
1 | const [,,...rest] = new Array;
147+
148+
> Output
149+
150+
`␊
151+
1 | const rest = (new Array).slice(2);␊
152+
`
153+
154+
> Error 1/1
155+
156+
`␊
157+
> 1 | const [,,...rest] = new Array;␊
158+
| ^^^^^^^^^^^ Array destructuring may not contain consecutive ignored values.␊
159+
`
160+
161+
## Invalid #14
162+
1 | const [,,...rest] = (0, foo);
163+
164+
> Output
165+
166+
`␊
167+
1 | const rest = (0, foo).slice(2);␊
168+
`
169+
170+
> Error 1/1
171+
172+
`␊
173+
> 1 | const [,,...rest] = (0, foo);␊
174+
| ^^^^^^^^^^^ Array destructuring may not contain consecutive ignored values.␊
175+
`
176+
177+
## Invalid #15
178+
1 | let [,,thirdElement] = new Array;
179+
180+
> Output
181+
182+
`␊
183+
1 | let thirdElement = (new Array)[2];␊
184+
`
185+
186+
> Error 1/1
187+
188+
`␊
189+
> 1 | let [,,thirdElement] = new Array;␊
190+
| ^^^^^^^^^^^^^^^^ Array destructuring may not contain consecutive ignored values.␊
191+
`
192+
193+
## Invalid #16
194+
1 | var [,,thirdElement] = (((0, foo)));
195+
196+
> Output
197+
198+
`␊
199+
1 | var thirdElement = (((0, foo)))[2];␊
200+
`
201+
202+
> Error 1/1
203+
204+
`␊
205+
> 1 | var [,,thirdElement] = (((0, foo)));␊
206+
| ^^^^^^^^^^^^^^^^ Array destructuring may not contain consecutive ignored values.␊
207+
`
208+
209+
## Invalid #17
210+
1 | let [,,[,,thirdElementInThirdElement]] = foo
211+
212+
> Output
213+
214+
`␊
215+
1 | let thirdElementInThirdElement = foo[2][2]␊
216+
`
217+
218+
> Error 1/2
219+
220+
`␊
221+
> 1 | let [,,[,,thirdElementInThirdElement]] = foo␊
222+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Array destructuring may not contain consecutive ignored values.␊
223+
`
224+
225+
> Error 2/2
226+
227+
`␊
228+
> 1 | let [,,[,,thirdElementInThirdElement]] = foo␊
229+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Array destructuring may not contain consecutive ignored values.␊
230+
`
231+
232+
## Invalid #18
233+
1 | let [,,{propertyOfThirdElement}] = foo
234+
235+
> Output
236+
237+
`␊
238+
1 | let {propertyOfThirdElement} = foo[2]␊
239+
`
240+
241+
> Error 1/1
242+
243+
`␊
244+
> 1 | let [,,{propertyOfThirdElement}] = foo␊
245+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Array destructuring may not contain consecutive ignored values.␊
246+
`
247+
248+
## Invalid #19
249+
1 | let [,,thirdElement] = foo, anotherVariable = bar;
250+
251+
> Output
252+
253+
`␊
254+
1 | let thirdElement = foo[2], anotherVariable = bar;␊
255+
`
256+
257+
> Error 1/1
258+
259+
`␊
260+
> 1 | let [,,thirdElement] = foo, anotherVariable = bar;␊
261+
| ^^^^^^^^^^^^^^^^ Array destructuring may not contain consecutive ignored values.␊
262+
`
263+
264+
## Invalid #20
265+
1 | let [,,thirdElement = {}] = foo;
266+
267+
> Error 1/1
268+
269+
`␊
270+
> 1 | let [,,thirdElement = {}] = foo;␊
271+
| ^^^^^^^^^^^^^^^^^^^^^ Array destructuring may not contain consecutive ignored values.␊
272+
`
513 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)