Skip to content

Commit

Permalink
Add scoped varialbles, and more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
armano2 committed Nov 8, 2018
1 parent 9c6a762 commit 3261b9a
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 20 deletions.
66 changes: 46 additions & 20 deletions lib/rules/no-mutating-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,36 +26,48 @@ module.exports = {
create (context) {
let mutatedNodes = []
let props = []
let scope = {
parent: null,
nodes: []
}

function checkForMutations () {
for (const prop of props) {
const propName = utils.getStaticPropertyName(prop.key)

for (const node of mutatedNodes) {
if (propName === node.name) {
context.report({
node: node.node,
message: 'Unexpected mutation of "{{key}}" prop.',
data: { key: node.name }
})
if (mutatedNodes.length > 0) {
for (const prop of props) {
for (const node of mutatedNodes) {
if (prop === node.name) {
context.report({
node: node.node,
message: 'Unexpected mutation of "{{key}}" prop.',
data: {
key: node.name
}
})
}
}
}
}
mutatedNodes = []
}

function isInScope (name) {
return scope.nodes.some(node => node.name === name)
}

function checkTemplateProperty (node) {
if (node.type === 'MemberExpression') {
const expression = utils.parseMemberExpression(node)
mutatedNodes.push({
name: expression[0] === 'this' ? expression[1] : expression[0],
node
})
const name = expression[0] === 'this' ? expression[1] : expression[0]
if (!isInScope(name)) {
mutatedNodes.push({ name, node })
}
} else if (node.type === 'Identifier') {
mutatedNodes.push({
name: node.name,
node
})
if (!isInScope(node.name)) {
mutatedNodes.push({
name: node.name,
node
})
}
}
}

Expand Down Expand Up @@ -101,10 +113,26 @@ module.exports = {
utils.executeOnVue(context, (obj) => {
props = utils.getComponentProps(obj)
.filter(cp => cp.key)
.map(cp => utils.getStaticPropertyName(cp.key))
checkForMutations()
}),

utils.defineTemplateBodyVisitor(context, {
VElement (node) {
scope = {
parent: scope,
nodes: scope.nodes.slice() // make copy
}

if (node.variables) {
for (const variable of node.variables) {
scope.nodes.push(variable.id)
}
}
},
'VElement:exit' () {
scope = scope.parent
},
'VExpressionContainer AssignmentExpression' (node) {
checkTemplateProperty(node.left)
},
Expand All @@ -125,11 +153,9 @@ module.exports = {
})
}
},

"VAttribute[directive=true][key.name='model'] VExpressionContainer" (node) {
checkTemplateProperty(node.expression)
},

"VElement[name='template']:exit" () {
checkForMutations()
}
Expand Down
72 changes: 72 additions & 0 deletions tests/lib/rules/no-mutating-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ ruleTester.run('no-mutating-props', rule, {
<input v-model="prop2">
<input v-model="this.prop3.text">
<input v-model="this.prop4">
<input :value="prop5.text" @input="$emit('input', $event.target.value)">
<div v-for="prop5 of data">
<input v-model="prop5">
</div>
<div v-for="(prop6, index) of data">
<input v-model="prop6">
</div>
<template v-for="(test, index) of data">
<template v-for="(prop6, index) of data">
<input v-model="prop6">
</template>
</template>
</div>
</template>
<script>
Expand All @@ -67,6 +79,40 @@ ruleTester.run('no-mutating-props', rule, {
</script>
`
},
{
filename: 'test.vue',
code: `
<template>
<div>
<input v-model="prop1.text">
<input v-model="prop2">
<input v-model="this.prop3.text">
<input v-model="this.prop4">
</div>
</template>
<script>
export default {
props: ['prop5', 'prop6', 'prop7', 'prop8']
}
</script>
`
},
{
filename: 'test.vue',
code: `
<template>
<div>
<input v-for="i in prop.slice()">
<input v-for="i in prop.foo.slice()">
</div>
</template>
<script>
export default {
props: ['prop']
}
</script>
`
},
{
filename: 'test.vue',
code: `
Expand Down Expand Up @@ -226,6 +272,32 @@ ruleTester.run('no-mutating-props', rule, {
line: 18
}
]
},
{
filename: 'test.vue',
code: `
<template>
<div>
<template v-for="(test, index) of data">
<template v-for="(prop, index) of data">
<input v-model="prop">
</template>
<input v-model="prop">
</template>
</div>
</template>
<script>
export default {
props: ['prop']
}
</script>
`,
errors: [
{
message: 'Unexpected mutation of "prop" prop.',
line: 8
}
]
}
]
})

0 comments on commit 3261b9a

Please sign in to comment.