diff --git a/lib/rules/no-async-in-computed-properties.js b/lib/rules/no-async-in-computed-properties.js index b12fa3407..b405c0475 100644 --- a/lib/rules/no-async-in-computed-properties.js +++ b/lib/rules/no-async-in-computed-properties.js @@ -8,6 +8,7 @@ const utils = require('../utils') /** * @typedef {import('../utils').VueObjectData} VueObjectData + * @typedef {import('../utils').VueVisitor} VueVisitor * @typedef {import('../utils').ComponentComputedProperty} ComponentComputedProperty */ @@ -97,11 +98,16 @@ module.exports = { /** * @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node - * @param {VueObjectData} data + * @param {VueObjectData|undefined} [info] */ - function onFunctionEnter(node, { node: vueNode }) { + function onFunctionEnter(node, info) { if (node.async) { - verify(node, node.body, 'async', computedPropertiesMap.get(vueNode)) + verify( + node, + node.body, + 'async', + info ? computedPropertiesMap.get(info.node) : null + ) } scopeStack = { @@ -118,10 +124,10 @@ module.exports = { * @param {ESNode} node * @param {BlockStatement | Expression} targetBody * @param {keyof expressionTypes} type - * @param {ComponentComputedProperty[]} computedProperties + * @param {ComponentComputedProperty[]|undefined|null} computedProperties */ - function verify(node, targetBody, type, computedProperties = []) { - for (const cp of computedProperties) { + function verify(node, targetBody, type, computedProperties) { + for (const cp of computedProperties || []) { if ( cp.value && node.loc.start.line >= cp.value.loc.start.line && @@ -158,7 +164,74 @@ module.exports = { } } } - return Object.assign( + const nodeVisitor = { + ':function': onFunctionEnter, + ':function:exit': onFunctionExit, + + /** + * @param {NewExpression} node + * @param {VueObjectData|undefined} [info] + */ + NewExpression(node, info) { + if (!scopeStack) { + return + } + if ( + node.callee.type === 'Identifier' && + node.callee.name === 'Promise' + ) { + verify( + node, + scopeStack.body, + 'new', + info ? computedPropertiesMap.get(info.node) : null + ) + } + }, + + /** + * @param {CallExpression} node + * @param {VueObjectData|undefined} [info] + */ + CallExpression(node, info) { + if (!scopeStack) { + return + } + if (isPromise(node)) { + verify( + node, + scopeStack.body, + 'promise', + info ? computedPropertiesMap.get(info.node) : null + ) + } else if (isTimedFunction(node)) { + verify( + node, + scopeStack.body, + 'timed', + info ? computedPropertiesMap.get(info.node) : null + ) + } + }, + + /** + * @param {AwaitExpression} node + * @param {VueObjectData|undefined} [info] + */ + AwaitExpression(node, info) { + if (!scopeStack) { + return + } + verify( + node, + scopeStack.body, + 'await', + info ? computedPropertiesMap.get(info.node) : null + ) + } + } + + return utils.compositingVisitors( { Program() { const tracker = new ReferenceTracker(context.getScope()) @@ -181,63 +254,14 @@ module.exports = { } } }, - utils.defineVueVisitor(context, { - onVueObjectEnter(node) { - computedPropertiesMap.set(node, utils.getComputedProperties(node)) - }, - ':function': onFunctionEnter, - ':function:exit': onFunctionExit, - - NewExpression(node, { node: vueNode }) { - if (!scopeStack) { - return - } - if ( - node.callee.type === 'Identifier' && - node.callee.name === 'Promise' - ) { - verify( - node, - scopeStack.body, - 'new', - computedPropertiesMap.get(vueNode) - ) - } - }, - - CallExpression(node, { node: vueNode }) { - if (!scopeStack) { - return - } - if (isPromise(node)) { - verify( - node, - scopeStack.body, - 'promise', - computedPropertiesMap.get(vueNode) - ) - } else if (isTimedFunction(node)) { - verify( - node, - scopeStack.body, - 'timed', - computedPropertiesMap.get(vueNode) - ) - } - }, - - AwaitExpression(node, { node: vueNode }) { - if (!scopeStack) { - return - } - verify( - node, - scopeStack.body, - 'await', - computedPropertiesMap.get(vueNode) - ) - } - }) + utils.isScriptSetup(context) + ? utils.defineScriptSetupVisitor(context, nodeVisitor) + : utils.defineVueVisitor(context, { + onVueObjectEnter(node) { + computedPropertiesMap.set(node, utils.getComputedProperties(node)) + }, + ...nodeVisitor + }) ) } } diff --git a/tests/lib/rules/no-async-in-computed-properties.js b/tests/lib/rules/no-async-in-computed-properties.js index 2a15712cf..c54b833af 100644 --- a/tests/lib/rules/no-async-in-computed-properties.js +++ b/tests/lib/rules/no-async-in-computed-properties.js @@ -15,6 +15,7 @@ const parserOptions = { ecmaVersion: 2020, sourceType: 'module' } +const parser = require.resolve('vue-eslint-parser') // ------------------------------------------------------------------------------ // Tests @@ -920,6 +921,207 @@ ruleTester.run('no-async-in-computed-properties', rule, { line: 5 } ] + }, + + { + filename: 'test.vue', + code: ` + + `, + parser, + parserOptions, + errors: [ + { + message: + 'Unexpected async function declaration in computed function.', + line: 4 + }, + { + message: 'Unexpected await operator in computed function.', + line: 5 + }, + { + message: + 'Unexpected async function declaration in computed function.', + line: 7 + }, + { + message: 'Unexpected await operator in computed function.', + line: 7 + }, + { + message: + 'Unexpected async function declaration in computed function.', + line: 8 + }, + { + message: 'Unexpected await operator in computed function.', + line: 9 + } + ] + }, + { + filename: 'test.vue', + code: ` + + `, + parser, + parserOptions, + errors: [ + { + message: + 'Unexpected async function declaration in computed function.', + line: 4 + }, + { + message: 'Unexpected Promise object in computed function.', + line: 5 + } + ] + }, + { + filename: 'test.vue', + code: ` + + `, + parser, + parserOptions, + errors: [ + { + message: 'Unexpected asynchronous action in computed function.', + line: 5 + }, + { + message: 'Unexpected asynchronous action in computed function.', + line: 8 + } + ] + }, + { + filename: 'test.vue', + code: ` + + `, + parser, + parserOptions, + errors: [ + { + message: 'Unexpected asynchronous action in computed function.', + line: 6 + }, + { + message: 'Unexpected asynchronous action in computed function.', + line: 11 + } + ] + }, + { + filename: 'test.vue', + code: ` + + `, + parser, + parserOptions, + errors: [ + { + message: 'Unexpected timed function in computed function.', + line: 5 + }, + { + message: 'Unexpected timed function in computed function.', + line: 6 + }, + { + message: 'Unexpected timed function in computed function.', + line: 7 + }, + { + message: 'Unexpected timed function in computed function.', + line: 8 + }, + { + message: 'Unexpected timed function in computed function.', + line: 9 + }, + { + message: 'Unexpected timed function in computed function.', + line: 10 + }, + { + message: 'Unexpected timed function in computed function.', + line: 11 + }, + { + message: 'Unexpected timed function in computed function.', + line: 12 + } + ] + }, + { + filename: 'test.vue', + code: ` + + `, + parser, + parserOptions, + errors: [ + { + message: + 'Unexpected async function declaration in computed function.', + line: 4 + } + ] } ] })