eslint-plugin-unicorn 70.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 +5 -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 +94 -10
- 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 +2 -2
- package/rules/explicit-length-check.js +3 -3
- package/rules/filename-case.js +4 -4
- package/rules/fix/remove-argument.js +34 -8
- package/rules/fix/remove-statement.js +1 -3
- package/rules/id-match.js +2 -2
- package/rules/isolated-functions.js +47 -7
- 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-chained-comparison.js +1 -1
- 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-mismatched-map-key.js +13 -20
- package/rules/no-named-default.js +2 -5
- package/rules/no-negated-array-predicate.js +4 -11
- package/rules/no-negated-comparison.js +7 -10
- package/rules/no-negation-in-equality-check.js +2 -5
- package/rules/no-process-exit.js +6 -6
- package/rules/no-static-only-class.js +2 -8
- package/rules/no-thenable.js +9 -15
- package/rules/no-undeclared-class-members.js +1 -5
- package/rules/no-unnecessary-array-flat-map.js +6 -5
- package/rules/no-unnecessary-global-this.js +5 -9
- package/rules/no-unused-properties.js +0 -1
- package/rules/no-useless-coercion.js +1 -2
- package/rules/no-useless-undefined.js +2 -2
- package/rules/prefer-array-find.js +2 -5
- package/rules/prefer-bigint-literals.js +1 -0
- package/rules/prefer-boolean-return.js +20 -3
- package/rules/prefer-default-parameters.js +2 -2
- package/rules/prefer-else-if.js +5 -9
- 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-minimal-ternary.js +4 -4
- package/rules/prefer-object-define-properties.js +1 -3
- 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-single-object-destructuring.js +2 -5
- package/rules/prefer-single-replace.js +2 -2
- package/rules/prefer-spread.js +22 -32
- package/rules/prefer-string-pad-start-end.js +1 -6
- 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/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/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 +90 -32
- 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
|
@@ -98,13 +98,51 @@ const create = context => {
|
|
|
98
98
|
|
|
99
99
|
options.comments = options.comments.map(comment => comment.toLowerCase());
|
|
100
100
|
|
|
101
|
-
const
|
|
101
|
+
const configuredGlobals = {
|
|
102
102
|
...(globals[`es${context.languageOptions.ecmaVersion}`] ?? globals.builtins),
|
|
103
103
|
...context.languageOptions.globals,
|
|
104
|
-
...options.overrideGlobals,
|
|
105
104
|
};
|
|
106
105
|
const checked = new WeakSet();
|
|
107
106
|
|
|
107
|
+
const getAllowedGlobalValue = reference => {
|
|
108
|
+
const {identifier, resolved} = reference;
|
|
109
|
+
const {name} = identifier;
|
|
110
|
+
|
|
111
|
+
if (Object.hasOwn(options.overrideGlobals, name)) {
|
|
112
|
+
const overrideGlobalValue = options.overrideGlobals[name];
|
|
113
|
+
|
|
114
|
+
if (overrideGlobalValue === 'off') {
|
|
115
|
+
return 'off';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (resolved && !sourceCode.isGlobalReference(identifier)) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return overrideGlobalValue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (
|
|
126
|
+
Object.hasOwn(configuredGlobals, name)
|
|
127
|
+
&& configuredGlobals[name] === 'off'
|
|
128
|
+
) {
|
|
129
|
+
return 'off';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (!sourceCode.isGlobalReference(identifier)) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (
|
|
137
|
+
!Object.hasOwn(configuredGlobals, name)
|
|
138
|
+
&& !resolved?.eslintExplicitGlobal
|
|
139
|
+
) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return resolved?.writeable ? 'writable' : 'readonly';
|
|
144
|
+
};
|
|
145
|
+
|
|
108
146
|
function * getFunctionContextProblems(node, reason, root = node) {
|
|
109
147
|
const messageId = functionContextReferenceMessageIds.get(node.type);
|
|
110
148
|
if (messageId) {
|
|
@@ -173,18 +211,20 @@ const create = context => {
|
|
|
173
211
|
continue;
|
|
174
212
|
}
|
|
175
213
|
|
|
176
|
-
|
|
214
|
+
const allowedGlobalValue = getAllowedGlobalValue(reference);
|
|
215
|
+
let problemReason = reason;
|
|
216
|
+
|
|
217
|
+
if (allowedGlobalValue !== undefined && allowedGlobalValue !== 'off') {
|
|
177
218
|
if (reference.isReadOnly()) {
|
|
178
219
|
continue;
|
|
179
220
|
}
|
|
180
221
|
|
|
181
|
-
const
|
|
182
|
-
const isGlobalWritable = [true, 'writable', 'writeable'].includes(globalsValue);
|
|
222
|
+
const isGlobalWritable = [true, 'writable', 'writeable'].includes(allowedGlobalValue);
|
|
183
223
|
if (isGlobalWritable) {
|
|
184
224
|
continue;
|
|
185
225
|
}
|
|
186
226
|
|
|
187
|
-
|
|
227
|
+
problemReason += ' (global variable is not writable)';
|
|
188
228
|
}
|
|
189
229
|
|
|
190
230
|
// Could consider checking for typeof operator here, like in no-undef?
|
|
@@ -192,7 +232,7 @@ const create = context => {
|
|
|
192
232
|
context.report({
|
|
193
233
|
node: identifier,
|
|
194
234
|
messageId: MESSAGE_ID_EXTERNALLY_SCOPED_VARIABLE,
|
|
195
|
-
data: {name: identifier.name, reason},
|
|
235
|
+
data: {name: identifier.name, reason: problemReason},
|
|
196
236
|
});
|
|
197
237
|
}
|
|
198
238
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import {isRegExp} from 'node:util/types';
|
|
3
|
-
import helperValidatorIdentifier from '@babel/helper-validator-identifier';
|
|
4
3
|
import {
|
|
5
4
|
getAvailableVariableName,
|
|
6
5
|
cartesianProductSamples,
|
|
@@ -9,6 +8,7 @@ import {
|
|
|
9
8
|
upperFirst,
|
|
10
9
|
lowerFirst,
|
|
11
10
|
isVirtualFilename,
|
|
11
|
+
isIdentifierName,
|
|
12
12
|
} from './utils/index.js';
|
|
13
13
|
import {defaultReplacements, defaultAllowList, defaultIgnore} from './shared/name-replacements.js';
|
|
14
14
|
import {
|
|
@@ -24,7 +24,6 @@ import {functionTypes} from './ast/index.js';
|
|
|
24
24
|
const MESSAGE_ID_REPLACE = 'replace';
|
|
25
25
|
const MESSAGE_ID_SUGGESTION = 'suggestion';
|
|
26
26
|
const MESSAGE_ID_RENAME = 'rename';
|
|
27
|
-
const {isIdentifierName} = helperValidatorIdentifier;
|
|
28
27
|
const anotherNameMessage = 'A more descriptive name will do too.';
|
|
29
28
|
const messages = {
|
|
30
29
|
[MESSAGE_ID_REPLACE]: `The {{nameTypeText}} \`{{discouragedName}}\` should be named \`{{replacement}}\`. ${anotherNameMessage}`,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import {getFunctionHeadLocation, getFunctionNameWithKind, isOpeningParenToken} from '@eslint-community/eslint-utils';
|
|
3
|
-
import helperValidatorIdentifier from '@babel/helper-validator-identifier';
|
|
4
3
|
import {camelCase} from 'change-case';
|
|
5
4
|
import {
|
|
6
5
|
getClassHeadLocation,
|
|
@@ -9,11 +8,10 @@ import {
|
|
|
9
8
|
getAvailableVariableName,
|
|
10
9
|
upperFirst,
|
|
11
10
|
isVirtualFilename,
|
|
11
|
+
isIdentifierName,
|
|
12
12
|
} from './utils/index.js';
|
|
13
13
|
import {isMemberExpression} from './ast/index.js';
|
|
14
14
|
|
|
15
|
-
const {isIdentifierName} = helperValidatorIdentifier;
|
|
16
|
-
|
|
17
15
|
const MESSAGE_ID_ERROR = 'no-anonymous-default-export/error';
|
|
18
16
|
const MESSAGE_ID_SUGGESTION = 'no-anonymous-default-export/suggestion';
|
|
19
17
|
const messages = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import isIdentifier from 'is-identifier';
|
|
2
2
|
import {findVariable} from '@eslint-community/eslint-utils';
|
|
3
3
|
import typedArray from './shared/typed-array.js';
|
|
4
4
|
import {isMethodCall, isUndefined} from './ast/index.js';
|
|
@@ -22,11 +22,6 @@ const ERROR_WITH_NAME_MESSAGE_ID = 'error-with-name';
|
|
|
22
22
|
const ERROR_WITHOUT_NAME_MESSAGE_ID = 'error-without-name';
|
|
23
23
|
const REPLACE_WITH_NAME_MESSAGE_ID = 'replace-with-name';
|
|
24
24
|
const REPLACE_WITHOUT_NAME_MESSAGE_ID = 'replace-without-name';
|
|
25
|
-
const {
|
|
26
|
-
isIdentifierName,
|
|
27
|
-
isKeyword,
|
|
28
|
-
isStrictBindReservedWord,
|
|
29
|
-
} = helperValidatorIdentifier;
|
|
30
25
|
const messages = {
|
|
31
26
|
[ERROR_WITH_NAME_MESSAGE_ID]: 'Do not pass function `{{name}}` directly to `.{{method}}(…)`.',
|
|
32
27
|
[ERROR_WITHOUT_NAME_MESSAGE_ID]: 'Do not pass function directly to `.{{method}}(…)`.',
|
|
@@ -301,10 +296,7 @@ function isDefinitelyNotFunctionValue(node, context, visitedVariables = new Set(
|
|
|
301
296
|
: false;
|
|
302
297
|
}
|
|
303
298
|
|
|
304
|
-
const isValidParameterName =
|
|
305
|
-
isIdentifierName(name)
|
|
306
|
-
&& !isKeyword(name)
|
|
307
|
-
&& !isStrictBindReservedWord(name, true);
|
|
299
|
+
const isValidParameterName = isIdentifier;
|
|
308
300
|
|
|
309
301
|
function getSuggestionParameters(callExpression, callback, parameters) {
|
|
310
302
|
if (callback.type !== 'Identifier') {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {hasSideEffect} from '@eslint-community/eslint-utils';
|
|
2
|
+
import {isBooleanLiteral} from './ast/index.js';
|
|
2
3
|
import {getParenthesizedText, isParenthesized, isBoolean} from './utils/index.js';
|
|
3
4
|
|
|
4
5
|
const MESSAGE_ID_ERROR = 'no-chained-comparison/error';
|
|
@@ -13,7 +14,6 @@ const equalityOperators = new Set(['===', '!==', '==', '!=']);
|
|
|
13
14
|
const comparisonOperators = orderingOperators.union(equalityOperators);
|
|
14
15
|
|
|
15
16
|
const isComparison = node => node.type === 'BinaryExpression' && comparisonOperators.has(node.operator);
|
|
16
|
-
const isBooleanLiteral = node => node.type === 'Literal' && typeof node.value === 'boolean';
|
|
17
17
|
|
|
18
18
|
// The `&&` rewrite is a `LogicalExpression`, which binds looser than any comparison. It can only
|
|
19
19
|
// replace `node` where a surrounding operator won't recapture it: at the top of an expression or
|
|
@@ -134,10 +134,7 @@ const create = context => {
|
|
|
134
134
|
});
|
|
135
135
|
|
|
136
136
|
context.on('BinaryExpression', node => {
|
|
137
|
-
if (
|
|
138
|
-
node.operator === 'in'
|
|
139
|
-
&& !isStaticPropertyKey(node.left)
|
|
140
|
-
)) {
|
|
137
|
+
if (node.operator !== 'in' || isStaticPropertyKey(node.left)) {
|
|
141
138
|
return;
|
|
142
139
|
}
|
|
143
140
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import {isCommentToken, hasSideEffect} from '@eslint-community/eslint-utils';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
containsSuspensionPoint,
|
|
4
|
+
getReferences,
|
|
5
|
+
isReactHookName,
|
|
6
|
+
trackBranchExits,
|
|
7
|
+
} from './utils/index.js';
|
|
3
8
|
|
|
4
9
|
const MESSAGE_ID = 'no-declarations-before-early-exit';
|
|
5
10
|
const messages = {
|
|
@@ -23,10 +28,6 @@ function isGuardStatement(node, branchAlwaysExits) {
|
|
|
23
28
|
return consequentExits !== alternateExits;
|
|
24
29
|
}
|
|
25
30
|
|
|
26
|
-
// https://github.com/facebook/react/blob/main/packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts
|
|
27
|
-
const isReactHookName = name =>
|
|
28
|
-
name === 'use' || /^use[\dA-Z]/.test(name);
|
|
29
|
-
|
|
30
31
|
// Matches `useFoo(…)` and `Namespace.useFoo(…)` (for example, `React.useMemo(…)`).
|
|
31
32
|
const isReactHookCall = node => {
|
|
32
33
|
if (node?.type !== 'CallExpression') {
|
|
@@ -142,7 +142,7 @@ const getLocalUpdateFrame = knownErrorVariableFrames =>
|
|
|
142
142
|
?? knownErrorVariableFrames.at(-1);
|
|
143
143
|
|
|
144
144
|
const updateExistingKnownErrorVariable = (knownErrorVariableFrames, variable, constructorName) => {
|
|
145
|
-
let
|
|
145
|
+
let isCrossesFunctionBoundary = false;
|
|
146
146
|
|
|
147
147
|
for (const frame of knownErrorVariableFrames.toReversed()) {
|
|
148
148
|
if (frame.knownErrorVariables.has(variable)) {
|
|
@@ -151,7 +151,7 @@ const updateExistingKnownErrorVariable = (knownErrorVariableFrames, variable, co
|
|
|
151
151
|
return true;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
if (!
|
|
154
|
+
if (!isCrossesFunctionBoundary) {
|
|
155
155
|
frame.knownErrorVariables.set(variable, undefined);
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -160,7 +160,7 @@ const updateExistingKnownErrorVariable = (knownErrorVariableFrames, variable, co
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
if (frame.isFunctionBoundary) {
|
|
163
|
-
|
|
163
|
+
isCrossesFunctionBoundary = true;
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
|
package/rules/no-for-loop.js
CHANGED
|
@@ -876,14 +876,14 @@ const create = context => {
|
|
|
876
876
|
|
|
877
877
|
let declarationElement = element;
|
|
878
878
|
let declarationType = 'const';
|
|
879
|
-
let
|
|
879
|
+
let isRemoveDeclaration = true;
|
|
880
880
|
|
|
881
881
|
if (elementNode) {
|
|
882
882
|
if (elementNode.id.type === 'ObjectPattern' || elementNode.id.type === 'ArrayPattern') {
|
|
883
|
-
|
|
883
|
+
isRemoveDeclaration = arrayReferences.length === 1;
|
|
884
884
|
}
|
|
885
885
|
|
|
886
|
-
if (
|
|
886
|
+
if (isRemoveDeclaration) {
|
|
887
887
|
declarationType = elementNode.parent.kind;
|
|
888
888
|
declarationElement = sourceCode.getText(elementNode.id);
|
|
889
889
|
}
|
|
@@ -911,7 +911,7 @@ const create = context => {
|
|
|
911
911
|
}
|
|
912
912
|
|
|
913
913
|
if (elementNode) {
|
|
914
|
-
yield
|
|
914
|
+
yield isRemoveDeclaration
|
|
915
915
|
? fixer.removeRange(getRemovalRange(elementNode, sourceCode))
|
|
916
916
|
: fixer.replaceText(elementNode.init, element);
|
|
917
917
|
}
|
|
@@ -90,12 +90,12 @@ function reportObjectPatternAndShouldSkipPropertyCheck(report, node, options) {
|
|
|
90
90
|
return true;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
const
|
|
93
|
+
const isAssignmentKeyEqualsValue = parent.key.name === parent.value.name;
|
|
94
94
|
|
|
95
95
|
const valueIsInvalid = parent.value.name && Boolean(keyword);
|
|
96
96
|
|
|
97
97
|
// Ignore destructuring if the option is set, unless a new identifier is created
|
|
98
|
-
if (valueIsInvalid && !
|
|
98
|
+
if (valueIsInvalid && !isAssignmentKeyEqualsValue) {
|
|
99
99
|
report(node, keyword);
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -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
|
|
|
@@ -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,12 +164,12 @@ 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 (
|
|
172
|
+
if (isNeedsReturnOrThrowParentheses) {
|
|
180
173
|
yield addParenthesesToReturnOrThrowExpression(fixer, parent, context);
|
|
181
174
|
return;
|
|
182
175
|
}
|
|
@@ -98,14 +98,14 @@ function * fix({
|
|
|
98
98
|
const tokenAfterBangIncludingComments = sourceCode.getTokenAfter(bangToken, {includeComments: true});
|
|
99
99
|
const operatorToken = getPunctuatorBinaryExpressionOperatorToken(comparison, context);
|
|
100
100
|
const {parent} = unaryExpression;
|
|
101
|
-
const
|
|
101
|
+
const isNeedsReturnOrThrowParentheses = (
|
|
102
102
|
(parent.type === 'ReturnStatement' || parent.type === 'ThrowStatement')
|
|
103
103
|
&& parent.argument === unaryExpression
|
|
104
104
|
&& !isOnSameLine(bangToken, tokenAfterBang, context)
|
|
105
105
|
&& !isParenthesized(unaryExpression, context)
|
|
106
106
|
);
|
|
107
107
|
|
|
108
|
-
if (!
|
|
108
|
+
if (!isNeedsReturnOrThrowParentheses) {
|
|
109
109
|
yield fixSpaceAroundKeyword(fixer, unaryExpression, context);
|
|
110
110
|
}
|
|
111
111
|
|
|
@@ -117,16 +117,13 @@ function * fix({
|
|
|
117
117
|
yield fixer.insertTextAfter(tokenAfterBangIncludingComments, ' ');
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
if (!(
|
|
121
|
-
parentNeedsGroupedComparison(parent)
|
|
122
|
-
&& !isParenthesized(unaryExpression, context)
|
|
123
|
-
)) {
|
|
120
|
+
if (!parentNeedsGroupedComparison(parent) || isParenthesized(unaryExpression, context)) {
|
|
124
121
|
yield removeParentheses(comparison, fixer, context);
|
|
125
122
|
}
|
|
126
123
|
|
|
127
124
|
yield fixer.replaceText(operatorToken, replacementOperator);
|
|
128
125
|
|
|
129
|
-
if (
|
|
126
|
+
if (isNeedsReturnOrThrowParentheses) {
|
|
130
127
|
yield addParenthesesToReturnOrThrowExpression(fixer, parent, context);
|
|
131
128
|
return;
|
|
132
129
|
}
|
|
@@ -178,21 +175,21 @@ function * fixLogical({
|
|
|
178
175
|
const bangToken = sourceCode.getFirstToken(unaryExpression);
|
|
179
176
|
const tokenAfterBang = sourceCode.getTokenAfter(bangToken);
|
|
180
177
|
const {parent} = unaryExpression;
|
|
181
|
-
const
|
|
178
|
+
const isNeedsReturnOrThrowParentheses = (
|
|
182
179
|
(parent.type === 'ReturnStatement' || parent.type === 'ThrowStatement')
|
|
183
180
|
&& parent.argument === unaryExpression
|
|
184
181
|
&& !isOnSameLine(bangToken, tokenAfterBang, context)
|
|
185
182
|
&& !isParenthesized(unaryExpression, context)
|
|
186
183
|
);
|
|
187
184
|
|
|
188
|
-
if (!
|
|
185
|
+
if (!isNeedsReturnOrThrowParentheses) {
|
|
189
186
|
yield fixSpaceAroundKeyword(fixer, unaryExpression, context);
|
|
190
187
|
}
|
|
191
188
|
|
|
192
189
|
yield fixer.remove(bangToken);
|
|
193
190
|
yield fixer.replaceText(logicalExpression, getFixedLogicalExpressionText(logicalExpression, context));
|
|
194
191
|
|
|
195
|
-
if (
|
|
192
|
+
if (isNeedsReturnOrThrowParentheses) {
|
|
196
193
|
yield addParenthesesToReturnOrThrowExpression(fixer, parent, context);
|
|
197
194
|
return;
|
|
198
195
|
}
|
|
@@ -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
|
|
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
|
|
|
@@ -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
|
|
|
@@ -179,11 +179,7 @@ const getDeclaredClassMemberNames = (classBody, sourceCode) => {
|
|
|
179
179
|
const names = new Set(['constructor']);
|
|
180
180
|
|
|
181
181
|
for (const member of classBody.body) {
|
|
182
|
-
if (!(
|
|
183
|
-
classMemberTypes.has(member.type)
|
|
184
|
-
&& member.static !== true
|
|
185
|
-
&& member.kind !== 'constructor'
|
|
186
|
-
)) {
|
|
182
|
+
if (!classMemberTypes.has(member.type) || member.static === true || member.kind === 'constructor') {
|
|
187
183
|
continue;
|
|
188
184
|
}
|
|
189
185
|
|