Skip to content

Commit b0b6474

Browse files
committed
Add new dom-elements-style-is-object rule (Fixes jsx-eslint#715)
1 parent 1ab2eec commit b0b6474

File tree

5 files changed

+487
-1
lines changed

5 files changed

+487
-1
lines changed

README.md

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

8080
# List of supported rules
8181

82+
* [react/dom-elements-style-is-object](docs/rules/dom-elements-style-is-object.md): Enforce style prop value being an object
8283
* [react/display-name](docs/rules/display-name.md): Prevent missing `displayName` in a React component definition
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
@@ -155,6 +156,7 @@ See [ESLint documentation](http://eslint.org/docs/user-guide/configuring#extendi
155156

156157
The rules enabled in this configuration are:
157158

159+
* [react/dom-elements-style-is-object](docs/rules/dom-elements-style-is-object.md)
158160
* [react/display-name](docs/rules/display-name.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)
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Enforce style prop value being an object (dom-elements-style-is-object)
2+
3+
Require that the value of the prop `style` be an object or a variable that is
4+
an object.
5+
6+
## Rule Details
7+
8+
The property values of an object passed to the style prop must be strings.
9+
10+
The following patterns are considered warnings:
11+
12+
```jsx
13+
<div style="color: 'red'" />
14+
15+
<div style={true} />
16+
17+
<Hello style={true} />
18+
19+
const styles = true;
20+
<div style={styles} />
21+
22+
const styles = { height: 100 };
23+
<div style={styles} />
24+
```
25+
26+
```js
27+
React.createElement("div", { style: "color: 'red'" });
28+
29+
React.createElement("div", { style: true });
30+
31+
React.createElement("Hello", { style: true });
32+
33+
const styles = true;
34+
React.createElement("div", { style: styles });
35+
36+
const styles = { height: 100 };
37+
React.createElement("div", { style: styles });
38+
```
39+
40+
41+
The following patterns are not considered warnings:
42+
43+
```jsx
44+
<div style={{ color: "red" }} />
45+
46+
<Hello style={{ color: "red" }} />
47+
48+
const styles = { color: "red" };
49+
<div style={styles} />
50+
```
51+
52+
```js
53+
React.createElement("div", { style: { color: 'red' }});
54+
55+
React.createElement("Hello", { style: { color: 'red' }});
56+
57+
const styles = { height: '100px' };
58+
React.createElement("div", { style: styles });
59+
```

index.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ var rules = {
5252
'jsx-no-target-blank': require('./lib/rules/jsx-no-target-blank'),
5353
'jsx-filename-extension': require('./lib/rules/jsx-filename-extension'),
5454
'require-optimization': require('./lib/rules/require-optimization'),
55-
'no-find-dom-node': require('./lib/rules/no-find-dom-node')
55+
'no-find-dom-node': require('./lib/rules/no-find-dom-node'),
56+
'dom-elements-style-is-object': require('./lib/rules/dom-elements-style-is-object')
5657
};
5758

5859
var ruleNames = Object.keys(rules);
@@ -72,6 +73,7 @@ module.exports = {
7273
}
7374
},
7475
rules: {
76+
'react/dom-elements-style-is-object': 2,
7577
'react/display-name': 2,
7678
'react/jsx-no-duplicate-props': 2,
7779
'react/jsx-no-undef': 2,
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**
2+
* @fileoverview Enforce style prop value being an object and havng sting values
3+
* @author David Petersen
4+
*/
5+
'use strict';
6+
7+
var variableUtil = require('../util/variable');
8+
9+
// ------------------------------------------------------------------------------
10+
// Rule Definition
11+
// ------------------------------------------------------------------------------
12+
13+
module.exports = {
14+
meta: {
15+
docs: {
16+
description: 'Enforce style prop value being an object and havng sting values',
17+
category: '',
18+
recommended: true
19+
},
20+
schema: []
21+
},
22+
23+
create: function(context) {
24+
/**
25+
* @param {object} node A ObjectExpression node
26+
*/
27+
function checkValuesAreStrings(node) {
28+
node.properties.forEach(function(property) {
29+
if (
30+
property.value.type !== 'Literal'
31+
|| typeof property.value.value !== 'string'
32+
) {
33+
context.report(property.value, 'Style object values must be strings');
34+
}
35+
});
36+
}
37+
38+
/**
39+
* @param {object} node A Identifier node
40+
*/
41+
function checkIdentifiers(node) {
42+
var variable = variableUtil.variablesInScope(context).find(function (item) {
43+
return item.name === node.name;
44+
});
45+
46+
if (!variable || !variable.defs[0].node.init) {
47+
return;
48+
}
49+
50+
if (variable.defs[0].node.init.type === 'Literal') {
51+
context.report(node, 'Style prop value must be an object');
52+
} else if (variable.defs[0].node.init.type === 'ObjectExpression') {
53+
checkValuesAreStrings(variable.defs[0].node.init);
54+
}
55+
}
56+
57+
return {
58+
CallExpression: function(node) {
59+
if (
60+
node.callee
61+
&& node.callee.type === 'MemberExpression'
62+
&& node.callee.property.name === 'createElement'
63+
&& node.arguments.length > 1
64+
) {
65+
if (node.arguments[1].type === 'ObjectExpression') {
66+
var style = node.arguments[1].properties.find(function(property) {
67+
return property.key.name === 'style';
68+
});
69+
if (style) {
70+
if (style.value.type === 'Identifier') {
71+
checkIdentifiers(style.value);
72+
} else if (style.value.type === 'Literal') {
73+
context.report(style.value, 'Style prop value must be an object');
74+
} else if (style.value.type === 'ObjectExpression') {
75+
checkValuesAreStrings(style.value);
76+
}
77+
}
78+
}
79+
}
80+
},
81+
82+
JSXAttribute: function(node) {
83+
if (node.name.name !== 'style') {
84+
return;
85+
}
86+
87+
if (
88+
node.value.type !== 'JSXExpressionContainer'
89+
|| node.value.expression.type === 'Literal'
90+
) {
91+
context.report(node, 'Style prop value must be an object');
92+
} else if (node.value.expression.type === 'ObjectExpression') {
93+
checkValuesAreStrings(node.value.expression);
94+
} else if (node.value.expression.type === 'Identifier') {
95+
checkIdentifiers(node.value.expression);
96+
}
97+
}
98+
};
99+
}
100+
};

0 commit comments

Comments
 (0)