Skip to content

Commit 31ef543

Browse files
committed
Add new options for no-duplicate-attributes vuejs#112
1 parent 3361366 commit 31ef543

File tree

3 files changed

+76
-11
lines changed

3 files changed

+76
-11
lines changed

docs/rules/no-duplicate-attributes.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,20 @@ This rule reports duplicate attributes.
2727

2828
## :wrench: Options
2929

30-
Nothing.
30+
`allowCoExistClass` - Enables [`v-bind:class`] directive can co-exist with the plain `class` attribute.
31+
`allowCoExistStyle` - Enables [`v-bind:style`] directive can co-exist with the plain `style` attribute.
32+
33+
```
34+
'vue/name-property-casing': [2, {
35+
allowCoExistClass: Boolean // default: true
36+
allowCoExistStyle: Boolean, // default: true
37+
}]
38+
```
3139

3240
## TODO: `<div foo foo></div>`
3341

3442
`parse5` remove duplicate attributes on the tokenization phase.
3543
Needs investigation to check.
44+
45+
[`v-bind:class`]: https://vuejs.org/v2/guide/class-and-style.html
46+
[`v-bind:style`]: https://vuejs.org/v2/guide/class-and-style.html

lib/rules/no-duplicate-attributes.js

+39-5
Original file line numberDiff line numberDiff line change
@@ -37,27 +37,48 @@ function getName (attribute) {
3737
* @returns {object} AST event handlers.
3838
*/
3939
function create (context) {
40-
const names = new Set()
40+
const options = context.options[0] || {}
41+
const allowCoExistStyle = Boolean(options.allowCoExistStyle !== false)
42+
const allowCoExistClass = Boolean(options.allowCoExistClass !== false)
43+
44+
const directiveNames = new Set()
45+
const attributeNames = new Set()
46+
47+
function isDuplicate (name) {
48+
if (allowCoExistStyle && name === 'style') {
49+
return directiveNames.has(name)
50+
}
51+
if (allowCoExistClass && name === 'class') {
52+
return directiveNames.has(name)
53+
}
54+
return directiveNames.has(name) || attributeNames.has(name)
55+
}
4156

4257
utils.registerTemplateBodyVisitor(context, {
4358
'VStartTag' () {
44-
names.clear()
59+
directiveNames.clear()
60+
attributeNames.clear()
4561
},
4662
'VAttribute' (node) {
4763
const name = getName(node)
4864
if (name == null) {
4965
return
5066
}
5167

52-
if (names.has(name)) {
68+
if (isDuplicate(name)) {
5369
context.report({
5470
node,
5571
loc: node.loc,
5672
message: "Duplicate attribute '{{name}}'.",
5773
data: { name }
5874
})
5975
}
60-
names.add(name)
76+
77+
if (node.directive) {
78+
directiveNames.add(name)
79+
} else {
80+
attributeNames.add(name)
81+
}
6182
}
6283
})
6384

@@ -77,6 +98,19 @@ module.exports = {
7798
recommended: false
7899
},
79100
fixable: false,
80-
schema: []
101+
102+
schema: [
103+
{
104+
type: 'object',
105+
properties: {
106+
allowCoExistClass: {
107+
type: 'boolean'
108+
},
109+
allowCoExistStyle: {
110+
type: 'boolean'
111+
}
112+
}
113+
}
114+
]
81115
}
82116
}

tests/lib/rules/no-duplicate-attributes.js

+25-5
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,22 @@ tester.run('no-duplicate-attributes', rule, {
3434
{
3535
filename: 'test.vue',
3636
code: '<template><div><div @click="foo" @click="bar"></div></div></template>'
37+
},
38+
{
39+
filename: 'test.vue',
40+
code: '<template><div><div style :style></div></div></template>'
41+
},
42+
{
43+
filename: 'test.vue',
44+
code: '<template><div><div class :class></div></div></template>'
3745
}
3846
],
3947
invalid: [
40-
// {
41-
// filename: "test.vue",
42-
// code: "<template><div><div foo foo></div></div></template>",
43-
// errors: ["Duplicate attribute 'foo'."],
44-
// },
48+
// {
49+
// filename: 'test.vue',
50+
// code: '<template><div><div foo foo></div></div></template>',
51+
// errors: ["Duplicate attribute 'foo'."]
52+
// },
4553
{
4654
filename: 'test.vue',
4755
code: '<template><div><div foo v-bind:foo></div></div></template>',
@@ -51,6 +59,18 @@ tester.run('no-duplicate-attributes', rule, {
5159
filename: 'test.vue',
5260
code: '<template><div><div foo :foo></div></div></template>',
5361
errors: ["Duplicate attribute 'foo'."]
62+
},
63+
{
64+
filename: 'test.vue',
65+
code: '<template><div><div style :style></div></div></template>',
66+
errors: ["Duplicate attribute 'style'."],
67+
options: [{ allowCoExistStyle: false }]
68+
},
69+
{
70+
filename: 'test.vue',
71+
code: '<template><div><div class :class></div></div></template>',
72+
errors: ["Duplicate attribute 'class'."],
73+
options: [{ allowCoExistClass: false }]
5474
}
5575
]
5676
})

0 commit comments

Comments
 (0)