avoid-new = function (context) { return { NewExpression: function (node) { if (node.callee.name === 'Promise') { context.report(node, 'Avoid creating new promises.') } } } }
n/a
no-callback-in-promise = function (context) { return { CallExpression: function (node) { if (!isCallback(node)) { // in general we send you packing if you're not a callback // but we also need to watch out for whatever.then(cb) if (hasPromiseCallback(node)) { var name = node.arguments && node.arguments[0] && node.arguments[0].name if (name === 'callback' || name === 'cb' || name === 'next' || name === 'done') { context.report(node.arguments[0], 'Avoid calling back inside of a promise.') } } return } if (context.getAncestors().some(isInsidePromise)) { context.report(node, 'Avoid calling back inside of a promise.') } } } }
n/a
no-nesting = function (context) { return { CallExpression: function (node) { if (!hasPromiseCallback(node)) return if (context.getAncestors().some(isInsidePromise)) { context.report(node, 'Avoid nesting promises.') } } } }
n/a
no-promise-in-callback = function (context) { return { CallExpression: function (node) { if (!isPromise(node)) return // if i'm returning the promise, it's probably not really a callback // function, and I should be okay.... if (node.parent.type === 'ReturnStatement') return // what about if the parent is an ArrowFunctionExpression // would that imply an implicit return? if (context.getAncestors().some(isInsideCallback)) { context.report(node.callee, 'Avoid using promises inside of callbacks.') } } } }
n/a
prefer-await-to-callbacks = function (context) { function checkLastParamsForCallback (node) { var len = node.params.length - 1 var lastParam = node.params[len] if (lastParam && (lastParam.name === 'callback' || lastParam.name === 'cb')) { context.report(lastParam, errorMessage) } } function isInsideYieldOrAwait () { return context.getAncestors().some(function (parent) { return parent.type === 'AwaitExpression' || parent.type === 'YieldExpression' }) } return { CallExpression: function (node) { // callbacks aren't allowed if (node.callee.name === 'cb' || node.callee.name === 'callback') { context.report(node, errorMessage) return } // thennables aren't allowed either var args = node.arguments var num = args.length - 1 var arg = num > -1 && node.arguments && node.arguments[num] if (arg && arg.type === 'FunctionExpression' || arg.type === 'ArrowFunctionExpression') { if (arg.params && arg.params[0] && arg.params[0].name === 'err') { if (!isInsideYieldOrAwait()) { context.report(arg, errorMessage) } } } }, FunctionDeclaration: checkLastParamsForCallback, FunctionExpression: checkLastParamsForCallback, ArrowFunctionExpression: checkLastParamsForCallback } }
n/a
prefer-await-to-then = function (context) { return { MemberExpression: function (node) { // you can then() if you are inside of a yield or await if (context.getAncestors().some(function (parent) { return parent.type === 'AwaitExpression' || parent.type === 'YieldExpression' })) { return } // if you're a then expression then you're probably a promise if (node.property && node.property.name === 'then') { context.report(node.property, 'Prefer await to then().') } } } }
n/a
create = function (context) { // funcInfoStack is a stack representing the stack of currently executing // functions // funcInfoStack[i].branchIDStack is a stack representing the currently // executing branches ("codePathSegment"s) within the given function // funcInfoStack[i].branchInfoMap is an object representing information // about all branches within the given function // funcInfoStack[i].branchInfoMap[j].good is a boolean representing whether // the given branch explictly `return`s or `throw`s. It starts as `false` // for every branch and is updated to `true` if a `return` or `throw` // statement is found // funcInfoStack[i].branchInfoMap[j].loc is a eslint SourceLocation object // for the given branch // example: // funcInfoStack = [ { branchIDStack: [ 's1_1' ], // branchInfoMap: // { s1_1: // { good: false, // loc: <loc> } } }, // { branchIDStack: ['s2_1', 's2_4'], // branchInfoMap: // { s2_1: // { good: false, // loc: <loc> }, // s2_2: // { good: true, // loc: <loc> }, // s2_4: // { good: false, // loc: <loc> } } } ] var funcInfoStack = [] function markCurrentBranchAsGood () { var funcInfo = peek(funcInfoStack) var currentBranchID = peek(funcInfo.branchIDStack) if (funcInfo.branchInfoMap[currentBranchID]) { funcInfo.branchInfoMap[currentBranchID].good = true } // else unreachable code } return { ReturnStatement: markCurrentBranchAsGood, ThrowStatement: markCurrentBranchAsGood, onCodePathSegmentStart: function (segment, node) { var funcInfo = peek(funcInfoStack) funcInfo.branchIDStack.push(segment.id) funcInfo.branchInfoMap[segment.id] = {good: false, node: node} }, onCodePathSegmentEnd: function (segment, node) { var funcInfo = peek(funcInfoStack) funcInfo.branchIDStack.pop() }, onCodePathStart: function (path, node) { funcInfoStack.push({ branchIDStack: [], branchInfoMap: {} }) }, onCodePathEnd: function (path, node) { var funcInfo = funcInfoStack.pop() if (!isInlineThenFunctionExpression(node)) { return } path.finalSegments.forEach((segment) => { var id = segment.id var branch = funcInfo.branchInfoMap[id] if (!branch.good) { if (hasParentReturnStatement(branch.node)) { return } // check shortcircuit syntax like `x && x()` and `y || x()`` var prevSegments = segment.prevSegments for (var ii = prevSegments.length - 1; ii >= 0; --ii) { var prevSegment = prevSegments[ii] if (funcInfo.branchInfoMap[prevSegment.id].good) return } context.report({ message: 'Each then() should return a value or throw', node: branch.node }) } }) } } }
n/a
create = function (context) { var options = context.options[0] || {} var allowThen = options.allowThen var terminationMethod = options.terminationMethod || 'catch' if (typeof terminationMethod === 'string') { terminationMethod = [terminationMethod] } return { ExpressionStatement: function (node) { if (!isPromise(node.expression)) { return } // somePromise.then(a, b) if (allowThen && node.expression.type === 'CallExpression' && node.expression.callee.type === 'MemberExpression' && node.expression.callee.property.name === 'then' && node.expression.arguments.length === 2 ) { return } // somePromise.catch() if (node.expression.type === 'CallExpression' && node.expression.callee.type === 'MemberExpression' && terminationMethod.indexOf(node.expression.callee.property.name) !== -1 ) { return } context.report(node, 'Expected ' + terminationMethod + '() or return') } } }
n/a
create = function (context) { var MESSAGE = '"function eslint-plugin-promise.rules.no-native.create" is not defined.' /** * Checks for and reports reassigned constants * * @param {Scope} scope - an escope Scope object * @returns {void} * @private */ return { 'Program:exit': function () { var scope = context.getScope() scope.implicit.left.forEach(function (ref) { if (ref.identifier.name !== 'Promise') { return } if (!isDeclared(scope, ref)) { context.report(ref.identifier, MESSAGE, { name: ref.identifier.name }) } }) } } }
n/a
create = function (context) { return { ReturnStatement: function (node) { if (isInPromise(context)) { if (node.argument) { if (node.argument.type === 'CallExpression') { if (node.argument.callee.type === 'MemberExpression') { if (node.argument.callee.object.name === 'Promise') { if (node.argument.callee.property.name === 'resolve') { context.report(node, resolveMessage) } else if (node.argument.callee.property.name === 'reject') { context.report(node, rejectMessage) } } } } } } } } }
n/a
create = function (context) { return { NewExpression: function (node) { if (node.callee.name === 'Promise' && node.arguments.length === 1) { var params = node.arguments[0].params if (!params || !params.length) { return } if (params[0].name !== 'resolve') { return context.report(node, 'Promise constructor parameters must be named resolve, reject') } if (params[1] && params[1].name !== 'reject') { return context.report(node, 'Promise constructor parameters must be named resolve, reject') } } } } }
n/a