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.
- package/package.json +26 -25
- package/readme.md +15 -1
- package/rules/ast/call-or-new-expression.js +2 -8
- package/rules/ast/is-member-expression.js +2 -8
- package/rules/comment-content.js +4 -4
- package/rules/consistent-boolean-name.js +727 -42
- package/rules/consistent-compound-words.js +1 -2
- package/rules/consistent-json-file-read.js +2 -5
- package/rules/dom-node-dataset.js +3 -7
- package/rules/escape-case.js +4 -4
- package/rules/expiring-todo-comments.js +25 -2
- package/rules/explicit-length-check.js +3 -3
- package/rules/filename-case.js +4 -4
- package/rules/fix/{add-parenthesizes-to-return-or-throw-expression.js → add-parentheses-to-return-or-throw-expression.js} +1 -1
- package/rules/fix/index.js +1 -1
- package/rules/fix/remove-argument.js +34 -8
- package/rules/fix/remove-statement.js +1 -3
- package/rules/fix/switch-new-expression-to-call-expression.js +2 -2
- package/rules/id-match.js +2 -2
- package/rules/index.js +10 -0
- package/rules/isolated-functions.js +203 -19
- package/rules/name-replacements.js +1 -2
- package/rules/no-anonymous-default-export.js +1 -3
- package/rules/no-array-callback-reference.js +2 -10
- package/rules/no-async-promise-finally.js +111 -0
- package/rules/no-chained-comparison.js +1 -1
- package/rules/no-collection-bracket-access.js +27 -4
- package/rules/no-computed-property-existence-check.js +1 -4
- package/rules/no-declarations-before-early-exit.js +6 -5
- package/rules/no-error-property-assignment.js +3 -3
- package/rules/no-for-loop.js +4 -4
- package/rules/no-keyword-prefix.js +2 -2
- package/rules/no-manually-wrapped-comments.js +5 -1
- package/rules/no-mismatched-map-key.js +13 -20
- package/rules/no-named-default.js +2 -5
- package/rules/no-negated-array-predicate.js +6 -13
- package/rules/no-negated-comparison.js +31 -71
- package/rules/no-negated-condition.js +2 -2
- package/rules/no-negation-in-equality-check.js +4 -7
- package/rules/no-non-function-verb-prefix.js +25 -2
- package/rules/no-process-exit.js +6 -6
- package/rules/no-return-array-push.js +9 -2
- package/rules/no-static-only-class.js +2 -8
- package/rules/no-thenable.js +9 -15
- package/rules/no-typeof-undefined.js +2 -2
- package/rules/no-undeclared-class-members.js +1 -5
- package/rules/no-unnecessary-array-flat-map.js +308 -0
- package/rules/no-unnecessary-await.js +2 -2
- package/rules/no-unnecessary-fetch-options.js +624 -0
- package/rules/no-unnecessary-global-this.js +5 -9
- package/rules/no-unsafe-promise-all-settled-values.js +865 -0
- package/rules/no-unused-properties.js +0 -1
- package/rules/no-useless-coercion.js +1 -2
- package/rules/no-useless-else.js +32 -1
- package/rules/no-useless-iterator-to-array.js +42 -16
- package/rules/no-useless-spread.js +2 -2
- package/rules/no-useless-undefined.js +2 -2
- package/rules/prefer-abort-signal-any.js +1391 -0
- package/rules/prefer-array-find.js +2 -5
- package/rules/prefer-array-flat-map.js +6 -11
- package/rules/prefer-array-from-range.js +98 -0
- package/rules/prefer-bigint-literals.js +1 -0
- package/rules/prefer-block-statement-over-iife.js +159 -0
- package/rules/prefer-boolean-return.js +20 -3
- package/rules/prefer-continue.js +6 -2
- package/rules/prefer-default-parameters.js +2 -2
- package/rules/prefer-early-return.js +3 -1
- package/rules/prefer-else-if.js +5 -9
- package/rules/prefer-group-by.js +576 -0
- package/rules/prefer-has-check.js +6 -3
- package/rules/prefer-https.js +3 -3
- package/rules/prefer-identifier-import-export-specifiers.js +1 -3
- package/rules/prefer-iterator-helpers.js +196 -0
- package/rules/prefer-minimal-ternary.js +4 -4
- package/rules/prefer-number-coercion.js +1 -1
- package/rules/prefer-object-define-properties.js +1 -3
- package/rules/prefer-object-iterable-methods.js +57 -14
- package/rules/prefer-observer-apis.js +2 -5
- package/rules/prefer-private-class-fields.js +1 -3
- package/rules/prefer-simple-sort-comparator.js +6 -6
- package/rules/prefer-simplified-conditions.js +584 -0
- package/rules/prefer-single-object-destructuring.js +2 -5
- package/rules/prefer-single-replace.js +2 -2
- package/rules/prefer-spread.js +25 -32
- package/rules/prefer-string-pad-start-end.js +1 -6
- package/rules/prefer-string-raw.js +2 -2
- package/rules/prefer-string-repeat.js +16 -9
- package/rules/prefer-string-replace-all.js +1 -1
- package/rules/prefer-ternary.js +5 -5
- package/rules/prefer-toggle-attribute.js +3 -3
- package/rules/prefer-top-level-await.js +6 -1
- package/rules/prefer-uint8array-base64.js +3 -1
- package/rules/require-proxy-trap-boolean-return.js +2 -2
- package/rules/rule/to-eslint-create.js +1 -2
- package/rules/rule/to-eslint-listener.js +1 -3
- package/rules/rule/to-eslint-problem.js +1 -3
- package/rules/rule/to-eslint-rule-fixer.js +1 -3
- package/rules/rule/to-eslint-rule.js +1 -3
- package/rules/rule/to-eslint-rules.js +1 -3
- package/rules/rule/unicorn-context.js +1 -3
- package/rules/rule/unicorn-listeners.js +1 -3
- package/rules/shared/array-range.js +66 -0
- package/rules/shared/iterator-helpers.js +43 -1
- package/rules/shared/no-array-mutate-rule.js +1 -3
- package/rules/shared/regexp-escape.js +4 -4
- package/rules/utils/can-tokens-be-adjacent.js +95 -0
- package/rules/utils/comparison.js +65 -0
- package/rules/utils/escape-string.js +2 -8
- package/rules/utils/get-available-variable-name.js +2 -13
- package/rules/utils/get-precedence.js +112 -0
- package/rules/utils/get-token-store.js +1 -3
- package/rules/utils/global-reference-tracker.js +3 -6
- package/rules/utils/index.js +4 -0
- package/rules/utils/is-boolean.js +103 -30
- package/rules/utils/is-identifier-name.js +5 -0
- package/rules/utils/is-promise-type.js +1 -3
- package/rules/utils/is-react-hook-name.js +5 -0
- package/rules/utils/parentheses/get-parent-syntax-opening-parenthesis.js +1 -3
- package/rules/utils/parentheses/iterate-surrounding-parentheses.js +1 -1
- package/rules/utils/should-add-parentheses-to-await-expression-argument.js +4 -9
- package/rules/utils/should-add-parentheses-to-call-expression-callee.js +6 -12
- package/rules/utils/should-add-parentheses-to-unary-expression.js +7 -14
- package/rules/utils/to-location.js +1 -3
- 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
|
|
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
|
-
|
|
138
|
+
isResult
|
|
146
139
|
|| skippedNodeTypes.has(node.type)
|
|
147
140
|
) {
|
|
148
141
|
return;
|
|
149
142
|
}
|
|
150
143
|
|
|
151
144
|
if (node.type === 'CallExpression') {
|
|
152
|
-
|
|
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
|
|
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
|
|
349
|
+
let isResult = false;
|
|
357
350
|
|
|
358
351
|
function visit(node) {
|
|
359
352
|
if (
|
|
360
|
-
|
|
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
|
-
|
|
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
|
|
387
|
+
return isResult;
|
|
395
388
|
}
|
|
396
389
|
|
|
397
390
|
function hasMapReceiverWrite(node, mapHasCall, context) {
|
|
398
391
|
const {visitorKeys} = context.sourceCode;
|
|
399
|
-
let
|
|
392
|
+
let isResult = false;
|
|
400
393
|
|
|
401
394
|
function visit(node) {
|
|
402
395
|
if (
|
|
403
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
-
&& !
|
|
167
|
+
&& !isNeedsReturnOrThrowParentheses
|
|
175
168
|
) {
|
|
176
169
|
yield fixSpaceAroundKeyword(fixer, unaryExpression, context);
|
|
177
170
|
}
|
|
178
171
|
|
|
179
|
-
if (
|
|
180
|
-
yield
|
|
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
|
-
|
|
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
|
-
&&
|
|
60
|
+
&& negatedComparisonOperators.has(node.operator);
|
|
76
61
|
|
|
77
62
|
const isLogicalExpressionWithOnlyComparisons = node =>
|
|
78
63
|
isComparison(node)
|
|
79
64
|
|| (
|
|
80
65
|
node.type === 'LogicalExpression'
|
|
81
|
-
&&
|
|
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
|
-
?
|
|
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 =
|
|
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
|
|
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 (!
|
|
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 (
|
|
148
|
-
yield
|
|
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
|
|
160
|
-
|
|
161
|
-
|
|
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,
|
|
146
|
+
return getFixedComparisonText(node, context);
|
|
187
147
|
}
|
|
188
148
|
|
|
189
|
-
const 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
|
-
||
|
|
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
|
|
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 (!
|
|
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 (
|
|
233
|
-
yield
|
|
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 =
|
|
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 (
|
|
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
|
-
|
|
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
|
|
121
|
+
yield addParenthesesToReturnOrThrowExpression(fixer, parent, context);
|
|
122
122
|
return;
|
|
123
123
|
}
|
|
124
124
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {fixSpaceAroundKeyword,
|
|
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
|
-
|
|
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
|
|
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 = ({
|
|
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',
|
package/rules/no-process-exit.js
CHANGED
|
@@ -11,9 +11,9 @@ const isWorkerThreads = node =>
|
|
|
11
11
|
|
|
12
12
|
/** @param {import('eslint').Rule.RuleContext} context */
|
|
13
13
|
const create = context => {
|
|
14
|
-
const
|
|
14
|
+
const isStartsWithHashBang = context.sourceCode.lines[0].indexOf('#!') === 0;
|
|
15
15
|
|
|
16
|
-
if (
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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' &&
|
|
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
|
-
|
|
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) {
|
package/rules/no-thenable.js
CHANGED
|
@@ -79,16 +79,13 @@ const cases = [
|
|
|
79
79
|
{
|
|
80
80
|
selector: 'CallExpression',
|
|
81
81
|
* getNodes(node, context) {
|
|
82
|
-
if (!(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
77
|
+
yield addParenthesesToReturnOrThrowExpression(fixer, parent, context);
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
80
|
|