Skip to content

Commit 17120df

Browse files
committed
Make no-danger-with-children deal with props that are variables (Fixes jsx-eslint#767)
1 parent b0747ea commit 17120df

File tree

2 files changed

+104
-25
lines changed

2 files changed

+104
-25
lines changed

lib/rules/no-danger-with-children.js

+53-25
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*/
55
'use strict';
66

7+
var variableUtil = require('../util/variable');
8+
79
// ------------------------------------------------------------------------------
810
// Rule Definition
911
// ------------------------------------------------------------------------------
@@ -17,31 +19,53 @@ module.exports = {
1719
schema: [] // no options
1820
},
1921
create: function(context) {
22+
/**
23+
* Takes a ObjectExpression and returns the value of the prop if it has it
24+
* @param {object} node - ObjectExpression node
25+
* @param {string} propName - name of the prop to look for
26+
*/
27+
function findObjectProp(node, propName) {
28+
return node.properties.find(function(prop) {
29+
return prop.key.name === propName;
30+
});
31+
}
32+
33+
/**
34+
* Takes a JSXElement and returns the value of the prop if it has it
35+
* @param {object} node - JSXElement node
36+
* @param {string} propName - name of the prop to look for
37+
*/
38+
function findJsxProp(node, propName) {
39+
var attributes = node.openingElement.attributes;
40+
return attributes.find(function (attribute) {
41+
if (attribute.type === 'JSXSpreadAttribute') {
42+
var variable = variableUtil.variablesInScope(context).find(function (item) {
43+
return item.name === attribute.argument.name;
44+
});
45+
if (variable && variable.defs[0].node.init) {
46+
return findObjectProp(variable.defs[0].node.init, propName);
47+
}
48+
}
49+
return attribute.name && attribute.name.name === propName;
50+
});
51+
}
52+
2053
return {
2154
JSXElement: function (node) {
2255
var hasChildren = false;
23-
var attributes = node.openingElement.attributes;
2456

2557
if (node.children.length) {
2658
hasChildren = true;
27-
} else {
28-
var childrenProp = attributes.find(function (attribute) {
29-
return attribute.name.name === 'children';
30-
});
31-
if (childrenProp) {
32-
hasChildren = true;
33-
}
59+
} else if (findJsxProp(node, 'children')) {
60+
hasChildren = true;
3461
}
3562

36-
if (attributes && hasChildren) {
37-
var jsxElement = attributes.find(function (attribute) {
38-
return attribute.name.name === 'dangerouslySetInnerHTML';
39-
});
40-
41-
42-
if (jsxElement) {
43-
context.report(node, 'Only set one of `children` or `props.dangerouslySetInnerHTML`');
44-
}
63+
if (
64+
node.openingElement.attributes
65+
&& hasChildren
66+
&& findJsxProp(node, 'dangerouslySetInnerHTML')
67+
) {
68+
context.report(node, 'Only set one of `children` or `props.dangerouslySetInnerHTML`');
4569
}
4670
},
4771
CallExpression: function (node) {
@@ -53,17 +77,21 @@ module.exports = {
5377
) {
5478
var hasChildren = false;
5579

56-
var props = node.arguments[1].properties;
57-
var dangerously = props.find(function(prop) {
58-
return prop.key.name === 'dangerouslySetInnerHTML';
59-
});
80+
var props = node.arguments[1];
6081

82+
if (props.type === 'Identifier') {
83+
var variable = variableUtil.variablesInScope(context).find(function (item) {
84+
return item.name === props.name;
85+
});
86+
if (variable && variable.defs[0].node.init) {
87+
props = variable.defs[0].node.init;
88+
}
89+
}
90+
91+
var dangerously = findObjectProp(props, 'dangerouslySetInnerHTML');
6192

6293
if (node.arguments.length === 2) {
63-
var childrenProp = props.find(function(prop) {
64-
return prop.key.name === 'children';
65-
});
66-
if (childrenProp) {
94+
if (findObjectProp(props, 'children')) {
6795
hasChildren = true;
6896
}
6997
} else {

tests/lib/rules/no-danger-with-children.js

+51
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,24 @@ ruleTester.run('no-danger-with-children', rule, {
3333
code: '<div dangerouslySetInnerHTML={{ __html: "HTML" }} />',
3434
parserOptions: parserOptions
3535
},
36+
{
37+
code: '<div children="Children" />',
38+
parserOptions: parserOptions
39+
},
40+
{
41+
code: [
42+
'const props = { dangerouslySetInnerHTML: { __html: "HTML" } };',
43+
'<div {...props} />'
44+
].join('\n'),
45+
parserOptions: parserOptions
46+
},
47+
{
48+
code: [
49+
'const props = { children: "Children" };',
50+
'<div {...props} />'
51+
].join('\n'),
52+
parserOptions: parserOptions
53+
},
3654
{
3755
code: '<Hello>Children</Hello>',
3856
parserOptions: parserOptions
@@ -73,6 +91,23 @@ ruleTester.run('no-danger-with-children', rule, {
7391
errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
7492
parserOptions: parserOptions
7593
},
94+
{
95+
code: [
96+
'const props = { dangerouslySetInnerHTML: { __html: "HTML" } };',
97+
'<div {...props}>Children</div>'
98+
].join('\n'),
99+
errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
100+
parserOptions: parserOptions
101+
},
102+
{
103+
code: [
104+
'const props = { children: "Children", dangerouslySetInnerHTML: { __html: "HTML" } };',
105+
'<div {...props} />',
106+
'//foobar'
107+
].join('\n'),
108+
errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
109+
parserOptions: parserOptions
110+
},
76111
{
77112
code: [
78113
'<Hello dangerouslySetInnerHTML={{ __html: "HTML" }}>',
@@ -134,6 +169,22 @@ ruleTester.run('no-danger-with-children', rule, {
134169
].join('\n'),
135170
errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
136171
parserOptions: parserOptions
172+
},
173+
{
174+
code: [
175+
'const props = { dangerouslySetInnerHTML: { __html: "HTML" } };',
176+
'React.createElement("div", props, "Children");'
177+
].join('\n'),
178+
errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
179+
parserOptions: parserOptions
180+
},
181+
{
182+
code: [
183+
'const props = { children: "Children", dangerouslySetInnerHTML: { __html: "HTML" } };',
184+
'React.createElement("div", props);'
185+
].join('\n'),
186+
errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
187+
parserOptions: parserOptions
137188
}
138189
]
139190
});

0 commit comments

Comments
 (0)