Skip to content

Commit 7c574f4

Browse files
armano2mysticatea
authored andcommitted
New: use-v-on-exact rule (fixes #271) (#602)
1 parent 45be306 commit 7c574f4

File tree

3 files changed

+167
-0
lines changed

3 files changed

+167
-0
lines changed

Diff for: docs/rules/use-v-on-extact.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Enforce usage of `exact` modifier on `v-on`
2+
3+
- :gear: This rule is included in `"plugin:vue/essential"`.
4+
5+
This rule enforce usage of `exact` modifier on `v-on` when there is another `v-on` with modifier.
6+
7+
:+1: Examples of **correct** code for this rule:
8+
9+
```html
10+
<template>
11+
<button @click="foo" :click="foo"></button>
12+
<button v-on:click.exact="foo" v-on:click.ctrl="foo"></button>
13+
</template>
14+
```
15+
16+
:-1: Examples of **incorrect** code for this rule:
17+
18+
```html
19+
<template>
20+
<button v-on:click="foo" v-on:click.ctrl="foo"></button>
21+
</template>
22+
```
23+
24+
## Related rules
25+
26+
- [vue/v-on-style](./v-on-style.md)
27+
- [vue/valid-v-on](./valid-v-on.md)

Diff for: lib/rules/use-v-on-exact.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @fileoverview enforce usage of `exact` modifier on `v-on`.
3+
* @author Armano
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+
docs: {
20+
description: 'enforce usage of `exact` modifier on `v-on`',
21+
category: undefined, // essential
22+
url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v5.0.0-beta.3/docs/rules/use-v-on-exact.md'
23+
},
24+
fixable: null,
25+
schema: []
26+
},
27+
28+
/**
29+
* Creates AST event handlers for use-v-on-exact.
30+
*
31+
* @param {RuleContext} context - The rule context.
32+
* @returns {Object} AST event handlers.
33+
*/
34+
create (context) {
35+
return utils.defineTemplateBodyVisitor(context, {
36+
VStartTag (node) {
37+
if (node.attributes.length > 1) {
38+
const groups = node.attributes
39+
.map(item => item.key)
40+
.filter(item => item && item.type === 'VDirectiveKey' && item.name === 'on')
41+
.reduce((rv, item) => {
42+
(rv[item.argument] = rv[item.argument] || []).push(item)
43+
return rv
44+
}, {})
45+
46+
const directives = Object.keys(groups).map(key => groups[key])
47+
// const directives = Object.values(groups) // Uncomment after node 6 is dropped
48+
.filter(item => item.length > 1)
49+
for (const group of directives) {
50+
if (group.some(item => item.modifiers.length > 0)) { // check if there are directives with modifiers
51+
const invalid = group.filter(item => item.modifiers.length === 0)
52+
for (const node of invalid) {
53+
context.report({
54+
node,
55+
loc: node.loc,
56+
message: "Consider to use '.exact' modifier."
57+
})
58+
}
59+
}
60+
}
61+
}
62+
}
63+
})
64+
}
65+
}

Diff for: tests/lib/rules/use-v-on-exact.js

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* @fileoverview enforce usage of `exact` modifier on `v-on`.
3+
* @author Armano
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const rule = require('../../../lib/rules/use-v-on-exact')
12+
13+
const RuleTester = require('eslint').RuleTester
14+
15+
// ------------------------------------------------------------------------------
16+
// Tests
17+
// ------------------------------------------------------------------------------
18+
19+
const ruleTester = new RuleTester({
20+
parser: 'vue-eslint-parser',
21+
parserOptions: { ecmaVersion: 2015 }
22+
})
23+
24+
ruleTester.run('use-v-on-exact', rule, {
25+
26+
valid: [
27+
{
28+
code: `<template><button @click="foo"/></template>`
29+
},
30+
{
31+
code: `<template><button @click="foo" :click="foo"/></template>`
32+
},
33+
{
34+
code: `<template><button @click.ctrl="foo"/></template>`
35+
},
36+
{
37+
code: `<template><button @click.exact="foo"/></template>`
38+
},
39+
{
40+
code: `<template><button @click.exact="foo" @click.ctrl="foo"/></template>`
41+
},
42+
{
43+
code: `<template><button v-on:click="foo"/></template>`
44+
},
45+
{
46+
code: `<template><button v-on:click.ctrl="foo"/></template>`
47+
},
48+
{
49+
code: `<template><button v-on:click.exact="foo"/></template>`
50+
},
51+
{
52+
code: `<template><button v-on:click.exact="foo" v-on:click.ctrl="foo"/></template>`
53+
},
54+
{
55+
code: `<template><button @click="foo" @focus="foo"/></template>`
56+
},
57+
{
58+
code: `<template><button @click="foo" @click="foo"/></template>`
59+
},
60+
{
61+
code: `<template><button @click="foo"/><button @click.ctrl="foo"/></template>`
62+
}
63+
],
64+
65+
invalid: [
66+
{
67+
code: `<template><button @click="foo" @click.ctrl="foo"/></template>`,
68+
errors: ["Consider to use '.exact' modifier."]
69+
},
70+
{
71+
code: `<template><button @click="foo" @focus="foo" @click.ctrl="foo"/></template>`,
72+
errors: ["Consider to use '.exact' modifier."]
73+
}
74+
]
75+
})

0 commit comments

Comments
 (0)