Repository: vue-a11y/eslint-plugin-vuejs-accessibility (ts)

Issue:
label-has-for doesn't report errors if there is no control wrapped inside
I'm using the accessibility plugin, especially the rule `label-has-for`. My configuration looks like the following:

```js
    'vuejs-accessibility/label-has-for': [
      'error',
      { required: { some: ['nesting', 'id'] } },
    ],
```

The problem is that the rule doesn't fire when I use it like that: 

```html
<label>
  <div></div>
</label>
```

It only fires when there is no elements in it:

```html
<label></label>
```

II think the `nesting` validation rule is broken. I took a look at the implementation and I think [this line](https://github.com/vue-a11y/eslint-plugin-vuejs-accessibility/blob/3715f6dbf3eecbd47ccf4530577d7e7a34813166/src/rules/label-has-for.js#L15) is incomplete. It should check if there is a form control inside the children 🙂 

Pull request description:
For the `label-has-for` rule, validate proper nesting
Closes #16 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d48ecb6..6e5010c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 ### Changed
 
 - For the `anchor-has-content` rule, allow anchors with explicit aria labels to pass.
+- For the `label-has-for` rule when validating that there is correct nesting, ensure that we're actually checking for form controls and not just checking for VElement nodes.
 
 ## [0.2.0] - 2020-06-26
 
diff --git a/src/rules/label-has-for.js b/src/rules/label-has-for.js
index 5fd2e18..3b0b363 100644
--- a/src/rules/label-has-for.js
+++ b/src/rules/label-has-for.js
@@ -2,20 +2,38 @@ const {
   defineTemplateBodyVisitor,
   getElementAttributeValue,
   getElementType,
-  hasAccessibleChild,
+  isHiddenFromScreenReader,
   makeDocsURL
 } = require("../utils");
 
-const validate = (node, rule, allowChildren) => {
-  if (allowChildren === true) {
-    return hasAccessibleChild(node);
-  }
+const controlTypes = ["input", "meter", "progress", "select", "textarea"];
 
-  if (rule === "nesting") {
-    return node.children.some((child) => child.type === "VElement");
-  }
+const validateNesting = (node, allowChildren) =>
+  node.children.some((child) => {
+    if (child.rawName === "slot") {
+      return allowChildren;
+    }
+
+    if (child.type === "VElement") {
+      return (
+        !isHiddenFromScreenReader(child) &&
+        (controlTypes.includes(getElementType(child)) ||
+          validateNesting(child, allowChildren))
+      );
+    }
 
-  return getElementAttributeValue(node, "for");
+    return false;
+  });
+
+const validate = (node, rule, allowChildren) => {
+  switch (rule) {
+    case "nesting":
+      return validateNesting(node, allowChildren);
+    case "id":
+      return getElementAttributeValue(node, "for");
+    default:
+      return false;
+  }
 };
 
 const isValidLabel = (node, required, allowChildren) => {


Test patch:
diff --git a/src/rules/__tests__/label-has-for.test.js b/src/rules/__tests__/label-has-for.test.js
index 149e353..25a39a4 100644
--- a/src/rules/__tests__/label-has-for.test.js
+++ b/src/rules/__tests__/label-has-for.test.js
@@ -5,18 +5,21 @@ makeRuleTester("label-has-for", rule, {
   valid: [
     "<label for='id'><input type='text' /></label>",
     "<label :for='id'><input type='text' :id='id' /></label>",
+    "<label for='id'><span><input type='text' /></span></label>",
     {
       code: "<label for='id' /><input type='text' />",
       options: [{ required: { some: ["nesting", "id"] } }]
     },
     {
-      code: "<label>name</label>",
-      options: [{ required: { some: ["nesting", "id"] }, allowChildren: true }]
+      code: "<label for='id'><slot /></label>",
+      options: [{ allowChildren: true }]
     }
   ],
   invalid: [
     "<label for='id' />",
     "<label><input type='text' /></label>",
+    "<label for='id'><slot /></label>",
+    "<label for='id'><div /></label>",
     {
       code: "<Label for='id' />",
       options: [{ components: ["Label"] }],