@typescript-eslint/eslint-plugin 8.56.2-alpha.0 → 8.56.2-alpha.10
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/dist/rules/no-base-to-string.js +7 -9
- package/dist/rules/no-duplicate-enum-values.js +1 -1
- package/dist/rules/no-unnecessary-condition.js +6 -9
- package/dist/rules/no-unsafe-assignment.js +2 -1
- package/dist/rules/no-useless-default-assignment.js +3 -0
- package/dist/rules/prefer-promise-reject-errors.d.ts +2 -0
- package/dist/rules/prefer-promise-reject-errors.js +8 -0
- package/dist/rules/prefer-readonly.js +57 -10
- package/dist/rules/strict-void-return.js +31 -11
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +16 -16
|
@@ -269,17 +269,15 @@ exports.default = (0, util_1.createRule)({
|
|
|
269
269
|
continue;
|
|
270
270
|
}
|
|
271
271
|
const declarations = candidate.getDeclarations();
|
|
272
|
-
|
|
273
|
-
// the default object toString.
|
|
274
|
-
//
|
|
275
|
-
// This may only matter for older versions of TS
|
|
276
|
-
// see https://github.com/typescript-eslint/typescript-eslint/issues/8585
|
|
277
|
-
if (declarations?.length !== 1) {
|
|
272
|
+
if (!declarations?.length) {
|
|
278
273
|
continue;
|
|
279
274
|
}
|
|
280
|
-
//
|
|
281
|
-
|
|
282
|
-
|
|
275
|
+
// If any declaration is not from the Object interface, this is
|
|
276
|
+
// user-defined (e.g. overloaded toString on a class or module).
|
|
277
|
+
// see https://github.com/typescript-eslint/typescript-eslint/issues/8585
|
|
278
|
+
// see https://github.com/typescript-eslint/typescript-eslint/issues/11945
|
|
279
|
+
if (declarations.some(declaration => !(ts.isInterfaceDeclaration(declaration.parent) &&
|
|
280
|
+
declaration.parent.name.text === 'Object'))) {
|
|
283
281
|
return false;
|
|
284
282
|
}
|
|
285
283
|
foundFallbackOnObject = true;
|
|
@@ -46,7 +46,7 @@ exports.default = (0, util_1.createRule)({
|
|
|
46
46
|
return initializer.operator === '-' ? -inner : inner;
|
|
47
47
|
}
|
|
48
48
|
case isStaticTemplateLiteral(initializer):
|
|
49
|
-
return initializer.quasis[0].value.cooked;
|
|
49
|
+
return initializer.quasis[0].value.cooked ?? undefined;
|
|
50
50
|
default:
|
|
51
51
|
return undefined;
|
|
52
52
|
}
|
|
@@ -396,14 +396,6 @@ exports.default = (0, util_1.createRule)({
|
|
|
396
396
|
// The right side will be checked if the LogicalExpression is used in a conditional context
|
|
397
397
|
checkNode(node.left);
|
|
398
398
|
}
|
|
399
|
-
function checkIfWhileLoopIsNecessaryConditional(node) {
|
|
400
|
-
if (allowConstantLoopConditionsOption === 'only-allowed-literals' &&
|
|
401
|
-
node.test.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
402
|
-
constantLoopConditionsAllowedLiterals.has(node.test.value)) {
|
|
403
|
-
return;
|
|
404
|
-
}
|
|
405
|
-
checkIfLoopIsNecessaryConditional(node);
|
|
406
|
-
}
|
|
407
399
|
/**
|
|
408
400
|
* Checks that a testable expression of a loop is necessarily conditional, reports otherwise.
|
|
409
401
|
*/
|
|
@@ -412,6 +404,11 @@ exports.default = (0, util_1.createRule)({
|
|
|
412
404
|
// e.g. `for(;;)`
|
|
413
405
|
return;
|
|
414
406
|
}
|
|
407
|
+
if (allowConstantLoopConditionsOption === 'only-allowed-literals' &&
|
|
408
|
+
node.test.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
409
|
+
constantLoopConditionsAllowedLiterals.has(node.test.value)) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
415
412
|
if (allowConstantLoopConditionsOption === 'always' &&
|
|
416
413
|
tsutils.isTrueLiteralType((0, util_1.getConstrainedTypeAtLocation)(services, node.test))) {
|
|
417
414
|
return;
|
|
@@ -663,7 +660,7 @@ exports.default = (0, util_1.createRule)({
|
|
|
663
660
|
checkIfBoolExpressionIsNecessaryConditional(test, parent.discriminant, test, '===');
|
|
664
661
|
}
|
|
665
662
|
},
|
|
666
|
-
WhileStatement:
|
|
663
|
+
WhileStatement: checkIfLoopIsNecessaryConditional,
|
|
667
664
|
};
|
|
668
665
|
},
|
|
669
666
|
});
|
|
@@ -169,7 +169,8 @@ exports.default = (0, util_1.createRule)({
|
|
|
169
169
|
}
|
|
170
170
|
else if (receiverProperty.key.type === utils_1.AST_NODE_TYPES.TemplateLiteral &&
|
|
171
171
|
receiverProperty.key.quasis.length === 1) {
|
|
172
|
-
|
|
172
|
+
const cooked = (0, util_1.nullThrows)(receiverProperty.key.quasis[0].value.cooked, 'cooked can only be null inside a TaggedTemplateExpression, which is not possible here');
|
|
173
|
+
key = cooked;
|
|
173
174
|
}
|
|
174
175
|
else {
|
|
175
176
|
// can't figure out the name, so skip it
|
|
@@ -236,6 +236,9 @@ exports.default = (0, util_1.createRule)({
|
|
|
236
236
|
if (signature.thisParameter) {
|
|
237
237
|
paramIndex--;
|
|
238
238
|
}
|
|
239
|
+
if (paramIndex < 0 || paramIndex >= params.length) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
239
242
|
return checker.getTypeOfSymbol(params[paramIndex]);
|
|
240
243
|
}
|
|
241
244
|
if (parent.type === utils_1.AST_NODE_TYPES.AssignmentPattern) {
|
|
@@ -20,6 +20,10 @@ exports.default = (0, util_1.createRule)({
|
|
|
20
20
|
type: 'object',
|
|
21
21
|
additionalProperties: false,
|
|
22
22
|
properties: {
|
|
23
|
+
allow: {
|
|
24
|
+
...util_1.typeOrValueSpecifiersSchema,
|
|
25
|
+
description: 'Type specifiers that can be used as Promise rejection reasons.',
|
|
26
|
+
},
|
|
23
27
|
allowEmptyReject: {
|
|
24
28
|
type: 'boolean',
|
|
25
29
|
description: 'Whether to allow calls to `Promise.reject()` with no arguments.',
|
|
@@ -38,6 +42,7 @@ exports.default = (0, util_1.createRule)({
|
|
|
38
42
|
},
|
|
39
43
|
defaultOptions: [
|
|
40
44
|
{
|
|
45
|
+
allow: [],
|
|
41
46
|
allowEmptyReject: false,
|
|
42
47
|
allowThrowingAny: false,
|
|
43
48
|
allowThrowingUnknown: false,
|
|
@@ -49,6 +54,9 @@ exports.default = (0, util_1.createRule)({
|
|
|
49
54
|
const argument = callExpression.arguments.at(0);
|
|
50
55
|
if (argument) {
|
|
51
56
|
const type = services.getTypeAtLocation(argument);
|
|
57
|
+
if ((0, util_1.typeMatchesSomeSpecifier)(type, options.allow, services.program)) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
52
60
|
if (options.allowThrowingAny && (0, util_1.isTypeAnyType)(type)) {
|
|
53
61
|
return;
|
|
54
62
|
}
|
|
@@ -222,7 +222,11 @@ exports.default = (0, util_1.createRule)({
|
|
|
222
222
|
name: context.sourceCode.getText(nameNode),
|
|
223
223
|
},
|
|
224
224
|
*fix(fixer) {
|
|
225
|
-
|
|
225
|
+
const readonlyInsertionTarget = esNode.type === utils_1.AST_NODE_TYPES.PropertyDefinition &&
|
|
226
|
+
esNode.computed
|
|
227
|
+
? (0, util_1.nullThrows)(context.sourceCode.getTokenBefore(nameNode), 'Expected to find a token before computed property name')
|
|
228
|
+
: nameNode;
|
|
229
|
+
yield fixer.insertTextBefore(readonlyInsertionTarget, 'readonly ');
|
|
226
230
|
if (typeAnnotation) {
|
|
227
231
|
yield fixer.insertTextAfter(nameNode, `: ${typeAnnotation}`);
|
|
228
232
|
}
|
|
@@ -239,9 +243,25 @@ exports.default = (0, util_1.createRule)({
|
|
|
239
243
|
}
|
|
240
244
|
},
|
|
241
245
|
MemberExpression(node) {
|
|
242
|
-
if (classScopeStack.length
|
|
246
|
+
if (classScopeStack.length === 0) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const classScope = classScopeStack[classScopeStack.length - 1];
|
|
250
|
+
if (!node.computed) {
|
|
243
251
|
const tsNode = services.esTreeNodeToTSNodeMap.get(node);
|
|
244
|
-
handlePropertyAccessExpression(tsNode, tsNode.parent,
|
|
252
|
+
handlePropertyAccessExpression(tsNode, tsNode.parent, classScope);
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
const tsNode = services.esTreeNodeToTSNodeMap.get(node);
|
|
256
|
+
if (ts.isElementAccessExpression(tsNode) &&
|
|
257
|
+
ts.isBinaryExpression(tsNode.parent) &&
|
|
258
|
+
tsNode.parent.left === tsNode &&
|
|
259
|
+
tsutils.isAssignmentKind(tsNode.parent.operatorToken.kind)) {
|
|
260
|
+
const memberName = (0, util_1.getStaticMemberAccessValue)(node, context);
|
|
261
|
+
if (typeof memberName === 'string') {
|
|
262
|
+
classScope.addVariableModificationByName(tsNode.expression, memberName);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
245
265
|
}
|
|
246
266
|
},
|
|
247
267
|
};
|
|
@@ -285,8 +305,7 @@ class ClassScope {
|
|
|
285
305
|
addDeclaredVariable(node) {
|
|
286
306
|
if (!(tsutils.isModifierFlagSet(node, ts.ModifierFlags.Private) ||
|
|
287
307
|
node.name.kind === ts.SyntaxKind.PrivateIdentifier) ||
|
|
288
|
-
tsutils.isModifierFlagSet(node, ts.ModifierFlags.Accessor | ts.ModifierFlags.Readonly)
|
|
289
|
-
ts.isComputedPropertyName(node.name)) {
|
|
308
|
+
tsutils.isModifierFlagSet(node, ts.ModifierFlags.Accessor | ts.ModifierFlags.Readonly)) {
|
|
290
309
|
return;
|
|
291
310
|
}
|
|
292
311
|
if (this.onlyInlineLambdas &&
|
|
@@ -294,25 +313,32 @@ class ClassScope {
|
|
|
294
313
|
!ts.isArrowFunction(node.initializer)) {
|
|
295
314
|
return;
|
|
296
315
|
}
|
|
316
|
+
const memberName = getMemberName(node.name);
|
|
317
|
+
if (memberName == null) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
297
320
|
(tsutils.isModifierFlagSet(node, ts.ModifierFlags.Static)
|
|
298
321
|
? this.privateModifiableStatics
|
|
299
|
-
: this.privateModifiableMembers).set(
|
|
322
|
+
: this.privateModifiableMembers).set(memberName, node);
|
|
300
323
|
}
|
|
301
324
|
addVariableModification(node) {
|
|
302
|
-
|
|
325
|
+
this.addVariableModificationByName(node.expression, node.name.text);
|
|
326
|
+
}
|
|
327
|
+
addVariableModificationByName(expression, memberName) {
|
|
328
|
+
const modifierType = this.checker.getTypeAtLocation(expression);
|
|
303
329
|
const relationOfModifierTypeToClass = this.getTypeToClassRelation(modifierType);
|
|
304
330
|
if (relationOfModifierTypeToClass === TypeToClassRelation.Instance &&
|
|
305
331
|
this.constructorScopeDepth === DIRECTLY_INSIDE_CONSTRUCTOR) {
|
|
306
|
-
this.memberVariableWithConstructorModifications.add(
|
|
332
|
+
this.memberVariableWithConstructorModifications.add(memberName);
|
|
307
333
|
return;
|
|
308
334
|
}
|
|
309
335
|
if (relationOfModifierTypeToClass === TypeToClassRelation.Instance ||
|
|
310
336
|
relationOfModifierTypeToClass === TypeToClassRelation.ClassAndInstance) {
|
|
311
|
-
this.memberVariableModifications.add(
|
|
337
|
+
this.memberVariableModifications.add(memberName);
|
|
312
338
|
}
|
|
313
339
|
if (relationOfModifierTypeToClass === TypeToClassRelation.Class ||
|
|
314
340
|
relationOfModifierTypeToClass === TypeToClassRelation.ClassAndInstance) {
|
|
315
|
-
this.staticVariableModifications.add(
|
|
341
|
+
this.staticVariableModifications.add(memberName);
|
|
316
342
|
}
|
|
317
343
|
}
|
|
318
344
|
enterConstructor(node) {
|
|
@@ -390,3 +416,24 @@ class ClassScope {
|
|
|
390
416
|
return this.memberVariableWithConstructorModifications.has(name);
|
|
391
417
|
}
|
|
392
418
|
}
|
|
419
|
+
function getMemberName(name) {
|
|
420
|
+
if (ts.isIdentifier(name) ||
|
|
421
|
+
ts.isPrivateIdentifier(name) ||
|
|
422
|
+
ts.isStringLiteral(name) ||
|
|
423
|
+
ts.isNoSubstitutionTemplateLiteral(name) ||
|
|
424
|
+
ts.isNumericLiteral(name)) {
|
|
425
|
+
return name.text;
|
|
426
|
+
}
|
|
427
|
+
if (ts.isComputedPropertyName(name)) {
|
|
428
|
+
const expression = name.expression;
|
|
429
|
+
if (ts.isNumericLiteral(expression)) {
|
|
430
|
+
return expression.text;
|
|
431
|
+
}
|
|
432
|
+
if (ts.isPropertyAccessExpression(expression) &&
|
|
433
|
+
ts.isIdentifier(expression.expression) &&
|
|
434
|
+
expression.expression.text === 'Symbol') {
|
|
435
|
+
return expression.getText();
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
return undefined;
|
|
439
|
+
}
|
|
@@ -164,11 +164,7 @@ exports.default = util.createRule({
|
|
|
164
164
|
if (argNode.type === utils_1.AST_NODE_TYPES.SpreadElement) {
|
|
165
165
|
continue;
|
|
166
166
|
}
|
|
167
|
-
//
|
|
168
|
-
if (checkExpressionNode(argNode)) {
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
171
|
-
// Check against the types from all of the call signatures
|
|
167
|
+
// Collect the types from all of the call signatures
|
|
172
168
|
const argExpectedReturnTypes = funcSignatures
|
|
173
169
|
.map(s => s.parameters[argIdx])
|
|
174
170
|
.filter(Boolean)
|
|
@@ -176,20 +172,44 @@ exports.default = util.createRule({
|
|
|
176
172
|
.flatMap(paramType => tsutils.unionConstituents(paramType))
|
|
177
173
|
.flatMap(paramType => paramType.getCallSignatures())
|
|
178
174
|
.map(paramSignature => paramSignature.getReturnType());
|
|
175
|
+
const hasSingleSignature = funcSignatures.length === 1;
|
|
176
|
+
const allSignaturesReturnVoid = argExpectedReturnTypes.every(type => isVoid(type) ||
|
|
177
|
+
// Treat as void even though it might be technically any.
|
|
178
|
+
isNullishOrAny(type) ||
|
|
179
|
+
// `getTypeOfSymbolAtLocation` returns unresolved type parameters
|
|
180
|
+
// (e.g. `T`), even for overloads that match the call.
|
|
181
|
+
//
|
|
182
|
+
// Since we can't tell whether a generic overload currently matches,
|
|
183
|
+
// we treat TypeParameters similar to void.
|
|
184
|
+
tsutils.isTypeParameter(type));
|
|
185
|
+
// Check against the contextual type first, but only when there is a
|
|
186
|
+
// single signature or when all signatures return void, because
|
|
187
|
+
// `getContextualType` resolves to the first overload's return type even
|
|
188
|
+
// though there may be another one that matches the call.
|
|
189
|
+
if ((hasSingleSignature || allSignaturesReturnVoid) &&
|
|
190
|
+
checkExpressionNode(argNode)) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
179
193
|
if (
|
|
180
194
|
// At least one return type is void
|
|
181
|
-
argExpectedReturnTypes.some(
|
|
195
|
+
argExpectedReturnTypes.some(isVoid) &&
|
|
182
196
|
// The rest are nullish or any
|
|
183
|
-
argExpectedReturnTypes.every(
|
|
184
|
-
ts.TypeFlags.Undefined |
|
|
185
|
-
ts.TypeFlags.Null |
|
|
186
|
-
ts.TypeFlags.Any |
|
|
187
|
-
ts.TypeFlags.Never))) {
|
|
197
|
+
argExpectedReturnTypes.every(isNullishOrAny)) {
|
|
188
198
|
// We treat this argument as void even though it might be technically any.
|
|
189
199
|
reportIfNonVoidFunction(argNode);
|
|
190
200
|
}
|
|
191
201
|
}
|
|
192
202
|
}
|
|
203
|
+
function isNullishOrAny(type) {
|
|
204
|
+
return tsutils.isTypeFlagSet(type, ts.TypeFlags.VoidLike |
|
|
205
|
+
ts.TypeFlags.Undefined |
|
|
206
|
+
ts.TypeFlags.Null |
|
|
207
|
+
ts.TypeFlags.Any |
|
|
208
|
+
ts.TypeFlags.Never);
|
|
209
|
+
}
|
|
210
|
+
function isVoid(type) {
|
|
211
|
+
return tsutils.isTypeFlagSet(type, ts.TypeFlags.Void);
|
|
212
|
+
}
|
|
193
213
|
/**
|
|
194
214
|
* Finds errors in an object property.
|
|
195
215
|
*
|