Skip to content

Commit 22bb2c2

Browse files
authored
Add vue/no-deprecated-dollar-listeners-api rule (#1133)
1 parent d78ec7d commit 22bb2c2

7 files changed

+303
-1
lines changed

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi
4040
|:--------|:------------|:---|
4141
| [vue/no-async-in-computed-properties](./no-async-in-computed-properties.md) | disallow asynchronous actions in computed properties | |
4242
| [vue/no-deprecated-data-object-declaration](./no-deprecated-data-object-declaration.md) | disallow using deprecated object declaration on data (in Vue.js 3.0.0+) | :wrench: |
43+
| [vue/no-deprecated-dollar-listeners-api](./no-deprecated-dollar-listeners-api.md) | disallow using deprecated `$listeners` (in Vue.js 3.0.0+) | |
4344
| [vue/no-deprecated-events-api](./no-deprecated-events-api.md) | disallow using deprecated events api (in Vue.js 3.0.0+) | |
4445
| [vue/no-deprecated-filter](./no-deprecated-filter.md) | disallow using deprecated filters syntax (in Vue.js 3.0.0+) | |
4546
| [vue/no-deprecated-functional-template](./no-deprecated-functional-template.md) | disallow using deprecated the `functional` template (in Vue.js 3.0.0+) | |
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/no-deprecated-dollar-listeners-api
5+
description: disallow using deprecated `$listeners` (in Vue.js 3.0.0+)
6+
---
7+
# vue/no-deprecated-dollar-listeners-api
8+
> disallow using deprecated `$listeners` (in Vue.js 3.0.0+)
9+
10+
- :gear: This rule is included in all of `"plugin:vue/vue3-essential"`, `"plugin:vue/vue3-strongly-recommended"` and `"plugin:vue/vue3-recommended"`.
11+
12+
## :book: Rule Details
13+
14+
This rule reports use of deprecated `$listeners`. (in Vue.js 3.0.0+).
15+
16+
<eslint-code-block :rules="{'vue/no-deprecated-dollar-listeners-api': ['error']}">
17+
18+
```vue
19+
<template>
20+
<!-- ✗ BAD -->
21+
<MyInput v-on="$listeners">
22+
</template>
23+
<script>
24+
export default {
25+
computed: {
26+
listeners() {
27+
return {
28+
/* ✗ BAD */
29+
...this.$listeners,
30+
input() { /* */ }
31+
}
32+
}
33+
}
34+
}
35+
</script>
36+
```
37+
38+
</eslint-code-block>
39+
40+
## :wrench: Options
41+
42+
Nothing.
43+
44+
## :books: Further reading
45+
46+
- [Vue RFCs - 0031-attr-fallthrough](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0031-attr-fallthrough.md)
47+
48+
## :mag: Implementation
49+
50+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-deprecated-dollar-listeners-api.js)
51+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-deprecated-dollar-listeners-api.js)

lib/configs/vue3-essential.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module.exports = {
88
rules: {
99
'vue/no-async-in-computed-properties': 'error',
1010
'vue/no-deprecated-data-object-declaration': 'error',
11+
'vue/no-deprecated-dollar-listeners-api': 'error',
1112
'vue/no-deprecated-events-api': 'error',
1213
'vue/no-deprecated-filter': 'error',
1314
'vue/no-deprecated-functional-template': 'error',

lib/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ module.exports = {
4141
'no-confusing-v-for-v-if': require('./rules/no-confusing-v-for-v-if'),
4242
'no-custom-modifiers-on-v-model': require('./rules/no-custom-modifiers-on-v-model'),
4343
'no-deprecated-data-object-declaration': require('./rules/no-deprecated-data-object-declaration'),
44+
'no-deprecated-dollar-listeners-api': require('./rules/no-deprecated-dollar-listeners-api'),
4445
'no-deprecated-events-api': require('./rules/no-deprecated-events-api'),
4546
'no-deprecated-filter': require('./rules/no-deprecated-filter'),
4647
'no-deprecated-functional-template': require('./rules/no-deprecated-functional-template'),
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @author Yosuke Ota
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const utils = require('../utils')
12+
13+
// ------------------------------------------------------------------------------
14+
// Rule Definition
15+
// ------------------------------------------------------------------------------
16+
17+
module.exports = {
18+
meta: {
19+
type: 'problem',
20+
docs: {
21+
description: 'disallow using deprecated `$listeners` (in Vue.js 3.0.0+)',
22+
categories: ['vue3-essential'],
23+
url: 'https://eslint.vuejs.org/rules/no-deprecated-dollar-listeners-api.html'
24+
},
25+
fixable: null,
26+
schema: [],
27+
messages: {
28+
deprecated: 'The `$listeners` is deprecated.'
29+
}
30+
},
31+
32+
create (context) {
33+
return utils.defineTemplateBodyVisitor(
34+
context,
35+
{
36+
'VExpressionContainer' (node) {
37+
for (const reference of node.references) {
38+
if (reference.variable != null) {
39+
// Not vm reference
40+
continue
41+
}
42+
if (reference.id.name === '$listeners') {
43+
context.report({
44+
node: reference.id,
45+
messageId: 'deprecated'
46+
})
47+
}
48+
}
49+
}
50+
},
51+
utils.defineVueVisitor(context,
52+
{
53+
'MemberExpression > ThisExpression' (node) {
54+
if (node.parent.property.name !== '$listeners') return
55+
56+
context.report({
57+
node: node.parent.property,
58+
messageId: 'deprecated'
59+
})
60+
}
61+
}
62+
)
63+
)
64+
}
65+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/**
2+
* @author Yosuke Ota
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const rule = require('../../../lib/rules/no-deprecated-dollar-listeners-api')
12+
13+
const RuleTester = require('eslint').RuleTester
14+
15+
// ------------------------------------------------------------------------------
16+
// Tests
17+
// ------------------------------------------------------------------------------
18+
19+
const ruleTester = new RuleTester({
20+
parser: require.resolve('vue-eslint-parser'),
21+
parserOptions: { ecmaVersion: 2018, sourceType: 'module' }
22+
})
23+
ruleTester.run('no-deprecated-dollar-listeners-api', rule, {
24+
25+
valid: [
26+
{
27+
filename: 'test.vue',
28+
code: `
29+
<template>
30+
<div v-bind="$attrs"/>
31+
</template>
32+
<script>
33+
export default {
34+
mounted () {
35+
this.$emit('start')
36+
}
37+
}
38+
</script>
39+
`
40+
},
41+
{
42+
filename: 'test.vue',
43+
code: `
44+
<script>
45+
export default {
46+
methods: {
47+
click () {
48+
this.$emit('click')
49+
}
50+
}
51+
}
52+
</script>
53+
`
54+
},
55+
{
56+
filename: 'test.vue',
57+
code: `
58+
<script>
59+
export default {
60+
}
61+
const another = function () {
62+
console.log(this.$listeners)
63+
}
64+
</script>
65+
`
66+
},
67+
{
68+
filename: 'test.vue',
69+
code: `
70+
<template>
71+
<div foo="$listeners"/>
72+
</template>
73+
`
74+
},
75+
{
76+
filename: 'test.vue',
77+
code: `
78+
<template>
79+
<div v-on="() => {
80+
function click ($listeners) {
81+
fn(foo.$listeners)
82+
fn($listeners)
83+
}
84+
}"/>
85+
<div v-for="$listeners in list">
86+
<div v-on="$listeners">
87+
</div>
88+
<VueComp>
89+
<template v-slot="{$listeners}">
90+
<div v-on="$listeners">
91+
</template>
92+
</VueComp>
93+
</template>
94+
<script>
95+
export default {
96+
methods: {
97+
click ($listeners) {
98+
foo.$listeners
99+
}
100+
}
101+
}
102+
</script>
103+
`
104+
}
105+
],
106+
107+
invalid: [
108+
{
109+
filename: 'test.vue',
110+
code: `
111+
<template>
112+
<div v-on="$listeners"/>
113+
</template>
114+
<script>
115+
export default {
116+
computed: {
117+
foo () {
118+
return this.$listeners
119+
}
120+
}
121+
}
122+
</script>
123+
`,
124+
errors: [
125+
{
126+
line: 3,
127+
column: 22,
128+
messageId: 'deprecated',
129+
endLine: 3,
130+
endColumn: 32
131+
},
132+
{
133+
line: 9,
134+
column: 27,
135+
messageId: 'deprecated',
136+
endLine: 9,
137+
endColumn: 37
138+
}
139+
]
140+
},
141+
142+
{
143+
filename: 'test.vue',
144+
code: `
145+
<template>
146+
<div v-for="listener in $listeners"/>
147+
<div :foo="$listeners"/>
148+
</template>
149+
<script>
150+
export default {
151+
computed: {
152+
foo () {
153+
fn(this.$listeners)
154+
}
155+
}
156+
}
157+
</script>
158+
`,
159+
errors: [
160+
{
161+
line: 3,
162+
column: 35,
163+
messageId: 'deprecated',
164+
endLine: 3,
165+
endColumn: 45
166+
},
167+
{
168+
line: 4,
169+
column: 22,
170+
messageId: 'deprecated',
171+
endLine: 4,
172+
endColumn: 32
173+
},
174+
{
175+
line: 10,
176+
column: 23,
177+
messageId: 'deprecated',
178+
endLine: 10,
179+
endColumn: 33
180+
}
181+
]
182+
}
183+
]
184+
})

tests/lib/rules/no-deprecated-events-api.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* eslint-disable eslint-plugin/consistent-output */
21
/**
32
* @fileoverview disallow using deprecated events api
43
* @author yoyo930021

0 commit comments

Comments
 (0)