eslint-plugin-unicorn 26.0.1 → 28.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/index.js +3 -0
  2. package/package.json +9 -7
  3. package/readme.md +11 -5
  4. package/rules/.DS_Store +0 -0
  5. package/rules/catch-error-name.js +7 -0
  6. package/rules/consistent-destructuring.js +4 -1
  7. package/rules/new-for-builtins.js +8 -6
  8. package/rules/no-array-callback-reference.js +20 -17
  9. package/rules/no-array-for-each.js +394 -0
  10. package/rules/no-array-push-push.js +115 -0
  11. package/rules/no-instanceof-array.js +21 -4
  12. package/rules/no-lonely-if.js +90 -31
  13. package/rules/no-new-buffer.js +63 -22
  14. package/rules/no-this-assignment.js +43 -0
  15. package/rules/no-unreadable-array-destructuring.js +50 -7
  16. package/rules/no-unused-properties.js +11 -7
  17. package/rules/numeric-separators-style.js +55 -17
  18. package/rules/prefer-array-index-of.js +6 -140
  19. package/rules/prefer-default-parameters.js +7 -1
  20. package/rules/prefer-includes.js +13 -3
  21. package/rules/prefer-query-selector.js +1 -1
  22. package/rules/prefer-reflect-apply.js +5 -5
  23. package/rules/prefer-set-has.js +8 -0
  24. package/rules/prefer-spread.js +345 -18
  25. package/rules/prefer-string-slice.js +7 -2
  26. package/rules/prefer-ternary.js +21 -1
  27. package/rules/prevent-abbreviations.js +40 -8
  28. package/rules/shared/simple-array-search-rule.js +129 -0
  29. package/rules/utils/get-call-expression-arguments-text.js +21 -0
  30. package/rules/utils/get-parentheses.js +25 -0
  31. package/rules/utils/get-parenthesized-times.js +13 -0
  32. package/rules/utils/get-property-name.js +30 -0
  33. package/rules/utils/get-references.js +5 -6
  34. package/rules/utils/has-same-range.js +7 -0
  35. package/rules/utils/is-assignment-pattern-shorthand-property-identifier.js +7 -2
  36. package/rules/utils/is-function-self-used-inside.js +43 -0
  37. package/rules/utils/is-literal-value.js +11 -1
  38. package/rules/utils/is-new-expression-with-parentheses.js +26 -0
  39. package/rules/utils/is-node-matches.js +36 -0
  40. package/rules/utils/is-shadowed.js +1 -3
  41. package/rules/utils/is-shorthand-property-identifier.js +7 -2
  42. package/rules/utils/method-selector.js +10 -4
  43. package/rules/utils/remove-spaces-after.js +14 -0
  44. package/rules/utils/replace-node-or-token-and-spaces-before.js +31 -0
  45. package/rules/utils/should-add-parentheses-to-expression-statement-expression.js +21 -0
  46. package/rules/utils/should-add-parentheses-to-member-expression-object.js +1 -22
  47. package/rules/utils/should-add-parentheses-to-spread-element-argument.js +22 -0
  48. package/rules/utils/switch-new-expression-to-call-expression.js +17 -0
  49. package/rules/utils/is-same-node.js +0 -11
package/index.js CHANGED
@@ -55,6 +55,8 @@ module.exports = {
55
55
  'unicorn/new-for-builtins': 'error',
56
56
  'unicorn/no-abusive-eslint-disable': 'error',
57
57
  'unicorn/no-array-callback-reference': 'error',
58
+ 'unicorn/no-array-for-each': 'error',
59
+ 'unicorn/no-array-push-push': 'error',
58
60
  'unicorn/no-array-reduce': 'error',
59
61
  'unicorn/no-console-spaces': 'error',
60
62
  'unicorn/no-for-loop': 'error',
@@ -69,6 +71,7 @@ module.exports = {
69
71
  'unicorn/no-null': 'error',
70
72
  'unicorn/no-object-as-default-parameter': 'error',
71
73
  'unicorn/no-process-exit': 'error',
74
+ 'unicorn/no-this-assignment': 'error',
72
75
  'unicorn/no-unreadable-array-destructuring': 'error',
73
76
  'unicorn/no-unsafe-regex': 'off',
74
77
  'unicorn/no-unused-properties': 'off',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-unicorn",
3
- "version": "26.0.1",
3
+ "version": "28.0.2",
4
4
  "description": "Various awesome ESLint rules",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/eslint-plugin-unicorn",
@@ -16,7 +16,7 @@
16
16
  "scripts": {
17
17
  "test": "xo && nyc ava",
18
18
  "create-rule": "node ./scripts/create-rule.js",
19
- "lint": "node ./test/lint/lint.js",
19
+ "run-rules-on-codebase": "node ./test/run-rules-on-codebase/lint.js",
20
20
  "integration": "node ./test/integration/test.js",
21
21
  "smoke": "eslint-remote-tester --config ./test/smoke/eslint-remote-tester.config.js"
22
22
  },
@@ -37,21 +37,23 @@
37
37
  "dependencies": {
38
38
  "ci-info": "^2.0.0",
39
39
  "clean-regexp": "^1.0.0",
40
- "eslint-ast-utils": "^1.1.0",
41
40
  "eslint-template-visitor": "^2.2.2",
42
41
  "eslint-utils": "^2.1.0",
42
+ "eslint-visitor-keys": "^2.0.0",
43
43
  "import-modules": "^2.1.0",
44
44
  "lodash": "^4.17.20",
45
45
  "pluralize": "^8.0.0",
46
46
  "read-pkg-up": "^7.0.1",
47
- "regexp-tree": "^0.1.21",
47
+ "regexp-tree": "^0.1.22",
48
48
  "reserved-words": "^0.1.2",
49
49
  "safe-regex": "^2.1.1",
50
50
  "semver": "^7.3.4"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@ava/babel": "^1.0.1",
54
- "@babel/code-frame": "7.12.11",
54
+ "@babel/code-frame": "7.12.13",
55
+ "@babel/core": "7.12.10",
56
+ "@babel/eslint-parser": "7.12.1",
55
57
  "@lubien/fixture-beta-package": "^1.0.0-beta.1",
56
58
  "@typescript-eslint/parser": "^4.12.0",
57
59
  "ava": "^3.15.0",
@@ -61,7 +63,7 @@
61
63
  "eslint": "^7.15.0",
62
64
  "eslint-ava-rule-tester": "^4.0.0",
63
65
  "eslint-plugin-eslint-plugin": "^2.3.0",
64
- "eslint-remote-tester": "^0.4.0",
66
+ "eslint-remote-tester": "^1.1.0",
65
67
  "execa": "^5.0.0",
66
68
  "listr": "^0.14.3",
67
69
  "mem": "8.0.0",
@@ -98,7 +100,7 @@
98
100
  "plugin:eslint-plugin/all"
99
101
  ],
100
102
  "ignores": [
101
- "test/integration/{fixtures,unicorn}/**",
103
+ "test/integration/{fixtures,fixtures-local}/**",
102
104
  ".cache-eslint-remote-tester",
103
105
  "eslint-remote-tester-results"
104
106
  ],
package/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- # eslint-plugin-unicorn [![Coverage Status](https://codecov.io/gh/sindresorhus/eslint-plugin-unicorn/branch/master/graph/badge.svg)](https://codecov.io/gh/sindresorhus/eslint-plugin-unicorn/branch/master)
1
+ # eslint-plugin-unicorn [![Coverage Status](https://codecov.io/gh/sindresorhus/eslint-plugin-unicorn/branch/main/graph/badge.svg)](https://codecov.io/gh/sindresorhus/eslint-plugin-unicorn/branch/main)
2
2
 
3
3
  <img src="https://cloud.githubusercontent.com/assets/170270/18659176/1cc373d0-7f33-11e6-890f-0ba35362ee7e.jpg" width="180" align="right">
4
4
 
@@ -49,6 +49,8 @@ Configure it in `package.json`.
49
49
  "unicorn/new-for-builtins": "error",
50
50
  "unicorn/no-abusive-eslint-disable": "error",
51
51
  "unicorn/no-array-callback-reference": "error",
52
+ "unicorn/no-array-for-each": "error",
53
+ "unicorn/no-array-push-push": "error",
52
54
  "unicorn/no-array-reduce": "error",
53
55
  "unicorn/no-console-spaces": "error",
54
56
  "unicorn/no-for-loop": "error",
@@ -63,6 +65,7 @@ Configure it in `package.json`.
63
65
  "unicorn/no-null": "error",
64
66
  "unicorn/no-object-as-default-parameter": "error",
65
67
  "unicorn/no-process-exit": "error",
68
+ "unicorn/no-this-assignment": "error",
66
69
  "unicorn/no-unreadable-array-destructuring": "error",
67
70
  "unicorn/no-unsafe-regex": "off",
68
71
  "unicorn/no-unused-properties": "off",
@@ -125,6 +128,8 @@ Configure it in `package.json`.
125
128
  - [new-for-builtins](docs/rules/new-for-builtins.md) - Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. *(partly fixable)*
126
129
  - [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) - Enforce specifying rules to disable in `eslint-disable` comments.
127
130
  - [no-array-callback-reference](docs/rules/no-array-callback-reference.md) - Prevent passing a function reference directly to iterator methods.
131
+ - [no-array-for-each](docs/rules/no-array-for-each.md) - Prefer `for…of` over `Array#forEach(…)`. *(partly fixable)*
132
+ - [no-array-push-push](docs/rules/no-array-push-push.md) - Enforce combining multiple `Array#push()` into one call. *(partly fixable)*
128
133
  - [no-array-reduce](docs/rules/no-array-reduce.md) - Disallow `Array#reduce()` and `Array#reduceRight()`.
129
134
  - [no-console-spaces](docs/rules/no-console-spaces.md) - Do not use leading/trailing space between `console.log` parameters. *(fixable)*
130
135
  - [no-for-loop](docs/rules/no-for-loop.md) - Do not use a `for` loop that can be replaced with a `for-of` loop. *(partly fixable)*
@@ -134,11 +139,12 @@ Configure it in `package.json`.
134
139
  - [no-lonely-if](docs/rules/no-lonely-if.md) - Disallow `if` statements as the only statement in `if` blocks without `else`. *(fixable)*
135
140
  - [no-nested-ternary](docs/rules/no-nested-ternary.md) - Disallow nested ternary expressions. *(partly fixable)*
136
141
  - [no-new-array](docs/rules/no-new-array.md) - Disallow `new Array()`. *(partly fixable)*
137
- - [no-new-buffer](docs/rules/no-new-buffer.md) - Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. *(fixable)*
142
+ - [no-new-buffer](docs/rules/no-new-buffer.md) - Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. *(partly fixable)*
138
143
  - [no-null](docs/rules/no-null.md) - Disallow the use of the `null` literal.
139
144
  - [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) - Disallow the use of objects as default parameters.
140
145
  - [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.
146
+ - [no-this-assignment](docs/rules/no-this-assignment.md) - Disallow assigning `this` to a variable.
147
+ - [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) - Disallow unreadable array destructuring. *(partly fixable)*
142
148
  - [no-unsafe-regex](docs/rules/no-unsafe-regex.md) - Disallow unsafe regular expressions.
143
149
  - [no-unused-properties](docs/rules/no-unused-properties.md) - Disallow unused object properties.
144
150
  - [no-useless-undefined](docs/rules/no-useless-undefined.md) - Disallow useless `undefined`. *(fixable)*
@@ -156,7 +162,7 @@ Configure it in `package.json`.
156
162
  - [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) - Prefer using `.dataset` on DOM elements over `.setAttribute(…)`. *(fixable)*
157
163
  - [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) - Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. *(fixable)*
158
164
  - [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) - Prefer `.textContent` over `.innerText`. *(fixable)*
159
- - [prefer-includes](docs/rules/prefer-includes.md) - Prefer `.includes()` over `.indexOf()` when checking for existence or non-existence. *(fixable)*
165
+ - [prefer-includes](docs/rules/prefer-includes.md) - Prefer `.includes()` over `.indexOf()` and `Array#some()` when checking for existence or non-existence. *(partly fixable)*
160
166
  - [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) - Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. *(partly fixable)*
161
167
  - [prefer-math-trunc](docs/rules/prefer-math-trunc.md) - Enforce the use of `Math.trunc` instead of bitwise operators. *(partly fixable)*
162
168
  - [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) - Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. *(fixable)*
@@ -167,7 +173,7 @@ Configure it in `package.json`.
167
173
  - [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) - Prefer `Reflect.apply()` over `Function#apply()`. *(fixable)*
168
174
  - [prefer-regexp-test](docs/rules/prefer-regexp-test.md) - Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. *(fixable)*
169
175
  - [prefer-set-has](docs/rules/prefer-set-has.md) - Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. *(fixable)*
170
- - [prefer-spread](docs/rules/prefer-spread.md) - Prefer the spread operator over `Array.from()`. *(fixable)*
176
+ - [prefer-spread](docs/rules/prefer-spread.md) - Prefer the spread operator over `Array.from()` and `Array#concat()`. *(partly fixable)*
171
177
  - [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) - Prefer `String#replaceAll()` over regex searches with the global flag. *(fixable)*
172
178
  - [prefer-string-slice](docs/rules/prefer-string-slice.md) - Prefer `String#slice()` over `String#substr()` and `String#substring()`. *(partly fixable)*
173
179
  - [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) - Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. *(fixable)*
package/rules/.DS_Store CHANGED
Binary file
@@ -69,6 +69,13 @@ const create = context => {
69
69
  const scope = context.getScope();
70
70
  const variable = findVariable(scope, node);
71
71
 
72
+ // This was reported https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1075#issuecomment-768072967
73
+ // But can't reproduce, just ignore this case
74
+ /* istanbul ignore next */
75
+ if (!variable) {
76
+ return;
77
+ }
78
+
72
79
  if (originalName === '_' && variable.references.length === 0) {
73
80
  return;
74
81
  }
@@ -92,7 +92,10 @@ const create = context => {
92
92
  property.value.type === 'Identifier'
93
93
  );
94
94
  const lastProperty = objectPattern.properties[objectPattern.properties.length - 1];
95
- const hasRest = lastProperty && lastProperty.type === 'RestElement';
95
+
96
+ // TODO: Remove `ExperimentalRestProperty` check when we drop support for `babel-eslint` #1040
97
+ const hasRest = lastProperty &&
98
+ (lastProperty.type === 'RestElement' || lastProperty.type === 'ExperimentalRestProperty');
96
99
 
97
100
  const expression = source.getText(node);
98
101
  const member = source.getText(node.property);
@@ -2,6 +2,7 @@
2
2
  const getDocumentationUrl = require('./utils/get-documentation-url');
3
3
  const builtins = require('./utils/builtins');
4
4
  const isShadowed = require('./utils/is-shadowed');
5
+ const switchNewExpressionToCallExpression = require('./utils/switch-new-expression-to-call-expression');
5
6
 
6
7
  const messages = {
7
8
  enforce: 'Use `new {{name}}()` instead of `{{name}}()`.',
@@ -12,6 +13,8 @@ const enforceNew = new Set(builtins.enforceNew);
12
13
  const disallowNew = new Set(builtins.disallowNew);
13
14
 
14
15
  const create = context => {
16
+ const sourceCode = context.getSourceCode();
17
+
15
18
  return {
16
19
  CallExpression: node => {
17
20
  const {callee, parent} = node;
@@ -37,8 +40,8 @@ const create = context => {
37
40
  }
38
41
  },
39
42
  NewExpression: node => {
40
- const {callee, range} = node;
41
- const {name, range: calleeRange} = callee;
43
+ const {callee} = node;
44
+ const {name} = callee;
42
45
 
43
46
  if (disallowNew.has(name) && !isShadowed(context.getScope(), callee)) {
44
47
  const problem = {
@@ -48,10 +51,9 @@ const create = context => {
48
51
  };
49
52
 
50
53
  if (name !== 'String' && name !== 'Boolean' && name !== 'Number') {
51
- problem.fix = fixer => fixer.removeRange([
52
- range[0],
53
- calleeRange[0]
54
- ]);
54
+ problem.fix = function * (fixer) {
55
+ yield * switchNewExpressionToCallExpression(node, sourceCode, fixer);
56
+ };
55
57
  }
56
58
 
57
59
  context.report(problem);
@@ -3,6 +3,7 @@ const {isParenthesized} = require('eslint-utils');
3
3
  const getDocumentationUrl = require('./utils/get-documentation-url');
4
4
  const methodSelector = require('./utils/method-selector');
5
5
  const {notFunctionSelector} = require('./utils/not-function');
6
+ const isNodeMatches = require('./utils/is-node-matches');
6
7
 
7
8
  const ERROR_WITH_NAME_MESSAGE_ID = 'error-with-name';
8
9
  const ERROR_WITHOUT_NAME_MESSAGE_ID = 'error-without-name';
@@ -25,7 +26,11 @@ const iteratorMethods = [
25
26
  ['find'],
26
27
  ['findIndex'],
27
28
  ['flatMap'],
28
- ['forEach'],
29
+ [
30
+ 'forEach', {
31
+ returnsUndefined: true
32
+ }
33
+ ],
29
34
  ['map'],
30
35
  [
31
36
  'reduce', {
@@ -58,14 +63,16 @@ const iteratorMethods = [
58
63
  ignore: ['Boolean'],
59
64
  minParameters: 1,
60
65
  extraSelector: '',
66
+ returnsUndefined: false,
61
67
  ...options
62
68
  };
63
69
  return [method, options];
64
70
  });
65
71
 
66
72
  const ignoredCallee = [
73
+ // http://bluebirdjs.com/docs/api/promise.map.html
67
74
  'Promise',
68
- 'React.children',
75
+ 'React.Children',
69
76
  'Children',
70
77
  'lodash',
71
78
  'underscore',
@@ -74,18 +81,6 @@ const ignoredCallee = [
74
81
  'async'
75
82
  ];
76
83
 
77
- const toSelector = name => {
78
- const splitted = name.split('.');
79
- return `[callee.${'object.'.repeat(splitted.length)}name!="${splitted.shift()}"]`;
80
- };
81
-
82
- // Select all the call expressions except the ones present in the ignore list.
83
- const ignoredCalleeSelector = [
84
- // `this.{map, filter, …}()`
85
- '[callee.object.type!="ThisExpression"]',
86
- ...ignoredCallee.map(name => toSelector(name))
87
- ].join('');
88
-
89
84
  function check(context, node, method, options) {
90
85
  const {type} = node;
91
86
 
@@ -105,7 +100,7 @@ function check(context, node, method, options) {
105
100
  suggest: []
106
101
  };
107
102
 
108
- const {parameters, minParameters} = options;
103
+ const {parameters, minParameters, returnsUndefined} = options;
109
104
  for (let parameterLength = minParameters; parameterLength <= parameters.length; parameterLength++) {
110
105
  const suggestionParameters = parameters.slice(0, parameterLength).join(', ');
111
106
 
@@ -124,7 +119,9 @@ function check(context, node, method, options) {
124
119
 
125
120
  return fixer.replaceText(
126
121
  node,
127
- `(${suggestionParameters}) => ${nodeText}(${suggestionParameters})`
122
+ returnsUndefined ?
123
+ `(${suggestionParameters}) => { ${nodeText}(${suggestionParameters}); }` :
124
+ `(${suggestionParameters}) => ${nodeText}(${suggestionParameters})`
128
125
  );
129
126
  }
130
127
  };
@@ -154,11 +151,17 @@ const create = context => {
154
151
  max: 2
155
152
  }),
156
153
  options.extraSelector,
157
- ignoredCalleeSelector,
158
154
  ignoredFirstArgumentSelector
159
155
  ].join('');
160
156
 
161
157
  rules[selector] = node => {
158
+ if (
159
+ isNodeMatches(node.callee.object, ignoredCallee) ||
160
+ node.callee.object.type === 'ThisExpression'
161
+ ) {
162
+ return;
163
+ }
164
+
162
165
  const [iterator] = node.arguments;
163
166
  check(context, iterator, method, options, sourceCode);
164
167
  };