Skip to content

Commit

Permalink
New: Add vue/no-deprecated-events-api rule (#1097)
Browse files Browse the repository at this point in the history
Co-authored-by: Yosuke Ota <otameshiyo23@gmail.com>
  • Loading branch information
yoyo930021 and ota-meshi committed Apr 21, 2020
1 parent cadec3b commit 35efedc
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/rules/README.md
Expand Up @@ -39,6 +39,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi
| Rule ID | Description | |
|:--------|:------------|:---|
| [vue/no-async-in-computed-properties](./no-async-in-computed-properties.md) | disallow asynchronous actions in computed properties | |
| [vue/no-deprecated-events-api](./no-deprecated-events-api.md) | disallow using deprecated events api | |
| [vue/no-deprecated-data-object-declaration](./no-deprecated-data-object-declaration.md) | disallow using deprecated object declaration on data | :wrench: |
| [vue/no-deprecated-filter](./no-deprecated-filter.md) | disallow using deprecated filters syntax | |
| [vue/no-deprecated-scope-attribute](./no-deprecated-scope-attribute.md) | disallow deprecated `scope` attribute (in Vue.js 2.5.0+) | :wrench: |
Expand Down
57 changes: 57 additions & 0 deletions docs/rules/no-deprecated-events-api.md
@@ -0,0 +1,57 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/no-deprecated-events-api
description: disallow using deprecated events api
---
# vue/no-deprecated-events-api
> disallow using deprecated events api
- :gear: This rule is included in all of `"plugin:vue/vue3-essential"`, `"plugin:vue/vue3-strongly-recommended"` and `"plugin:vue/vue3-recommended"`.

## :book: Rule Details

This rule reports use of deprecated `$on`, `$off` `$once` api. (in Vue.js 3.0.0+).

<eslint-code-block :rules="{'vue/no-deprecated-events-api': ['error']}">

```vue
<script>
/* ✗ BAD */
export default {
mounted () {
this.$on('start', function(args) {
console.log('start')
})
this.$emit('start')
}
}
/* ✓ GOOD */
import mitt from 'mitt'
const emitter = mitt()
export default {
mounted () {
emitter.on('start', function(args) {
console.log('start')
})
emitter.emit('start')
}
}
</script>
```

</eslint-code-block>

## :wrench: Options

Nothing.

## :books: Further reading

- [RFC: events api change](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0020-events-api-change.md)

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-deprecated-events-api.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-deprecated-events-api.js)
1 change: 1 addition & 0 deletions lib/configs/vue3-essential.js
Expand Up @@ -7,6 +7,7 @@ module.exports = {
extends: require.resolve('./base'),
rules: {
'vue/no-async-in-computed-properties': 'error',
'vue/no-deprecated-events-api': 'error',
'vue/no-deprecated-data-object-declaration': 'error',
'vue/no-deprecated-filter': 'error',
'vue/no-deprecated-scope-attribute': 'error',
Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -40,6 +40,7 @@ module.exports = {
'no-boolean-default': require('./rules/no-boolean-default'),
'no-confusing-v-for-v-if': require('./rules/no-confusing-v-for-v-if'),
'no-custom-modifiers-on-v-model': require('./rules/no-custom-modifiers-on-v-model'),
'no-deprecated-events-api': require('./rules/no-deprecated-events-api'),
'no-deprecated-data-object-declaration': require('./rules/no-deprecated-data-object-declaration'),
'no-deprecated-filter': require('./rules/no-deprecated-filter'),
'no-deprecated-scope-attribute': require('./rules/no-deprecated-scope-attribute'),
Expand Down
57 changes: 57 additions & 0 deletions lib/rules/no-deprecated-events-api.js
@@ -0,0 +1,57 @@
/**
* @fileoverview disallow using deprecated events api
* @author yoyo930021
*/
'use strict'

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

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

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = {
meta: {
type: 'problem',
docs: {
description: 'disallow using deprecated events api',
categories: ['vue3-essential'],
url: 'https://eslint.vuejs.org/rules/no-deprecated-events-api.html'
},
fixable: null,
schema: [],
messages: {
noDeprecatedEventsApi: 'The Events api `$on`, `$off` `$once` is deprecated. Using external library instead, for example mitt.'
}
},

create (context) {
const forbiddenNodes = []

return Object.assign(
{
'CallExpression > MemberExpression > ThisExpression' (node) {
if (!['$on', '$off', '$once'].includes(node.parent.property.name)) return
forbiddenNodes.push(node.parent.parent)
}
},
utils.executeOnVue(context, (obj) => {
forbiddenNodes.forEach(node => {
if (
node.loc.start.line >= obj.loc.start.line &&
node.loc.end.line <= obj.loc.end.line
) {
context.report({
node,
messageId: 'noDeprecatedEventsApi'
})
}
})
})
)
}
}
161 changes: 161 additions & 0 deletions tests/lib/rules/no-deprecated-events-api.js
@@ -0,0 +1,161 @@
/* eslint-disable eslint-plugin/consistent-output */
/**
* @fileoverview disallow using deprecated events api
* @author yoyo930021
*/
'use strict'

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

const rule = require('../../../lib/rules/no-deprecated-events-api')

const RuleTester = require('eslint').RuleTester

const parserOptions = {
ecmaVersion: 2018,
sourceType: 'module'
}

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

const ruleTester = new RuleTester()
ruleTester.run('no-deprecated-events-api', rule, {

valid: [
{
filename: 'test.js',
code: `
createApp({
mounted () {
this.$emit('start')
}
})
`,
parserOptions
},
{
filename: 'test.js',
code: `
createApp({
methods: {
click () {
this.$emit('click')
}
}
})
`,
parserOptions
},
{
filename: 'test.js',
code: `
const another = function () {
this.$on('start', args => {
console.log('start')
})
}
createApp({
mounted () {
this.$emit('start')
}
})
`,
parserOptions
},
{
filename: 'test.js',
code: `
app.component('some-comp', {
mounted () {
this.$emit('start')
}
})
`,
parserOptions
},
{
filename: 'test.vue',
code: `
export default {
mounted () {
this.$emit('start')
}
}
`,
parserOptions
},
{
filename: 'test.vue',
code: `
import mitt from 'mitt'
const emitter = mitt()
export default {
setup () {
emitter.on('foo', e => console.log('foo', e))
emitter.emit('foo', { a: 'b' })
emitter.off('foo', onFoo)
}
}
`,
parserOptions
}
],

invalid: [
{
filename: 'test.js',
code: `
app.component('some-comp', {
mounted () {
this.$on('start', function (args) {
console.log('start', args)
})
}
})
`,
parserOptions,
errors: [{
message: 'The Events api `$on`, `$off` `$once` is deprecated. Using external library instead, for example mitt.',
line: 4
}]
},
{
filename: 'test.js',
code: `
app.component('some-comp', {
mounted () {
this.$off('start')
}
})
`,
parserOptions,
errors: [{
message: 'The Events api `$on`, `$off` `$once` is deprecated. Using external library instead, for example mitt.',
line: 4
}]
},
{
filename: 'test.vue',
code: `
export default {
mounted () {
this.$once('start', function () {
console.log('start')
})
}
}
`,
parserOptions,
errors: [{
message: 'The Events api `$on`, `$off` `$once` is deprecated. Using external library instead, for example mitt.',
line: 4
}]
}
]
})

0 comments on commit 35efedc

Please sign in to comment.