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

Issue:
Label with deeply nested input raises  form-control-has-label error
Hello, 

I am implementing this package on one of my projects but I an running into an issue. I have a radio control component with the following structure:

```html
<label>
  <div>
    <input type="radio" />
  </div>
  <div>
      <slot />
  </div>
</label>
```

I am receiving an error related to the `form-control-has-label` rule, even if the input is correctly wrapped into a label tag.

I am not sure if it's related but in my ESLint config I've also added the following rule:

```
"vuejs-accessibility/label-has-for": [
      1,
      {
        "required": {
          "some": ["nesting", "id"]
        }
      }
    ]
```

Any hint on how to solve this problem? 

Thank you in advance!

Pull request:
Support deeply nested input controls for form-control-has-label
Fixes #12

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a9a77e4..7fade71 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 
 ## [Unreleased]
 
+### Changed
+
+- Support deeply nested `input` controls for the `form-control-has-label` rule.
+
 ## [0.1.2] - 2020-05-11
 
 ### Changed
diff --git a/bin/lint b/bin/lint
new file mode 100755
index 0000000..aee16a0
--- /dev/null
+++ b/bin/lint
@@ -0,0 +1,15 @@
+#!/usr/bin/env node
+
+const { CLIEngine } = require("eslint");
+const a11yPlugin = require("../src");
+
+(async function () {
+  const cli = new CLIEngine({ baseConfig: a11yPlugin.configs.recommended });
+  cli.addPlugin("eslint-plugin-vuejs-accessibility", a11yPlugin);
+
+  const report = cli.executeOnFiles(process.argv.slice(2));
+  console.log(cli.getFormatter()(report.results));
+})().catch((error) => {
+  process.exitCode = 1;
+  console.error(error);
+});
diff --git a/docs/label-has-for.md b/docs/label-has-for.md
index 3dc0007..eeb4637 100644
--- a/docs/label-has-for.md
+++ b/docs/label-has-for.md
@@ -40,7 +40,9 @@ The `required` option (defaults to `"required": { "every": ["nesting", "id"] }`)
 The `allowChildren` option (defaults to `false`) determines whether default slot content is allowed to be passed into a `label` element. For example, the following pattern, by default, is not allowed:
 
 ```vue
-<label>Foo</label>
+<label>
+  <slot />
+</label>
 ```
 
 However, if `allowChildren` is set to `true`, no error will be raised. If you want to pass in default slot content without raising an error because you cannot be sure what the default slot will render, then set `allowChildren` to `true`.
diff --git a/src/rules/form-control-has-label.js b/src/rules/form-control-has-label.js
index b09b89a..2ee4280 100644
--- a/src/rules/form-control-has-label.js
+++ b/src/rules/form-control-has-label.js
@@ -11,7 +11,11 @@ const isLabelElement = (node) =>
 
 const hasLabelElement = (node) => {
   const { parent } = node;
-  return [parent, ...parent.children].some(isLabelElement);
+
+  return (
+    [parent, ...parent.children].some(isLabelElement) ||
+    (parent && parent.type === "VElement" && hasLabelElement(parent))
+  );
 };
 
 module.exports = {


Test patch:
diff --git a/src/rules/__tests__/form-control-has-label.test.js b/src/rules/__tests__/form-control-has-label.test.js
index 15e5524..975b61e 100644
--- a/src/rules/__tests__/form-control-has-label.test.js
+++ b/src/rules/__tests__/form-control-has-label.test.js
@@ -6,7 +6,17 @@ makeRuleTester("form-control-has-label", rule, {
     "<label for=''><input type='text' /></label>",
     "<input type='text' aria-label='test' />",
     "<label for=''>text</label><input type='text' />",
-    "<input type='button'>"
+    "<input type='button'>",
+    `
+      <label>
+        <div>
+          <input type="radio" />
+        </div>
+        <div>
+          <slot />
+        </div>
+      </label>
+    `
   ],
   invalid: ["<input type='text' />", "<textarea type='text'></textarea>"]
 });