eslint-plugin-unicorn 69.0.0 → 71.0.0

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 (124) hide show
  1. package/package.json +26 -25
  2. package/readme.md +15 -1
  3. package/rules/ast/call-or-new-expression.js +2 -8
  4. package/rules/ast/is-member-expression.js +2 -8
  5. package/rules/comment-content.js +4 -4
  6. package/rules/consistent-boolean-name.js +727 -42
  7. package/rules/consistent-compound-words.js +1 -2
  8. package/rules/consistent-json-file-read.js +2 -5
  9. package/rules/dom-node-dataset.js +3 -7
  10. package/rules/escape-case.js +4 -4
  11. package/rules/expiring-todo-comments.js +25 -2
  12. package/rules/explicit-length-check.js +3 -3
  13. package/rules/filename-case.js +4 -4
  14. package/rules/fix/{add-parenthesizes-to-return-or-throw-expression.js → add-parentheses-to-return-or-throw-expression.js} +1 -1
  15. package/rules/fix/index.js +1 -1
  16. package/rules/fix/remove-argument.js +34 -8
  17. package/rules/fix/remove-statement.js +1 -3
  18. package/rules/fix/switch-new-expression-to-call-expression.js +2 -2
  19. package/rules/id-match.js +2 -2
  20. package/rules/index.js +10 -0
  21. package/rules/isolated-functions.js +203 -19
  22. package/rules/name-replacements.js +1 -2
  23. package/rules/no-anonymous-default-export.js +1 -3
  24. package/rules/no-array-callback-reference.js +2 -10
  25. package/rules/no-async-promise-finally.js +111 -0
  26. package/rules/no-chained-comparison.js +1 -1
  27. package/rules/no-collection-bracket-access.js +27 -4
  28. package/rules/no-computed-property-existence-check.js +1 -4
  29. package/rules/no-declarations-before-early-exit.js +6 -5
  30. package/rules/no-error-property-assignment.js +3 -3
  31. package/rules/no-for-loop.js +4 -4
  32. package/rules/no-keyword-prefix.js +2 -2
  33. package/rules/no-manually-wrapped-comments.js +5 -1
  34. package/rules/no-mismatched-map-key.js +13 -20
  35. package/rules/no-named-default.js +2 -5
  36. package/rules/no-negated-array-predicate.js +6 -13
  37. package/rules/no-negated-comparison.js +31 -71
  38. package/rules/no-negated-condition.js +2 -2
  39. package/rules/no-negation-in-equality-check.js +4 -7
  40. package/rules/no-non-function-verb-prefix.js +25 -2
  41. package/rules/no-process-exit.js +6 -6
  42. package/rules/no-return-array-push.js +9 -2
  43. package/rules/no-static-only-class.js +2 -8
  44. package/rules/no-thenable.js +9 -15
  45. package/rules/no-typeof-undefined.js +2 -2
  46. package/rules/no-undeclared-class-members.js +1 -5
  47. package/rules/no-unnecessary-array-flat-map.js +308 -0
  48. package/rules/no-unnecessary-await.js +2 -2
  49. package/rules/no-unnecessary-fetch-options.js +624 -0
  50. package/rules/no-unnecessary-global-this.js +5 -9
  51. package/rules/no-unsafe-promise-all-settled-values.js +865 -0
  52. package/rules/no-unused-properties.js +0 -1
  53. package/rules/no-useless-coercion.js +1 -2
  54. package/rules/no-useless-else.js +32 -1
  55. package/rules/no-useless-iterator-to-array.js +42 -16
  56. package/rules/no-useless-spread.js +2 -2
  57. package/rules/no-useless-undefined.js +2 -2
  58. package/rules/prefer-abort-signal-any.js +1391 -0
  59. package/rules/prefer-array-find.js +2 -5
  60. package/rules/prefer-array-flat-map.js +6 -11
  61. package/rules/prefer-array-from-range.js +98 -0
  62. package/rules/prefer-bigint-literals.js +1 -0
  63. package/rules/prefer-block-statement-over-iife.js +159 -0
  64. package/rules/prefer-boolean-return.js +20 -3
  65. package/rules/prefer-continue.js +6 -2
  66. package/rules/prefer-default-parameters.js +2 -2
  67. package/rules/prefer-early-return.js +3 -1
  68. package/rules/prefer-else-if.js +5 -9
  69. package/rules/prefer-group-by.js +576 -0
  70. package/rules/prefer-has-check.js +6 -3
  71. package/rules/prefer-https.js +3 -3
  72. package/rules/prefer-identifier-import-export-specifiers.js +1 -3
  73. package/rules/prefer-iterator-helpers.js +196 -0
  74. package/rules/prefer-minimal-ternary.js +4 -4
  75. package/rules/prefer-number-coercion.js +1 -1
  76. package/rules/prefer-object-define-properties.js +1 -3
  77. package/rules/prefer-object-iterable-methods.js +57 -14
  78. package/rules/prefer-observer-apis.js +2 -5
  79. package/rules/prefer-private-class-fields.js +1 -3
  80. package/rules/prefer-simple-sort-comparator.js +6 -6
  81. package/rules/prefer-simplified-conditions.js +584 -0
  82. package/rules/prefer-single-object-destructuring.js +2 -5
  83. package/rules/prefer-single-replace.js +2 -2
  84. package/rules/prefer-spread.js +25 -32
  85. package/rules/prefer-string-pad-start-end.js +1 -6
  86. package/rules/prefer-string-raw.js +2 -2
  87. package/rules/prefer-string-repeat.js +16 -9
  88. package/rules/prefer-string-replace-all.js +1 -1
  89. package/rules/prefer-ternary.js +5 -5
  90. package/rules/prefer-toggle-attribute.js +3 -3
  91. package/rules/prefer-top-level-await.js +6 -1
  92. package/rules/prefer-uint8array-base64.js +3 -1
  93. package/rules/require-proxy-trap-boolean-return.js +2 -2
  94. package/rules/rule/to-eslint-create.js +1 -2
  95. package/rules/rule/to-eslint-listener.js +1 -3
  96. package/rules/rule/to-eslint-problem.js +1 -3
  97. package/rules/rule/to-eslint-rule-fixer.js +1 -3
  98. package/rules/rule/to-eslint-rule.js +1 -3
  99. package/rules/rule/to-eslint-rules.js +1 -3
  100. package/rules/rule/unicorn-context.js +1 -3
  101. package/rules/rule/unicorn-listeners.js +1 -3
  102. package/rules/shared/array-range.js +66 -0
  103. package/rules/shared/iterator-helpers.js +43 -1
  104. package/rules/shared/no-array-mutate-rule.js +1 -3
  105. package/rules/shared/regexp-escape.js +4 -4
  106. package/rules/utils/can-tokens-be-adjacent.js +95 -0
  107. package/rules/utils/comparison.js +65 -0
  108. package/rules/utils/escape-string.js +2 -8
  109. package/rules/utils/get-available-variable-name.js +2 -13
  110. package/rules/utils/get-precedence.js +112 -0
  111. package/rules/utils/get-token-store.js +1 -3
  112. package/rules/utils/global-reference-tracker.js +3 -6
  113. package/rules/utils/index.js +4 -0
  114. package/rules/utils/is-boolean.js +103 -30
  115. package/rules/utils/is-identifier-name.js +5 -0
  116. package/rules/utils/is-promise-type.js +1 -3
  117. package/rules/utils/is-react-hook-name.js +5 -0
  118. package/rules/utils/parentheses/get-parent-syntax-opening-parenthesis.js +1 -3
  119. package/rules/utils/parentheses/iterate-surrounding-parentheses.js +1 -1
  120. package/rules/utils/should-add-parentheses-to-await-expression-argument.js +4 -9
  121. package/rules/utils/should-add-parentheses-to-call-expression-callee.js +6 -12
  122. package/rules/utils/should-add-parentheses-to-unary-expression.js +7 -14
  123. package/rules/utils/to-location.js +1 -3
  124. package/rules/utils/track-branch-exits.js +8 -7
@@ -1,7 +1,7 @@
1
1
  import {findVariable, getStaticValue} from '@eslint-community/eslint-utils';
2
2
  import {isMethodCall} from './ast/index.js';
3
3
  import {isReference, isSame, unwrapExpression} from './utils/comparison.js';
4
- import {isKnownNonMap} from './utils/index.js';
4
+ import {isComparableStaticValue, isKnownNonMap} from './utils/index.js';
5
5
 
6
6
  /**
7
7
  @import {TSESTree as ESTree} from '@typescript-eslint/types';
@@ -21,13 +21,6 @@ const skippedNodeTypes = new Set([
21
21
  'FunctionExpression',
22
22
  ]);
23
23
 
24
- const isComparableStaticValue = value =>
25
- value === null
26
- || (
27
- typeof value !== 'object'
28
- && typeof value !== 'function'
29
- );
30
-
31
24
  const isSameValueZero = (left, right) =>
32
25
  left === right
33
26
  || (
@@ -132,7 +125,7 @@ function patternContainsSameBinding(node, mapHasRoot, context) {
132
125
 
133
126
  function hasCallExpression(node, context) {
134
127
  const {visitorKeys} = context.sourceCode;
135
- let result = false;
128
+ let isResult = false;
136
129
 
137
130
  function visit(node) {
138
131
  if (!node) {
@@ -142,14 +135,14 @@ function hasCallExpression(node, context) {
142
135
  node = unwrapExpression(node);
143
136
 
144
137
  if (
145
- result
138
+ isResult
146
139
  || skippedNodeTypes.has(node.type)
147
140
  ) {
148
141
  return;
149
142
  }
150
143
 
151
144
  if (node.type === 'CallExpression') {
152
- result = true;
145
+ isResult = true;
153
146
  return;
154
147
  }
155
148
 
@@ -170,7 +163,7 @@ function hasCallExpression(node, context) {
170
163
 
171
164
  visit(node);
172
165
 
173
- return result;
166
+ return isResult;
174
167
  }
175
168
 
176
169
  function areDifferentKeys(left, right, context) {
@@ -353,11 +346,11 @@ function isNestedMapHasGuard(node, mapHasCall, context) {
353
346
 
354
347
  function hasSameMapHasCall(node, mapHasCall, context) {
355
348
  const {visitorKeys} = context.sourceCode;
356
- let result = false;
349
+ let isResult = false;
357
350
 
358
351
  function visit(node) {
359
352
  if (
360
- result
353
+ isResult
361
354
  || !node
362
355
  || skippedNodeTypes.has(node.type)
363
356
  ) {
@@ -370,7 +363,7 @@ function hasSameMapHasCall(node, mapHasCall, context) {
370
363
  nestedMapHasCall
371
364
  && isSameMapReceiver(unwrapExpression(mapHasCall).callee.object, unwrapExpression(nestedMapHasCall).callee.object, context)
372
365
  ) {
373
- result = true;
366
+ isResult = true;
374
367
  return;
375
368
  }
376
369
 
@@ -391,16 +384,16 @@ function hasSameMapHasCall(node, mapHasCall, context) {
391
384
 
392
385
  visit(node);
393
386
 
394
- return result;
387
+ return isResult;
395
388
  }
396
389
 
397
390
  function hasMapReceiverWrite(node, mapHasCall, context) {
398
391
  const {visitorKeys} = context.sourceCode;
399
- let result = false;
392
+ let isResult = false;
400
393
 
401
394
  function visit(node) {
402
395
  if (
403
- result
396
+ isResult
404
397
  || !node
405
398
  || skippedNodeTypes.has(node.type)
406
399
  || isNestedMapHasGuard(node, mapHasCall, context)
@@ -409,7 +402,7 @@ function hasMapReceiverWrite(node, mapHasCall, context) {
409
402
  }
410
403
 
411
404
  if (isMapReceiverWrite(node, mapHasCall, context)) {
412
- result = true;
405
+ isResult = true;
413
406
  return;
414
407
  }
415
408
 
@@ -430,7 +423,7 @@ function hasMapReceiverWrite(node, mapHasCall, context) {
430
423
 
431
424
  visit(node);
432
425
 
433
- return result;
426
+ return isResult;
434
427
  }
435
428
 
436
429
  function getMapAccessProblems(node, mapHasCall, context, reportedAccessKeys) {
@@ -97,12 +97,9 @@ const create = context => {
97
97
  });
98
98
 
99
99
  context.on('ExportSpecifier', specifier => {
100
- if (!(
101
- isValueExport(specifier)
100
+ if (!(isValueExport(specifier)
102
101
  && specifier.exported.name === 'default'
103
- && isValueExport(specifier.parent)
104
- && !specifier.parent.source
105
- )) {
102
+ && isValueExport(specifier.parent)) || specifier.parent.source) {
106
103
  return;
107
104
  }
108
105
 
@@ -8,7 +8,7 @@ import {
8
8
  shouldAddParenthesesToUnaryExpressionArgument,
9
9
  } from './utils/index.js';
10
10
  import {
11
- addParenthesizesToReturnOrThrowExpression,
11
+ addParenthesesToReturnOrThrowExpression,
12
12
  fixSpaceAroundKeyword,
13
13
  } from './fix/index.js';
14
14
  import {isFunction, isMethodCall} from './ast/index.js';
@@ -24,13 +24,6 @@ const replacementMethod = new Map([
24
24
  ]);
25
25
  const methods = replacementMethod.keys().toArray();
26
26
 
27
- const predicateBodyTypesRequiringParentheses = new Set([
28
- 'TSAsExpression',
29
- 'TSNonNullExpression',
30
- 'TSSatisfiesExpression',
31
- 'TSTypeAssertion',
32
- ]);
33
-
34
27
  const needsParenthesesInConciseArrowBody = (node, text) =>
35
28
  node.parent.type === 'ArrowFunctionExpression'
36
29
  && node.parent.body === node
@@ -75,7 +68,7 @@ function getReplacementPredicateText(node, context) {
75
68
  }
76
69
 
77
70
  const text = context.sourceCode.getText(node);
78
- const needsParentheses = predicateBodyTypesRequiringParentheses.has(node.type) || shouldAddParenthesesToUnaryExpressionArgument(node, '!');
71
+ const needsParentheses = shouldAddParenthesesToUnaryExpressionArgument(node, '!');
79
72
 
80
73
  return {
81
74
  node,
@@ -158,7 +151,7 @@ const create = context => {
158
151
  replacement,
159
152
  },
160
153
  * fix(fixer) {
161
- const needsReturnOrThrowParentheses = (
154
+ const isNeedsReturnOrThrowParentheses = (
162
155
  (parent.type === 'ReturnStatement' || parent.type === 'ThrowStatement')
163
156
  && parent.argument === unaryExpression
164
157
  && !isOnSameLine(bangToken, tokenAfterBang, context)
@@ -171,13 +164,13 @@ const create = context => {
171
164
 
172
165
  if (
173
166
  tokenStore === sourceCode
174
- && !needsReturnOrThrowParentheses
167
+ && !isNeedsReturnOrThrowParentheses
175
168
  ) {
176
169
  yield fixSpaceAroundKeyword(fixer, unaryExpression, context);
177
170
  }
178
171
 
179
- if (needsReturnOrThrowParentheses) {
180
- yield addParenthesizesToReturnOrThrowExpression(fixer, parent, context);
172
+ if (isNeedsReturnOrThrowParentheses) {
173
+ yield addParenthesesToReturnOrThrowExpression(fixer, parent, context);
181
174
  return;
182
175
  }
183
176
 
@@ -1,13 +1,21 @@
1
1
  import {
2
2
  removeParentheses,
3
3
  fixSpaceAroundKeyword,
4
- addParenthesizesToReturnOrThrowExpression,
4
+ addParenthesesToReturnOrThrowExpression,
5
5
  } from './fix/index.js';
6
6
  import {
7
7
  isParenthesized,
8
8
  isOnSameLine,
9
9
  needsSemicolon,
10
10
  } from './utils/index.js';
11
+ import {
12
+ getBinaryExpressionWithReplacedOperatorText,
13
+ getPunctuatorBinaryExpressionOperatorToken,
14
+ hasLowerLogicalOperatorPrecedence,
15
+ negatedComparisonOperators,
16
+ negatedEqualityOperators,
17
+ negatedLogicalOperators,
18
+ } from './utils/comparison.js';
11
19
 
12
20
  const MESSAGE_ID_ERROR = 'no-negated-comparison/error';
13
21
  const MESSAGE_ID_LOGICAL_ERROR = 'no-negated-comparison/logical-error';
@@ -20,29 +28,6 @@ const messages = {
20
28
  [MESSAGE_ID_LOGICAL_SUGGESTION]: 'Switch to opposite comparisons.',
21
29
  };
22
30
 
23
- const operatorReplacements = new Map([
24
- ['===', '!=='],
25
- ['!==', '==='],
26
- ['==', '!='],
27
- ['!=', '=='],
28
- ['>', '<='],
29
- ['>=', '<'],
30
- ['<', '>='],
31
- ['<=', '>'],
32
- ]);
33
-
34
- const safelyFixableOperators = new Set([
35
- '===',
36
- '!==',
37
- '==',
38
- '!=',
39
- ]);
40
-
41
- const logicalOperatorReplacements = new Map([
42
- ['&&', '||'],
43
- ['||', '&&'],
44
- ]);
45
-
46
31
  const defaultOptions = {
47
32
  checkLogicalExpressions: false,
48
33
  };
@@ -72,20 +57,20 @@ const isNegation = node =>
72
57
 
73
58
  const isComparison = node =>
74
59
  node.type === 'BinaryExpression'
75
- && operatorReplacements.has(node.operator);
60
+ && negatedComparisonOperators.has(node.operator);
76
61
 
77
62
  const isLogicalExpressionWithOnlyComparisons = node =>
78
63
  isComparison(node)
79
64
  || (
80
65
  node.type === 'LogicalExpression'
81
- && logicalOperatorReplacements.has(node.operator)
66
+ && negatedLogicalOperators.has(node.operator)
82
67
  && isLogicalExpressionWithOnlyComparisons(node.left)
83
68
  && isLogicalExpressionWithOnlyComparisons(node.right)
84
69
  );
85
70
 
86
71
  const isSafelyFixableLogicalExpression = node =>
87
72
  isComparison(node)
88
- ? safelyFixableOperators.has(node.operator)
73
+ ? negatedEqualityOperators.has(node.operator)
89
74
  : isSafelyFixableLogicalExpression(node.left) && isSafelyFixableLogicalExpression(node.right);
90
75
 
91
76
  const parentNeedsGroupedComparison = parent => [
@@ -111,19 +96,16 @@ function * fix({
111
96
  const bangToken = sourceCode.getFirstToken(unaryExpression);
112
97
  const tokenAfterBang = sourceCode.getTokenAfter(bangToken);
113
98
  const tokenAfterBangIncludingComments = sourceCode.getTokenAfter(bangToken, {includeComments: true});
114
- const operatorToken = sourceCode.getTokenAfter(
115
- comparison.left,
116
- token => token.type === 'Punctuator' && token.value === comparison.operator,
117
- );
99
+ const operatorToken = getPunctuatorBinaryExpressionOperatorToken(comparison, context);
118
100
  const {parent} = unaryExpression;
119
- const needsReturnOrThrowParentheses = (
101
+ const isNeedsReturnOrThrowParentheses = (
120
102
  (parent.type === 'ReturnStatement' || parent.type === 'ThrowStatement')
121
103
  && parent.argument === unaryExpression
122
104
  && !isOnSameLine(bangToken, tokenAfterBang, context)
123
105
  && !isParenthesized(unaryExpression, context)
124
106
  );
125
107
 
126
- if (!needsReturnOrThrowParentheses) {
108
+ if (!isNeedsReturnOrThrowParentheses) {
127
109
  yield fixSpaceAroundKeyword(fixer, unaryExpression, context);
128
110
  }
129
111
 
@@ -135,17 +117,14 @@ function * fix({
135
117
  yield fixer.insertTextAfter(tokenAfterBangIncludingComments, ' ');
136
118
  }
137
119
 
138
- if (!(
139
- parentNeedsGroupedComparison(parent)
140
- && !isParenthesized(unaryExpression, context)
141
- )) {
120
+ if (!parentNeedsGroupedComparison(parent) || isParenthesized(unaryExpression, context)) {
142
121
  yield removeParentheses(comparison, fixer, context);
143
122
  }
144
123
 
145
124
  yield fixer.replaceText(operatorToken, replacementOperator);
146
125
 
147
- if (needsReturnOrThrowParentheses) {
148
- yield addParenthesizesToReturnOrThrowExpression(fixer, parent, context);
126
+ if (isNeedsReturnOrThrowParentheses) {
127
+ yield addParenthesesToReturnOrThrowExpression(fixer, parent, context);
149
128
  return;
150
129
  }
151
130
 
@@ -156,37 +135,18 @@ function * fix({
156
135
  }
157
136
  }
158
137
 
159
- const logicalOperatorPrecedence = {
160
- '||': 1,
161
- '&&': 2,
162
- };
163
-
164
- const getOperatorToken = (comparison, sourceCode) => sourceCode.getTokenAfter(
165
- comparison.left,
166
- token => token.type === 'Punctuator' && token.value === comparison.operator,
138
+ const getFixedComparisonText = (comparison, context) => getBinaryExpressionWithReplacedOperatorText(
139
+ comparison,
140
+ context,
141
+ negatedComparisonOperators.get(comparison.operator),
167
142
  );
168
143
 
169
- const getFixedComparisonText = (comparison, sourceCode) => {
170
- const operatorToken = getOperatorToken(comparison, sourceCode);
171
- const [comparisonStart] = sourceCode.getRange(comparison);
172
- const [operatorStart, operatorEnd] = sourceCode.getRange(operatorToken);
173
- const comparisonText = sourceCode.getText(comparison);
174
-
175
- return [
176
- comparisonText.slice(0, operatorStart - comparisonStart),
177
- operatorReplacements.get(comparison.operator),
178
- comparisonText.slice(operatorEnd - comparisonStart),
179
- ].join('');
180
- };
181
-
182
144
  const getFixedLogicalExpressionText = (node, context, parentOperator) => {
183
- const {sourceCode} = context;
184
-
185
145
  if (isComparison(node)) {
186
- return getFixedComparisonText(node, sourceCode);
146
+ return getFixedComparisonText(node, context);
187
147
  }
188
148
 
189
- const operator = logicalOperatorReplacements.get(node.operator);
149
+ const operator = negatedLogicalOperators.get(node.operator);
190
150
  const text = [
191
151
  getFixedLogicalExpressionText(node.left, context, operator),
192
152
  operator,
@@ -197,7 +157,7 @@ const getFixedLogicalExpressionText = (node, context, parentOperator) => {
197
157
  operator !== parentOperator
198
158
  && isParenthesized(node, context)
199
159
  )
200
- || logicalOperatorPrecedence[operator] < logicalOperatorPrecedence[parentOperator]
160
+ || hasLowerLogicalOperatorPrecedence(operator, parentOperator)
201
161
  );
202
162
 
203
163
  return needsParentheses
@@ -215,22 +175,22 @@ function * fixLogical({
215
175
  const bangToken = sourceCode.getFirstToken(unaryExpression);
216
176
  const tokenAfterBang = sourceCode.getTokenAfter(bangToken);
217
177
  const {parent} = unaryExpression;
218
- const needsReturnOrThrowParentheses = (
178
+ const isNeedsReturnOrThrowParentheses = (
219
179
  (parent.type === 'ReturnStatement' || parent.type === 'ThrowStatement')
220
180
  && parent.argument === unaryExpression
221
181
  && !isOnSameLine(bangToken, tokenAfterBang, context)
222
182
  && !isParenthesized(unaryExpression, context)
223
183
  );
224
184
 
225
- if (!needsReturnOrThrowParentheses) {
185
+ if (!isNeedsReturnOrThrowParentheses) {
226
186
  yield fixSpaceAroundKeyword(fixer, unaryExpression, context);
227
187
  }
228
188
 
229
189
  yield fixer.remove(bangToken);
230
190
  yield fixer.replaceText(logicalExpression, getFixedLogicalExpressionText(logicalExpression, context));
231
191
 
232
- if (needsReturnOrThrowParentheses) {
233
- yield addParenthesizesToReturnOrThrowExpression(fixer, parent, context);
192
+ if (isNeedsReturnOrThrowParentheses) {
193
+ yield addParenthesesToReturnOrThrowExpression(fixer, parent, context);
234
194
  return;
235
195
  }
236
196
 
@@ -253,7 +213,7 @@ const create = context => {
253
213
 
254
214
  if (isComparison(argument)) {
255
215
  const comparison = argument;
256
- const replacementOperator = operatorReplacements.get(comparison.operator);
216
+ const replacementOperator = negatedComparisonOperators.get(comparison.operator);
257
217
  const problem = {
258
218
  node: unaryExpression,
259
219
  messageId: MESSAGE_ID_ERROR,
@@ -267,7 +227,7 @@ const create = context => {
267
227
  replacementOperator,
268
228
  });
269
229
 
270
- if (safelyFixableOperators.has(comparison.operator)) {
230
+ if (negatedEqualityOperators.has(comparison.operator)) {
271
231
  problem.fix = fixFunction;
272
232
  } else {
273
233
  problem.suggest = [
@@ -5,7 +5,7 @@ https://github.com/eslint/eslint/blob/5c39425fc55ecc0b97bbd07ac22654c0eb4f789c/l
5
5
  import {
6
6
  removeParentheses,
7
7
  fixSpaceAroundKeyword,
8
- addParenthesizesToReturnOrThrowExpression,
8
+ addParenthesesToReturnOrThrowExpression,
9
9
  } from './fix/index.js';
10
10
  import {
11
11
  getParenthesizedRange,
@@ -118,7 +118,7 @@ const create = context => {
118
118
  && !isParenthesized(node, context)
119
119
  && !isParenthesized(test, context)
120
120
  ) {
121
- yield addParenthesizesToReturnOrThrowExpression(fixer, parent, context);
121
+ yield addParenthesesToReturnOrThrowExpression(fixer, parent, context);
122
122
  return;
123
123
  }
124
124
 
@@ -1,4 +1,4 @@
1
- import {fixSpaceAroundKeyword, addParenthesizesToReturnOrThrowExpression} from './fix/index.js';
1
+ import {fixSpaceAroundKeyword, addParenthesesToReturnOrThrowExpression} from './fix/index.js';
2
2
  import {needsSemicolon, isParenthesized, isOnSameLine} from './utils/index.js';
3
3
 
4
4
  const MESSAGE_ID_ERROR = 'no-negation-in-equality-check/error';
@@ -23,11 +23,8 @@ const create = context => {
23
23
  context.on('BinaryExpression', binaryExpression => {
24
24
  const {operator, left} = binaryExpression;
25
25
 
26
- if (!(
27
- isEqualityCheck(binaryExpression)
28
- && isNegatedExpression(left)
29
- && !isNegatedExpression(left.argument)
30
- )) {
26
+ if (!(isEqualityCheck(binaryExpression)
27
+ && isNegatedExpression(left)) || isNegatedExpression(left.argument)) {
31
28
  return;
32
29
  }
33
30
 
@@ -58,7 +55,7 @@ const create = context => {
58
55
  ) {
59
56
  const returnToken = sourceCode.getFirstToken(parent);
60
57
  if (!isOnSameLine(returnToken, tokenAfterBang, context)) {
61
- yield addParenthesizesToReturnOrThrowExpression(fixer, parent, context);
58
+ yield addParenthesesToReturnOrThrowExpression(fixer, parent, context);
62
59
  }
63
60
  }
64
61
 
@@ -1,3 +1,4 @@
1
+ import {isRegExp} from 'node:util/types';
1
2
  import {
2
3
  isNullishType,
3
4
  isTypeScriptFile,
@@ -31,8 +32,12 @@ const messages = {
31
32
 
32
33
  const isUppercaseAscii = character => character >= 'A' && character <= 'Z';
33
34
 
34
- const prepareOptions = ({verbs}) => ({
35
+ const prepareOptions = ({
36
+ verbs,
37
+ ignore = [],
38
+ }) => ({
35
39
  verbs: verbs.toSorted((first, second) => second.length - first.length),
40
+ ignore: ignore.map(pattern => isRegExp(pattern) ? pattern : new RegExp(pattern, 'u')),
36
41
  });
37
42
 
38
43
  function getVerbPrefix(name, verbs) {
@@ -129,6 +134,15 @@ const getIntersectionTypeCallability = (type, checker, program, visitedTypes) =>
129
134
  const isInDeclaredModule = (node, sourceCode) =>
130
135
  sourceCode.getAncestors(node).some(ancestor => ancestor.type === 'TSModuleDeclaration' && ancestor.declare);
131
136
 
137
+ function isIgnoredName(name, ignore) {
138
+ return ignore.some(regexp => {
139
+ regexp.lastIndex = 0;
140
+ const isIgnored = regexp.test(name);
141
+ regexp.lastIndex = 0;
142
+ return isIgnored;
143
+ });
144
+ }
145
+
132
146
  function getTypeCallability(type, checker, program, visitedTypes = new Set()) {
133
147
  if (isIgnoredType(type)) {
134
148
  return unknown;
@@ -184,6 +198,10 @@ function getProblem(identifier, context, options, typeNode = identifier) {
184
198
  return;
185
199
  }
186
200
 
201
+ if (isIgnoredName(identifier.name, options.ignore)) {
202
+ return;
203
+ }
204
+
187
205
  const {parserServices} = context.sourceCode;
188
206
  let type;
189
207
  try {
@@ -298,6 +316,11 @@ const schema = [
298
316
  uniqueItems: true,
299
317
  description: 'Function-style verb prefixes to check.',
300
318
  },
319
+ ignore: {
320
+ type: 'array',
321
+ uniqueItems: true,
322
+ description: 'Patterns to ignore.',
323
+ },
301
324
  },
302
325
  },
303
326
  ];
@@ -313,7 +336,7 @@ const config = {
313
336
  requiresTypeChecking: true,
314
337
  },
315
338
  schema,
316
- defaultOptions: [{verbs: defaultVerbs}],
339
+ defaultOptions: [{verbs: defaultVerbs, ignore: []}],
317
340
  messages,
318
341
  languages: [
319
342
  'js/js',
@@ -11,9 +11,9 @@ const isWorkerThreads = node =>
11
11
 
12
12
  /** @param {import('eslint').Rule.RuleContext} context */
13
13
  const create = context => {
14
- const startsWithHashBang = context.sourceCode.lines[0].indexOf('#!') === 0;
14
+ const isStartsWithHashBang = context.sourceCode.lines[0].indexOf('#!') === 0;
15
15
 
16
- if (startsWithHashBang) {
16
+ if (isStartsWithHashBang) {
17
17
  return;
18
18
  }
19
19
 
@@ -22,7 +22,7 @@ const create = context => {
22
22
  let processEventHandlerDepth = 0;
23
23
 
24
24
  // Only report if it's outside a worker thread context. See #328.
25
- let requiredWorkerThreadsModule = false;
25
+ let isRequiredWorkerThreadsModule = false;
26
26
  const problemNodes = [];
27
27
 
28
28
  const isProcessEventHandler = node => isMethodCall(node, {
@@ -39,7 +39,7 @@ const create = context => {
39
39
  isStaticRequire(callExpression)
40
40
  && isWorkerThreads(callExpression.arguments[0])
41
41
  ) {
42
- requiredWorkerThreadsModule = true;
42
+ isRequiredWorkerThreadsModule = true;
43
43
  }
44
44
  });
45
45
 
@@ -49,7 +49,7 @@ const create = context => {
49
49
  importDeclaration.source.type === 'Literal'
50
50
  && isWorkerThreads(importDeclaration.source)
51
51
  ) {
52
- requiredWorkerThreadsModule = true;
52
+ isRequiredWorkerThreadsModule = true;
53
53
  }
54
54
  });
55
55
 
@@ -81,7 +81,7 @@ const create = context => {
81
81
  });
82
82
 
83
83
  context.onExit('Program', function * () {
84
- if (requiredWorkerThreadsModule) {
84
+ if (isRequiredWorkerThreadsModule) {
85
85
  return;
86
86
  }
87
87
 
@@ -1,5 +1,5 @@
1
1
  import {isMethodCall} from './ast/index.js';
2
- import {isKnownNonArray, needsSemicolon} from './utils/index.js';
2
+ import {isArray, isKnownNonArray, needsSemicolon} from './utils/index.js';
3
3
 
4
4
  const MESSAGE_ID_ERROR = 'no-return-array-push/error';
5
5
  const MESSAGE_ID_SUGGESTION = 'no-return-array-push/suggestion';
@@ -10,7 +10,10 @@ const messages = {
10
10
 
11
11
  const ignoredCallees = [
12
12
  'stream.push',
13
+ 'router.push',
13
14
  'this.push',
15
+ 'this.router.push',
16
+ 'this.$router.push',
14
17
  'this.stream.push',
15
18
  'process.stdin.push',
16
19
  'process.stdout.push',
@@ -53,6 +56,10 @@ function isStaticMemberPath(node, path) {
53
56
 
54
57
  const isIgnoredCallee = callee => ignoredCallees.some(ignoredCallee => isStaticMemberPath(callee, ignoredCallee));
55
58
 
59
+ const isIgnoredPushCallee = (callExpression, context) =>
60
+ isIgnoredCallee(callExpression.callee)
61
+ && !isArray(callExpression.callee.object, context);
62
+
56
63
  function getCallExpressionResultNode(callExpression) {
57
64
  let node = callExpression;
58
65
 
@@ -133,7 +140,7 @@ const create = context => {
133
140
  const {name: method} = property;
134
141
 
135
142
  if (
136
- (method === 'push' && isIgnoredCallee(callExpression.callee))
143
+ (method === 'push' && isIgnoredPushCallee(callExpression, context))
137
144
  || isReturnValueDiscarded(callExpression)
138
145
  || isResultMemberAccessed(callExpression)
139
146
  || isKnownNonArray(callExpression.callee.object, context)
@@ -38,16 +38,10 @@ function isStaticMember(node) {
38
38
  }
39
39
 
40
40
  // TypeScript class
41
- if (
42
- isDeclare
41
+ return !(isDeclare
43
42
  || isReadonly
44
43
  || accessibility !== undefined
45
- || (Array.isArray(decorators) && decorators.length > 0)
46
- ) {
47
- return false;
48
- }
49
-
50
- return true;
44
+ || (Array.isArray(decorators) && decorators.length > 0));
51
45
  }
52
46
 
53
47
  function * switchClassMemberToObjectProperty(node, context, fixer) {
@@ -79,16 +79,13 @@ const cases = [
79
79
  {
80
80
  selector: 'CallExpression',
81
81
  * getNodes(node, context) {
82
- if (!(
83
- isMethodCall(node, {
84
- objects: ['Object', 'Reflect'],
85
- method: 'defineProperty',
86
- minimumArguments: 3,
87
- optionalCall: false,
88
- optionalMember: false,
89
- })
90
- && node.arguments[0].type !== 'SpreadElement'
91
- )) {
82
+ if (!isMethodCall(node, {
83
+ objects: ['Object', 'Reflect'],
84
+ method: 'defineProperty',
85
+ minimumArguments: 3,
86
+ optionalCall: false,
87
+ optionalMember: false,
88
+ }) || node.arguments[0].type === 'SpreadElement') {
92
89
  return;
93
90
  }
94
91
 
@@ -117,11 +114,8 @@ const cases = [
117
114
  }
118
115
 
119
116
  for (const pairs of node.arguments[0].elements) {
120
- if (!(
121
- pairs?.type === 'ArrayExpression'
122
- && pairs.elements[0]
123
- && pairs.elements[0].type !== 'SpreadElement'
124
- )) {
117
+ if (!(pairs?.type === 'ArrayExpression'
118
+ && pairs.elements[0]) || pairs.elements[0].type === 'SpreadElement') {
125
119
  continue;
126
120
  }
127
121
 
@@ -1,6 +1,6 @@
1
1
  import {isLiteral} from './ast/index.js';
2
2
  import {
3
- addParenthesizesToReturnOrThrowExpression,
3
+ addParenthesesToReturnOrThrowExpression,
4
4
  removeSpacesAfter,
5
5
  } from './fix/index.js';
6
6
  import {
@@ -74,7 +74,7 @@ const create = context => {
74
74
  && !isParenthesized(binaryExpression, context)
75
75
  && !isParenthesized(typeofNode, context)
76
76
  ) {
77
- yield addParenthesizesToReturnOrThrowExpression(fixer, parent, context);
77
+ yield addParenthesesToReturnOrThrowExpression(fixer, parent, context);
78
78
  return;
79
79
  }
80
80