Skip to content

Commit 35efedc

Browse files
New: Add vue/no-deprecated-events-api rule (#1097)
Co-authored-by: Yosuke Ota <[email protected]>
1 parent cadec3b commit 35efedc

File tree

6 files changed

+278
-0
lines changed

6 files changed

+278
-0
lines changed

docs/rules/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi
3939
| Rule ID | Description | |
4040
|:--------|:------------|:---|
4141
| [vue/no-async-in-computed-properties](./no-async-in-computed-properties.md) | disallow asynchronous actions in computed properties | |
42+
| [vue/no-deprecated-events-api](./no-deprecated-events-api.md) | disallow using deprecated events api | |
4243
| [vue/no-deprecated-data-object-declaration](./no-deprecated-data-object-declaration.md) | disallow using deprecated object declaration on data | :wrench: |
4344
| [vue/no-deprecated-filter](./no-deprecated-filter.md) | disallow using deprecated filters syntax | |
4445
| [vue/no-deprecated-scope-attribute](./no-deprecated-scope-attribute.md) | disallow deprecated `scope` attribute (in Vue.js 2.5.0+) | :wrench: |
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/no-deprecated-events-api
5+
description: disallow using deprecated events api
6+
---
7+
# vue/no-deprecated-events-api
8+
> disallow using deprecated events api
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 `$on`, `$off` `$once` api. (in Vue.js 3.0.0+).
15+
16+
<eslint-code-block :rules="{'vue/no-deprecated-events-api': ['error']}">
17+
18+
```vue
19+
<script>
20+
/* ✗ BAD */
21+
export default {
22+
mounted () {
23+
this.$on('start', function(args) {
24+
console.log('start')
25+
})
26+
this.$emit('start')
27+
}
28+
}
29+
30+
/* ✓ GOOD */
31+
import mitt from 'mitt'
32+
const emitter = mitt()
33+
export default {
34+
mounted () {
35+
emitter.on('start', function(args) {
36+
console.log('start')
37+
})
38+
emitter.emit('start')
39+
}
40+
}
41+
</script>
42+
```
43+
44+
</eslint-code-block>
45+
46+
## :wrench: Options
47+
48+
Nothing.
49+
50+
## :books: Further reading
51+
52+
- [RFC: events api change](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0020-events-api-change.md)
53+
54+
## :mag: Implementation
55+
56+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-deprecated-events-api.js)
57+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-deprecated-events-api.js)

lib/configs/vue3-essential.js

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module.exports = {
77
extends: require.resolve('./base'),
88
rules: {
99
'vue/no-async-in-computed-properties': 'error',
10+
'vue/no-deprecated-events-api': 'error',
1011
'vue/no-deprecated-data-object-declaration': 'error',
1112
'vue/no-deprecated-filter': 'error',
1213
'vue/no-deprecated-scope-attribute': 'error',

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ module.exports = {
4040
'no-boolean-default': require('./rules/no-boolean-default'),
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'),
43+
'no-deprecated-events-api': require('./rules/no-deprecated-events-api'),
4344
'no-deprecated-data-object-declaration': require('./rules/no-deprecated-data-object-declaration'),
4445
'no-deprecated-filter': require('./rules/no-deprecated-filter'),
4546
'no-deprecated-scope-attribute': require('./rules/no-deprecated-scope-attribute'),

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

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* @fileoverview disallow using deprecated events api
3+
* @author yoyo930021
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 events api',
22+
categories: ['vue3-essential'],
23+
url: 'https://eslint.vuejs.org/rules/no-deprecated-events-api.html'
24+
},
25+
fixable: null,
26+
schema: [],
27+
messages: {
28+
noDeprecatedEventsApi: 'The Events api `$on`, `$off` `$once` is deprecated. Using external library instead, for example mitt.'
29+
}
30+
},
31+
32+
create (context) {
33+
const forbiddenNodes = []
34+
35+
return Object.assign(
36+
{
37+
'CallExpression > MemberExpression > ThisExpression' (node) {
38+
if (!['$on', '$off', '$once'].includes(node.parent.property.name)) return
39+
forbiddenNodes.push(node.parent.parent)
40+
}
41+
},
42+
utils.executeOnVue(context, (obj) => {
43+
forbiddenNodes.forEach(node => {
44+
if (
45+
node.loc.start.line >= obj.loc.start.line &&
46+
node.loc.end.line <= obj.loc.end.line
47+
) {
48+
context.report({
49+
node,
50+
messageId: 'noDeprecatedEventsApi'
51+
})
52+
}
53+
})
54+
})
55+
)
56+
}
57+
}
+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/* eslint-disable eslint-plugin/consistent-output */
2+
/**
3+
* @fileoverview disallow using deprecated events api
4+
* @author yoyo930021
5+
*/
6+
'use strict'
7+
8+
// ------------------------------------------------------------------------------
9+
// Requirements
10+
// ------------------------------------------------------------------------------
11+
12+
const rule = require('../../../lib/rules/no-deprecated-events-api')
13+
14+
const RuleTester = require('eslint').RuleTester
15+
16+
const parserOptions = {
17+
ecmaVersion: 2018,
18+
sourceType: 'module'
19+
}
20+
21+
// ------------------------------------------------------------------------------
22+
// Tests
23+
// ------------------------------------------------------------------------------
24+
25+
const ruleTester = new RuleTester()
26+
ruleTester.run('no-deprecated-events-api', rule, {
27+
28+
valid: [
29+
{
30+
filename: 'test.js',
31+
code: `
32+
createApp({
33+
mounted () {
34+
this.$emit('start')
35+
}
36+
})
37+
`,
38+
parserOptions
39+
},
40+
{
41+
filename: 'test.js',
42+
code: `
43+
createApp({
44+
methods: {
45+
click () {
46+
this.$emit('click')
47+
}
48+
}
49+
})
50+
`,
51+
parserOptions
52+
},
53+
{
54+
filename: 'test.js',
55+
code: `
56+
const another = function () {
57+
this.$on('start', args => {
58+
console.log('start')
59+
})
60+
}
61+
62+
createApp({
63+
mounted () {
64+
this.$emit('start')
65+
}
66+
})
67+
`,
68+
parserOptions
69+
},
70+
{
71+
filename: 'test.js',
72+
code: `
73+
app.component('some-comp', {
74+
mounted () {
75+
this.$emit('start')
76+
}
77+
})
78+
`,
79+
parserOptions
80+
},
81+
{
82+
filename: 'test.vue',
83+
code: `
84+
export default {
85+
mounted () {
86+
this.$emit('start')
87+
}
88+
}
89+
`,
90+
parserOptions
91+
},
92+
{
93+
filename: 'test.vue',
94+
code: `
95+
import mitt from 'mitt'
96+
const emitter = mitt()
97+
98+
export default {
99+
setup () {
100+
emitter.on('foo', e => console.log('foo', e))
101+
emitter.emit('foo', { a: 'b' })
102+
emitter.off('foo', onFoo)
103+
}
104+
}
105+
`,
106+
parserOptions
107+
}
108+
],
109+
110+
invalid: [
111+
{
112+
filename: 'test.js',
113+
code: `
114+
app.component('some-comp', {
115+
mounted () {
116+
this.$on('start', function (args) {
117+
console.log('start', args)
118+
})
119+
}
120+
})
121+
`,
122+
parserOptions,
123+
errors: [{
124+
message: 'The Events api `$on`, `$off` `$once` is deprecated. Using external library instead, for example mitt.',
125+
line: 4
126+
}]
127+
},
128+
{
129+
filename: 'test.js',
130+
code: `
131+
app.component('some-comp', {
132+
mounted () {
133+
this.$off('start')
134+
}
135+
})
136+
`,
137+
parserOptions,
138+
errors: [{
139+
message: 'The Events api `$on`, `$off` `$once` is deprecated. Using external library instead, for example mitt.',
140+
line: 4
141+
}]
142+
},
143+
{
144+
filename: 'test.vue',
145+
code: `
146+
export default {
147+
mounted () {
148+
this.$once('start', function () {
149+
console.log('start')
150+
})
151+
}
152+
}
153+
`,
154+
parserOptions,
155+
errors: [{
156+
message: 'The Events api `$on`, `$off` `$once` is deprecated. Using external library instead, for example mitt.',
157+
line: 4
158+
}]
159+
}
160+
]
161+
})

0 commit comments

Comments
 (0)