Skip to content

Changed vue/no-deprecated-dollar-listeners-api and vue/no-deprecated-events-api rules to track the this variable. #1143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions lib/rules/no-deprecated-dollar-listeners-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,19 @@ module.exports = {
},
utils.defineVueVisitor(context,
{
'MemberExpression > ThisExpression' (node) {
if (node.parent.property.name !== '$listeners') return
'MemberExpression' (node) {
if (
node.property.type !== 'Identifier' ||
node.property.name !== '$listeners'
) {
return
}
if (!utils.isThis(node.object, context)) {
return
}

context.report({
node: node.parent.property,
node: node.property,
messageId: 'deprecated'
})
}
Expand Down
16 changes: 13 additions & 3 deletions lib/rules/no-deprecated-events-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,21 @@ module.exports = {
create (context) {
return utils.defineVueVisitor(context,
{
'CallExpression > MemberExpression > ThisExpression' (node) {
if (!['$on', '$off', '$once'].includes(node.parent.property.name)) return
'CallExpression > MemberExpression' (node) {
const call = node.parent
if (
call.callee !== node ||
node.property.type !== 'Identifier' ||
!['$on', '$off', '$once'].includes(node.property.name)
) {
return
}
if (!utils.isThis(node.object, context)) {
return
}

context.report({
node: node.parent.parent,
node: node.property,
messageId: 'noDeprecatedEventsApi'
})
}
Expand Down
3 changes: 1 addition & 2 deletions lib/rules/require-explicit-emits.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,7 @@ module.exports = {

// verify $emit
if (emit && emit.name === '$emit') {
const objectType = emit.member.object.type
if (objectType === 'Identifier' || objectType === 'ThisExpression') {
if (utils.isThis(emit.member.object, context)) {
// verify this.$emit()
verify(emitsDeclarations, nameLiteralNode, vueNode)
}
Expand Down
30 changes: 29 additions & 1 deletion lib/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const VOID_ELEMENT_NAMES = new Set(require('./void-elements.json'))
const assert = require('assert')
const path = require('path')
const vueEslintParser = require('vue-eslint-parser')
const { findVariable } = require('eslint-utils')

/**
* @type { WeakMap<RuleContext, Token[]> }
Expand Down Expand Up @@ -855,7 +856,34 @@ module.exports = {
* @param {T} node
* @return {T}
*/
unwrapTypes
unwrapTypes,

/**
* Check whether the given node is `this` or variable that stores `this`.
* @param {ASTNode} node The node to check
* @returns {boolean} `true` if the given node is `this`.
*/
isThis (node, context) {
if (node.type === 'ThisExpression') {
return true
}
if (node.type !== 'Identifier') {
return false
}
const variable = findVariable(context.getScope(), node)

if (variable != null && variable.defs.length === 1) {
const def = variable.defs[0]
if (
def.parent &&
def.parent.kind === 'const' &&
def.node.id.type === 'Identifier'
) {
return def.node && def.node.init && def.node.init.type === 'ThisExpression'
}
}
return false
}
}

/**
Expand Down
62 changes: 62 additions & 0 deletions tests/lib/rules/no-deprecated-dollar-listeners-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,21 @@ ruleTester.run('no-deprecated-dollar-listeners-api', rule, {
}
</script>
`
},
{
filename: 'test.vue',
code: `
<script>
export default {
computed: {
foo () {
const {vm} = this
return vm.$listeners
}
}
}
</script>
`
}
],

Expand Down Expand Up @@ -179,6 +194,53 @@ ruleTester.run('no-deprecated-dollar-listeners-api', rule, {
endColumn: 33
}
]
},
{
filename: 'test.vue',
code: `
<script>
export default {
computed: {
foo () {
const vm = this
return vm.$listeners
}
}
}
</script>
`,
errors: [
{
line: 7,
column: 25,
messageId: 'deprecated'
}
]
},
{
filename: 'test.vue',
code: `
<script>
export default {
computed: {
foo () {
const vm = this
function fn() {
return vm.$listeners
}
return fn()
}
}
}
</script>
`,
errors: [
{
line: 8,
column: 27,
messageId: 'deprecated'
}
]
}
]
})
29 changes: 29 additions & 0 deletions tests/lib/rules/no-deprecated-events-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ ruleTester.run('no-deprecated-events-api', rule, {
}
`,
parserOptions
},
{
filename: 'test.vue',
code: `
export default {
mounted () {
a(this.$on)
}
}
`,
parserOptions
}
],

Expand Down Expand Up @@ -155,6 +166,24 @@ ruleTester.run('no-deprecated-events-api', rule, {
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 () {
const vm = this
vm.$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: 5
}]
}
]
})