@typescript-eslint/eslint-plugin 8.31.2-alpha.8 → 8.32.1-alpha.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/dist/rules/await-thenable.js +2 -2
- package/dist/rules/enum-utils/shared.js +1 -1
- package/dist/rules/no-confusing-void-expression.js +3 -3
- package/dist/rules/no-floating-promises.d.ts.map +1 -1
- package/dist/rules/no-floating-promises.js +15 -27
- package/dist/rules/no-meaningless-void-operator.js +1 -1
- package/dist/rules/no-misused-promises.js +8 -8
- package/dist/rules/no-misused-spread.js +2 -2
- package/dist/rules/no-redundant-type-constituents.js +1 -1
- package/dist/rules/no-unnecessary-condition.js +5 -5
- package/dist/rules/no-unnecessary-template-expression.js +1 -1
- package/dist/rules/no-unnecessary-type-assertion.js +2 -2
- package/dist/rules/no-unnecessary-type-conversion.d.ts.map +1 -1
- package/dist/rules/no-unnecessary-type-conversion.js +4 -2
- package/dist/rules/no-unsafe-enum-comparison.js +4 -4
- package/dist/rules/no-unsafe-unary-minus.js +1 -1
- package/dist/rules/non-nullable-type-assertion-style.js +1 -1
- package/dist/rules/only-throw-error.d.ts +1 -0
- package/dist/rules/only-throw-error.d.ts.map +1 -1
- package/dist/rules/only-throw-error.js +47 -0
- package/dist/rules/prefer-find.js +2 -2
- package/dist/rules/prefer-nullish-coalescing.js +2 -2
- package/dist/rules/prefer-optional-chain-utils/analyzeChain.js +1 -1
- package/dist/rules/prefer-optional-chain-utils/checkNullishAndReport.js +1 -1
- package/dist/rules/prefer-optional-chain-utils/gatherLogicalOperands.js +1 -1
- package/dist/rules/prefer-reduce-type-parameter.js +2 -2
- package/dist/rules/prefer-regexp-exec.js +1 -1
- package/dist/rules/restrict-plus-operands.js +4 -4
- package/dist/rules/strict-boolean-expressions.d.ts.map +1 -1
- package/dist/rules/strict-boolean-expressions.js +3 -3
- package/dist/rules/switch-exhaustiveness-check.js +4 -4
- package/dist/rules/unbound-method.d.ts.map +1 -1
- package/dist/rules/unbound-method.js +2 -2
- package/dist/rules/use-unknown-in-catch-callback-variable.js +1 -1
- package/dist/util/isArrayMethodCallWithPredicate.js +2 -2
- package/dist/util/promiseUtils.d.ts +28 -0
- package/dist/util/promiseUtils.d.ts.map +1 -0
- package/dist/util/promiseUtils.js +98 -0
- package/dist/util/truthinessUtils.js +4 -4
- package/docs/rules/only-throw-error.mdx +6 -0
- package/package.json +15 -17
@@ -87,7 +87,7 @@ exports.default = (0, util_1.createRule)({
|
|
87
87
|
return;
|
88
88
|
}
|
89
89
|
const hasAsyncIteratorSymbol = tsutils
|
90
|
-
.
|
90
|
+
.unionConstituents(type)
|
91
91
|
.some(typePart => tsutils.getWellKnownSymbolPropertyOfType(typePart, 'asyncIterator', checker) != null);
|
92
92
|
if (!hasAsyncIteratorSymbol) {
|
93
93
|
context.report({
|
@@ -118,7 +118,7 @@ exports.default = (0, util_1.createRule)({
|
|
118
118
|
continue;
|
119
119
|
}
|
120
120
|
const hasAsyncDisposeSymbol = tsutils
|
121
|
-
.
|
121
|
+
.unionConstituents(type)
|
122
122
|
.some(typePart => tsutils.getWellKnownSymbolPropertyOfType(typePart, 'asyncDispose', checker) != null);
|
123
123
|
if (!hasAsyncDisposeSymbol) {
|
124
124
|
context.report({
|
@@ -327,7 +327,7 @@ exports.default = (0, util_1.createRule)({
|
|
327
327
|
return callSignatures.some(signature => {
|
328
328
|
const returnType = signature.getReturnType();
|
329
329
|
return tsutils
|
330
|
-
.
|
330
|
+
.unionConstituents(returnType)
|
331
331
|
.some(tsutils.isIntrinsicVoidType);
|
332
332
|
});
|
333
333
|
}
|
@@ -342,14 +342,14 @@ exports.default = (0, util_1.createRule)({
|
|
342
342
|
if (functionTSNode.type) {
|
343
343
|
const returnType = checker.getTypeFromTypeNode(functionTSNode.type);
|
344
344
|
return tsutils
|
345
|
-
.
|
345
|
+
.unionConstituents(returnType)
|
346
346
|
.some(tsutils.isIntrinsicVoidType);
|
347
347
|
}
|
348
348
|
if (ts.isExpression(functionTSNode)) {
|
349
349
|
const functionType = checker.getContextualType(functionTSNode);
|
350
350
|
if (functionType) {
|
351
351
|
return tsutils
|
352
|
-
.
|
352
|
+
.unionConstituents(functionType)
|
353
353
|
.some(isFunctionReturnTypeIncludesVoid);
|
354
354
|
}
|
355
355
|
}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"no-floating-promises.d.ts","sourceRoot":"","sources":["../../src/rules/no-floating-promises.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,0BAA0B,CAAC;AAMnE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;
|
1
|
+
{"version":3,"file":"no-floating-promises.d.ts","sourceRoot":"","sources":["../../src/rules/no-floating-promises.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,0BAA0B,CAAC;AAMnE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAmBpD,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,sBAAsB,CAAC,EAAE,oBAAoB,EAAE,CAAC;QAChD,yBAAyB,CAAC,EAAE,oBAAoB,EAAE,CAAC;QACnD,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB;CACF,CAAC;AAEF,MAAM,MAAM,SAAS,GACjB,UAAU,GACV,kBAAkB,GAClB,iBAAiB,GACjB,sBAAsB,GACtB,0BAA0B,GAC1B,iCAAiC,GACjC,qCAAqC,GACrC,cAAc,CAAC;;AAmBnB,wBAqZG"}
|
@@ -37,6 +37,7 @@ const utils_1 = require("@typescript-eslint/utils");
|
|
37
37
|
const tsutils = __importStar(require("ts-api-utils"));
|
38
38
|
const ts = __importStar(require("typescript"));
|
39
39
|
const util_1 = require("../util");
|
40
|
+
const promiseUtils_1 = require("../util/promiseUtils");
|
40
41
|
const messageBase = 'Promises must be awaited, end with a call to .catch, or end with a call to .then with a rejection handler.';
|
41
42
|
const messageBaseVoid = 'Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler' +
|
42
43
|
' or be explicitly marked as ignored with the `void` operator.';
|
@@ -256,33 +257,20 @@ exports.default = (0, util_1.createRule)({
|
|
256
257
|
if (node.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
257
258
|
// If the outer expression is a call, a `.catch()` or `.then()` with
|
258
259
|
// rejection handler handles the promise.
|
259
|
-
const
|
260
|
-
if (
|
261
|
-
const
|
262
|
-
|
263
|
-
|
264
|
-
: undefined;
|
265
|
-
if (catchRejectionHandler) {
|
266
|
-
if (isValidRejectionHandler(catchRejectionHandler)) {
|
260
|
+
const promiseHandlingMethodCall = (0, promiseUtils_1.parseCatchCall)(node, context) ?? (0, promiseUtils_1.parseThenCall)(node, context);
|
261
|
+
if (promiseHandlingMethodCall != null) {
|
262
|
+
const onRejected = promiseHandlingMethodCall.onRejected;
|
263
|
+
if (onRejected != null) {
|
264
|
+
if (isValidRejectionHandler(onRejected)) {
|
267
265
|
return { isUnhandled: false };
|
268
266
|
}
|
269
267
|
return { isUnhandled: true, nonFunctionHandler: true };
|
270
268
|
}
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
return { isUnhandled: false };
|
277
|
-
}
|
278
|
-
return { isUnhandled: true, nonFunctionHandler: true };
|
279
|
-
}
|
280
|
-
// `x.finally()` is transparent to resolution of the promise, so check `x`.
|
281
|
-
// ("object" in this context is the `x` in `x.finally()`)
|
282
|
-
const promiseFinallyObject = methodName === 'finally' ? callee.object : undefined;
|
283
|
-
if (promiseFinallyObject) {
|
284
|
-
return isUnhandledPromise(checker, promiseFinallyObject);
|
285
|
-
}
|
269
|
+
return { isUnhandled: true };
|
270
|
+
}
|
271
|
+
const promiseFinallyCall = (0, promiseUtils_1.parseFinallyCall)(node, context);
|
272
|
+
if (promiseFinallyCall != null) {
|
273
|
+
return isUnhandledPromise(checker, promiseFinallyCall.object);
|
286
274
|
}
|
287
275
|
// All other cases are unhandled.
|
288
276
|
return { isUnhandled: true };
|
@@ -309,7 +297,7 @@ exports.default = (0, util_1.createRule)({
|
|
309
297
|
function isPromiseArray(node) {
|
310
298
|
const type = checker.getTypeAtLocation(node);
|
311
299
|
for (const ty of tsutils
|
312
|
-
.
|
300
|
+
.unionConstituents(type)
|
313
301
|
.map(t => checker.getApparentType(t))) {
|
314
302
|
if (checker.isArrayType(ty)) {
|
315
303
|
const arrayType = checker.getTypeArguments(ty)[0];
|
@@ -334,7 +322,7 @@ exports.default = (0, util_1.createRule)({
|
|
334
322
|
return false;
|
335
323
|
}
|
336
324
|
// Otherwise, we always consider the built-in Promise to be Promise-like...
|
337
|
-
const typeParts = tsutils.
|
325
|
+
const typeParts = tsutils.unionConstituents(checker.getApparentType(type));
|
338
326
|
if (typeParts.some(typePart => (0, util_1.isBuiltinSymbolLike)(services.program, typePart, 'Promise'))) {
|
339
327
|
return true;
|
340
328
|
}
|
@@ -363,7 +351,7 @@ exports.default = (0, util_1.createRule)({
|
|
363
351
|
},
|
364
352
|
});
|
365
353
|
function hasMatchingSignature(type, matcher) {
|
366
|
-
for (const t of tsutils.
|
354
|
+
for (const t of tsutils.unionConstituents(type)) {
|
367
355
|
if (t.getCallSignatures().some(matcher)) {
|
368
356
|
return true;
|
369
357
|
}
|
@@ -372,7 +360,7 @@ function hasMatchingSignature(type, matcher) {
|
|
372
360
|
}
|
373
361
|
function isFunctionParam(checker, param, node) {
|
374
362
|
const type = checker.getApparentType(checker.getTypeOfSymbolAtLocation(param, node));
|
375
|
-
for (const t of tsutils.
|
363
|
+
for (const t of tsutils.unionConstituents(type)) {
|
376
364
|
if (t.getCallSignatures().length !== 0) {
|
377
365
|
return true;
|
378
366
|
}
|
@@ -79,7 +79,7 @@ exports.default = (0, util_1.createRule)({
|
|
79
79
|
]);
|
80
80
|
};
|
81
81
|
const argType = services.getTypeAtLocation(node.argument);
|
82
|
-
const unionParts = tsutils.
|
82
|
+
const unionParts = tsutils.unionConstituents(argType);
|
83
83
|
if (unionParts.every(part => part.flags & (ts.TypeFlags.Void | ts.TypeFlags.Undefined))) {
|
84
84
|
context.report({
|
85
85
|
node,
|
@@ -551,7 +551,7 @@ exports.default = (0, util_1.createRule)({
|
|
551
551
|
});
|
552
552
|
function isSometimesThenable(checker, node) {
|
553
553
|
const type = checker.getTypeAtLocation(node);
|
554
|
-
for (const subType of tsutils.
|
554
|
+
for (const subType of tsutils.unionConstituents(checker.getApparentType(type))) {
|
555
555
|
if (tsutils.isThenableType(checker, node, subType)) {
|
556
556
|
return true;
|
557
557
|
}
|
@@ -564,7 +564,7 @@ function isSometimesThenable(checker, node) {
|
|
564
564
|
// branches is thenable.
|
565
565
|
function isAlwaysThenable(checker, node) {
|
566
566
|
const type = checker.getTypeAtLocation(node);
|
567
|
-
for (const subType of tsutils.
|
567
|
+
for (const subType of tsutils.unionConstituents(checker.getApparentType(type))) {
|
568
568
|
const thenProp = subType.getProperty('then');
|
569
569
|
// If one of the alternates has no then property, it is not thenable in all
|
570
570
|
// cases.
|
@@ -576,7 +576,7 @@ function isAlwaysThenable(checker, node) {
|
|
576
576
|
// be of the right form to consider it thenable.
|
577
577
|
const thenType = checker.getTypeOfSymbolAtLocation(thenProp, node);
|
578
578
|
let hasThenableSignature = false;
|
579
|
-
for (const subType of tsutils.
|
579
|
+
for (const subType of tsutils.unionConstituents(thenType)) {
|
580
580
|
for (const signature of subType.getCallSignatures()) {
|
581
581
|
if (signature.parameters.length !== 0 &&
|
582
582
|
isFunctionParam(checker, signature.parameters[0], node)) {
|
@@ -602,7 +602,7 @@ function isAlwaysThenable(checker, node) {
|
|
602
602
|
}
|
603
603
|
function isFunctionParam(checker, param, node) {
|
604
604
|
const type = checker.getApparentType(checker.getTypeOfSymbolAtLocation(param, node));
|
605
|
-
for (const subType of tsutils.
|
605
|
+
for (const subType of tsutils.unionConstituents(type)) {
|
606
606
|
if (subType.getCallSignatures().length !== 0) {
|
607
607
|
return true;
|
608
608
|
}
|
@@ -641,7 +641,7 @@ function voidFunctionArguments(checker, node) {
|
|
641
641
|
const type = checker.getTypeAtLocation(node.expression);
|
642
642
|
// We can't use checker.getResolvedSignature because it prefers an early '() => void' over a later '() => Promise<void>'
|
643
643
|
// See https://github.com/microsoft/TypeScript/issues/48077
|
644
|
-
for (const subType of tsutils.
|
644
|
+
for (const subType of tsutils.unionConstituents(type)) {
|
645
645
|
// Standard function calls and `new` have two different types of signatures
|
646
646
|
const signatures = ts.isCallExpression(node)
|
647
647
|
? subType.getCallSignatures()
|
@@ -698,7 +698,7 @@ function anySignatureIsThenableType(checker, node, type) {
|
|
698
698
|
* @returns Whether type is a thenable-returning function.
|
699
699
|
*/
|
700
700
|
function isThenableReturningFunctionType(checker, node, type) {
|
701
|
-
for (const subType of tsutils.
|
701
|
+
for (const subType of tsutils.unionConstituents(type)) {
|
702
702
|
if (anySignatureIsThenableType(checker, node, subType)) {
|
703
703
|
return true;
|
704
704
|
}
|
@@ -710,7 +710,7 @@ function isThenableReturningFunctionType(checker, node, type) {
|
|
710
710
|
*/
|
711
711
|
function isVoidReturningFunctionType(checker, node, type) {
|
712
712
|
let hadVoidReturn = false;
|
713
|
-
for (const subType of tsutils.
|
713
|
+
for (const subType of tsutils.unionConstituents(type)) {
|
714
714
|
for (const signature of subType.getCallSignatures()) {
|
715
715
|
const returnType = signature.getReturnType();
|
716
716
|
// If a certain positional argument accepts both thenable and void returns,
|
@@ -729,7 +729,7 @@ function isVoidReturningFunctionType(checker, node, type) {
|
|
729
729
|
function returnsThenable(checker, node) {
|
730
730
|
const type = checker.getApparentType(checker.getTypeAtLocation(node));
|
731
731
|
return tsutils
|
732
|
-
.
|
732
|
+
.unionConstituents(type)
|
733
733
|
.some(t => anySignatureIsThenableType(checker, node, t));
|
734
734
|
}
|
735
735
|
function getHeritageTypes(checker, tsNode) {
|
@@ -97,7 +97,7 @@ exports.default = (0, util_1.createRule)({
|
|
97
97
|
}
|
98
98
|
}
|
99
99
|
function getMapSpreadSuggestions(node, type) {
|
100
|
-
const types = tsutils.
|
100
|
+
const types = tsutils.unionConstituents(type);
|
101
101
|
if (types.some(t => !isMap(services.program, t))) {
|
102
102
|
return null;
|
103
103
|
}
|
@@ -208,7 +208,7 @@ exports.default = (0, util_1.createRule)({
|
|
208
208
|
});
|
209
209
|
function isIterable(type, checker) {
|
210
210
|
return tsutils
|
211
|
-
.
|
211
|
+
.typeConstituents(type)
|
212
212
|
.some(t => !!tsutils.getWellKnownSymbolPropertyOfType(t, 'iterator', checker));
|
213
213
|
}
|
214
214
|
function isArray(checker, type) {
|
@@ -168,7 +168,7 @@ function unionTypePartsUnlessBoolean(type) {
|
|
168
168
|
tsutils.isFalseLiteralType(type.types[0]) &&
|
169
169
|
tsutils.isTrueLiteralType(type.types[1])
|
170
170
|
? [type]
|
171
|
-
: tsutils.
|
171
|
+
: tsutils.unionConstituents(type);
|
172
172
|
}
|
173
173
|
exports.default = (0, util_1.createRule)({
|
174
174
|
name: 'no-redundant-type-constituents',
|
@@ -44,14 +44,14 @@ function isNullishType(type) {
|
|
44
44
|
return tsutils.isTypeFlagSet(type, nullishFlag);
|
45
45
|
}
|
46
46
|
function isAlwaysNullish(type) {
|
47
|
-
return tsutils.
|
47
|
+
return tsutils.unionConstituents(type).every(isNullishType);
|
48
48
|
}
|
49
49
|
/**
|
50
50
|
* Note that this differs from {@link isNullableType} in that it doesn't consider
|
51
51
|
* `any` or `unknown` to be nullable.
|
52
52
|
*/
|
53
53
|
function isPossiblyNullish(type) {
|
54
|
-
return tsutils.
|
54
|
+
return tsutils.unionConstituents(type).some(isNullishType);
|
55
55
|
}
|
56
56
|
function toStaticValue(type) {
|
57
57
|
// type.isLiteral() only covers numbers/bigints and strings, hence the rest of the branches.
|
@@ -198,13 +198,13 @@ exports.default = (0, util_1.createRule)({
|
|
198
198
|
function nodeIsArrayType(node) {
|
199
199
|
const nodeType = (0, util_1.getConstrainedTypeAtLocation)(services, node);
|
200
200
|
return tsutils
|
201
|
-
.
|
201
|
+
.unionConstituents(nodeType)
|
202
202
|
.some(part => checker.isArrayType(part));
|
203
203
|
}
|
204
204
|
function nodeIsTupleType(node) {
|
205
205
|
const nodeType = (0, util_1.getConstrainedTypeAtLocation)(services, node);
|
206
206
|
return tsutils
|
207
|
-
.
|
207
|
+
.unionConstituents(nodeType)
|
208
208
|
.some(part => checker.isTupleType(part));
|
209
209
|
}
|
210
210
|
function isArrayIndexExpression(node) {
|
@@ -223,7 +223,7 @@ exports.default = (0, util_1.createRule)({
|
|
223
223
|
// `any` or `unknown` or a naked type variable
|
224
224
|
function isConditionalAlwaysNecessary(type) {
|
225
225
|
return tsutils
|
226
|
-
.
|
226
|
+
.unionConstituents(type)
|
227
227
|
.some(part => (0, util_1.isTypeAnyType)(part) ||
|
228
228
|
(0, util_1.isTypeUnknownType)(part) ||
|
229
229
|
(0, util_1.isTypeFlagSet)(part, ts.TypeFlags.TypeVariable));
|
@@ -77,7 +77,7 @@ exports.default = (0, util_1.createRule)({
|
|
77
77
|
return isStringLike(type);
|
78
78
|
}
|
79
79
|
function isEnumMemberType(type) {
|
80
|
-
return tsutils.
|
80
|
+
return tsutils.typeConstituents(type).some(t => {
|
81
81
|
const symbol = t.getSymbol();
|
82
82
|
return !!(symbol?.valueDeclaration && ts.isEnumMember(symbol.valueDeclaration));
|
83
83
|
});
|
@@ -171,10 +171,10 @@ exports.default = (0, util_1.createRule)({
|
|
171
171
|
(0, util_1.isTypeFlagSet)(cast, ts.TypeFlags.Undefined) &&
|
172
172
|
tsutils.isCompilerOptionEnabled(compilerOptions, 'exactOptionalPropertyTypes')) {
|
173
173
|
const uncastParts = tsutils
|
174
|
-
.
|
174
|
+
.unionConstituents(uncast)
|
175
175
|
.filter(part => !(0, util_1.isTypeFlagSet)(part, ts.TypeFlags.Undefined));
|
176
176
|
const castParts = tsutils
|
177
|
-
.
|
177
|
+
.unionConstituents(cast)
|
178
178
|
.filter(part => !(0, util_1.isTypeFlagSet)(part, ts.TypeFlags.Undefined));
|
179
179
|
if (uncastParts.length !== castParts.length) {
|
180
180
|
return false;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"no-unnecessary-type-conversion.d.ts","sourceRoot":"","sources":["../../src/rules/no-unnecessary-type-conversion.ts"],"names":[],"mappings":"AAgBA,KAAK,UAAU,GACX,eAAe,GACf,kBAAkB,GAClB,2BAA2B,CAAC;;AAEhC,
|
1
|
+
{"version":3,"file":"no-unnecessary-type-conversion.d.ts","sourceRoot":"","sources":["../../src/rules/no-unnecessary-type-conversion.ts"],"names":[],"mappings":"AAgBA,KAAK,UAAU,GACX,eAAe,GACf,kBAAkB,GAClB,2BAA2B,CAAC;;AAEhC,wBAsVG"}
|
@@ -34,7 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
34
34
|
})();
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
36
36
|
const utils_1 = require("@typescript-eslint/utils");
|
37
|
-
const
|
37
|
+
const tsutils = __importStar(require("ts-api-utils"));
|
38
38
|
const ts = __importStar(require("typescript"));
|
39
39
|
const util_1 = require("../util");
|
40
40
|
exports.default = (0, util_1.createRule)({
|
@@ -57,7 +57,9 @@ exports.default = (0, util_1.createRule)({
|
|
57
57
|
defaultOptions: [],
|
58
58
|
create(context) {
|
59
59
|
function doesUnderlyingTypeMatchFlag(type, typeFlag) {
|
60
|
-
return
|
60
|
+
return tsutils
|
61
|
+
.unionConstituents(type)
|
62
|
+
.every(t => (0, util_1.isTypeFlagSet)(t, typeFlag));
|
61
63
|
}
|
62
64
|
const services = (0, util_1.getParserServices)(context);
|
63
65
|
function handleUnaryOperator(node, typeFlag, typeString, violation, isDoubleOperator) {
|
@@ -46,13 +46,13 @@ function typeViolates(leftTypeParts, rightType) {
|
|
46
46
|
(leftEnumValueTypes.has(ts.TypeFlags.String) && isStringLike(rightType)));
|
47
47
|
}
|
48
48
|
function isNumberLike(type) {
|
49
|
-
const typeParts = tsutils.
|
49
|
+
const typeParts = tsutils.intersectionConstituents(type);
|
50
50
|
return typeParts.some(typePart => {
|
51
51
|
return tsutils.isTypeFlagSet(typePart, ts.TypeFlags.Number | ts.TypeFlags.NumberLike);
|
52
52
|
});
|
53
53
|
}
|
54
54
|
function isStringLike(type) {
|
55
|
-
const typeParts = tsutils.
|
55
|
+
const typeParts = tsutils.intersectionConstituents(type);
|
56
56
|
return typeParts.some(typePart => {
|
57
57
|
return tsutils.isTypeFlagSet(typePart, ts.TypeFlags.String | ts.TypeFlags.StringLike);
|
58
58
|
});
|
@@ -116,8 +116,8 @@ exports.default = (0, util_1.createRule)({
|
|
116
116
|
// declare const something: Fruit | Vegetable;
|
117
117
|
// something === Fruit.Apple;
|
118
118
|
// ```
|
119
|
-
const leftTypeParts = tsutils.
|
120
|
-
const rightTypeParts = tsutils.
|
119
|
+
const leftTypeParts = tsutils.unionConstituents(leftType);
|
120
|
+
const rightTypeParts = tsutils.unionConstituents(rightType);
|
121
121
|
// If a type exists in both sides, we consider this comparison safe:
|
122
122
|
//
|
123
123
|
// ```ts
|
@@ -61,7 +61,7 @@ exports.default = util.createRule({
|
|
61
61
|
const argType = util.getConstrainedTypeAtLocation(services, node.argument);
|
62
62
|
const checker = services.program.getTypeChecker();
|
63
63
|
if (tsutils
|
64
|
-
.
|
64
|
+
.unionConstituents(argType)
|
65
65
|
.some(type => !tsutils.isTypeFlagSet(type, ts.TypeFlags.Any |
|
66
66
|
ts.TypeFlags.Never |
|
67
67
|
ts.TypeFlags.BigIntLike |
|
@@ -60,7 +60,7 @@ exports.default = (0, util_1.createRule)({
|
|
60
60
|
if (tsutils.isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.Unknown)) {
|
61
61
|
return undefined;
|
62
62
|
}
|
63
|
-
return tsutils.
|
63
|
+
return tsutils.unionConstituents(type);
|
64
64
|
};
|
65
65
|
const couldBeNullish = (type) => {
|
66
66
|
if (type.flags & ts.TypeFlags.TypeParameter) {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"only-throw-error.d.ts","sourceRoot":"","sources":["../../src/rules/only-throw-error.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"only-throw-error.d.ts","sourceRoot":"","sources":["../../src/rules/only-throw-error.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAepD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE5C,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,KAAK,CAAC,EAAE,oBAAoB,EAAE,CAAC;QAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC;CACF,CAAC;;AAEF,wBA4JG"}
|
@@ -34,8 +34,10 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
34
34
|
})();
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
36
36
|
const utils_1 = require("@typescript-eslint/utils");
|
37
|
+
const ts_api_utils_1 = require("ts-api-utils");
|
37
38
|
const ts = __importStar(require("typescript"));
|
38
39
|
const util_1 = require("../util");
|
40
|
+
const promiseUtils_1 = require("../util/promiseUtils");
|
39
41
|
exports.default = (0, util_1.createRule)({
|
40
42
|
name: 'only-throw-error',
|
41
43
|
meta: {
|
@@ -59,6 +61,10 @@ exports.default = (0, util_1.createRule)({
|
|
59
61
|
...util_1.typeOrValueSpecifiersSchema,
|
60
62
|
description: 'Type specifiers that can be thrown.',
|
61
63
|
},
|
64
|
+
allowRethrowing: {
|
65
|
+
type: 'boolean',
|
66
|
+
description: 'Whether to allow rethrowing caught values that are not `Error` objects.',
|
67
|
+
},
|
62
68
|
allowThrowingAny: {
|
63
69
|
type: 'boolean',
|
64
70
|
description: 'Whether to always allow throwing values typed as `any`.',
|
@@ -74,6 +80,7 @@ exports.default = (0, util_1.createRule)({
|
|
74
80
|
defaultOptions: [
|
75
81
|
{
|
76
82
|
allow: [],
|
83
|
+
allowRethrowing: true,
|
77
84
|
allowThrowingAny: true,
|
78
85
|
allowThrowingUnknown: true,
|
79
86
|
},
|
@@ -81,11 +88,51 @@ exports.default = (0, util_1.createRule)({
|
|
81
88
|
create(context, [options]) {
|
82
89
|
const services = (0, util_1.getParserServices)(context);
|
83
90
|
const allow = options.allow;
|
91
|
+
function isRethrownError(node) {
|
92
|
+
if (node.type !== utils_1.AST_NODE_TYPES.Identifier) {
|
93
|
+
return false;
|
94
|
+
}
|
95
|
+
const scope = context.sourceCode.getScope(node);
|
96
|
+
const smVariable = (0, util_1.nullThrows)((0, util_1.findVariable)(scope, node), `Variable ${node.name} should exist in scope manager`);
|
97
|
+
const variableDefinitions = smVariable.defs.filter(def => def.isVariableDefinition);
|
98
|
+
if (variableDefinitions.length !== 1) {
|
99
|
+
return false;
|
100
|
+
}
|
101
|
+
const def = smVariable.defs[0];
|
102
|
+
// try { /* ... */ } catch (x) { throw x; }
|
103
|
+
if (def.node.type === utils_1.AST_NODE_TYPES.CatchClause) {
|
104
|
+
return true;
|
105
|
+
}
|
106
|
+
// promise.catch(x => { throw x; })
|
107
|
+
// promise.then(onFulfilled, x => { throw x; })
|
108
|
+
if (def.node.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression &&
|
109
|
+
def.node.params.length >= 1 &&
|
110
|
+
def.node.params[0] === def.name &&
|
111
|
+
def.node.parent.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
112
|
+
const callExpression = def.node.parent;
|
113
|
+
const parsedPromiseHandlingCall = (0, promiseUtils_1.parseCatchCall)(callExpression, context) ??
|
114
|
+
(0, promiseUtils_1.parseThenCall)(callExpression, context);
|
115
|
+
if (parsedPromiseHandlingCall != null) {
|
116
|
+
const { object, onRejected } = parsedPromiseHandlingCall;
|
117
|
+
if (onRejected === def.node) {
|
118
|
+
const tsObjectNode = services.esTreeNodeToTSNodeMap.get(object);
|
119
|
+
// make sure we're actually dealing with a promise
|
120
|
+
if ((0, ts_api_utils_1.isThenableType)(services.program.getTypeChecker(), tsObjectNode)) {
|
121
|
+
return true;
|
122
|
+
}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
return false;
|
127
|
+
}
|
84
128
|
function checkThrowArgument(node) {
|
85
129
|
if (node.type === utils_1.AST_NODE_TYPES.AwaitExpression ||
|
86
130
|
node.type === utils_1.AST_NODE_TYPES.YieldExpression) {
|
87
131
|
return;
|
88
132
|
}
|
133
|
+
if (options.allowRethrowing && isRethrownError(node)) {
|
134
|
+
return;
|
135
|
+
}
|
89
136
|
const type = services.getTypeAtLocation(node);
|
90
137
|
if ((0, util_1.typeMatchesSomeSpecifier)(type, allow, services.program)) {
|
91
138
|
return;
|
@@ -109,7 +109,7 @@ exports.default = (0, util_1.createRule)({
|
|
109
109
|
*/
|
110
110
|
function isArrayish(type) {
|
111
111
|
let isAtLeastOneArrayishComponent = false;
|
112
|
-
for (const unionPart of tsutils.
|
112
|
+
for (const unionPart of tsutils.unionConstituents(type)) {
|
113
113
|
if (tsutils.isIntrinsicNullType(unionPart) ||
|
114
114
|
tsutils.isIntrinsicUndefinedType(unionPart)) {
|
115
115
|
continue;
|
@@ -117,7 +117,7 @@ exports.default = (0, util_1.createRule)({
|
|
117
117
|
// apparently checker.isArrayType(T[] & S[]) => false.
|
118
118
|
// so we need to check the intersection parts individually.
|
119
119
|
const isArrayOrIntersectionThereof = tsutils
|
120
|
-
.
|
120
|
+
.intersectionConstituents(unionPart)
|
121
121
|
.every(intersectionPart => checker.isArrayType(intersectionPart) ||
|
122
122
|
checker.isTupleType(intersectionPart));
|
123
123
|
if (!isArrayOrIntersectionThereof) {
|
@@ -195,9 +195,9 @@ exports.default = (0, util_1.createRule)({
|
|
195
195
|
return false;
|
196
196
|
}
|
197
197
|
if (tsutils
|
198
|
-
.
|
198
|
+
.typeConstituents(type)
|
199
199
|
.some(t => tsutils
|
200
|
-
.
|
200
|
+
.intersectionConstituents(t)
|
201
201
|
.some(t => tsutils.isTypeFlagSet(t, ignorableFlags)))) {
|
202
202
|
return false;
|
203
203
|
}
|
@@ -43,7 +43,7 @@ const compareNodes_1 = require("./compareNodes");
|
|
43
43
|
const gatherLogicalOperands_1 = require("./gatherLogicalOperands");
|
44
44
|
function includesType(parserServices, node, typeFlagIn) {
|
45
45
|
const typeFlag = typeFlagIn | ts.TypeFlags.Any | ts.TypeFlags.Unknown;
|
46
|
-
const types = (0, ts_api_utils_1.
|
46
|
+
const types = (0, ts_api_utils_1.unionConstituents)(parserServices.getTypeAtLocation(node));
|
47
47
|
for (const type of types) {
|
48
48
|
if ((0, util_1.isTypeFlagSet)(type, typeFlag)) {
|
49
49
|
return true;
|
@@ -39,7 +39,7 @@ const ts_api_utils_1 = require("ts-api-utils");
|
|
39
39
|
const ts = __importStar(require("typescript"));
|
40
40
|
function checkNullishAndReport(context, parserServices, { requireNullish }, maybeNullishNodes, descriptor) {
|
41
41
|
if (!requireNullish ||
|
42
|
-
maybeNullishNodes.some(node => (0, ts_api_utils_1.
|
42
|
+
maybeNullishNodes.some(node => (0, ts_api_utils_1.unionConstituents)(parserServices.getTypeAtLocation(node)).some(t => (0, type_utils_1.isTypeFlagSet)(t, ts.TypeFlags.Null | ts.TypeFlags.Undefined)))) {
|
43
43
|
context.report(descriptor);
|
44
44
|
}
|
45
45
|
}
|
@@ -72,7 +72,7 @@ var NullishComparisonType;
|
|
72
72
|
const NULLISH_FLAGS = ts.TypeFlags.Null | ts.TypeFlags.Undefined;
|
73
73
|
function isValidFalseBooleanCheckType(node, disallowFalseyLiteral, parserServices, options) {
|
74
74
|
const type = parserServices.getTypeAtLocation(node);
|
75
|
-
const types = (0, ts_api_utils_1.
|
75
|
+
const types = (0, ts_api_utils_1.unionConstituents)(type);
|
76
76
|
if (disallowFalseyLiteral &&
|
77
77
|
/*
|
78
78
|
```
|
@@ -56,9 +56,9 @@ exports.default = (0, util_1.createRule)({
|
|
56
56
|
const checker = services.program.getTypeChecker();
|
57
57
|
function isArrayType(type) {
|
58
58
|
return tsutils
|
59
|
-
.
|
59
|
+
.unionConstituents(type)
|
60
60
|
.every(unionPart => tsutils
|
61
|
-
.
|
61
|
+
.intersectionConstituents(unionPart)
|
62
62
|
.every(t => checker.isArrayType(t) || checker.isTupleType(t)));
|
63
63
|
}
|
64
64
|
return {
|
@@ -147,7 +147,7 @@ exports.default = (0, util_1.createRule)({
|
|
147
147
|
});
|
148
148
|
}
|
149
149
|
const argumentType = services.getTypeAtLocation(argumentNode);
|
150
|
-
const argumentTypes = collectArgumentTypes(tsutils.
|
150
|
+
const argumentTypes = collectArgumentTypes(tsutils.unionConstituents(argumentType));
|
151
151
|
switch (argumentTypes) {
|
152
152
|
case ArgumentType.RegExp:
|
153
153
|
return context.report({
|
@@ -156,7 +156,7 @@ exports.default = (0, util_1.createRule)({
|
|
156
156
|
continue;
|
157
157
|
}
|
158
158
|
// RegExps also contain ts.TypeFlags.Any & ts.TypeFlags.Object
|
159
|
-
for (const subBaseType of tsutils.
|
159
|
+
for (const subBaseType of tsutils.unionConstituents(baseType)) {
|
160
160
|
const typeName = (0, util_1.getTypeName)(typeChecker, subBaseType);
|
161
161
|
if (typeName === 'RegExp'
|
162
162
|
? !allowRegExp ||
|
@@ -221,11 +221,11 @@ exports.default = (0, util_1.createRule)({
|
|
221
221
|
});
|
222
222
|
function isDeeplyObjectType(type) {
|
223
223
|
return type.isIntersection()
|
224
|
-
? tsutils.
|
225
|
-
: tsutils.
|
224
|
+
? tsutils.intersectionConstituents(type).every(tsutils.isObjectType)
|
225
|
+
: tsutils.unionConstituents(type).every(tsutils.isObjectType);
|
226
226
|
}
|
227
227
|
function isTypeFlagSetInUnion(type, flag) {
|
228
228
|
return tsutils
|
229
|
-
.
|
229
|
+
.unionConstituents(type)
|
230
230
|
.some(subType => tsutils.isTypeFlagSet(subType, flag));
|
231
231
|
}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"strict-boolean-expressions.d.ts","sourceRoot":"","sources":["../../src/rules/strict-boolean-expressions.ts"],"names":[],"mappings":"AAsBA,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,sDAAsD,CAAC,EAAE,OAAO,CAAC;QACjE,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB;CACF,CAAC;AAEF,KAAK,uBAAuB,GACxB,mBAAmB,GACnB,+BAA+B,GAC/B,4BAA4B,GAC5B,8BAA8B,GAC9B,8BAA8B,GAC9B,8BAA8B,GAC9B,uBAAuB,GACvB,sBAAsB,GACtB,sBAAsB,GACtB,qBAAqB,GACrB,sBAAsB,CAAC;AAE3B,MAAM,MAAM,SAAS,GACjB,yBAAyB,GACzB,uCAAuC,GACvC,oCAAoC,GACpC,gCAAgC,GAChC,0BAA0B,GAC1B,wBAAwB,GACxB,4BAA4B,GAC5B,iCAAiC,GACjC,yBAAyB,GACzB,yBAAyB,GACzB,gCAAgC,GAChC,0BAA0B,GAC1B,yBAAyB,GACzB,2BAA2B,GAC3B,mBAAmB,GACnB,wBAAwB,GACxB,uBAAuB,CAAC;;AAE5B,
|
1
|
+
{"version":3,"file":"strict-boolean-expressions.d.ts","sourceRoot":"","sources":["../../src/rules/strict-boolean-expressions.ts"],"names":[],"mappings":"AAsBA,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,sDAAsD,CAAC,EAAE,OAAO,CAAC;QACjE,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB;CACF,CAAC;AAEF,KAAK,uBAAuB,GACxB,mBAAmB,GACnB,+BAA+B,GAC/B,4BAA4B,GAC5B,8BAA8B,GAC9B,8BAA8B,GAC9B,8BAA8B,GAC9B,uBAAuB,GACvB,sBAAsB,GACtB,sBAAsB,GACtB,qBAAqB,GACrB,sBAAsB,CAAC;AAE3B,MAAM,MAAM,SAAS,GACjB,yBAAyB,GACzB,uCAAuC,GACvC,oCAAoC,GACpC,gCAAgC,GAChC,0BAA0B,GAC1B,wBAAwB,GACxB,4BAA4B,GAC5B,iCAAiC,GACjC,yBAAyB,GACzB,yBAAyB,GACzB,gCAAgC,GAChC,0BAA0B,GAC1B,yBAAyB,GACzB,2BAA2B,GAC3B,mBAAmB,GACnB,wBAAwB,GACxB,uBAAuB,CAAC;;AAE5B,wBAq/BG"}
|
@@ -237,7 +237,7 @@ exports.default = (0, util_1.createRule)({
|
|
237
237
|
return type;
|
238
238
|
});
|
239
239
|
const flattenTypes = [
|
240
|
-
...new Set(returnTypes.flatMap(type => tsutils.
|
240
|
+
...new Set(returnTypes.flatMap(type => tsutils.unionConstituents(type))),
|
241
241
|
];
|
242
242
|
const types = inspectVariantTypes(flattenTypes);
|
243
243
|
const reportType = determineReportType(types);
|
@@ -774,7 +774,7 @@ exports.default = (0, util_1.createRule)({
|
|
774
774
|
*/
|
775
775
|
function checkNode(node) {
|
776
776
|
const type = (0, util_1.getConstrainedTypeAtLocation)(services, node);
|
777
|
-
const types = inspectVariantTypes(tsutils.
|
777
|
+
const types = inspectVariantTypes(tsutils.unionConstituents(type));
|
778
778
|
const reportType = determineReportType(types);
|
779
779
|
if (reportType != null) {
|
780
780
|
context.report({
|
@@ -799,7 +799,7 @@ exports.default = (0, util_1.createRule)({
|
|
799
799
|
// If incoming type is either "true" or "false", there will be one type
|
800
800
|
// object with intrinsicName set accordingly
|
801
801
|
// If incoming type is boolean, there will be two type objects with
|
802
|
-
// intrinsicName set "true" and "false" each because of ts-api-utils.
|
802
|
+
// intrinsicName set "true" and "false" each because of ts-api-utils.unionConstituents()
|
803
803
|
if (booleans.length === 1) {
|
804
804
|
variantTypes.add(tsutils.isTrueLiteralType(booleans[0]) ? 'truthy boolean' : 'boolean');
|
805
805
|
}
|
@@ -122,8 +122,8 @@ exports.default = (0, util_1.createRule)({
|
|
122
122
|
caseTypes.add(caseType);
|
123
123
|
}
|
124
124
|
const missingLiteralBranchTypes = [];
|
125
|
-
for (const unionPart of tsutils.
|
126
|
-
for (const intersectionPart of tsutils.
|
125
|
+
for (const unionPart of tsutils.unionConstituents(discriminantType)) {
|
126
|
+
for (const intersectionPart of tsutils.intersectionConstituents(unionPart)) {
|
127
127
|
if (caseTypes.has(intersectionPart) ||
|
128
128
|
!isTypeLiteralLikeType(intersectionPart)) {
|
129
129
|
continue;
|
@@ -284,8 +284,8 @@ function isTypeLiteralLikeType(type) {
|
|
284
284
|
*/
|
285
285
|
function doesTypeContainNonLiteralType(type) {
|
286
286
|
return tsutils
|
287
|
-
.
|
287
|
+
.unionConstituents(type)
|
288
288
|
.some(type => tsutils
|
289
|
-
.
|
289
|
+
.intersectionConstituents(type)
|
290
290
|
.every(subType => !isTypeLiteralLikeType(subType)));
|
291
291
|
}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"unbound-method.d.ts","sourceRoot":"","sources":["../../src/rules/unbound-method.ts"],"names":[],"mappings":"AAkBA,UAAU,MAAM;IACd,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC;AAE/B,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,8BAA8B,CAAC;;AAiFpE,
|
1
|
+
{"version":3,"file":"unbound-method.d.ts","sourceRoot":"","sources":["../../src/rules/unbound-method.ts"],"names":[],"mappings":"AAkBA,UAAU,MAAM;IACd,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC;AAE/B,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,8BAA8B,CAAC;;AAiFpE,wBA4KG"}
|
@@ -215,8 +215,8 @@ exports.default = (0, util_1.createRule)({
|
|
215
215
|
}
|
216
216
|
}
|
217
217
|
for (const intersectionPart of tsutils
|
218
|
-
.
|
219
|
-
.flatMap(unionPart => tsutils.
|
218
|
+
.unionConstituents(services.getTypeAtLocation(node))
|
219
|
+
.flatMap(unionPart => tsutils.intersectionConstituents(unionPart))) {
|
220
220
|
const reported = checkIfMethodAndReport(property.key, intersectionPart.getProperty(property.key.name));
|
221
221
|
if (reported) {
|
222
222
|
break;
|
@@ -63,7 +63,7 @@ exports.default = (0, util_1.createRule)({
|
|
63
63
|
const { esTreeNodeToTSNodeMap, program } = (0, util_1.getParserServices)(context);
|
64
64
|
const checker = program.getTypeChecker();
|
65
65
|
function isFlaggableHandlerType(type) {
|
66
|
-
for (const unionPart of tsutils.
|
66
|
+
for (const unionPart of tsutils.unionConstituents(type)) {
|
67
67
|
const callSignatures = tsutils.getCallSignaturesOfType(unionPart);
|
68
68
|
if (callSignatures.length === 0) {
|
69
69
|
// Ignore any non-function components to the type. Those are not this rule's problem.
|
@@ -58,7 +58,7 @@ function isArrayMethodCallWithPredicate(context, services, node) {
|
|
58
58
|
const checker = services.program.getTypeChecker();
|
59
59
|
const type = (0, type_utils_1.getConstrainedTypeAtLocation)(services, node.callee.object);
|
60
60
|
return tsutils
|
61
|
-
.
|
62
|
-
.flatMap(part => tsutils.
|
61
|
+
.unionConstituents(type)
|
62
|
+
.flatMap(part => tsutils.intersectionConstituents(part))
|
63
63
|
.some(t => checker.isArrayType(t) || checker.isTupleType(t));
|
64
64
|
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import type { TSESTree } from '@typescript-eslint/utils';
|
2
|
+
import type { RuleContext } from '@typescript-eslint/utils/ts-eslint';
|
3
|
+
/**
|
4
|
+
* Parses a syntactically possible `Promise.then()` call. Does not check the
|
5
|
+
* type of the callee.
|
6
|
+
*/
|
7
|
+
export declare function parseThenCall(node: TSESTree.CallExpression, context: RuleContext<string, unknown[]>): {
|
8
|
+
onFulfilled?: TSESTree.Expression | undefined;
|
9
|
+
onRejected?: TSESTree.Expression | undefined;
|
10
|
+
object: TSESTree.Expression;
|
11
|
+
} | undefined;
|
12
|
+
/**
|
13
|
+
* Parses a syntactically possible `Promise.catch()` call. Does not check the
|
14
|
+
* type of the callee.
|
15
|
+
*/
|
16
|
+
export declare function parseCatchCall(node: TSESTree.CallExpression, context: RuleContext<string, unknown[]>): {
|
17
|
+
onRejected?: TSESTree.Expression | undefined;
|
18
|
+
object: TSESTree.Expression;
|
19
|
+
} | undefined;
|
20
|
+
/**
|
21
|
+
* Parses a syntactically possible `Promise.finally()` call. Does not check the
|
22
|
+
* type of the callee.
|
23
|
+
*/
|
24
|
+
export declare function parseFinallyCall(node: TSESTree.CallExpression, context: RuleContext<string, unknown[]>): {
|
25
|
+
object: TSESTree.Expression;
|
26
|
+
onFinally?: TSESTree.Expression | undefined;
|
27
|
+
} | undefined;
|
28
|
+
//# sourceMappingURL=promiseUtils.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"promiseUtils.d.ts","sourceRoot":"","sources":["../../src/util/promiseUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AAMtE;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,QAAQ,CAAC,cAAc,EAC7B,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,GAErC;IACE,WAAW,CAAC,EAAE,QAAQ,CAAC,UAAU,GAAG,SAAS,CAAC;IAC9C,UAAU,CAAC,EAAE,QAAQ,CAAC,UAAU,GAAG,SAAS,CAAC;IAC7C,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC;CAC7B,GACD,SAAS,CAqCZ;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,CAAC,cAAc,EAC7B,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,GAErC;IACE,UAAU,CAAC,EAAE,QAAQ,CAAC,UAAU,GAAG,SAAS,CAAC;IAC7C,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC;CAC7B,GACD,SAAS,CAuBZ;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,QAAQ,CAAC,cAAc,EAC7B,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,GAErC;IACE,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC;IAC5B,SAAS,CAAC,EAAE,QAAQ,CAAC,UAAU,GAAG,SAAS,CAAC;CAC7C,GACD,SAAS,CAsBZ"}
|
@@ -0,0 +1,98 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.parseThenCall = parseThenCall;
|
4
|
+
exports.parseCatchCall = parseCatchCall;
|
5
|
+
exports.parseFinallyCall = parseFinallyCall;
|
6
|
+
const utils_1 = require("@typescript-eslint/utils");
|
7
|
+
const misc_1 = require("./misc");
|
8
|
+
/**
|
9
|
+
* Parses a syntactically possible `Promise.then()` call. Does not check the
|
10
|
+
* type of the callee.
|
11
|
+
*/
|
12
|
+
function parseThenCall(node, context) {
|
13
|
+
if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
14
|
+
const methodName = (0, misc_1.getStaticMemberAccessValue)(node.callee, context);
|
15
|
+
if (methodName === 'then') {
|
16
|
+
if (node.arguments.length >= 1) {
|
17
|
+
if (node.arguments[0].type === utils_1.AST_NODE_TYPES.SpreadElement) {
|
18
|
+
return {
|
19
|
+
object: node.callee.object,
|
20
|
+
};
|
21
|
+
}
|
22
|
+
if (node.arguments.length >= 2) {
|
23
|
+
if (node.arguments[1].type === utils_1.AST_NODE_TYPES.SpreadElement) {
|
24
|
+
return {
|
25
|
+
object: node.callee.object,
|
26
|
+
onFulfilled: node.arguments[0],
|
27
|
+
};
|
28
|
+
}
|
29
|
+
return {
|
30
|
+
object: node.callee.object,
|
31
|
+
onFulfilled: node.arguments[0],
|
32
|
+
onRejected: node.arguments[1],
|
33
|
+
};
|
34
|
+
}
|
35
|
+
return {
|
36
|
+
object: node.callee.object,
|
37
|
+
onFulfilled: node.arguments[0],
|
38
|
+
};
|
39
|
+
}
|
40
|
+
return {
|
41
|
+
object: node.callee.object,
|
42
|
+
};
|
43
|
+
}
|
44
|
+
}
|
45
|
+
return undefined;
|
46
|
+
}
|
47
|
+
/**
|
48
|
+
* Parses a syntactically possible `Promise.catch()` call. Does not check the
|
49
|
+
* type of the callee.
|
50
|
+
*/
|
51
|
+
function parseCatchCall(node, context) {
|
52
|
+
if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
53
|
+
const methodName = (0, misc_1.getStaticMemberAccessValue)(node.callee, context);
|
54
|
+
if (methodName === 'catch') {
|
55
|
+
if (node.arguments.length >= 1) {
|
56
|
+
if (node.arguments[0].type === utils_1.AST_NODE_TYPES.SpreadElement) {
|
57
|
+
return {
|
58
|
+
object: node.callee.object,
|
59
|
+
};
|
60
|
+
}
|
61
|
+
return {
|
62
|
+
object: node.callee.object,
|
63
|
+
onRejected: node.arguments[0],
|
64
|
+
};
|
65
|
+
}
|
66
|
+
return {
|
67
|
+
object: node.callee.object,
|
68
|
+
};
|
69
|
+
}
|
70
|
+
}
|
71
|
+
return undefined;
|
72
|
+
}
|
73
|
+
/**
|
74
|
+
* Parses a syntactically possible `Promise.finally()` call. Does not check the
|
75
|
+
* type of the callee.
|
76
|
+
*/
|
77
|
+
function parseFinallyCall(node, context) {
|
78
|
+
if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
79
|
+
const methodName = (0, misc_1.getStaticMemberAccessValue)(node.callee, context);
|
80
|
+
if (methodName === 'finally') {
|
81
|
+
if (node.arguments.length >= 1) {
|
82
|
+
if (node.arguments[0].type === utils_1.AST_NODE_TYPES.SpreadElement) {
|
83
|
+
return {
|
84
|
+
object: node.callee.object,
|
85
|
+
};
|
86
|
+
}
|
87
|
+
return {
|
88
|
+
object: node.callee.object,
|
89
|
+
onFinally: node.arguments[0],
|
90
|
+
};
|
91
|
+
}
|
92
|
+
return {
|
93
|
+
object: node.callee.object,
|
94
|
+
};
|
95
|
+
}
|
96
|
+
}
|
97
|
+
return undefined;
|
98
|
+
}
|
@@ -41,18 +41,18 @@ const getValueOfLiteralType_1 = require("./getValueOfLiteralType");
|
|
41
41
|
const isTruthyLiteral = (type) => tsutils.isTrueLiteralType(type) ||
|
42
42
|
(type.isLiteral() && !!(0, getValueOfLiteralType_1.getValueOfLiteralType)(type));
|
43
43
|
const isPossiblyFalsy = (type) => tsutils
|
44
|
-
.
|
44
|
+
.unionConstituents(type)
|
45
45
|
// Intersections like `string & {}` can also be possibly falsy,
|
46
46
|
// requiring us to look into the intersection.
|
47
|
-
.flatMap(type => tsutils.
|
47
|
+
.flatMap(type => tsutils.intersectionConstituents(type))
|
48
48
|
// PossiblyFalsy flag includes literal values, so exclude ones that
|
49
49
|
// are definitely truthy
|
50
50
|
.filter(t => !isTruthyLiteral(t))
|
51
51
|
.some(type => tsutils.isTypeFlagSet(type, ts.TypeFlags.PossiblyFalsy));
|
52
52
|
exports.isPossiblyFalsy = isPossiblyFalsy;
|
53
53
|
const isPossiblyTruthy = (type) => tsutils
|
54
|
-
.
|
55
|
-
.map(type => tsutils.
|
54
|
+
.unionConstituents(type)
|
55
|
+
.map(type => tsutils.intersectionConstituents(type))
|
56
56
|
.some(intersectionParts =>
|
57
57
|
// It is possible to define intersections that are always falsy,
|
58
58
|
// like `"" & { __brand: string }`.
|
@@ -123,6 +123,11 @@ interface Options {
|
|
123
123
|
| string
|
124
124
|
)[];
|
125
125
|
|
126
|
+
/**
|
127
|
+
* Whether to allow rethrowing caught values that are not `Error` objects.
|
128
|
+
*/
|
129
|
+
allowRethrowing?: boolean;
|
130
|
+
|
126
131
|
/**
|
127
132
|
* Whether to always allow throwing values typed as `any`.
|
128
133
|
*/
|
@@ -136,6 +141,7 @@ interface Options {
|
|
136
141
|
|
137
142
|
const defaultOptions: Options = {
|
138
143
|
allow: [],
|
144
|
+
allowRethrowing: false,
|
139
145
|
allowThrowingAny: true,
|
140
146
|
allowThrowingUnknown: true,
|
141
147
|
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@typescript-eslint/eslint-plugin",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.32.1-alpha.0",
|
4
4
|
"description": "TypeScript plugin for ESLint",
|
5
5
|
"files": [
|
6
6
|
"dist",
|
@@ -50,50 +50,48 @@
|
|
50
50
|
],
|
51
51
|
"scripts": {
|
52
52
|
"build": "tsc -b tsconfig.build.json",
|
53
|
-
"clean": "
|
54
|
-
"postclean": "rimraf dist && rimraf coverage",
|
53
|
+
"clean": "rimraf dist/ coverage/",
|
55
54
|
"format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore",
|
56
55
|
"generate:breaking-changes": "tsx tools/generate-breaking-changes.mts",
|
57
56
|
"generate:configs": "npx nx generate-configs repo",
|
58
57
|
"lint": "npx nx lint",
|
59
58
|
"test": "vitest --run --config=$INIT_CWD/vitest.config.mts",
|
60
|
-
"test-single": "vitest --run --config=$INIT_CWD/vitest.config.mts",
|
59
|
+
"test-single": "vitest --run --config=$INIT_CWD/vitest.config.mts --no-coverage",
|
61
60
|
"check-types": "npx nx typecheck"
|
62
61
|
},
|
63
62
|
"dependencies": {
|
64
63
|
"@eslint-community/regexpp": "^4.10.0",
|
65
|
-
"@typescript-eslint/scope-manager": "8.
|
66
|
-
"@typescript-eslint/type-utils": "8.
|
67
|
-
"@typescript-eslint/utils": "8.
|
68
|
-
"@typescript-eslint/visitor-keys": "8.
|
64
|
+
"@typescript-eslint/scope-manager": "8.32.1-alpha.0",
|
65
|
+
"@typescript-eslint/type-utils": "8.32.1-alpha.0",
|
66
|
+
"@typescript-eslint/utils": "8.32.1-alpha.0",
|
67
|
+
"@typescript-eslint/visitor-keys": "8.32.1-alpha.0",
|
69
68
|
"graphemer": "^1.4.0",
|
70
|
-
"ignore": "^
|
69
|
+
"ignore": "^7.0.0",
|
71
70
|
"natural-compare": "^1.4.0",
|
72
|
-
"ts-api-utils": "^2.0
|
71
|
+
"ts-api-utils": "^2.1.0"
|
73
72
|
},
|
74
73
|
"devDependencies": {
|
75
|
-
"@types/marked": "^5.0.2",
|
76
74
|
"@types/mdast": "^4.0.3",
|
77
75
|
"@types/natural-compare": "*",
|
78
|
-
"@typescript-eslint/rule-schema-to-typescript-types": "8.
|
79
|
-
"@typescript-eslint/rule-tester": "8.
|
80
|
-
"@vitest/coverage-v8": "^3.1.
|
76
|
+
"@typescript-eslint/rule-schema-to-typescript-types": "8.32.1-alpha.0",
|
77
|
+
"@typescript-eslint/rule-tester": "8.32.1-alpha.0",
|
78
|
+
"@vitest/coverage-v8": "^3.1.2",
|
81
79
|
"ajv": "^6.12.6",
|
82
80
|
"cross-fetch": "*",
|
83
81
|
"eslint": "*",
|
84
82
|
"json-schema": "*",
|
85
83
|
"markdown-table": "^3.0.3",
|
86
|
-
"marked": "^
|
84
|
+
"marked": "^15.0.0",
|
87
85
|
"mdast-util-from-markdown": "^2.0.0",
|
88
86
|
"mdast-util-mdx": "^3.0.0",
|
89
87
|
"micromark-extension-mdxjs": "^3.0.0",
|
90
88
|
"prettier": "^3.2.5",
|
91
89
|
"rimraf": "*",
|
92
|
-
"title-case": "^
|
90
|
+
"title-case": "^4.0.0",
|
93
91
|
"tsx": "*",
|
94
92
|
"typescript": "*",
|
95
93
|
"unist-util-visit": "^5.0.0",
|
96
|
-
"vitest": "^3.1.
|
94
|
+
"vitest": "^3.1.2"
|
97
95
|
},
|
98
96
|
"peerDependencies": {
|
99
97
|
"@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0",
|