@@ -25,6 +25,33 @@ const casing = require('../utils/casing')
25
25
* @property {VElement | null } else - The node associated with the 'v-else' directive, or null if there isn't one.
26
26
*/
27
27
28
+ /**
29
+ * Checks if a given node has sibling nodes of the same type that are also conditionally rendered.
30
+ * This is used to determine if multiple instances of the same component are being conditionally
31
+ * rendered within the same parent scope.
32
+ *
33
+ * @param {VElement } node - The Vue component node to check for conditional rendering siblings.
34
+ * @param {string } componentName - The name of the component to check for sibling instances.
35
+ * @returns {boolean } True if there are sibling nodes of the same type and conditionally rendered, false otherwise.
36
+ */
37
+ const hasConditionalRenderedSiblings = ( node , componentName ) => {
38
+ if ( node . parent && node . parent . type === 'VElement' ) {
39
+ const siblings = node . parent . children . filter (
40
+ ( child ) => child . type === 'VElement'
41
+ )
42
+
43
+ return siblings . some (
44
+ ( sibling ) =>
45
+ sibling !== node &&
46
+ sibling . type === 'VElement' &&
47
+ sibling . rawName === componentName &&
48
+ hasConditionalDirective ( sibling )
49
+ )
50
+ }
51
+
52
+ return false
53
+ }
54
+
28
55
/**
29
56
* Checks for the presence of a 'key' attribute in the given node. If the 'key' attribute is missing
30
57
* and the node is part of a conditional family a report is generated.
@@ -44,35 +71,39 @@ const checkForKey = (
44
71
uniqueKey ,
45
72
conditionalFamilies
46
73
) => {
47
- if ( node . parent && node . parent . type === 'VElement' ) {
74
+ if (
75
+ node . parent &&
76
+ node . parent . type === 'VElement' &&
77
+ hasConditionalRenderedSiblings ( node , componentName )
78
+ ) {
48
79
const conditionalFamily = conditionalFamilies . get ( node . parent )
49
80
50
- if (
51
- conditionalFamily &&
52
- ( utils . hasDirective ( node , 'bind' , 'key' ) ||
53
- utils . hasAttribute ( node , 'key' ) ||
54
- ! hasConditionalDirective ( node ) ||
55
- ! ( conditionalFamily . else || conditionalFamily . elseIf . length > 0 ) )
56
- ) {
57
- return
58
- }
81
+ if ( conditionalFamily && ! utils . hasAttribute ( node , 'key' ) ) {
82
+ let needsKey = false
59
83
60
- context . report ( {
61
- node : node . startTag ,
62
- loc : node . startTag . loc ,
63
- messageId : 'requireKey' ,
64
- data : {
65
- componentName
66
- } ,
67
- fix ( fixer ) {
68
- const afterComponentNamePosition =
69
- node . startTag . range [ 0 ] + componentName . length + 1
70
- return fixer . insertTextBeforeRange (
71
- [ afterComponentNamePosition , afterComponentNamePosition ] ,
72
- ` key="${ uniqueKey } "`
73
- )
84
+ if ( node === conditionalFamily . if || node === conditionalFamily . else ) {
85
+ needsKey = true
86
+ } else if ( conditionalFamily . elseIf . includes ( node ) ) {
87
+ needsKey = true
74
88
}
75
- } )
89
+
90
+ if ( needsKey ) {
91
+ context . report ( {
92
+ node : node . startTag ,
93
+ loc : node . startTag . loc ,
94
+ messageId : 'requireKey' ,
95
+ data : { componentName } ,
96
+ fix ( fixer ) {
97
+ const afterComponentNamePosition =
98
+ node . startTag . range [ 0 ] + componentName . length + 1
99
+ return fixer . insertTextBeforeRange (
100
+ [ afterComponentNamePosition , afterComponentNamePosition ] ,
101
+ ` key="${ uniqueKey } "`
102
+ )
103
+ }
104
+ } )
105
+ }
106
+ }
76
107
}
77
108
}
78
109
0 commit comments