Permalink
Cannot retrieve contributors at this time
132 lines (111 sloc)
5.37 KB
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
codeql-action/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @fileoverview restrict values that can be used as Promise rejection reasons | |
* @author Teddy Katz | |
*/ | |
"use strict"; | |
const astUtils = require("./utils/ast-utils"); | |
//------------------------------------------------------------------------------ | |
// Rule Definition | |
//------------------------------------------------------------------------------ | |
/** @type {import('../shared/types').Rule} */ | |
module.exports = { | |
meta: { | |
type: "suggestion", | |
docs: { | |
description: "Require using Error objects as Promise rejection reasons", | |
recommended: false, | |
url: "https://eslint.org/docs/latest/rules/prefer-promise-reject-errors" | |
}, | |
fixable: null, | |
schema: [ | |
{ | |
type: "object", | |
properties: { | |
allowEmptyReject: { type: "boolean", default: false } | |
}, | |
additionalProperties: false | |
} | |
], | |
messages: { | |
rejectAnError: "Expected the Promise rejection reason to be an Error." | |
} | |
}, | |
create(context) { | |
const ALLOW_EMPTY_REJECT = context.options.length && context.options[0].allowEmptyReject; | |
const sourceCode = context.sourceCode; | |
//---------------------------------------------------------------------- | |
// Helpers | |
//---------------------------------------------------------------------- | |
/** | |
* Checks the argument of a reject() or Promise.reject() CallExpression, and reports it if it can't be an Error | |
* @param {ASTNode} callExpression A CallExpression node which is used to reject a Promise | |
* @returns {void} | |
*/ | |
function checkRejectCall(callExpression) { | |
if (!callExpression.arguments.length && ALLOW_EMPTY_REJECT) { | |
return; | |
} | |
if ( | |
!callExpression.arguments.length || | |
!astUtils.couldBeError(callExpression.arguments[0]) || | |
callExpression.arguments[0].type === "Identifier" && callExpression.arguments[0].name === "undefined" | |
) { | |
context.report({ | |
node: callExpression, | |
messageId: "rejectAnError" | |
}); | |
} | |
} | |
/** | |
* Determines whether a function call is a Promise.reject() call | |
* @param {ASTNode} node A CallExpression node | |
* @returns {boolean} `true` if the call is a Promise.reject() call | |
*/ | |
function isPromiseRejectCall(node) { | |
return astUtils.isSpecificMemberAccess(node.callee, "Promise", "reject"); | |
} | |
//---------------------------------------------------------------------- | |
// Public | |
//---------------------------------------------------------------------- | |
return { | |
// Check `Promise.reject(value)` calls. | |
CallExpression(node) { | |
if (isPromiseRejectCall(node)) { | |
checkRejectCall(node); | |
} | |
}, | |
/* | |
* Check for `new Promise((resolve, reject) => {})`, and check for reject() calls. | |
* This function is run on "NewExpression:exit" instead of "NewExpression" to ensure that | |
* the nodes in the expression already have the `parent` property. | |
*/ | |
"NewExpression:exit"(node) { | |
if ( | |
node.callee.type === "Identifier" && node.callee.name === "Promise" && | |
node.arguments.length && astUtils.isFunction(node.arguments[0]) && | |
node.arguments[0].params.length > 1 && node.arguments[0].params[1].type === "Identifier" | |
) { | |
sourceCode.getDeclaredVariables(node.arguments[0]) | |
/* | |
* Find the first variable that matches the second parameter's name. | |
* If the first parameter has the same name as the second parameter, then the variable will actually | |
* be "declared" when the first parameter is evaluated, but then it will be immediately overwritten | |
* by the second parameter. It's not possible for an expression with the variable to be evaluated before | |
* the variable is overwritten, because functions with duplicate parameters cannot have destructuring or | |
* default assignments in their parameter lists. Therefore, it's not necessary to explicitly account for | |
* this case. | |
*/ | |
.find(variable => variable.name === node.arguments[0].params[1].name) | |
// Get the references to that variable. | |
.references | |
// Only check the references that read the parameter's value. | |
.filter(ref => ref.isRead()) | |
// Only check the references that are used as the callee in a function call, e.g. `reject(foo)`. | |
.filter(ref => ref.identifier.parent.type === "CallExpression" && ref.identifier === ref.identifier.parent.callee) | |
// Check the argument of the function call to determine whether it's an Error. | |
.forEach(ref => checkRejectCall(ref.identifier.parent)); | |
} | |
} | |
}; | |
} | |
}; |