diff --git a/__tests__/no-promise-in-callback.js b/__tests__/no-promise-in-callback.js index a11142b9..92d1c7f3 100644 --- a/__tests__/no-promise-in-callback.js +++ b/__tests__/no-promise-in-callback.js @@ -38,6 +38,19 @@ ruleTester.run('no-promise-in-callback', rule, { // weird case, we assume it's not a big deal if you return (even though you may be cheating) 'a(function(err) { return doThing().then(a) })', + + { + code: ` + function fn(err) { + return { promise: Promise.resolve(err) }; + } + `, + options: [ + { + exemptDeclarations: true, + }, + ], + }, ], invalid: [ diff --git a/docs/rules/no-promise-in-callback.md b/docs/rules/no-promise-in-callback.md index 2ca1abcb..bab05e8d 100644 --- a/docs/rules/no-promise-in-callback.md +++ b/docs/rules/no-promise-in-callback.md @@ -30,6 +30,12 @@ promisify(doSomething)() .catch(console.error) ``` +## Options + +### `exemptDeclarations` + +Whether or not to exempt function declarations. Defaults to `false`. + ## When Not To Use It If you do not want to be notified when using promises inside of callbacks, you diff --git a/rules/lib/is-inside-callback.js b/rules/lib/is-inside-callback.js index b1bb80e3..bd813b4a 100644 --- a/rules/lib/is-inside-callback.js +++ b/rules/lib/is-inside-callback.js @@ -2,11 +2,15 @@ const isInsidePromise = require('./is-inside-promise') -function isInsideCallback(node) { +/** + * @param {import('eslint').Rule.Node} node + * @param {boolean} [exemptDeclarations] + */ +function isInsideCallback(node, exemptDeclarations) { const isFunction = node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression' || - node.type === 'FunctionDeclaration' // this may be controversial + (!exemptDeclarations && node.type === 'FunctionDeclaration') // this may be controversial // it's totally fine to use promises inside promises if (isInsidePromise(node)) return diff --git a/rules/no-promise-in-callback.js b/rules/no-promise-in-callback.js index fefd22e3..5f769205 100644 --- a/rules/no-promise-in-callback.js +++ b/rules/no-promise-in-callback.js @@ -17,12 +17,23 @@ module.exports = { description: 'Disallow using promises inside of callbacks.', url: getDocsUrl('no-promise-in-callback'), }, - schema: [], + schema: [ + { + type: 'object', + properties: { + exemptDeclarations: { + type: 'boolean', + }, + }, + additionalProperties: false, + }, + ], messages: { avoidPromiseInCallback: 'Avoid using promises inside of callbacks.', }, }, create(context) { + const { exemptDeclarations = false } = context.options[0] || {} return { CallExpression(node) { if (!isPromise(node)) return @@ -34,7 +45,11 @@ module.exports = { // what about if the parent is an ArrowFunctionExpression // would that imply an implicit return? - if (getAncestors(context, node).some(isInsideCallback)) { + if ( + getAncestors(context, node).some((ancestor) => { + return isInsideCallback(ancestor, exemptDeclarations) + }) + ) { context.report({ node: node.callee, messageId: 'avoidPromiseInCallback',