@@ -27,18 +27,30 @@ function isLabelElement(
27
27
return isMatchingElement ( node , allLabelComponents ) ;
28
28
}
29
29
30
- function hasLabelElement (
30
+ function hasNestedLabelElement (
31
31
node : AST . VElement ,
32
32
options : FormControlHasLabelOptions
33
33
) : boolean {
34
34
const { parent } = node ;
35
35
36
- return (
37
- [ parent , ...parent . children ] . some ( ( node ) =>
38
- isLabelElement ( node , options )
39
- ) ||
40
- ( parent && parent . type === "VElement" && hasLabelElement ( parent , options ) )
41
- ) ;
36
+ if ( isLabelElement ( parent , options ) ) {
37
+ return true ;
38
+ }
39
+
40
+ return ( parent && parent . type === "VElement" && hasNestedLabelElement ( parent , options ) ) ;
41
+ }
42
+
43
+ /**
44
+ * Check if the form control at least has an "id" to be associated with a label
45
+ * Can't really check for the label with a matching "for" attribute, because
46
+ * checking every element in the file may lead to bad performance.
47
+ */
48
+ function hasIdForLabelElement (
49
+ node : AST . VElement
50
+ ) : boolean {
51
+ const id = getElementAttributeValue ( node , "id" ) ;
52
+
53
+ return Boolean ( id ) ;
42
54
}
43
55
44
56
const rule : Rule . RuleModule = {
@@ -104,7 +116,8 @@ const rule: Rule.RuleModule = {
104
116
if (
105
117
! isAriaHidden ( node ) &&
106
118
! hasAriaLabel ( node ) &&
107
- ! hasLabelElement ( node , options )
119
+ ! hasNestedLabelElement ( node , options ) &&
120
+ ! hasIdForLabelElement ( node )
108
121
) {
109
122
context . report ( { node : node as any , messageId : "default" } ) ;
110
123
}
0 commit comments