Repository: yannickcr/eslint-plugin-react (js)

Issue:
False positives on "Declare only one React component per file" (react/no-multi-comp)
```js
import test from "jest-ava-api"
import React, { createElement } from "react"
import { createRenderer } from "react-addons-test-utils"

const renderer = (...args) => { // I guess this is detected as a component
  const render = createRenderer()
  render.render(...args)
  return render.getRenderOutput()
}

test("what", () => {
  return {
    isActive: () => false, // what?
  }
})
```

react/no-multi-comp is detecting 2 components here since I get a warning on the last () => false.
Both are wrong.

Ps: the code does not make sense as it is as I removed some part to make the debugging more easy.

Not that if I does not import createElement, the error seems to disappear  (but I need this...)

Pull request:
Bug fix for false positives with no-multi-comp
Previously, when createElement was destructured from React, it would
cause any function defined in the file to be flagged as a React
Component. This change makes it such that the function must call
createElement to be considered a component.

Fixes #1088 

---
Source of bug:
https://github.com/yannickcr/eslint-plugin-react/commit/416deff06d90b100f991bfbf86f7484061dca0d2#diff-bafb3355a409c4ba076a9e3d609ad65bR294

Note: Not sure if this is the best place for this test. I feel like component detection testing should have its own place where it happens. It seems like you have to run the whole test suite to see if Components are still being detected correctly. Thankfully the whole test suite runs fairly quickly.

Patch:
diff --git a/lib/util/Components.js b/lib/util/Components.js
index 1eacf099..688a87df 100644
--- a/lib/util/Components.js
+++ b/lib/util/Components.js
@@ -237,7 +237,7 @@ function componentRule(rule, context) {
      * @returns {Boolean} True if React.createElement called
      */
     isReactCreateElement: function(node) {
-      return (
+      var calledOnReact = (
         node &&
         node.callee &&
         node.callee.object &&
@@ -245,6 +245,17 @@ function componentRule(rule, context) {
         node.callee.property &&
         node.callee.property.name === 'createElement'
       );
+
+      var calledDirectly = (
+        node &&
+        node.callee &&
+        node.callee.name === 'createElement'
+      );
+
+      if (this.hasDestructuredReactCreateElement()) {
+        return calledDirectly || calledOnReact;
+      }
+      return calledOnReact;
     },
 
     /**
@@ -290,10 +301,7 @@ function componentRule(rule, context) {
         node[property] &&
         node[property].type === 'JSXElement'
       ;
-      var returnsReactCreateElement =
-        this.hasDestructuredReactCreateElement() ||
-        this.isReactCreateElement(node[property])
-      ;
+      var returnsReactCreateElement = this.isReactCreateElement(node[property]);
 
       return Boolean(
         returnsConditionalJSX ||


Test patch:
diff --git a/tests/lib/rules/no-multi-comp.js b/tests/lib/rules/no-multi-comp.js
index bbf2f32d..747538e2 100644
--- a/tests/lib/rules/no-multi-comp.js
+++ b/tests/lib/rules/no-multi-comp.js
@@ -10,6 +10,7 @@
 
 var rule = require('../../../lib/rules/no-multi-comp');
 var RuleTester = require('eslint').RuleTester;
+var assign = require('object.assign');
 
 var parserOptions = {
   ecmaVersion: 6,
@@ -89,6 +90,21 @@ ruleTester.run('no-multi-comp', rule, {
     options: [{
       ignoreStateless: true
     }]
+  }, {
+    // multiple non-components
+    code: [
+      'import React, { createElement } from "react"',
+      'const helperFoo = () => {',
+      '  return true;',
+      '};',
+      'function helperBar() {',
+      '  return false;',
+      '};',
+      'function RealComponent() {',
+      '  return createElement("img");',
+      '};'
+    ].join('\n'),
+    parserOptions: assign({sourceType: 'module'}, parserOptions)
   }],
 
   invalid: [{