107 lines
4.2 KiB
Plaintext
107 lines
4.2 KiB
Plaintext
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const utils_1 = require("@typescript-eslint/utils");
|
|
const eslint_utils_1 = require("@typescript-eslint/utils/eslint-utils");
|
|
const util_1 = require("../util");
|
|
exports.default = (0, util_1.createRule)({
|
|
name: 'prefer-promise-reject-errors',
|
|
meta: {
|
|
type: 'suggestion',
|
|
docs: {
|
|
description: 'Require using Error objects as Promise rejection reasons',
|
|
recommended: 'strict',
|
|
extendsBaseRule: true,
|
|
requiresTypeChecking: true,
|
|
},
|
|
schema: [
|
|
{
|
|
type: 'object',
|
|
properties: {
|
|
allowEmptyReject: {
|
|
type: 'boolean',
|
|
},
|
|
},
|
|
additionalProperties: false,
|
|
},
|
|
],
|
|
messages: {
|
|
rejectAnError: 'Expected the Promise rejection reason to be an Error.',
|
|
},
|
|
},
|
|
defaultOptions: [
|
|
{
|
|
allowEmptyReject: false,
|
|
},
|
|
],
|
|
create(context, [options]) {
|
|
const services = (0, util_1.getParserServices)(context);
|
|
function checkRejectCall(callExpression) {
|
|
const argument = callExpression.arguments.at(0);
|
|
if (argument) {
|
|
const type = services.getTypeAtLocation(argument);
|
|
if ((0, util_1.isErrorLike)(services.program, type) ||
|
|
(0, util_1.isReadonlyErrorLike)(services.program, type)) {
|
|
return;
|
|
}
|
|
}
|
|
else if (options.allowEmptyReject) {
|
|
return;
|
|
}
|
|
context.report({
|
|
node: callExpression,
|
|
messageId: 'rejectAnError',
|
|
});
|
|
}
|
|
function skipChainExpression(node) {
|
|
return node.type === utils_1.AST_NODE_TYPES.ChainExpression
|
|
? node.expression
|
|
: node;
|
|
}
|
|
function typeAtLocationIsLikePromise(node) {
|
|
const type = services.getTypeAtLocation(node);
|
|
return ((0, util_1.isPromiseConstructorLike)(services.program, type) ||
|
|
(0, util_1.isPromiseLike)(services.program, type));
|
|
}
|
|
return {
|
|
CallExpression(node) {
|
|
const callee = skipChainExpression(node.callee);
|
|
if (callee.type !== utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
return;
|
|
}
|
|
const rejectMethodCalled = callee.computed
|
|
? callee.property.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
callee.property.value === 'reject'
|
|
: callee.property.name === 'reject';
|
|
if (!rejectMethodCalled ||
|
|
!typeAtLocationIsLikePromise(callee.object)) {
|
|
return;
|
|
}
|
|
checkRejectCall(node);
|
|
},
|
|
NewExpression(node) {
|
|
const callee = skipChainExpression(node.callee);
|
|
if (!(0, util_1.isPromiseConstructorLike)(services.program, services.getTypeAtLocation(callee))) {
|
|
return;
|
|
}
|
|
const executor = node.arguments.at(0);
|
|
if (!executor || !(0, util_1.isFunction)(executor)) {
|
|
return;
|
|
}
|
|
const rejectParamNode = executor.params.at(1);
|
|
if (!rejectParamNode || !(0, util_1.isIdentifier)(rejectParamNode)) {
|
|
return;
|
|
}
|
|
// reject param is always present in variables declared by executor
|
|
const rejectVariable = (0, eslint_utils_1.getDeclaredVariables)(context, executor).find(variable => variable.identifiers.includes(rejectParamNode));
|
|
rejectVariable.references.forEach(ref => {
|
|
if (ref.identifier.parent.type !== utils_1.AST_NODE_TYPES.CallExpression ||
|
|
ref.identifier !== ref.identifier.parent.callee) {
|
|
return;
|
|
}
|
|
checkRejectCall(ref.identifier.parent);
|
|
});
|
|
},
|
|
};
|
|
},
|
|
});
|
|
//# sourceMappingURL=prefer-promise-reject-errors.js.map |