Skip to content

Commit df4cf52

Browse files
committed
Update prop-types rule to check props usage (fixes #4)
1 parent d009e45 commit df4cf52

File tree

3 files changed

+85
-10
lines changed

3 files changed

+85
-10
lines changed

docs/rules/prop-types.md

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Prevent missing propTypes in a React component definition (prop-types)
1+
# Prevent missing props validation in a React component definition (prop-types)
22

33
PropTypes improve the reusability of your component by validating the received data.
44

@@ -14,11 +14,26 @@ var Hello = React.createClass({
1414
return <div>Hello {this.props.name}</div>;
1515
}
1616
});
17+
18+
var Hello = React.createClass({
19+
propTypes: {
20+
fistname: React.PropTypes.string.isRequired
21+
},
22+
render: function() {
23+
return <div>Hello {this.props.fistname} {this.props.lastname}</div>; // lastname type is not defined in propTypes
24+
}
25+
});
1726
```
1827

1928
The following patterns are not considered warnings:
2029

2130
```js
31+
var Hello = React.createClass({
32+
render: function() {
33+
return <div>Hello World</div>;
34+
}
35+
});
36+
2237
var Hello = React.createClass({
2338
propTypes: {
2439
name: React.PropTypes.string.isRequired

lib/rules/prop-types.js

+21-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* @fileoverview Prevent missing propTypes in a React component definition
2+
* @fileoverview Prevent missing props validation in a React component definition
33
* @author Yannick Croissant
44
*/
55
'use strict';
@@ -10,7 +10,8 @@
1010

1111
module.exports = function(context) {
1212

13-
var hasPropTypes = false;
13+
var declaredPropTypes = [];
14+
var usedPropTypes = [];
1415

1516
function isComponentDefinition(node) {
1617
return (
@@ -29,6 +30,13 @@ module.exports = function(context) {
2930

3031
return {
3132

33+
'MemberExpression': function(node) {
34+
if (node.object.type !== 'ThisExpression' || node.property.name !== 'props') {
35+
return;
36+
}
37+
usedPropTypes.push(node.parent.property.name);
38+
},
39+
3240
'ObjectExpression': function(node) {
3341

3442
if (!isComponentDefinition(node.parent)) {
@@ -37,8 +45,11 @@ module.exports = function(context) {
3745

3846
node.properties.forEach(function(property) {
3947
var keyName = property.key.name || property.key.value;
40-
if (keyName === 'propTypes') {
41-
hasPropTypes = true;
48+
if (keyName !== 'propTypes') {
49+
return;
50+
}
51+
for (var i = 0, j = property.value.properties.length; i < j; i++) {
52+
declaredPropTypes.push(property.value.properties[i].key.name);
4253
}
4354
});
4455
},
@@ -49,11 +60,14 @@ module.exports = function(context) {
4960
return;
5061
}
5162

52-
if (!hasPropTypes) {
53-
context.report(node, 'Component definition is missing props validation');
63+
for (var i = 0, j = usedPropTypes.length; i < j; i++) {
64+
if (declaredPropTypes.indexOf(usedPropTypes[i]) === -1) {
65+
context.report(node, '\'' + usedPropTypes[i] + '\' is missing in props validation');
66+
}
5467
}
5568

56-
hasPropTypes = false;
69+
declaredPropTypes.length = 0;
70+
usedPropTypes.length = 0;
5771
}
5872
};
5973

tests/lib/rules/prop-types.js

+48-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* @fileoverview Prevent missing propTypes in a React component definition
2+
* @fileoverview Prevent missing props validation in a React component definition
33
* @author Yannick Croissant
44
*/
55
'use strict';
@@ -32,6 +32,29 @@ eslintTester.addRuleTest('lib/rules/prop-types', {
3232
ecmaFeatures: {
3333
jsx: true
3434
}
35+
}, {
36+
code: '\
37+
var Hello = React.createClass({\
38+
propTypes: {\
39+
name: React.PropTypes.object.isRequired\
40+
},\
41+
render: function() {\
42+
return <div>Hello {this.props.name.firstname}</div>;\
43+
}\
44+
});',
45+
ecmaFeatures: {
46+
jsx: true
47+
}
48+
}, {
49+
code: '\
50+
var Hello = React.createClass({\
51+
render: function() {\
52+
return <div>Hello World</div>;\
53+
}\
54+
});',
55+
ecmaFeatures: {
56+
jsx: true
57+
}
3558
}
3659
],
3760

@@ -47,7 +70,30 @@ eslintTester.addRuleTest('lib/rules/prop-types', {
4770
jsx: true
4871
},
4972
errors: [{
50-
message: 'Component definition is missing props validation'
73+
message: '\'name\' is missing in props validation'
74+
}]
75+
}, {
76+
code: '\
77+
var Hello = React.createClass({\
78+
propTypes: {\
79+
name: React.PropTypes.string.isRequired\
80+
},\
81+
render: function() {\
82+
return <div>Hello {this.props.name} and {this.props.propWithoutTypeDefinition}</div>;\
83+
}\
84+
});\
85+
var Hello2 = React.createClass({\
86+
render: function() {\
87+
return <div>Hello {this.props.name}</div>;\
88+
}\
89+
});',
90+
ecmaFeatures: {
91+
jsx: true
92+
},
93+
errors: [{
94+
message: '\'propWithoutTypeDefinition\' is missing in props validation'
95+
}, {
96+
message: '\'name\' is missing in props validation'
5197
}]
5298
}
5399
]

0 commit comments

Comments
 (0)