diff --git a/lib/rules/v-if-else-key.js b/lib/rules/v-if-else-key.js index 75add9ca0..a83d436b8 100644 --- a/lib/rules/v-if-else-key.js +++ b/lib/rules/v-if-else-key.js @@ -25,6 +25,28 @@ const casing = require('../utils/casing') * @property {VElement | null} else - The node associated with the 'v-else' directive, or null if there isn't one. */ +/** + * Checks if a given node has sibling nodes of the same type that are also conditionally rendered. + * This is used to determine if multiple instances of the same component are being conditionally + * rendered within the same parent scope. + * + * @param {VElement} node - The Vue component node to check for conditional rendering siblings. + * @param {string} componentName - The name of the component to check for sibling instances. + * @returns {boolean} True if there are sibling nodes of the same type and conditionally rendered, false otherwise. + */ +const hasConditionalRenderedSiblings = (node, componentName) => { + if (!node.parent || node.parent.type !== 'VElement') { + return false + } + return node.parent.children.some( + (sibling) => + sibling !== node && + sibling.type === 'VElement' && + sibling.rawName === componentName && + hasConditionalDirective(sibling) + ) +} + /** * Checks for the presence of a 'key' attribute in the given node. If the 'key' attribute is missing * and the node is part of a conditional family a report is generated. @@ -44,26 +66,31 @@ const checkForKey = ( uniqueKey, conditionalFamilies ) => { - if (node.parent && node.parent.type === 'VElement') { - const conditionalFamily = conditionalFamilies.get(node.parent) + if ( + !node.parent || + node.parent.type !== 'VElement' || + !hasConditionalRenderedSiblings(node, componentName) + ) { + return + } - if ( - conditionalFamily && - (utils.hasDirective(node, 'bind', 'key') || - utils.hasAttribute(node, 'key') || - !hasConditionalDirective(node) || - !(conditionalFamily.else || conditionalFamily.elseIf.length > 0)) - ) { - return - } + const conditionalFamily = conditionalFamilies.get(node.parent) + + if (!conditionalFamily || utils.hasAttribute(node, 'key')) { + return + } + + const needsKey = + conditionalFamily.if === node || + conditionalFamily.else === node || + conditionalFamily.elseIf.includes(node) + if (needsKey) { context.report({ node: node.startTag, loc: node.startTag.loc, messageId: 'requireKey', - data: { - componentName - }, + data: { componentName }, fix(fixer) { const afterComponentNamePosition = node.startTag.range[0] + componentName.length + 1 @@ -190,13 +217,18 @@ module.exports = { if (node.parent && node.parent.type === 'VElement') { let conditionalFamily = conditionalFamilies.get(node.parent) - if (conditionType === 'if' && !conditionalFamily) { + if (!conditionalFamily) { conditionalFamily = createConditionalFamily(node) conditionalFamilies.set(node.parent, conditionalFamily) } if (conditionalFamily) { switch (conditionType) { + case 'if': { + conditionalFamily = createConditionalFamily(node) + conditionalFamilies.set(node.parent, conditionalFamily) + break + } case 'else-if': { conditionalFamily.elseIf.push(node) break diff --git a/tests/lib/rules/v-if-else-key.js b/tests/lib/rules/v-if-else-key.js index 16d975a0a..46c42f52f 100644 --- a/tests/lib/rules/v-if-else-key.js +++ b/tests/lib/rules/v-if-else-key.js @@ -127,6 +127,90 @@ tester.run('v-if-else-key', rule, { } ` + }, + { + filename: 'test.vue', + code: ` + + + ` + }, + { + filename: 'test.vue', + code: ` + + + ` + }, + { + filename: 'test.vue', + code: ` + + + ` } ], invalid: [ @@ -424,6 +508,74 @@ tester.run('v-if-else-key', rule, { line: 6 } ] + }, + { + filename: 'test.vue', + code: ` + + + `, + output: ` + + + `, + errors: [ + { + message: + "Conditionally rendered repeated component 'ComponentA' expected to have a 'key' attribute.", + line: 4 + }, + { + message: + "Conditionally rendered repeated component 'ComponentA' expected to have a 'key' attribute.", + line: 5 + }, + { + message: + "Conditionally rendered repeated component 'ComponentA' expected to have a 'key' attribute.", + line: 7 + }, + { + message: + "Conditionally rendered repeated component 'ComponentA' expected to have a 'key' attribute.", + line: 8 + }, + { + message: + "Conditionally rendered repeated component 'ComponentA' expected to have a 'key' attribute.", + line: 9 + } + ] } ] }) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy