Skip to content

Commit

Permalink
Report $set and $nextTick in computed properties (#1750)
Browse files Browse the repository at this point in the history
* Report `set`/`nextTick` in `vue/no-side-effects-in-computed-properties`

* Don't check `nextTick` in `no-side-effects-in-computed-properties`

* Report `nextTick` in `no-async-in-computed-properties`
  • Loading branch information
FloEdelmann committed Jan 6, 2022
1 parent 2472ffa commit e7b77aa
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 4 deletions.
26 changes: 26 additions & 0 deletions lib/rules/no-async-in-computed-properties.js
Expand Up @@ -58,6 +58,24 @@ function isPromise(node) {
return false
}

/**
* @param {CallExpression} node
* @param {RuleContext} context
*/
function isNextTick(node, context) {
const callee = utils.skipChainExpression(node.callee)
if (callee.type === 'MemberExpression') {
const name = utils.getStaticPropertyName(callee)
return (
(utils.isThis(callee.object, context) && name === '$nextTick') ||
(callee.object.type === 'Identifier' &&
callee.object.name === 'Vue' &&
name === 'nextTick')
)
}
return false
}

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -90,6 +108,7 @@ module.exports = {

const expressionTypes = {
promise: 'asynchronous action',
nextTick: 'asynchronous action',
await: 'await operator',
async: 'async function declaration',
new: 'Promise object',
Expand Down Expand Up @@ -211,6 +230,13 @@ module.exports = {
'timed',
info ? computedPropertiesMap.get(info.node) : null
)
} else if (isNextTick(node, context)) {
verify(
node,
scopeStack.body,
'nextTick',
info ? computedPropertiesMap.get(info.node) : null
)
}
},

Expand Down
17 changes: 13 additions & 4 deletions lib/rules/no-side-effects-in-computed-properties.js
Expand Up @@ -83,15 +83,24 @@ module.exports = {
)
})
if (computedProperty) {
if (!utils.isThis(node, context)) {
return
}
const mem = node.parent
if (mem.object !== node) {
return
}

const invalid = utils.findMutating(mem)
const isThis = utils.isThis(node, context)
const isVue = node.type === 'Identifier' && node.name === 'Vue'

const isVueSet =
mem.parent.type === 'CallExpression' &&
mem.property.type === 'Identifier' &&
((isThis && mem.property.name === '$set') ||
(isVue && mem.property.name === 'set'))

const invalid = isVueSet
? { node: mem.property }
: isThis && utils.findMutating(mem)

if (invalid) {
context.report({
node: invalid.node,
Expand Down
63 changes: 63 additions & 0 deletions tests/lib/rules/no-async-in-computed-properties.js
Expand Up @@ -627,6 +627,69 @@ ruleTester.run('no-async-in-computed-properties', rule, {
}
]
},
{
filename: 'test.vue',
code: `
new Vue({
computed: {
foo () {
this.$nextTick(() => {})
Vue.nextTick(() => {})
return 'foo'
}
}
})
`,
parserOptions,
errors: [
{
message: 'Unexpected asynchronous action in "foo" computed property.',
line: 5
},
{
message: 'Unexpected asynchronous action in "foo" computed property.',
line: 6
}
]
},
{
filename: 'test.vue',
code: `
new Vue({
computed: {
async foo () {
await this.$nextTick()
await Vue.nextTick()
return 'foo'
}
}
})
`,
parserOptions,
errors: [
{
message:
'Unexpected async function declaration in "foo" computed property.',
line: 4
},
{
message: 'Unexpected await operator in "foo" computed property.',
line: 5
},
{
message: 'Unexpected asynchronous action in "foo" computed property.',
line: 5
},
{
message: 'Unexpected await operator in "foo" computed property.',
line: 6
},
{
message: 'Unexpected asynchronous action in "foo" computed property.',
line: 6
}
]
},
{
filename: 'test.vue',
code: `
Expand Down
22 changes: 22 additions & 0 deletions tests/lib/rules/no-side-effects-in-computed-properties.js
Expand Up @@ -446,6 +446,28 @@ ruleTester.run('no-side-effects-in-computed-properties', rule, {
'Unexpected side effect in "test3" computed property.'
]
},
{
// https://github.com/vuejs/eslint-plugin-vue/issues/1744
code: `app.component('test', {
computed: {
fooBar() {
this.$set(this, 'foo', 'lorem');
Vue.set(this, 'bar', 'ipsum');
return this.foo + ' ' + this.bar
},
}
})`,
errors: [
{
line: 4,
message: 'Unexpected side effect in "fooBar" computed property.'
},
{
line: 5,
message: 'Unexpected side effect in "fooBar" computed property.'
}
]
},
{
filename: 'test.vue',
code: `
Expand Down

0 comments on commit e7b77aa

Please sign in to comment.