Skip to content

Commit b2c8cf5

Browse files
author
Evgueni Naverniouk
committed
Merge branch 'master' into 226-unused-prop-types
# Conflicts: # index.js
2 parents d923dc6 + 7024678 commit b2c8cf5

13 files changed

+514
-48
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
106106
* [react/self-closing-comp](docs/rules/self-closing-comp.md): Prevent extra closing tags for components without children (fixable)
107107
* [react/sort-comp](docs/rules/sort-comp.md): Enforce component methods order
108108
* [react/sort-prop-types](docs/rules/sort-prop-types.md): Enforce propTypes declarations alphabetical sorting
109+
* [react/style-prop-object](docs/rules/style-prop-object.md): Enforce style prop value being an object
109110

110111
## JSX-specific rules
111112

docs/rules/prefer-stateless-function.md

+44-7
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,33 @@ This rule will check your class based React components for
88

99
* methods/properties other than `displayName`, `propTypes`, `render` and useless constructor (same detection as ESLint [no-useless-constructor rule](http://eslint.org/docs/rules/no-useless-constructor))
1010
* instance property other than `this.props` and `this.context`
11+
* extension of `React.PureComponent` ()
1112
* presence of `ref` attribute in JSX
1213
* `render` method that return anything but JSX: `undefined`, `null`, etc. (only in React <15.0.0, see [shared settings](https://github.com/yannickcr/eslint-plugin-react/blob/master/README.md#configuration) for React version configuration)
1314

14-
If none of these 4 elements are found, the rule will warn you to write this component as a pure function.
15+
If none of these elements are found, the rule will warn you to write this component as a pure function.
1516

16-
The following pattern is considered warnings:
17+
The following pattern is considered a warning:
1718

18-
```js
19+
```jsx
1920
var Hello = React.createClass({
2021
render: function() {
2122
return <div>Hello {this.props.name}</div>;
2223
}
2324
});
2425
```
2526

26-
The following pattern is not considered warnings:
27+
The following pattern is not considered a warning:
2728

28-
```js
29+
```jsx
2930
const Foo = function(props) {
3031
return <div>{props.foo}</div>;
3132
};
3233
```
3334

34-
The following pattern is not considered warning in React <15.0.0:
35+
The following pattern is not considered a warning in React <15.0.0:
3536

36-
```js
37+
```jsx
3738
class Foo extends React.Component {
3839
render() {
3940
if (!this.props.foo) {
@@ -43,3 +44,39 @@ class Foo extends React.Component {
4344
}
4445
}
4546
```
47+
48+
49+
## Rule Options
50+
51+
```js
52+
...
53+
"prefer-stateless-function": [<enabled>, { "ignorePureComponent": <ignorePureComponent> }]
54+
...
55+
```
56+
57+
* `enabled`: for enabling the rule. 0=off, 1=warn, 2=error. Defaults to 0.
58+
* `ignorePureComponent`: optional boolean set to `true` to ignore components extending from `React.PureComponent` (default to `false`).
59+
60+
### `ignorePureComponent`
61+
62+
When `true` the rule will ignore Components extending from `React.PureComponent` that use `this.props` or `this.context`.
63+
64+
The following patterns is considered okay and does not cause warnings:
65+
66+
```jsx
67+
class Foo extends React.PureComponent {
68+
render() {
69+
return <div>{this.props.foo}</div>;
70+
}
71+
}
72+
```
73+
74+
The following pattern is considered a warning because it's not using props or context:
75+
76+
```jsx
77+
class Foo extends React.PureComponent {
78+
render() {
79+
return <div>Bar</div>;
80+
}
81+
}
82+
```

docs/rules/style-prop-object.md

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Enforce style prop value being an object (style-prop-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 following patterns are considered warnings:
9+
10+
```jsx
11+
<div style="color: 'red'" />
12+
13+
<div style={true} />
14+
15+
<Hello style={true} />
16+
17+
const styles = true;
18+
<div style={styles} />
19+
```
20+
21+
```js
22+
React.createElement("div", { style: "color: 'red'" });
23+
24+
React.createElement("div", { style: true });
25+
26+
React.createElement("Hello", { style: true });
27+
28+
const styles = true;
29+
React.createElement("div", { style: styles });
30+
```
31+
32+
33+
The following patterns are not considered warnings:
34+
35+
```jsx
36+
<div style={{ color: "red" }} />
37+
38+
<Hello style={{ color: "red" }} />
39+
40+
const styles = { color: "red" };
41+
<div style={styles} />
42+
```
43+
44+
```js
45+
React.createElement("div", { style: { color: 'red' }});
46+
47+
React.createElement("Hello", { style: { color: 'red' }});
48+
49+
const styles = { height: '100px' };
50+
React.createElement("div", { style: styles });
51+
```

index.js

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ var rules = {
5555
'require-optimization': require('./lib/rules/require-optimization'),
5656
'no-find-dom-node': require('./lib/rules/no-find-dom-node'),
5757
'no-danger-with-children': require('./lib/rules/no-danger-with-children'),
58+
'style-prop-object': require('./lib/rules/style-prop-object'),
5859
'no-unused-prop-types': require('./lib/rules/no-unused-prop-types')
5960
};
6061

lib/rules/jsx-uses-vars.js

-7
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,6 @@ module.exports = {
2323
create: function(context) {
2424

2525
return {
26-
JSXExpressionContainer: function(node) {
27-
if (node.expression.type !== 'Identifier') {
28-
return;
29-
}
30-
variableUtil.markVariableAsUsed(context, node.expression.name);
31-
},
32-
3326
JSXOpeningElement: function(node) {
3427
var name;
3528
if (node.name.namespace && node.name.namespace.name) {

lib/rules/no-multi-comp.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ module.exports = {
4343
* @returns {Boolean} True if the component is ignored, false if not.
4444
*/
4545
function isIgnored(component) {
46-
return ignoreStateless === true && /Function/.test(component.node.type);
46+
return ignoreStateless && /Function/.test(component.node.type);
4747
}
4848

4949
// --------------------------------------------------------------------------

lib/rules/prefer-stateless-function.js

+48-3
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,23 @@ module.exports = {
2020
category: 'Stylistic Issues',
2121
recommended: false
2222
},
23-
schema: []
23+
schema: [{
24+
type: 'object',
25+
properties: {
26+
ignorePureComponents: {
27+
default: false,
28+
type: 'boolean'
29+
}
30+
},
31+
additionalProperties: false
32+
}]
2433
},
2534

2635
create: Components.detect(function(context, components, utils) {
2736

37+
var configuration = context.options[0] || {};
38+
var ignorePureComponents = configuration.ignorePureComponents || false;
39+
2840
var sourceCode = context.getSourceCode();
2941

3042
// --------------------------------------------------------------------------
@@ -213,6 +225,16 @@ module.exports = {
213225
});
214226
}
215227

228+
/**
229+
* Mark component as pure as declared
230+
* @param {ASTNode} node The AST node being checked.
231+
*/
232+
var markSCUAsDeclared = function (node) {
233+
components.set(node, {
234+
hasSCU: true
235+
});
236+
};
237+
216238
/**
217239
* Mark a setState as used
218240
* @param {ASTNode} node The AST node being checked.
@@ -223,6 +245,16 @@ module.exports = {
223245
});
224246
}
225247

248+
/**
249+
* Mark a props or context as used
250+
* @param {ASTNode} node The AST node being checked.
251+
*/
252+
function markPropsOrContextAsUsed(node) {
253+
components.set(node, {
254+
usePropsOrContext: true
255+
});
256+
}
257+
226258
/**
227259
* Mark a ref as used
228260
* @param {ASTNode} node The AST node being checked.
@@ -244,6 +276,12 @@ module.exports = {
244276
}
245277

246278
return {
279+
ClassDeclaration: function (node) {
280+
if (ignorePureComponents && utils.isPureComponent(node)) {
281+
markSCUAsDeclared(node);
282+
}
283+
},
284+
247285
// Mark `this` destructuring as a usage of `this`
248286
VariableDeclarator: function(node) {
249287
// Ignore destructuring on other than `this`
@@ -256,6 +294,7 @@ module.exports = {
256294
return name !== 'props' && name !== 'context';
257295
});
258296
if (!useThis) {
297+
markPropsOrContextAsUsed(node);
259298
return;
260299
}
261300
markThisAsUsed(node);
@@ -264,11 +303,13 @@ module.exports = {
264303
// Mark `this` usage
265304
MemberExpression: function(node) {
266305
// Ignore calls to `this.props` and `this.context`
267-
if (
268-
node.object.type !== 'ThisExpression' ||
306+
if (node.object.type !== 'ThisExpression') {
307+
return;
308+
} else if (
269309
(node.property.name || node.property.value) === 'props' ||
270310
(node.property.name || node.property.value) === 'context'
271311
) {
312+
markPropsOrContextAsUsed(node);
272313
return;
273314
}
274315
markThisAsUsed(node);
@@ -322,6 +363,10 @@ module.exports = {
322363
continue;
323364
}
324365

366+
if (list[component].hasSCU && list[component].usePropsOrContext) {
367+
continue;
368+
}
369+
325370
context.report({
326371
node: list[component].node,
327372
message: 'Component should be written as a pure function'

lib/rules/require-optimization.js

+2-20
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
'use strict';
66

77
var Components = require('../util/Components');
8-
var pragmaUtil = require('../util/pragma');
98

109
module.exports = {
1110
meta: {
@@ -29,15 +28,11 @@ module.exports = {
2928
}]
3029
},
3130

32-
create: Components.detect(function (context, components) {
31+
create: Components.detect(function (context, components, utils) {
3332
var MISSING_MESSAGE = 'Component is not optimized. Please add a shouldComponentUpdate method.';
3433
var configuration = context.options[0] || {};
3534
var allowDecorators = configuration.allowDecorators || [];
3635

37-
var pragma = pragmaUtil.getFromContext(context);
38-
var pureComponentRegExp = new RegExp('^(' + pragma + '\\.)?PureComponent$');
39-
var sourceCode = context.getSourceCode();
40-
4136
/**
4237
* Checks to see if our component is decorated by PureRenderMixin via reactMixin
4338
* @param {ASTNode} node The AST node being checked.
@@ -89,19 +84,6 @@ module.exports = {
8984
return false;
9085
};
9186

92-
/**
93-
* Checks to see if our component extends React.PureComponent
94-
* @param {ASTNode} node The AST node being checked.
95-
* @returns {Boolean} True if node extends React.PureComponent, false if not.
96-
*/
97-
var isPureComponent = function (node) {
98-
if (node.superClass) {
99-
return pureComponentRegExp.test(sourceCode.getText(node.superClass));
100-
}
101-
102-
return false;
103-
};
104-
10587
/**
10688
* Checks if we are declaring a shouldComponentUpdate method
10789
* @param {ASTNode} node The AST node being checked.
@@ -186,7 +168,7 @@ module.exports = {
186168
},
187169

188170
ClassDeclaration: function (node) {
189-
if (!(hasPureRenderDecorator(node) || hasCustomDecorator(node) || isPureComponent(node))) {
171+
if (!(hasPureRenderDecorator(node) || hasCustomDecorator(node) || utils.isPureComponent(node))) {
190172
return;
191173
}
192174
markSCUAsDeclared(node);

0 commit comments

Comments
 (0)