/** * @author Yosuke Ota * See LICENSE file in root directory for full license. */ 'use strict' // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const utils = require('../utils') /** * @typedef {import('../utils').VueObjectData} VueObjectData */ // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { type: 'problem', docs: { description: 'disallow accessing computed properties in `data`.', categories: ['vue3-essential', 'essential'], url: 'https://eslint.vuejs.org/rules/no-computed-properties-in-data.html' }, fixable: null, schema: [], messages: { cannotBeUsed: 'The computed property cannot be used in `data()` because it is before initialization.' } }, /** @param {RuleContext} context */ create(context) { /** @type {Map}>} */ const contextMap = new Map() /** * @typedef {object} ScopeStack * @property {ScopeStack | null} upper * @property {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node */ /** @type {ScopeStack | null} */ let scopeStack = null return utils.compositingVisitors( { /** * @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node */ ':function'(node) { scopeStack = { upper: scopeStack, node } }, ':function:exit'() { scopeStack = scopeStack && scopeStack.upper } }, utils.defineVueVisitor(context, { onVueObjectEnter(node) { const dataProperty = utils.findProperty(node, 'data') if ( !dataProperty || (dataProperty.value.type !== 'FunctionExpression' && dataProperty.value.type !== 'ArrowFunctionExpression') ) { return } const computedNames = new Set() for (const computed of utils.iterateProperties( node, new Set(['computed']) )) { computedNames.add(computed.name) } contextMap.set(node, { data: dataProperty.value, computedNames }) }, /** * @param {MemberExpression} node * @param {VueObjectData} vueData */ MemberExpression(node, vueData) { if (!scopeStack || !utils.isThis(node.object, context)) { return } const ctx = contextMap.get(vueData.node) if (!ctx || ctx.data !== scopeStack.node) { return } const name = utils.getStaticPropertyName(node) if (!name || !ctx.computedNames.has(name)) { return } context.report({ node, messageId: 'cannotBeUsed' }) } }) ) } }