Skip to content

Commit 8148833

Browse files
authored
[Fix] Update void-dom-elements-no-children createElement checks
Merge pull request jsx-eslint#1080 from jomasti/issue-1073
2 parents c45ab86 + 416deff commit 8148833

File tree

3 files changed

+98
-22
lines changed

3 files changed

+98
-22
lines changed

lib/rules/void-dom-elements-no-children.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
var find = require('array.prototype.find');
99
var has = require('has');
1010

11+
var Components = require('../util/Components');
12+
1113
// ------------------------------------------------------------------------------
1214
// Helpers
1315
// ------------------------------------------------------------------------------
@@ -55,7 +57,7 @@ module.exports = {
5557
schema: []
5658
},
5759

58-
create: function(context) {
60+
create: Components.detect(function(context, components, utils) {
5961
return {
6062
JSXElement: function(node) {
6163
var elementName = node.openingElement.name.name;
@@ -93,11 +95,11 @@ module.exports = {
9395
},
9496

9597
CallExpression: function(node) {
96-
if (node.callee.type !== 'MemberExpression') {
98+
if (node.callee.type !== 'MemberExpression' && node.callee.type !== 'Identifier') {
9799
return;
98100
}
99101

100-
if (node.callee.property.name !== 'createElement') {
102+
if (!utils.hasDestructuredReactCreateElement() && !utils.isReactCreateElement(node)) {
101103
return;
102104
}
103105

@@ -109,6 +111,10 @@ module.exports = {
109111
return;
110112
}
111113

114+
if (args.length < 2) {
115+
return;
116+
}
117+
112118
var firstChild = args[2];
113119
if (firstChild) {
114120
// e.g. React.createElement('br', undefined, 'Foo')
@@ -137,5 +143,5 @@ module.exports = {
137143
}
138144
}
139145
};
140-
}
146+
})
141147
};

lib/util/Components.js

+36-18
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,40 @@ function componentRule(rule, context) {
213213
return false;
214214
},
215215

216+
/**
217+
* Check if createElement is destructured from React import
218+
*
219+
* @returns {Boolean} True if createElement is destructured from React
220+
*/
221+
hasDestructuredReactCreateElement: function() {
222+
var variables = variableUtil.variablesInScope(context);
223+
var variable = variableUtil.getVariable(variables, 'createElement');
224+
if (variable) {
225+
var map = variable.scope.set;
226+
if (map.has('React')) {
227+
return true;
228+
}
229+
}
230+
return false;
231+
},
232+
233+
/**
234+
* Checks to see if node is called within React.createElement
235+
*
236+
* @param {ASTNode} node The AST node being checked.
237+
* @returns {Boolean} True if React.createElement called
238+
*/
239+
isReactCreateElement: function(node) {
240+
return (
241+
node &&
242+
node.callee &&
243+
node.callee.object &&
244+
node.callee.object.name === 'React' &&
245+
node.callee.property &&
246+
node.callee.property.name === 'createElement'
247+
);
248+
},
249+
216250
/**
217251
* Check if the node is returning JSX
218252
*
@@ -256,25 +290,9 @@ function componentRule(rule, context) {
256290
node[property] &&
257291
node[property].type === 'JSXElement'
258292
;
259-
var destructuredReactCreateElement = function () {
260-
var variables = variableUtil.variablesInScope(context);
261-
var variable = variableUtil.getVariable(variables, 'createElement');
262-
if (variable) {
263-
var map = variable.scope.set;
264-
if (map.has('React')) {
265-
return true;
266-
}
267-
}
268-
return false;
269-
};
270293
var returnsReactCreateElement =
271-
destructuredReactCreateElement() ||
272-
node[property] &&
273-
node[property].callee &&
274-
node[property].callee.object &&
275-
node[property].callee.object.name === 'React' &&
276-
node[property].callee.property &&
277-
node[property].callee.property.name === 'createElement'
294+
this.hasDestructuredReactCreateElement() ||
295+
this.isReactCreateElement(node[property])
278296
;
279297

280298
return Boolean(

tests/lib/rules/void-dom-elements-no-children.js

+52
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,28 @@ ruleTester.run('void-dom-elements-no-children', rule, {
5454
{
5555
code: 'React.createElement("div", { dangerouslySetInnerHTML: { __html: "Foo" } });',
5656
parserOptions: parserOptions
57+
}, {
58+
code: 'document.createElement("img")',
59+
parserOptions: parserOptions
60+
}, {
61+
code: 'React.createElement("img");',
62+
parserOptions: parserOptions
63+
}, {
64+
code: [
65+
'import React from "react";',
66+
'const { createElement } = React;',
67+
'createElement("div")'
68+
].join('\n'),
69+
parser: 'babel-eslint',
70+
parserOptions: parserOptions
71+
}, {
72+
code: [
73+
'import React from "react";',
74+
'const { createElement } = React;',
75+
'createElement("img")'
76+
].join('\n'),
77+
parser: 'babel-eslint',
78+
parserOptions: parserOptions
5779
}
5880
],
5981
invalid: [
@@ -91,6 +113,36 @@ ruleTester.run('void-dom-elements-no-children', rule, {
91113
code: 'React.createElement("br", { dangerouslySetInnerHTML: { __html: "Foo" } });',
92114
errors: [{message: errorMessage('br')}],
93115
parserOptions: parserOptions
116+
},
117+
{
118+
code: [
119+
'import React from "react";',
120+
'const createElement = React.createElement;',
121+
'createElement("img", {}, "Foo");'
122+
].join('\n'),
123+
errors: [{message: errorMessage('img')}],
124+
parser: 'babel-eslint',
125+
parserOptions: parserOptions
126+
},
127+
{
128+
code: [
129+
'import React from "react";',
130+
'const createElement = React.createElement;',
131+
'createElement("img", { children: "Foo" });'
132+
].join('\n'),
133+
errors: [{message: errorMessage('img')}],
134+
parser: 'babel-eslint',
135+
parserOptions: parserOptions
136+
},
137+
{
138+
code: [
139+
'import React from "react";',
140+
'const createElement = React.createElement;',
141+
'createElement("img", { dangerouslySetInnerHTML: { __html: "Foo" } });'
142+
].join('\n'),
143+
errors: [{message: errorMessage('img')}],
144+
parser: 'babel-eslint',
145+
parserOptions: parserOptions
94146
}
95147
]
96148
});

0 commit comments

Comments
 (0)