Skip to content
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

Add rule use-v-on-exact #271 #602

Merged
merged 3 commits into from
Oct 20, 2018
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
27 changes: 27 additions & 0 deletions docs/rules/use-v-on-extact.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Enforce usage of `exact` modifier on `v-on`

- :gear: This rule is included in `"plugin:vue/essential"`.

This rule enforce usage of `exact` modifier on `v-on` when there is another `v-on` with modifier.

:+1: Examples of **correct** code for this rule:

```html
<template>
<button @click="foo" :click="foo"></button>
<button v-on:click.exact="foo" v-on:click.ctrl="foo"></button>
</template>
```

:-1: Examples of **incorrect** code for this rule:

```html
<template>
<button v-on:click="foo" v-on:click.ctrl="foo"></button>
</template>
```

## Related rules

- [vue/v-on-style](./v-on-style.md)
- [vue/valid-v-on](./valid-v-on.md)
65 changes: 65 additions & 0 deletions lib/rules/use-v-on-exact.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* @fileoverview enforce usage of `exact` modifier on `v-on`.
* @author Armano
*/
'use strict'

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

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

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

module.exports = {
meta: {
docs: {
description: 'enforce usage of `exact` modifier on `v-on`',
category: undefined, // essential
url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v5.0.0-beta.3/docs/rules/use-v-on-exact.md'
},
fixable: null,
schema: []
},

/**
* Creates AST event handlers for use-v-on-exact.
*
* @param {RuleContext} context - The rule context.
* @returns {Object} AST event handlers.
*/
create (context) {
return utils.defineTemplateBodyVisitor(context, {
VStartTag (node) {
if (node.attributes.length > 1) {
const groups = node.attributes
.map(item => item.key)
.filter(item => item && item.type === 'VDirectiveKey' && item.name === 'on')
.reduce((rv, item) => {
(rv[item.argument] = rv[item.argument] || []).push(item)
return rv
}, {})

const directives = Object.keys(groups).map(key => groups[key])
// const directives = Object.values(groups) // Uncomment after node 6 is dropped
.filter(item => item.length > 1)
for (const group of directives) {
if (group.some(item => item.modifiers.length > 0)) { // check if there are directives with modifiers
const invalid = group.filter(item => item.modifiers.length === 0)
for (const node of invalid) {
context.report({
node,
loc: node.loc,
message: "Consider to use '.exact' modifier."
})
}
}
}
}
}
})
}
}
75 changes: 75 additions & 0 deletions tests/lib/rules/use-v-on-exact.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* @fileoverview enforce usage of `exact` modifier on `v-on`.
* @author Armano
*/
'use strict'

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

const rule = require('../../../lib/rules/use-v-on-exact')

const RuleTester = require('eslint').RuleTester

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

const ruleTester = new RuleTester({
parser: 'vue-eslint-parser',
parserOptions: { ecmaVersion: 2015 }
})

ruleTester.run('use-v-on-exact', rule, {

valid: [
{
code: `<template><button @click="foo"/></template>`
},
{
code: `<template><button @click="foo" :click="foo"/></template>`
},
{
code: `<template><button @click.ctrl="foo"/></template>`
},
{
code: `<template><button @click.exact="foo"/></template>`
},
{
code: `<template><button @click.exact="foo" @click.ctrl="foo"/></template>`
},
{
code: `<template><button v-on:click="foo"/></template>`
},
{
code: `<template><button v-on:click.ctrl="foo"/></template>`
},
{
code: `<template><button v-on:click.exact="foo"/></template>`
},
{
code: `<template><button v-on:click.exact="foo" v-on:click.ctrl="foo"/></template>`
},
{
code: `<template><button @click="foo" @focus="foo"/></template>`
},
{
code: `<template><button @click="foo" @click="foo"/></template>`
},
{
code: `<template><button @click="foo"/><button @click.ctrl="foo"/></template>`
}
],

invalid: [
{
code: `<template><button @click="foo" @click.ctrl="foo"/></template>`,
errors: ["Consider to use '.exact' modifier."]
},
{
code: `<template><button @click="foo" @focus="foo" @click.ctrl="foo"/></template>`,
errors: ["Consider to use '.exact' modifier."]
}
]
})