diff --git a/lib/util/Components.js b/lib/util/Components.js index 37816a3bd4..a71884b731 100644 --- a/lib/util/Components.js +++ b/lib/util/Components.js @@ -255,9 +255,23 @@ function componentRule(rule, context) { node[property] && node[property].type === 'JSXElement' ; + var destructuredReactCreateElement = function () { + var variables = variableUtil.variablesInScope(context); + var variable = variableUtil.getVariable(variables, 'createElement'); + if (variable) { + var map = variable.scope.set; + if (map.has('React')) { + return true; + } + } + return false; + }; var returnsReactCreateElement = + destructuredReactCreateElement() || node[property] && node[property].callee && + node[property].callee.object && + node[property].callee.object.name === 'React' && node[property].callee.property && node[property].callee.property.name === 'createElement' ; diff --git a/lib/util/variable.js b/lib/util/variable.js index 81ae18d465..6ec67c686e 100644 --- a/lib/util/variable.js +++ b/lib/util/variable.js @@ -11,16 +11,21 @@ * @returns {Boolean} True if the variable was found, false if not. */ function findVariable(variables, name) { - var i; - var len; - - for (i = 0, len = variables.length; i < len; i++) { - if (variables[i].name === name) { - return true; - } - } + return variables.some(function (variable) { + return variable.name === name; + }); +} - return false; +/** + * Find and return a particular variable in a list + * @param {Array} variables The variables list. + * @param {Array} name The name of the variable to search. + * @returns {Object} Variable if the variable was found, null if not. + */ +function getVariable(variables, name) { + return variables.find(function (variable) { + return variable.name === name; + }); } /** @@ -52,5 +57,6 @@ function variablesInScope(context) { module.exports = { findVariable: findVariable, + getVariable: getVariable, variablesInScope: variablesInScope }; diff --git a/tests/lib/rules/display-name.js b/tests/lib/rules/display-name.js index 28ef63d7fa..3f8db25185 100644 --- a/tests/lib/rules/display-name.js +++ b/tests/lib/rules/display-name.js @@ -378,6 +378,19 @@ ruleTester.run('display-name', rule, { ')' ].join('\n'), parser: 'babel-eslint' + }, { + code: [ + 'module.exports = {', + ' createElement: tagName => document.createElement(tagName)', + '};' + ].join('\n'), + parser: 'babel-eslint' + }, { + code: [ + 'const { createElement } = document;', + 'createElement("a");' + ].join('\n'), + parser: 'babel-eslint' }], invalid: [{ @@ -548,5 +561,40 @@ ruleTester.run('display-name', rule, { errors: [{ message: 'Component definition is missing display name' }] + }, { + code: [ + 'import React, { createElement } from "react";', + 'export default (props) => {', + ' return createElement("div", {}, "hello");', + '};' + ].join('\n'), + parser: 'babel-eslint', + errors: [{ + message: 'Component definition is missing display name' + }] + }, { + code: [ + 'import React from "react";', + 'const { createElement } = React;', + 'export default (props) => {', + ' return createElement("div", {}, "hello");', + '};' + ].join('\n'), + parser: 'babel-eslint', + errors: [{ + message: 'Component definition is missing display name' + }] + }, { + code: [ + 'import React from "react";', + 'const createElement = React.createElement;', + 'export default (props) => {', + ' return createElement("div", {}, "hello");', + '};' + ].join('\n'), + parser: 'babel-eslint', + errors: [{ + message: 'Component definition is missing display name' + }] }] });