From cd74105d29d6126d11d710c060bfb52a5e4715b2 Mon Sep 17 00:00:00 2001 From: waynzh Date: Tue, 5 Nov 2024 19:50:51 +0800 Subject: [PATCH 1/7] feat(no-duplicate-attr-inheritance): ignore multi root --- lib/rules/no-duplicate-attr-inheritance.js | 31 ++++++++++++++----- .../rules/no-duplicate-attr-inheritance.js | 9 ++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/lib/rules/no-duplicate-attr-inheritance.js b/lib/rules/no-duplicate-attr-inheritance.js index 654929bd1..77c10c551 100644 --- a/lib/rules/no-duplicate-attr-inheritance.js +++ b/lib/rules/no-duplicate-attr-inheritance.js @@ -26,6 +26,8 @@ module.exports = { create(context) { /** @type {string | number | boolean | RegExp | BigInt | null} */ let inheritsAttrs = true + /** @type {VReference[]} */ + const attrsRefs = [] /** @param {ObjectExpression} node */ function processOptions(node) { @@ -54,7 +56,7 @@ module.exports = { if (!inheritsAttrs) { return } - const attrsRef = node.references.find((reference) => { + const reference = node.references.find((reference) => { if (reference.variable != null) { // Not vm reference return false @@ -62,14 +64,29 @@ module.exports = { return reference.id.name === '$attrs' }) - if (attrsRef) { - context.report({ - node: attrsRef.id, - messageId: 'noDuplicateAttrInheritance' - }) + if (reference) { + attrsRefs.push(reference) } } - }) + }), + { + 'Program:exit'(program) { + const element = program.templateBody + if (element == null) { + return + } + + const rootElements = element.children.filter(utils.isVElement) + if (rootElements.length === 1 && attrsRefs.length > 0) { + for (const attrsRef of attrsRefs) { + context.report({ + node: attrsRef.id, + messageId: 'noDuplicateAttrInheritance' + }) + } + } + } + } ) } } diff --git a/tests/lib/rules/no-duplicate-attr-inheritance.js b/tests/lib/rules/no-duplicate-attr-inheritance.js index e38711a54..1a7671e07 100644 --- a/tests/lib/rules/no-duplicate-attr-inheritance.js +++ b/tests/lib/rules/no-duplicate-attr-inheritance.js @@ -43,6 +43,15 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, { ` }, + { + filename: 'test.vue', + code: ` + + + ` + }, { filename: 'test.vue', code: ` From 9d94342d2155b56c318368cee288b4d3e694fd7d Mon Sep 17 00:00:00 2001 From: waynzh Date: Sat, 9 Nov 2024 23:32:46 +0800 Subject: [PATCH 2/7] feat: check multi root --- lib/rules/no-duplicate-attr-inheritance.js | 42 +++++++++- .../rules/no-duplicate-attr-inheritance.js | 84 +++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) diff --git a/lib/rules/no-duplicate-attr-inheritance.js b/lib/rules/no-duplicate-attr-inheritance.js index 77c10c551..702ab32a4 100644 --- a/lib/rules/no-duplicate-attr-inheritance.js +++ b/lib/rules/no-duplicate-attr-inheritance.js @@ -6,6 +6,43 @@ const utils = require('../utils') +/** @param {VElement[]} elements */ +function isConditionalGroup(elements) { + let hasIf = false + let hasElse = false + + for (const element of elements) { + if (utils.hasDirective(element, 'if')) { + if (hasIf || hasElse) { + return false + } + hasIf = true + } else if (utils.hasDirective(element, 'else-if')) { + if (!hasIf || hasElse) { + return false + } + } else if (utils.hasDirective(element, 'else')) { + if (!hasIf || hasElse) { + return false + } + hasElse = true + } else { + return false + } + } + + return hasIf && (elements.length === 1 || hasElse) +} + +/** @param {VElement[]} elements */ +function isMultiRoot(elements) { + if (elements.length > 1 && !isConditionalGroup(elements)) { + return true + } + + return false +} + module.exports = { meta: { type: 'suggestion', @@ -77,7 +114,10 @@ module.exports = { } const rootElements = element.children.filter(utils.isVElement) - if (rootElements.length === 1 && attrsRefs.length > 0) { + // ignore multi root + if (isMultiRoot(rootElements)) return + + if (attrsRefs.length > 0) { for (const attrsRef of attrsRefs) { context.report({ node: attrsRef.id, diff --git a/tests/lib/rules/no-duplicate-attr-inheritance.js b/tests/lib/rules/no-duplicate-attr-inheritance.js index 1a7671e07..8845bf800 100644 --- a/tests/lib/rules/no-duplicate-attr-inheritance.js +++ b/tests/lib/rules/no-duplicate-attr-inheritance.js @@ -52,6 +52,47 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, { ` }, + // ignore multi root + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, { filename: 'test.vue', code: ` @@ -160,6 +201,49 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, { line: 5 } ] + }, + // single root with a condition group + { + filename: 'test.vue', + code: ` + + `, + errors: [{ message: 'Set "inheritAttrs" to false.' }] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: [{ message: 'Set "inheritAttrs" to false.' }] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: [{ message: 'Set "inheritAttrs" to false.' }] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: [{ message: 'Set "inheritAttrs" to false.' }] } ] }) From b1645d7f05360ab7b2189bfefbb818cc715ba322 Mon Sep 17 00:00:00 2001 From: waynzh Date: Sun, 10 Nov 2024 23:32:29 +0800 Subject: [PATCH 3/7] feat: add option --- lib/rules/no-duplicate-attr-inheritance.js | 21 ++++++++++--- .../rules/no-duplicate-attr-inheritance.js | 30 +++++++++++++++---- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/lib/rules/no-duplicate-attr-inheritance.js b/lib/rules/no-duplicate-attr-inheritance.js index 702ab32a4..e20627f54 100644 --- a/lib/rules/no-duplicate-attr-inheritance.js +++ b/lib/rules/no-duplicate-attr-inheritance.js @@ -35,7 +35,7 @@ function isConditionalGroup(elements) { } /** @param {VElement[]} elements */ -function isMultiRoot(elements) { +function isMultiRootNodes(elements) { if (elements.length > 1 && !isConditionalGroup(elements)) { return true } @@ -54,13 +54,26 @@ module.exports = { url: 'https://eslint.vuejs.org/rules/no-duplicate-attr-inheritance.html' }, fixable: null, - schema: [], + schema: [ + { + type: 'object', + properties: { + checkMultiRootNodes: { + type: 'boolean' + } + }, + additionalProperties: false + } + ], messages: { noDuplicateAttrInheritance: 'Set "inheritAttrs" to false.' } }, /** @param {RuleContext} context */ create(context) { + const options = context.options[0] || {} + const checkMultiRootNodes = options.checkMultiRootNodes === true + /** @type {string | number | boolean | RegExp | BigInt | null} */ let inheritsAttrs = true /** @type {VReference[]} */ @@ -114,8 +127,8 @@ module.exports = { } const rootElements = element.children.filter(utils.isVElement) - // ignore multi root - if (isMultiRoot(rootElements)) return + + if (checkMultiRootNodes && isMultiRootNodes(rootElements)) return if (attrsRefs.length > 0) { for (const attrsRef of attrsRefs) { diff --git a/tests/lib/rules/no-duplicate-attr-inheritance.js b/tests/lib/rules/no-duplicate-attr-inheritance.js index 8845bf800..47ca62b2e 100644 --- a/tests/lib/rules/no-duplicate-attr-inheritance.js +++ b/tests/lib/rules/no-duplicate-attr-inheritance.js @@ -50,7 +50,8 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, { defineOptions({ inheritAttrs: true }) - ` + `, + options: [{ checkMultiRootNodes: true }] }, // ignore multi root { @@ -61,7 +62,8 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, {
- ` + `, + options: [{ checkMultiRootNodes: true }] }, { filename: 'test.vue', @@ -71,7 +73,8 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, {
- ` + `, + options: [{ checkMultiRootNodes: true }] }, { filename: 'test.vue', @@ -81,7 +84,8 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, {
- ` + `, + options: [{ checkMultiRootNodes: true }] }, { filename: 'test.vue', @@ -91,7 +95,8 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, {
- ` + `, + options: [{ checkMultiRootNodes: true }] }, { filename: 'test.vue', @@ -202,6 +207,17 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, { } ] }, + { + filename: 'test.vue', + code: ` + + + `, + options: [{ checkMultiRootNodes: false }], + errors: [{ message: 'Set "inheritAttrs" to false.' }] + }, // single root with a condition group { filename: 'test.vue', @@ -212,6 +228,7 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, {
`, + options: [{ checkMultiRootNodes: true }], errors: [{ message: 'Set "inheritAttrs" to false.' }] }, { @@ -224,6 +241,7 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, {
`, + options: [{ checkMultiRootNodes: true }], errors: [{ message: 'Set "inheritAttrs" to false.' }] }, { @@ -234,6 +252,7 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, {
`, + options: [{ checkMultiRootNodes: true }], errors: [{ message: 'Set "inheritAttrs" to false.' }] }, { @@ -243,6 +262,7 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, {
`, + options: [{ checkMultiRootNodes: true }], errors: [{ message: 'Set "inheritAttrs" to false.' }] } ] From 8694e4d335b2e5fdafaf7879f40f3e4047d93f34 Mon Sep 17 00:00:00 2001 From: waynzh Date: Tue, 12 Nov 2024 15:24:59 +0800 Subject: [PATCH 4/7] feat: update --- docs/rules/no-duplicate-attr-inheritance.md | 35 +++++- lib/rules/no-duplicate-attr-inheritance.js | 2 +- .../rules/no-duplicate-attr-inheritance.js | 115 +++++++++--------- 3 files changed, 90 insertions(+), 62 deletions(-) diff --git a/docs/rules/no-duplicate-attr-inheritance.md b/docs/rules/no-duplicate-attr-inheritance.md index 0f1b60340..7cb34b63d 100644 --- a/docs/rules/no-duplicate-attr-inheritance.md +++ b/docs/rules/no-duplicate-attr-inheritance.md @@ -15,7 +15,7 @@ since: v7.0.0 This rule aims to prevent duplicate attribute inheritance. This rule to warn to apply `inheritAttrs: false` when it detects `v-bind="$attrs"` being used. - + ```vue