Skip to content

Commit b464cf1

Browse files
pfhayesyannickcr
authored andcommitted
Add skipUndeclared option to prop-types rule
1 parent cc39fb8 commit b464cf1

File tree

3 files changed

+143
-2
lines changed

3 files changed

+143
-2
lines changed

docs/rules/prop-types.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ This rule can take one argument to ignore some specific props during validation.
109109
* `enabled`: for enabling the rule. 0=off, 1=warn, 2=error. Defaults to 0.
110110
* `ignore`: optional array of props name to ignore during validation.
111111
* `customValidators`: optional array of validators used for propTypes validation.
112+
* `skipUndeclared`: only error on components that have a propTypes block declared
112113

113114
### As for "exceptions"
114115

lib/rules/prop-types.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ module.exports = {
4242
items: {
4343
type: 'string'
4444
}
45+
},
46+
skipUndeclared: {
47+
type: 'boolean'
4548
}
4649
},
4750
additionalProperties: false
@@ -54,6 +57,7 @@ module.exports = {
5457
var configuration = context.options[0] || {};
5558
var ignored = configuration.ignore || [];
5659
var customValidators = configuration.customValidators || [];
60+
var skipUndeclared = configuration.skipUndeclared || false;
5761
// Used to track the type annotations in scope.
5862
// Necessary because babel's scopes do not track type annotations.
5963
var stack = null;
@@ -134,7 +138,6 @@ module.exports = {
134138
* @returns {Boolean} True if we are declaring a prop, false if not.
135139
*/
136140
function isPropTypesDeclaration(node) {
137-
138141
// Special case for class properties
139142
// (babel-eslint does not expose property name so we have to rely on tokens)
140143
if (node && node.type === 'ClassProperty') {
@@ -179,10 +182,12 @@ module.exports = {
179182
* @returns {Boolean} True if the component must be validated, false if not.
180183
*/
181184
function mustBeValidated(component) {
185+
var isSkippedByConfig = skipUndeclared && typeof component.declaredPropTypes === 'undefined';
182186
return Boolean(
183187
component &&
184188
component.usedPropTypes &&
185-
!component.ignorePropsValidation
189+
!component.ignorePropsValidation &&
190+
!isSkippedByConfig
186191
);
187192
}
188193

tests/lib/rules/prop-types.js

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,62 @@ ruleTester.run('prop-types', rule, {
13051305
'}'
13061306
].join('\n'),
13071307
parser: 'babel-eslint'
1308+
}, {
1309+
code: [
1310+
'var Hello = React.createClass({',
1311+
' render: function() {',
1312+
' return <div>{this.props.name}</div>;',
1313+
' }',
1314+
'});'
1315+
].join('\n'),
1316+
options: [{skipUndeclared: true}],
1317+
parserOptions: parserOptions
1318+
}, {
1319+
code: [
1320+
'var Hello = React.createClass({',
1321+
' render: function() {',
1322+
' return <div>{this.props.name}</div>;',
1323+
' }',
1324+
'});'
1325+
].join('\n'),
1326+
options: [{skipUndeclared: true}],
1327+
parserOptions: parserOptions
1328+
}, {
1329+
code: [
1330+
'class Hello extends React.Component {',
1331+
' render() {',
1332+
' return <div>{this.props.name}</div>;',
1333+
' }',
1334+
'}'
1335+
].join('\n'),
1336+
options: [{skipUndeclared: true}],
1337+
parserOptions: parserOptions
1338+
}, {
1339+
code: [
1340+
'var Hello = React.createClass({',
1341+
' propTypes: {',
1342+
' name: React.PropTypes.object.isRequired',
1343+
' },',
1344+
' render: function() {',
1345+
' return <div>{this.props.name}</div>;',
1346+
' }',
1347+
'});'
1348+
].join('\n'),
1349+
options: [{skipUndeclared: true}],
1350+
parserOptions: parserOptions
1351+
}, {
1352+
code: [
1353+
'var Hello = React.createClass({',
1354+
' propTypes: {',
1355+
' name: React.PropTypes.object.isRequired',
1356+
' },',
1357+
' render: function() {',
1358+
' return <div>{this.props.name}</div>;',
1359+
' }',
1360+
'});'
1361+
].join('\n'),
1362+
options: [{skipUndeclared: false}],
1363+
parserOptions: parserOptions
13081364
}
13091365
],
13101366

@@ -2312,6 +2368,85 @@ ruleTester.run('prop-types', rule, {
23122368
column: 27,
23132369
type: 'Property'
23142370
}]
2371+
}, {
2372+
code: [
2373+
'var Hello = React.createClass({',
2374+
' propTypes: {},',
2375+
' render: function() {',
2376+
' return <div>{this.props.firstname}</div>;',
2377+
' }',
2378+
'});'
2379+
].join('\n'),
2380+
options: [{skipUndeclared: true}],
2381+
parserOptions: parserOptions,
2382+
errors: [{
2383+
message: '\'firstname\' is missing in props validation',
2384+
line: 4,
2385+
column: 29
2386+
}]
2387+
}, {
2388+
code: [
2389+
'var Hello = function(props) {',
2390+
' return <div>{props.firstname}</div>;',
2391+
'};',
2392+
'Hello.propTypes = {}'
2393+
].join('\n'),
2394+
options: [{skipUndeclared: true}],
2395+
parserOptions: parserOptions,
2396+
errors: [{
2397+
message: '\'firstname\' is missing in props validation',
2398+
line: 2,
2399+
column: 22
2400+
}]
2401+
}, {
2402+
code: [
2403+
'class Hello extends React.Component {',
2404+
' static get propTypes() {',
2405+
' return {};',
2406+
' }',
2407+
' render() {',
2408+
' return <div>{this.props.firstname}</div>;',
2409+
' }',
2410+
'}'
2411+
].join('\n'),
2412+
options: [{skipUndeclared: true}],
2413+
parserOptions: parserOptions,
2414+
errors: [{
2415+
message: '\'firstname\' is missing in props validation',
2416+
line: 6,
2417+
column: 29
2418+
}]
2419+
}, {
2420+
code: [
2421+
'class Hello extends React.Component {',
2422+
' render() {',
2423+
' return <div>{this.props.firstname}</div>;',
2424+
' }',
2425+
'}',
2426+
'Hello.propTypes = {};'
2427+
].join('\n'),
2428+
options: [{skipUndeclared: true}],
2429+
parserOptions: parserOptions,
2430+
errors: [{
2431+
message: '\'firstname\' is missing in props validation',
2432+
line: 3,
2433+
column: 29
2434+
}]
2435+
}, {
2436+
code: [
2437+
'var Hello = React.createClass({',
2438+
' render: function() {',
2439+
' return <div>{this.props.firstname}</div>;',
2440+
' }',
2441+
'});'
2442+
].join('\n'),
2443+
options: [{skipUndeclared: false}],
2444+
parserOptions: parserOptions,
2445+
errors: [{
2446+
message: '\'firstname\' is missing in props validation',
2447+
line: 3,
2448+
column: 29
2449+
}]
23152450
}
23162451
]
23172452
});

0 commit comments

Comments
 (0)