Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring #1154

Merged
merged 2 commits into from May 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 1 addition & 4 deletions lib/rules/no-async-in-computed-properties.js
Expand Up @@ -115,10 +115,7 @@ module.exports = {
})
}
return utils.defineVueVisitor(context, {
ObjectExpression (node, { node: vueNode }) {
if (node !== vueNode) {
return
}
onVueObjectEnter (node) {
computedPropertiesMap.set(node, utils.getComputedProperties(node))
},
':function': onFunctionEnter,
Expand Down
19 changes: 6 additions & 13 deletions lib/rules/no-lifecycle-after-await.js
Expand Up @@ -50,22 +50,15 @@ module.exports = {
},
utils.defineVueVisitor(context,
{
'Property[value.type=/^(Arrow)?FunctionExpression$/]' (node, { node: vueNode }) {
if (node.parent !== vueNode) {
return
}
if (utils.getStaticPropertyName(node) !== 'setup') {
return
}

setupFunctions.set(node.value, {
setupProperty: node,
afterAwait: false
})
},
':function' (node) {
scopeStack = { upper: scopeStack, functionNode: node }
},
onSetupFunctionEnter (node) {
setupFunctions.set(node, {
setupProperty: node.parent,
afterAwait: false
})
},
'AwaitExpression' () {
const setupFunctionData = setupFunctions.get(scopeStack.functionNode)
if (!setupFunctionData) {
Expand Down
76 changes: 6 additions & 70 deletions lib/rules/no-mutating-props.js
Expand Up @@ -124,64 +124,12 @@ module.exports = {
* @param {string} name
*/
function verifyMutating (props, name) {
const invalid = findMutating(props)
const invalid = utils.findMutating(props)
if (invalid) {
report(invalid.node, name)
}
}

/**
* @param {MemberExpression|Identifier} props
* @returns { { kind: 'assignment' | 'update' | 'call' , node: Node, pathNodes: MemberExpression[] } }
*/
function findMutating (props) {
/** @type {MemberExpression[]} */
const pathNodes = []
let node = props
let target = node.parent
while (true) {
if (target.type === 'AssignmentExpression') {
if (target.left === node) {
// this.xxx <=|+=|-=>
return {
kind: 'assignment',
node: target,
pathNodes
}
}
} else if (target.type === 'UpdateExpression') {
// this.xxx <++|-->
return {
kind: 'update',
node: target,
pathNodes
}
} else if (target.type === 'CallExpression') {
if (node !== props && target.callee === node) {
const callName = utils.getStaticPropertyName(node)
if (callName && /^push|pop|shift|unshift|reverse|splice|sort|copyWithin|fill$/u.exec(callName)) {
// this.xxx.push()
pathNodes.pop()
return {
kind: 'call',
node: target,
pathNodes
}
}
}
} else if (target.type === 'MemberExpression') {
if (target.object === node) {
pathNodes.push(target)
node = target
target = target.parent
continue // loop
}
}

return null
}
}

/**
* @param {Pattern} param
* @param {string[]} path
Expand Down Expand Up @@ -220,32 +168,20 @@ module.exports = {
return Object.assign({},
utils.defineVueVisitor(context,
{
ObjectExpression (node, { node: vueNode }) {
if (node !== vueNode) {
return
}
onVueObjectEnter (node) {
propsMap.set(node, new Set(utils.getComponentProps(node).map(p => p.propName)))
},
'ObjectExpression:exit' (node, { node: vueNode, type }) {
if (node !== vueNode) {
return
}
onVueObjectExit (node, { type }) {
if (!vueObjectData || vueObjectData.type !== 'export') {
vueObjectData = {
type,
object: node
}
}
},
'Property[value.type=/^(Arrow)?FunctionExpression$/]' (node, { node: vueNode }) {
if (node.parent !== vueNode) {
return
}
if (utils.getStaticPropertyName(node) !== 'setup') {
return
}
onSetupFunctionEnter (node) {
/** @type {Pattern} */
const propsParam = node.value.params[0]
const propsParam = node.params[0]
if (!propsParam) {
// no arguments
return
Expand All @@ -268,7 +204,7 @@ module.exports = {
/** @type {Identifier} */
const id = reference.identifier

const invalid = findMutating(id)
const invalid = utils.findMutating(id)
if (!invalid) {
continue
}
Expand Down
18 changes: 6 additions & 12 deletions lib/rules/no-setup-props-destructure.js
Expand Up @@ -52,14 +52,11 @@ module.exports = {
let scopeStack = null

return utils.defineVueVisitor(context, {
'Property[value.type=/^(Arrow)?FunctionExpression$/]' (node, { node: vueNode }) {
if (node.parent !== vueNode) {
return
}
if (utils.getStaticPropertyName(node) !== 'setup') {
return
}
const propsParam = node.value.params[0]
':function' (node) {
scopeStack = { upper: scopeStack, functionNode: node }
},
onSetupFunctionEnter (node) {
const propsParam = node.params[0]
if (!propsParam) {
// no arguments
return
Expand All @@ -85,10 +82,7 @@ module.exports = {

propsReferenceIds.add(reference.identifier)
}
setupScopePropsReferenceIds.set(node.value, propsReferenceIds)
},
':function' (node) {
scopeStack = { upper: scopeStack, functionNode: node }
setupScopePropsReferenceIds.set(node, propsReferenceIds)
},
'VariableDeclarator' (node) {
const propsReferenceIds = setupScopePropsReferenceIds.get(scopeStack.functionNode)
Expand Down
73 changes: 35 additions & 38 deletions lib/rules/no-side-effects-in-computed-properties.js
Expand Up @@ -6,6 +6,12 @@

const utils = require('../utils')

/**
* @typedef {import('vue-eslint-parser').AST.ESLintObjectExpression} ObjectExpression
* @typedef {import('vue-eslint-parser').AST.ESLintMemberExpression} MemberExpression
* @typedef {import('../utils').ComponentComputedProperty} ComponentComputedProperty
*/

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
Expand All @@ -23,6 +29,7 @@ module.exports = {
},

create (context) {
/** @type {Map<ObjectExpression, ComponentComputedProperty[]>} */
const computedPropertiesMap = new Map()
let scopeStack = { upper: null, body: null }

Expand All @@ -34,53 +41,43 @@ module.exports = {
scopeStack = scopeStack.upper
}

function verify (node, targetBody, computedProperties) {
computedProperties.forEach(cp => {
if (
cp.value &&
node.loc.start.line >= cp.value.loc.start.line &&
node.loc.end.line <= cp.value.loc.end.line &&
targetBody === cp.value
) {
context.report({
node: node,
message: 'Unexpected side effect in "{{key}}" computed property.',
data: { key: cp.key }
})
}
})
}

return utils.defineVueVisitor(context, {
ObjectExpression (node, { node: vueNode }) {
if (node !== vueNode) {
return
}
onVueObjectEnter (node) {
computedPropertiesMap.set(node, utils.getComputedProperties(node))
},
':function': onFunctionEnter,
':function:exit': onFunctionExit,

// this.xxx <=|+=|-=>
'AssignmentExpression' (node, { node: vueNode }) {
if (node.left.type !== 'MemberExpression') return
if (utils.parseMemberExpression(node.left)[0] === 'this') {
verify(node, scopeStack.body, computedPropertiesMap.get(vueNode))
'MemberExpression > :matches(Identifier, ThisExpression)' (node, { node: vueNode }) {
const targetBody = scopeStack.body
const computedProperty = computedPropertiesMap.get(vueNode).find(cp => {
return (
cp.value &&
node.loc.start.line >= cp.value.loc.start.line &&
node.loc.end.line <= cp.value.loc.end.line &&
targetBody === cp.value
)
})
if (!computedProperty) {
return
}
},
// this.xxx <++|-->
'UpdateExpression > MemberExpression' (node, { node: vueNode }) {
if (utils.parseMemberExpression(node)[0] === 'this') {
verify(node, scopeStack.body, computedPropertiesMap.get(vueNode))

if (!utils.isThis(node, context)) {
return
}
/** @type {MemberExpression} */
const mem = node.parent
if (mem.object !== node) {
return
}
},
// this.xxx.func()
'CallExpression' (node, { node: vueNode }) {
const code = utils.parseMemberOrCallExpression(node)
const MUTATION_REGEX = /(this.)((?!(concat|slice|map|filter)\().)[^\)]*((push|pop|shift|unshift|reverse|splice|sort|copyWithin|fill)\()/g

if (MUTATION_REGEX.test(code)) {
verify(node, scopeStack.body, computedPropertiesMap.get(vueNode))
const invalid = utils.findMutating(mem)
if (invalid) {
context.report({
node: invalid.node,
message: 'Unexpected side effect in "{{key}}" computed property.',
data: { key: computedProperty.key }
})
}
}
}
Expand Down
20 changes: 5 additions & 15 deletions lib/rules/no-unused-properties.js
Expand Up @@ -412,12 +412,8 @@ module.exports = {
const scriptVisitor = Object.assign(
{},
utils.defineVueVisitor(context, {
ObjectExpression (node, vueData) {
if (node !== vueData.node) {
return
}

const container = getVueComponentPropertiesContainer(vueData.node)
onVueObjectEnter (node) {
const container = getVueComponentPropertiesContainer(node)
const watcherNames = new Set()
for (const watcher of utils.iterateProperties(node, new Set([GROUP_WATCHER]))) {
watcherNames.add(watcher.name)
Expand All @@ -429,20 +425,14 @@ module.exports = {
container.properties.push(prop)
}
},
'Property[value.type=/^(Arrow)?FunctionExpression$/]' (node, vueData) {
if (node.parent !== vueData.node) {
return
}
if (utils.getStaticPropertyName(node) !== 'setup') {
return
}
onSetupFunctionEnter (node, vueData) {
const container = getVueComponentPropertiesContainer(vueData.node)
const propsParam = node.value.params[0]
const propsParam = node.params[0]
if (!propsParam) {
// no arguments
return
}
const paramsUsedProps = getParamsUsedProps(node.value)
const paramsUsedProps = getParamsUsedProps(node)
const paramUsedProps = paramsUsedProps.getParam(0)

for (const { usedNames, unknown } of iterateUsedProps(paramUsedProps)) {
Expand Down
19 changes: 6 additions & 13 deletions lib/rules/no-watch-after-await.js
Expand Up @@ -76,22 +76,15 @@ module.exports = {
},
utils.defineVueVisitor(context,
{
'Property[value.type=/^(Arrow)?FunctionExpression$/]' (node, { node: vueNode }) {
if (node.parent !== vueNode) {
return
}
if (utils.getStaticPropertyName(node) !== 'setup') {
return
}

setupFunctions.set(node.value, {
setupProperty: node,
afterAwait: false
})
},
':function' (node) {
scopeStack = { upper: scopeStack, functionNode: node }
},
onSetupFunctionEnter (node) {
setupFunctions.set(node, {
setupProperty: node.parent,
afterAwait: false
})
},
'AwaitExpression' () {
const setupFunctionData = setupFunctions.get(scopeStack.functionNode)
if (!setupFunctionData) {
Expand Down