Skip to content

Commit

Permalink
Add new dom-elements-no-danger-with-children rule (Fixes jsx-eslint#710)
Browse files Browse the repository at this point in the history
Prevents dangerouslySetInnerHTML and children from being used at the same time
  • Loading branch information
petersendidit committed Jul 26, 2016
1 parent 8b8eba7 commit 8ed6f7e
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
# List of supported rules

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

* [react/display-name](docs/rules/display-name.md)
* [react/dom-elements-no-danger-with-children](docs/rules/dom-elements-no-danger-with-children.md)
* [react/jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md)
* [react/jsx-no-undef](docs/rules/jsx-no-undef.md)
* [react/jsx-uses-react](docs/rules/jsx-uses-react.md)
Expand Down
39 changes: 39 additions & 0 deletions docs/rules/dom-elements-no-danger-with-children.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Prevent problem with children and props.dangerouslySetInnerHTML (dom-elements-no-danger-with-children)

This rule helps prevent problems caused by using children and the dangerouslySetInnerHTML prop at the same time

## Rule Details

The following patterns are considered warnings:

```js
<div dangerouslySetInnerHTML={{ __html: "HTML" }}>
Children
</div>
```

```js
React.createElement("div", { dangerouslySetInnerHTML: { __html: "HTML" } }, "Children");
```


The following patterns are not considered warnings:

```js
<div dangerouslySetInnerHTML={{ __html: "HTML" }} />
```

```js
<div>
Children
</div>
```

```js
React.createElement("div", { dangerouslySetInnerHTML: { __html: "HTML" } });
```

```js
React.createElement("div", {}, "Children");
```

4 changes: 3 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ var rules = {
'jsx-no-target-blank': require('./lib/rules/jsx-no-target-blank'),
'jsx-filename-extension': require('./lib/rules/jsx-filename-extension'),
'require-optimization': require('./lib/rules/require-optimization'),
'no-find-dom-node': require('./lib/rules/no-find-dom-node')
'no-find-dom-node': require('./lib/rules/no-find-dom-node'),
'dom-elements-no-danger-with-children': require('./lib/rules/dom-elements-no-danger-with-children')
};

var ruleNames = Object.keys(rules);
Expand All @@ -70,6 +71,7 @@ module.exports = {
},
rules: {
'react/display-name': 2,
'react/dom-elements-no-danger-with-children': 2,
'react/jsx-no-duplicate-props': 2,
'react/jsx-no-undef': 2,
'react/jsx-uses-react': 2,
Expand Down
68 changes: 68 additions & 0 deletions lib/rules/dom-elements-no-danger-with-children.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* @fileoverview Report when a dom element is using both children and dangerouslySetInnerHTML
* @author David Petersen
*/
'use strict';

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
module.exports = {
meta: {
docs: {
description: 'Report when a dom element is using both children and dangerouslySetInnerHTML',
category: '',
recommended: true
},
schema: [] // no options
},
create: function(context) {
return {
JSXElement: function (node) {
if (!node.children.length) {
return;
}
var attributes = node.openingElement.attributes;
if (attributes) {
var jsxElement = attributes.find(function (attribute) {
return attribute.name.name === 'dangerouslySetInnerHTML';
});
if (jsxElement) {
context.report(node, 'Only set one of `children` or `props.dangerouslySetInnerHTML`');
}
}
},
CallExpression: function (node) {
if (
node.callee
&& node.callee.type === 'MemberExpression'
&& node.callee.property.name === 'createElement'
&& node.arguments.length > 1
) {
var hasChildren = false;

var props = node.arguments[1].properties;
var dangerously = props.find(function(prop) {
return prop.key.name === 'dangerouslySetInnerHTML';
});


if (node.arguments.length === 2) {
var childrenProp = props.find(function(prop) {
return prop.key.name === 'children';
});
if (childrenProp) {
hasChildren = true;
}
} else {
hasChildren = true;
}

if (dangerously && hasChildren) {
context.report(node, 'Only set one of `children` or `props.dangerouslySetInnerHTML`');
}
}
}
};
}
};
80 changes: 80 additions & 0 deletions tests/lib/rules/dom-elements-no-danger-with-children.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* @fileoverview Report when a dom element is using both children and dangerouslySetInnerHTML
* @author David Petersen
*/
'use strict';

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

var rule = require('../../../lib/rules/dom-elements-no-danger-with-children');
var RuleTester = require('eslint').RuleTester;

var parserOptions = {
ecmaVersion: 6,
ecmaFeatures: {
jsx: true
}
};

// ------------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------------

var ruleTester = new RuleTester();
ruleTester.run('dom-elements-no-danger-with-children', rule, {
valid: [
{
code: '<div>Children</div>',
parserOptions: parserOptions
},
{
code: '<div dangerouslySetInnerHTML={{ __html: "HTML" }} />',
parserOptions: parserOptions
},
{
code: 'React.createElement("div", { dangerouslySetInnerHTML: { __html: "HTML" } });',
parserOptions: parserOptions
},
{
code: 'React.createElement("div", {}, "Children");',
parserOptions: parserOptions
}
],
invalid: [
{
code: [
'<div dangerouslySetInnerHTML={{ __html: "HTML" }}>',
' Children',
'</div>'
].join('\n'),
errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
parserOptions: parserOptions
},
{
code: [
'React.createElement(',
' "div",',
' { dangerouslySetInnerHTML: { __html: "HTML" } },',
' "Children"',
');'
].join('\n'),
errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
parserOptions: parserOptions
},
{
code: [
'React.createElement(',
' "div",',
' {',
' dangerouslySetInnerHTML: { __html: "HTML" },',
' children: "Children",',
' }',
');'
].join('\n'),
errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
parserOptions: parserOptions
}
]
});

0 comments on commit 8ed6f7e

Please sign in to comment.