Skip to content

Commit

Permalink
Add new dom-elements-style-is-object rule (Fixes jsx-eslint#715)
Browse files Browse the repository at this point in the history
  • Loading branch information
petersendidit committed Aug 8, 2016
1 parent 1ab2eec commit b0b6474
Show file tree
Hide file tree
Showing 5 changed files with 487 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#

# List of supported rules

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

The rules enabled in this configuration are:

* [react/dom-elements-style-is-object](docs/rules/dom-elements-style-is-object.md)
* [react/display-name](docs/rules/display-name.md)
* [react/jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md)
* [react/jsx-no-undef](docs/rules/jsx-no-undef.md)
Expand Down
59 changes: 59 additions & 0 deletions docs/rules/dom-elements-style-is-object.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Enforce style prop value being an object (dom-elements-style-is-object)

Require that the value of the prop `style` be an object or a variable that is
an object.

## Rule Details

The property values of an object passed to the style prop must be strings.

The following patterns are considered warnings:

```jsx
<div style="color: 'red'" />

<div style={true} />

<Hello style={true} />

const styles = true;
<div style={styles} />

const styles = { height: 100 };
<div style={styles} />
```

```js
React.createElement("div", { style: "color: 'red'" });

React.createElement("div", { style: true });

React.createElement("Hello", { style: true });

const styles = true;
React.createElement("div", { style: styles });

const styles = { height: 100 };
React.createElement("div", { style: styles });
```


The following patterns are not considered warnings:

```jsx
<div style={{ color: "red" }} />

<Hello style={{ color: "red" }} />

const styles = { color: "red" };
<div style={styles} />
```

```js
React.createElement("div", { style: { color: 'red' }});

React.createElement("Hello", { style: { color: 'red' }});

const styles = { height: '100px' };
React.createElement("div", { style: styles });
```
4 changes: 3 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,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-style-is-object': require('./lib/rules/dom-elements-style-is-object')
};

var ruleNames = Object.keys(rules);
Expand All @@ -72,6 +73,7 @@ module.exports = {
}
},
rules: {
'react/dom-elements-style-is-object': 2,
'react/display-name': 2,
'react/jsx-no-duplicate-props': 2,
'react/jsx-no-undef': 2,
Expand Down
100 changes: 100 additions & 0 deletions lib/rules/dom-elements-style-is-object.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* @fileoverview Enforce style prop value being an object and havng sting values
* @author David Petersen
*/
'use strict';

var variableUtil = require('../util/variable');

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = {
meta: {
docs: {
description: 'Enforce style prop value being an object and havng sting values',
category: '',
recommended: true
},
schema: []
},

create: function(context) {
/**
* @param {object} node A ObjectExpression node
*/
function checkValuesAreStrings(node) {
node.properties.forEach(function(property) {
if (
property.value.type !== 'Literal'
|| typeof property.value.value !== 'string'
) {
context.report(property.value, 'Style object values must be strings');
}
});
}

/**
* @param {object} node A Identifier node
*/
function checkIdentifiers(node) {
var variable = variableUtil.variablesInScope(context).find(function (item) {
return item.name === node.name;
});

if (!variable || !variable.defs[0].node.init) {
return;
}

if (variable.defs[0].node.init.type === 'Literal') {
context.report(node, 'Style prop value must be an object');
} else if (variable.defs[0].node.init.type === 'ObjectExpression') {
checkValuesAreStrings(variable.defs[0].node.init);
}
}

return {
CallExpression: function(node) {
if (
node.callee
&& node.callee.type === 'MemberExpression'
&& node.callee.property.name === 'createElement'
&& node.arguments.length > 1
) {
if (node.arguments[1].type === 'ObjectExpression') {
var style = node.arguments[1].properties.find(function(property) {
return property.key.name === 'style';
});
if (style) {
if (style.value.type === 'Identifier') {
checkIdentifiers(style.value);
} else if (style.value.type === 'Literal') {
context.report(style.value, 'Style prop value must be an object');
} else if (style.value.type === 'ObjectExpression') {
checkValuesAreStrings(style.value);
}
}
}
}
},

JSXAttribute: function(node) {
if (node.name.name !== 'style') {
return;
}

if (
node.value.type !== 'JSXExpressionContainer'
|| node.value.expression.type === 'Literal'
) {
context.report(node, 'Style prop value must be an object');
} else if (node.value.expression.type === 'ObjectExpression') {
checkValuesAreStrings(node.value.expression);
} else if (node.value.expression.type === 'Identifier') {
checkIdentifiers(node.value.expression);
}
}
};
}
};
Loading

0 comments on commit b0b6474

Please sign in to comment.