Skip to content

Commit

Permalink
Add new vue/no-arrow-functions-in-watch rule (#1155)
Browse files Browse the repository at this point in the history
* Add 'vue/no-arrow-functions-in-watch' rule

* Add property type check in 'vue/no-arrow-functions-in-watch'

* Modify to check error line info in 'vue/no-arrow-functions-in-watch' tests
  • Loading branch information
sosukesuzuki committed May 23, 2020
1 parent f03b2d8 commit f8b3014
Show file tree
Hide file tree
Showing 5 changed files with 319 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/rules/README.md
Expand Up @@ -286,6 +286,7 @@ For example:
| [vue/keyword-spacing](./keyword-spacing.md) | enforce consistent spacing before and after keywords | :wrench: |
| [vue/match-component-file-name](./match-component-file-name.md) | require component name property to match its file name | |
| [vue/max-len](./max-len.md) | enforce a maximum line length | |
| [vue/no-arrow-functions-in-watch](./no-arrow-functions-in-watch.md)| disallows using arrow functions to define wathcer | |
| [vue/no-boolean-default](./no-boolean-default.md) | disallow boolean defaults | :wrench: |
| [vue/no-duplicate-attr-inheritance](./no-duplicate-attr-inheritance.md) | enforce `inheritAttrs` to be set to `false` when using `v-bind="$attrs"` | |
| [vue/no-empty-pattern](./no-empty-pattern.md) | disallow empty destructuring patterns | |
Expand Down
61 changes: 61 additions & 0 deletions docs/rules/no-arrow-functions-in-watch.md
@@ -0,0 +1,61 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/no-arrow-functions-in-watch
description: disallow arrow functions to define watcher
---
# vue/no-arrow-functions-in-watch
> disallow using arrow functions to define watcher
## :book: Rule Details

This rules disallows using arrow functions to defined watcher.The reason is arrow functions bind the parent context, so `this` will not be the Vue instance as you expect.([see here for more details](https://vuejs.org/v2/api/#watch))

<eslint-code-block :rules="{'vue/no-arrow-functions-in-watch': ['error']}">

```vue
<script>
export default {
watch: {
/* ✓ GOOD */
a: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
},
b: 'someMethod',
c: {
handler: function (val, oldVal) { /* ... */ },
deep: true
},
d: {
handler: 'someMethod',
immediate: true
},
e: [
'handle1',
function handle2 (val, oldVal) { /* ... */ },
{
handler: function handle3 (val, oldVal) { /* ... */ },
/* ... */
}
],
'e.f': function (val, oldVal) { /* ... */ }
/* ✗ BAD */
foo: (val, oldVal) => {
console.log('new: %s, old: %s', val, oldVal)
}
}
}
</script>
```

</eslint-code-block>

## :wrench: Options

Nothing.

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-arrow-functions-in-watch.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-arrow-functions-in-watch.js)
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -40,6 +40,7 @@ module.exports = {
'multiline-html-element-content-newline': require('./rules/multiline-html-element-content-newline'),
'mustache-interpolation-spacing': require('./rules/mustache-interpolation-spacing'),
'name-property-casing': require('./rules/name-property-casing'),
'no-arrow-functions-in-watch': require('./rules/no-arrow-functions-in-watch'),
'no-async-in-computed-properties': require('./rules/no-async-in-computed-properties'),
'no-boolean-default': require('./rules/no-boolean-default'),
'no-confusing-v-for-v-if': require('./rules/no-confusing-v-for-v-if'),
Expand Down
39 changes: 39 additions & 0 deletions lib/rules/no-arrow-functions-in-watch.js
@@ -0,0 +1,39 @@
/**
* @author Sosuke Suzuki
*/
'use strict'

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

module.exports = {
meta: {
type: 'problem',
docs: {
description: 'disallow using arrow functions to define watcher',
categories: undefined,
url: 'https://eslint.vuejs.org/rules/no-arrow-functions-in-watch.html'
},
fixable: null,
schema: []
},
create (context) {
return utils.executeOnVue(context, (obj) => {
const watchNode = obj.properties.find((property) => utils.getStaticPropertyName(property) === 'watch')
if (watchNode == null) {
return
}
const watchValue = watchNode.value
if (watchValue.type !== 'ObjectExpression') {
return
}
for (const property of watchValue.properties) {
if (property.type === 'Property' && property.value.type === 'ArrowFunctionExpression') {
context.report({
node: property,
message: 'You should not use an arrow function to define a watcher.'
})
}
}
})
}
}
217 changes: 217 additions & 0 deletions tests/lib/rules/no-arrow-functions-in-watch.js
@@ -0,0 +1,217 @@
/**
* @author Sosuke Suzuki
*/

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

const rule = require('../../../lib/rules/no-arrow-functions-in-watch')
const RuleTester = require('eslint').RuleTester

// ------------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------------

const ruleTester = new RuleTester({
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module'
}
})
ruleTester.run('no-arrow-functions-in-watch', rule, {
valid: [
{
filename: 'test.vue',
code: `
export default {}
`
},
{
filename: 'test.vue',
code: `
export default {
watch: {}
}
`
},
{
filename: 'test.vue',
code: `
export default {
watch: {
foo() {}
},
}
`
},
{
filename: 'test.vue',
code: `
export default {
watch: {
foo: function() {}
},
}
`
},
{
filename: 'test.vue',
code: `
export default {
watch: {
foo() {},
bar() {}
},
}
`
},
{
filename: 'test.vue',
code: `
export default {
watch: {
foo: function() {},
bar: function() {}
},
}
`
},
{
filename: 'test.vue',
code: `
export default {
watch: {
...obj,
foo: function() {},
bar: function() {}
},
}
`
},
{
filename: 'test.vue',
code: `
export default {
data: {
a: 1,
b: 2,
c: 3,
d: 4,
e: {
f: {
g: 5
}
}
},
watch: {
a: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
},
b: 'someMethod',
c: {
handler: function (val, oldVal) {},
deep: true
},
d: {
handler: 'someMethod',
immediate: true
},
e: [
'handle1',
function handle2 (val, oldVal) {},
{
handler: function handle3 (val, oldVal) {},
/* ... */
}
],
'e.f': function (val, oldVal) { /* ... */ }
}
}`
}
],
invalid: [
{
filename: 'test.vue',
code: `
export default {
watch: {
foo: () => {}
},
}`,
errors: ['You should not use an arrow function to define a watcher.']
},
{
filename: 'test.vue',
code: `
export default {
watch: {
foo() {},
bar: () => {}
}
}`,
errors: [{
message: 'You should not use an arrow function to define a watcher.',
line: 5
}]
},
{
filename: 'test.vue',
code: `
export default {
watch: {
foo: function() {},
bar: () => {}
}
}`,
errors: [{
message: 'You should not use an arrow function to define a watcher.',
line: 5
}]
},
{
filename: 'test.vue',
code: `
export default {
data: {
a: 1,
b: 2,
c: 3,
d: 4,
e: {
f: {
g: 5
}
}
},
watch: {
a: (val, oldVal) => {
console.log('new: %s, old: %s', val, oldVal)
},
b: 'someMethod',
c: {
handler: function (val, oldVal) {},
deep: true
},
d: {
handler: 'someMethod',
immediate: true
},
e: [
'handle1',
function handle2 (val, oldVal) {},
{
handler: function handle3 (val, oldVal) {},
/* ... */
}
],
'e.f': function (val, oldVal) { /* ... */ }
}
}`,
errors: [{
message: 'You should not use an arrow function to define a watcher.',
line: 15
}]
}
]
})

0 comments on commit f8b3014

Please sign in to comment.