vue hello world项目
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

195 lines
5.5 KiB

/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'
const { ReferenceTracker, findVariable } = require('eslint-utils')
const utils = require('../utils')
module.exports = {
meta: {
type: 'suggestion',
docs: {
description:
'disallow use of value wrapped by `ref()` (Composition API) as an operand',
categories: ['vue3-essential'],
url: 'https://eslint.vuejs.org/rules/no-ref-as-operand.html'
},
fixable: 'code',
schema: [],
messages: {
requireDotValue:
'Must use `.value` to read or write the value wrapped by `{{method}}()`.'
}
},
/** @param {RuleContext} context */
create(context) {
/**
* @typedef {object} ReferenceData
* @property {VariableDeclarator} variableDeclarator
* @property {VariableDeclaration | null} variableDeclaration
* @property {string} method
*/
/** @type {Map<Identifier, ReferenceData>} */
const refReferenceIds = new Map()
/**
* @param {Identifier} node
*/
function reportIfRefWrapped(node) {
const data = refReferenceIds.get(node)
if (!data) {
return
}
context.report({
node,
messageId: 'requireDotValue',
data: {
method: data.method
},
fix(fixer) {
return fixer.insertTextAfter(node, '.value')
}
})
}
return {
Program() {
const tracker = new ReferenceTracker(context.getScope())
const traceMap = utils.createCompositionApiTraceMap({
[ReferenceTracker.ESM]: true,
ref: {
[ReferenceTracker.CALL]: true
},
computed: {
[ReferenceTracker.CALL]: true
},
toRef: {
[ReferenceTracker.CALL]: true
},
customRef: {
[ReferenceTracker.CALL]: true
},
shallowRef: {
[ReferenceTracker.CALL]: true
}
})
for (const { node, path } of tracker.iterateEsmReferences(traceMap)) {
const variableDeclarator = node.parent
if (
!variableDeclarator ||
variableDeclarator.type !== 'VariableDeclarator' ||
variableDeclarator.id.type !== 'Identifier'
) {
continue
}
const variable = findVariable(
context.getScope(),
variableDeclarator.id
)
if (!variable) {
continue
}
const variableDeclaration =
(variableDeclarator.parent &&
variableDeclarator.parent.type === 'VariableDeclaration' &&
variableDeclarator.parent) ||
null
for (const reference of variable.references) {
if (!reference.isRead()) {
continue
}
refReferenceIds.set(reference.identifier, {
variableDeclarator,
variableDeclaration,
method: path[1]
})
}
}
},
// if (refValue)
/** @param {Identifier} node */
'IfStatement>Identifier'(node) {
reportIfRefWrapped(node)
},
// switch (refValue)
/** @param {Identifier} node */
'SwitchStatement>Identifier'(node) {
reportIfRefWrapped(node)
},
// -refValue, +refValue, !refValue, ~refValue, typeof refValue
/** @param {Identifier} node */
'UnaryExpression>Identifier'(node) {
reportIfRefWrapped(node)
},
// refValue++, refValue--
/** @param {Identifier} node */
'UpdateExpression>Identifier'(node) {
reportIfRefWrapped(node)
},
// refValue+1, refValue-1
/** @param {Identifier} node */
'BinaryExpression>Identifier'(node) {
reportIfRefWrapped(node)
},
// refValue+=1, refValue-=1, foo+=refValue, foo-=refValue
/** @param {Identifier & {parent: AssignmentExpression}} node */
'AssignmentExpression>Identifier'(node) {
if (node.parent.operator === '=' && node.parent.left !== node) {
return
}
reportIfRefWrapped(node)
},
// refValue || other, refValue && other. ignore: other || refValue
/** @param {Identifier & {parent: LogicalExpression}} node */
'LogicalExpression>Identifier'(node) {
if (node.parent.left !== node) {
return
}
// Report only constants.
const data = refReferenceIds.get(node)
if (!data) {
return
}
if (
!data.variableDeclaration ||
data.variableDeclaration.kind !== 'const'
) {
return
}
reportIfRefWrapped(node)
},
// refValue ? x : y
/** @param {Identifier & {parent: ConditionalExpression}} node */
'ConditionalExpression>Identifier'(node) {
if (node.parent.test !== node) {
return
}
reportIfRefWrapped(node)
},
// `${refValue}`
/** @param {Identifier} node */
'TemplateLiteral>Identifier'(node) {
reportIfRefWrapped(node)
},
// refValue.x
/** @param {Identifier & {parent: MemberExpression}} node */
'MemberExpression>Identifier'(node) {
if (node.parent.object !== node) {
return
}
const name = utils.getStaticPropertyName(node.parent)
if (
name === 'value' ||
name == null ||
// WritableComputedRef
name === 'effect'
) {
return
}
reportIfRefWrapped(node)
}
}
}
}