From 33631a36b1ec6a671d8874b06cbe589cb38a782b Mon Sep 17 00:00:00 2001 From: Armano Date: Tue, 1 Aug 2017 21:08:13 +0200 Subject: [PATCH 1/2] Add new options for `no-duplicate-attributes`. fixes #112 --- docs/rules/no-duplicate-attributes.md | 13 ++++++- lib/rules/no-duplicate-attributes.js | 44 +++++++++++++++++++--- tests/lib/rules/no-duplicate-attributes.js | 30 ++++++++++++--- 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/docs/rules/no-duplicate-attributes.md b/docs/rules/no-duplicate-attributes.md index 12c8d0335..3cf820de6 100644 --- a/docs/rules/no-duplicate-attributes.md +++ b/docs/rules/no-duplicate-attributes.md @@ -27,9 +27,20 @@ This rule reports duplicate attributes. ## :wrench: Options -Nothing. +`allowCoexistClass` - Enables [`v-bind:class`] directive can coexist with the plain `class` attribute. +`allowCoexistStyle` - Enables [`v-bind:style`] directive can coexist with the plain `style` attribute. + +``` +'vue/name-property-casing': [2, { + allowCoexistClass: Boolean // default: true + allowCoexistStyle: Boolean, // default: true +}] +``` ## TODO: `
` `parse5` remove duplicate attributes on the tokenization phase. Needs investigation to check. + +[`v-bind:class`]: https://vuejs.org/v2/guide/class-and-style.html +[`v-bind:style`]: https://vuejs.org/v2/guide/class-and-style.html diff --git a/lib/rules/no-duplicate-attributes.js b/lib/rules/no-duplicate-attributes.js index 65a566fb1..207220bb5 100644 --- a/lib/rules/no-duplicate-attributes.js +++ b/lib/rules/no-duplicate-attributes.js @@ -37,11 +37,27 @@ function getName (attribute) { * @returns {Object} AST event handlers. */ function create (context) { - const names = new Set() + const options = context.options[0] || {} + const allowCoexistStyle = Boolean(options.allowCoexistStyle !== false) + const allowCoexistClass = Boolean(options.allowCoexistClass !== false) + + const directiveNames = new Set() + const attributeNames = new Set() + + function isDuplicate (name) { + if (allowCoexistStyle && name === 'style') { + return directiveNames.has(name) + } + if (allowCoexistClass && name === 'class') { + return directiveNames.has(name) + } + return directiveNames.has(name) || attributeNames.has(name) + } utils.registerTemplateBodyVisitor(context, { 'VStartTag' () { - names.clear() + directiveNames.clear() + attributeNames.clear() }, 'VAttribute' (node) { const name = getName(node) @@ -49,7 +65,7 @@ function create (context) { return } - if (names.has(name)) { + if (isDuplicate(name)) { context.report({ node, loc: node.loc, @@ -57,7 +73,12 @@ function create (context) { data: { name } }) } - names.add(name) + + if (node.directive) { + directiveNames.add(name) + } else { + attributeNames.add(name) + } } }) @@ -77,6 +98,19 @@ module.exports = { recommended: false }, fixable: false, - schema: [] + + schema: [ + { + type: 'object', + properties: { + allowCoexistClass: { + type: 'boolean' + }, + allowCoexistStyle: { + type: 'boolean' + } + } + } + ] } } diff --git a/tests/lib/rules/no-duplicate-attributes.js b/tests/lib/rules/no-duplicate-attributes.js index ba47a7eec..27921415b 100644 --- a/tests/lib/rules/no-duplicate-attributes.js +++ b/tests/lib/rules/no-duplicate-attributes.js @@ -34,14 +34,22 @@ tester.run('no-duplicate-attributes', rule, { { filename: 'test.vue', code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' } ], invalid: [ - // { - // filename: "test.vue", - // code: "", - // errors: ["Duplicate attribute 'foo'."], - // }, + // { + // filename: 'test.vue', + // code: '', + // errors: ["Duplicate attribute 'foo'."] + // }, { filename: 'test.vue', code: '', @@ -51,6 +59,18 @@ tester.run('no-duplicate-attributes', rule, { filename: 'test.vue', code: '', errors: ["Duplicate attribute 'foo'."] + }, + { + filename: 'test.vue', + code: '', + errors: ["Duplicate attribute 'style'."], + options: [{ allowCoexistStyle: false }] + }, + { + filename: 'test.vue', + code: '', + errors: ["Duplicate attribute 'class'."], + options: [{ allowCoexistClass: false }] } ] }) From e36d99bdd098a2921dabab3c1d4d83d2d7006c79 Mon Sep 17 00:00:00 2001 From: Armano Date: Thu, 3 Aug 2017 13:54:19 +0200 Subject: [PATCH 2/2] Improve validating coexist elements --- lib/rules/no-duplicate-attributes.js | 15 ++++++--------- tests/lib/rules/no-duplicate-attributes.js | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/lib/rules/no-duplicate-attributes.js b/lib/rules/no-duplicate-attributes.js index 207220bb5..53b918ed1 100644 --- a/lib/rules/no-duplicate-attributes.js +++ b/lib/rules/no-duplicate-attributes.js @@ -38,18 +38,15 @@ function getName (attribute) { */ function create (context) { const options = context.options[0] || {} - const allowCoexistStyle = Boolean(options.allowCoexistStyle !== false) - const allowCoexistClass = Boolean(options.allowCoexistClass !== false) + const allowCoexistStyle = options.allowCoexistStyle !== false + const allowCoexistClass = options.allowCoexistClass !== false const directiveNames = new Set() const attributeNames = new Set() - function isDuplicate (name) { - if (allowCoexistStyle && name === 'style') { - return directiveNames.has(name) - } - if (allowCoexistClass && name === 'class') { - return directiveNames.has(name) + function isDuplicate (name, isDirective) { + if ((allowCoexistStyle && name === 'style') || (allowCoexistClass && name === 'class')) { + return isDirective ? directiveNames.has(name) : attributeNames.has(name) } return directiveNames.has(name) || attributeNames.has(name) } @@ -65,7 +62,7 @@ function create (context) { return } - if (isDuplicate(name)) { + if (isDuplicate(name, node.directive)) { context.report({ node, loc: node.loc, diff --git a/tests/lib/rules/no-duplicate-attributes.js b/tests/lib/rules/no-duplicate-attributes.js index 27921415b..03cd71c74 100644 --- a/tests/lib/rules/no-duplicate-attributes.js +++ b/tests/lib/rules/no-duplicate-attributes.js @@ -42,6 +42,16 @@ tester.run('no-duplicate-attributes', rule, { { filename: 'test.vue', code: '' + }, + { + filename: 'test.vue', + code: '', + options: [{ allowCoexistStyle: true }] + }, + { + filename: 'test.vue', + code: '', + options: [{ allowCoexistStyle: true }] } ], invalid: [ @@ -71,6 +81,18 @@ tester.run('no-duplicate-attributes', rule, { code: '', errors: ["Duplicate attribute 'class'."], options: [{ allowCoexistClass: false }] + }, + { + filename: 'test.vue', + code: '', + errors: ["Duplicate attribute 'style'."], + options: [{ allowCoexistStyle: false }] + }, + { + filename: 'test.vue', + code: '', + errors: ["Duplicate attribute 'class'."], + options: [{ allowCoexistClass: false }] } ] })