Skip to content

Commit f8b3014

Browse files
authored
Add new vue/no-arrow-functions-in-watch rule (#1155)
* 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
1 parent f03b2d8 commit f8b3014

File tree

5 files changed

+319
-0
lines changed

5 files changed

+319
-0
lines changed

Diff for: docs/rules/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ For example:
286286
| [vue/keyword-spacing](./keyword-spacing.md) | enforce consistent spacing before and after keywords | :wrench: |
287287
| [vue/match-component-file-name](./match-component-file-name.md) | require component name property to match its file name | |
288288
| [vue/max-len](./max-len.md) | enforce a maximum line length | |
289+
| [vue/no-arrow-functions-in-watch](./no-arrow-functions-in-watch.md)| disallows using arrow functions to define wathcer | |
289290
| [vue/no-boolean-default](./no-boolean-default.md) | disallow boolean defaults | :wrench: |
290291
| [vue/no-duplicate-attr-inheritance](./no-duplicate-attr-inheritance.md) | enforce `inheritAttrs` to be set to `false` when using `v-bind="$attrs"` | |
291292
| [vue/no-empty-pattern](./no-empty-pattern.md) | disallow empty destructuring patterns | |

Diff for: docs/rules/no-arrow-functions-in-watch.md

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/no-arrow-functions-in-watch
5+
description: disallow arrow functions to define watcher
6+
---
7+
# vue/no-arrow-functions-in-watch
8+
> disallow using arrow functions to define watcher
9+
10+
## :book: Rule Details
11+
12+
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))
13+
14+
<eslint-code-block :rules="{'vue/no-arrow-functions-in-watch': ['error']}">
15+
16+
```vue
17+
<script>
18+
export default {
19+
watch: {
20+
/* ✓ GOOD */
21+
a: function (val, oldVal) {
22+
console.log('new: %s, old: %s', val, oldVal)
23+
},
24+
b: 'someMethod',
25+
c: {
26+
handler: function (val, oldVal) { /* ... */ },
27+
deep: true
28+
},
29+
d: {
30+
handler: 'someMethod',
31+
immediate: true
32+
},
33+
e: [
34+
'handle1',
35+
function handle2 (val, oldVal) { /* ... */ },
36+
{
37+
handler: function handle3 (val, oldVal) { /* ... */ },
38+
/* ... */
39+
}
40+
],
41+
'e.f': function (val, oldVal) { /* ... */ }
42+
43+
/* ✗ BAD */
44+
foo: (val, oldVal) => {
45+
console.log('new: %s, old: %s', val, oldVal)
46+
}
47+
}
48+
}
49+
</script>
50+
```
51+
52+
</eslint-code-block>
53+
54+
## :wrench: Options
55+
56+
Nothing.
57+
58+
## :mag: Implementation
59+
60+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-arrow-functions-in-watch.js)
61+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-arrow-functions-in-watch.js)

Diff for: lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ module.exports = {
4040
'multiline-html-element-content-newline': require('./rules/multiline-html-element-content-newline'),
4141
'mustache-interpolation-spacing': require('./rules/mustache-interpolation-spacing'),
4242
'name-property-casing': require('./rules/name-property-casing'),
43+
'no-arrow-functions-in-watch': require('./rules/no-arrow-functions-in-watch'),
4344
'no-async-in-computed-properties': require('./rules/no-async-in-computed-properties'),
4445
'no-boolean-default': require('./rules/no-boolean-default'),
4546
'no-confusing-v-for-v-if': require('./rules/no-confusing-v-for-v-if'),

Diff for: lib/rules/no-arrow-functions-in-watch.js

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* @author Sosuke Suzuki
3+
*/
4+
'use strict'
5+
6+
const utils = require('../utils')
7+
8+
module.exports = {
9+
meta: {
10+
type: 'problem',
11+
docs: {
12+
description: 'disallow using arrow functions to define watcher',
13+
categories: undefined,
14+
url: 'https://eslint.vuejs.org/rules/no-arrow-functions-in-watch.html'
15+
},
16+
fixable: null,
17+
schema: []
18+
},
19+
create (context) {
20+
return utils.executeOnVue(context, (obj) => {
21+
const watchNode = obj.properties.find((property) => utils.getStaticPropertyName(property) === 'watch')
22+
if (watchNode == null) {
23+
return
24+
}
25+
const watchValue = watchNode.value
26+
if (watchValue.type !== 'ObjectExpression') {
27+
return
28+
}
29+
for (const property of watchValue.properties) {
30+
if (property.type === 'Property' && property.value.type === 'ArrowFunctionExpression') {
31+
context.report({
32+
node: property,
33+
message: 'You should not use an arrow function to define a watcher.'
34+
})
35+
}
36+
}
37+
})
38+
}
39+
}

Diff for: tests/lib/rules/no-arrow-functions-in-watch.js

+217
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
/**
2+
* @author Sosuke Suzuki
3+
*/
4+
5+
// ------------------------------------------------------------------------------
6+
// Requirements
7+
// ------------------------------------------------------------------------------
8+
9+
const rule = require('../../../lib/rules/no-arrow-functions-in-watch')
10+
const RuleTester = require('eslint').RuleTester
11+
12+
// ------------------------------------------------------------------------------
13+
// Tests
14+
// ------------------------------------------------------------------------------
15+
16+
const ruleTester = new RuleTester({
17+
parserOptions: {
18+
ecmaVersion: 2018,
19+
sourceType: 'module'
20+
}
21+
})
22+
ruleTester.run('no-arrow-functions-in-watch', rule, {
23+
valid: [
24+
{
25+
filename: 'test.vue',
26+
code: `
27+
export default {}
28+
`
29+
},
30+
{
31+
filename: 'test.vue',
32+
code: `
33+
export default {
34+
watch: {}
35+
}
36+
`
37+
},
38+
{
39+
filename: 'test.vue',
40+
code: `
41+
export default {
42+
watch: {
43+
foo() {}
44+
},
45+
}
46+
`
47+
},
48+
{
49+
filename: 'test.vue',
50+
code: `
51+
export default {
52+
watch: {
53+
foo: function() {}
54+
},
55+
}
56+
`
57+
},
58+
{
59+
filename: 'test.vue',
60+
code: `
61+
export default {
62+
watch: {
63+
foo() {},
64+
bar() {}
65+
},
66+
}
67+
`
68+
},
69+
{
70+
filename: 'test.vue',
71+
code: `
72+
export default {
73+
watch: {
74+
foo: function() {},
75+
bar: function() {}
76+
},
77+
}
78+
`
79+
},
80+
{
81+
filename: 'test.vue',
82+
code: `
83+
export default {
84+
watch: {
85+
...obj,
86+
foo: function() {},
87+
bar: function() {}
88+
},
89+
}
90+
`
91+
},
92+
{
93+
filename: 'test.vue',
94+
code: `
95+
export default {
96+
data: {
97+
a: 1,
98+
b: 2,
99+
c: 3,
100+
d: 4,
101+
e: {
102+
f: {
103+
g: 5
104+
}
105+
}
106+
},
107+
watch: {
108+
a: function (val, oldVal) {
109+
console.log('new: %s, old: %s', val, oldVal)
110+
},
111+
b: 'someMethod',
112+
c: {
113+
handler: function (val, oldVal) {},
114+
deep: true
115+
},
116+
d: {
117+
handler: 'someMethod',
118+
immediate: true
119+
},
120+
e: [
121+
'handle1',
122+
function handle2 (val, oldVal) {},
123+
{
124+
handler: function handle3 (val, oldVal) {},
125+
/* ... */
126+
}
127+
],
128+
'e.f': function (val, oldVal) { /* ... */ }
129+
}
130+
}`
131+
}
132+
],
133+
invalid: [
134+
{
135+
filename: 'test.vue',
136+
code: `
137+
export default {
138+
watch: {
139+
foo: () => {}
140+
},
141+
}`,
142+
errors: ['You should not use an arrow function to define a watcher.']
143+
},
144+
{
145+
filename: 'test.vue',
146+
code: `
147+
export default {
148+
watch: {
149+
foo() {},
150+
bar: () => {}
151+
}
152+
}`,
153+
errors: [{
154+
message: 'You should not use an arrow function to define a watcher.',
155+
line: 5
156+
}]
157+
},
158+
{
159+
filename: 'test.vue',
160+
code: `
161+
export default {
162+
watch: {
163+
foo: function() {},
164+
bar: () => {}
165+
}
166+
}`,
167+
errors: [{
168+
message: 'You should not use an arrow function to define a watcher.',
169+
line: 5
170+
}]
171+
},
172+
{
173+
filename: 'test.vue',
174+
code: `
175+
export default {
176+
data: {
177+
a: 1,
178+
b: 2,
179+
c: 3,
180+
d: 4,
181+
e: {
182+
f: {
183+
g: 5
184+
}
185+
}
186+
},
187+
watch: {
188+
a: (val, oldVal) => {
189+
console.log('new: %s, old: %s', val, oldVal)
190+
},
191+
b: 'someMethod',
192+
c: {
193+
handler: function (val, oldVal) {},
194+
deep: true
195+
},
196+
d: {
197+
handler: 'someMethod',
198+
immediate: true
199+
},
200+
e: [
201+
'handle1',
202+
function handle2 (val, oldVal) {},
203+
{
204+
handler: function handle3 (val, oldVal) {},
205+
/* ... */
206+
}
207+
],
208+
'e.f': function (val, oldVal) { /* ... */ }
209+
}
210+
}`,
211+
errors: [{
212+
message: 'You should not use an arrow function to define a watcher.',
213+
line: 15
214+
}]
215+
}
216+
]
217+
})

0 commit comments

Comments
 (0)