Skip to content

Commit 710a14e

Browse files
committed
Add new dom-elements-no-danger-with-children rule (Fixes jsx-eslint#710)
Prevents dangerouslySetInnerHTML and children from being used at the same time
1 parent 8b8eba7 commit 710a14e

File tree

5 files changed

+164
-1
lines changed

5 files changed

+164
-1
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
8080
# List of supported rules
8181

8282
* [react/display-name](docs/rules/display-name.md): Prevent missing `displayName` in a React component definition
83+
* [react/dom-elements-no-danger-with-children](docs/rules/dom-elements-no-danger-with-children.md): Prevent problem with children and props.dangerouslySetInnerHTML
8384
* [react/forbid-prop-types](docs/rules/forbid-prop-types.md): Forbid certain propTypes
8485
* [react/no-danger](docs/rules/no-danger.md): Prevent usage of dangerous JSX properties
8586
* [react/no-deprecated](docs/rules/no-deprecated.md): Prevent usage of deprecated methods
@@ -156,6 +157,7 @@ See [ESLint documentation](http://eslint.org/docs/user-guide/configuring#extendi
156157
The rules enabled in this configuration are:
157158

158159
* [react/display-name](docs/rules/display-name.md)
160+
* [react/dom-elements-no-danger-with-children](docs/rules/dom-elements-no-danger-with-children.md)
159161
* [react/jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md)
160162
* [react/jsx-no-undef](docs/rules/jsx-no-undef.md)
161163
* [react/jsx-uses-react](docs/rules/jsx-uses-react.md)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Prevent problem with children and props.dangerouslySetInnerHTML (dom-elements-no-danger-with-children)
2+
3+
This rule helps prevent problems caused by using children and the dangerouslySetInnerHTML prop at the same time
4+
5+
## Rule Details
6+
7+
The following patterns are considered warnings:
8+
9+
```js
10+
<div dangerouslySetInnerHTML={{ __html: "HTML" }}>
11+
Children
12+
</div>
13+
```
14+
15+
```js
16+
React.createElement("div", { dangerouslySetInnerHTML: { __html: "HTML" } }, "Children");
17+
```
18+
19+
20+
The following patterns are not considered warnings:
21+
22+
```js
23+
<div dangerouslySetInnerHTML={{ __html: "HTML" }} />
24+
```
25+
26+
```js
27+
<div>
28+
Children
29+
</div>
30+
```
31+
32+
```js
33+
React.createElement("div", { dangerouslySetInnerHTML: { __html: "HTML" } });
34+
```
35+
36+
```js
37+
React.createElement("div", {}, "Children");
38+
```
39+

index.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ var rules = {
5050
'jsx-no-target-blank': require('./lib/rules/jsx-no-target-blank'),
5151
'jsx-filename-extension': require('./lib/rules/jsx-filename-extension'),
5252
'require-optimization': require('./lib/rules/require-optimization'),
53-
'no-find-dom-node': require('./lib/rules/no-find-dom-node')
53+
'no-find-dom-node': require('./lib/rules/no-find-dom-node'),
54+
'dom-elements-no-danger-with-children': require('./lib/rules/dom-elements-no-danger-with-children')
5455
};
5556

5657
var ruleNames = Object.keys(rules);
@@ -70,6 +71,7 @@ module.exports = {
7071
},
7172
rules: {
7273
'react/display-name': 2,
74+
'react/dom-elements-no-danger-with-children': 2,
7375
'react/jsx-no-duplicate-props': 2,
7476
'react/jsx-no-undef': 2,
7577
'react/jsx-uses-react': 2,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @fileoverview Report when a dom element is using both children and dangerouslySetInnerHTML
3+
* @author David Petersen
4+
*/
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Rule Definition
9+
// ------------------------------------------------------------------------------
10+
module.exports = {
11+
meta: {
12+
docs: {
13+
description: 'Report when a dom element is using both children and dangerouslySetInnerHTML',
14+
category: '',
15+
recommended: true
16+
},
17+
schema: [] // no options
18+
},
19+
create: function(context) {
20+
return {
21+
JSXElement: function (node) {
22+
if (!node.children.length) {
23+
return;
24+
}
25+
var attributes = node.openingElement.attributes;
26+
if (attributes) {
27+
var jsxElement = attributes.find(function (attribute) {
28+
return attribute.name.name === 'dangerouslySetInnerHTML';
29+
});
30+
if (jsxElement) {
31+
context.report(node, 'Only set one of `children` or `props.dangerouslySetInnerHTML`');
32+
}
33+
}
34+
},
35+
CallExpression: function (node) {
36+
if (
37+
node.callee
38+
&& node.callee.type === 'MemberExpression'
39+
&& node.callee.property.name === 'createElement'
40+
&& node.arguments.length > 2
41+
) {
42+
var props = node.arguments[1].properties;
43+
var dangerously = props.find(function(prop) {
44+
return prop.key.name === 'dangerouslySetInnerHTML';
45+
});
46+
if (dangerously) {
47+
context.report(node, 'Only set one of `children` or `props.dangerouslySetInnerHTML`');
48+
}
49+
}
50+
}
51+
};
52+
}
53+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* @fileoverview Report when a dom element is using both children and dangerouslySetInnerHTML
3+
* @author David Petersen
4+
*/
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
var rule = require('../../../lib/rules/dom-elements-no-danger-with-children');
12+
var RuleTester = require('eslint').RuleTester;
13+
14+
var parserOptions = {
15+
ecmaVersion: 6,
16+
ecmaFeatures: {
17+
jsx: true
18+
}
19+
};
20+
21+
// ------------------------------------------------------------------------------
22+
// Tests
23+
// ------------------------------------------------------------------------------
24+
25+
var ruleTester = new RuleTester();
26+
ruleTester.run('dom-elements-no-danger-with-children', rule, {
27+
valid: [
28+
{
29+
code: '<div>Children</div>',
30+
parserOptions: parserOptions
31+
},
32+
{
33+
code: '<div dangerouslySetInnerHTML={{ __html: "HTML" }} />',
34+
parserOptions: parserOptions
35+
},
36+
{
37+
code: 'React.createElement("div", { dangerouslySetInnerHTML: { __html: "HTML" } });',
38+
parserOptions: parserOptions
39+
},
40+
{
41+
code: 'React.createElement("div", {}, "Children");',
42+
parserOptions: parserOptions
43+
}
44+
],
45+
invalid: [
46+
{
47+
code: [
48+
'<div dangerouslySetInnerHTML={{ __html: "HTML" }}>',
49+
' Children',
50+
'</div>'
51+
].join('\n'),
52+
errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
53+
parserOptions: parserOptions
54+
},
55+
{
56+
code: [
57+
'React.createElement(',
58+
' "div",',
59+
' { dangerouslySetInnerHTML: { __html: "HTML" } },',
60+
' "Children"',
61+
');'
62+
].join('\n'),
63+
errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
64+
parserOptions: parserOptions
65+
}
66+
]
67+
});

0 commit comments

Comments
 (0)