Skip to content

Commit d7f5e49

Browse files
committed
Add forbid-foreign-prop-types rule
People may want to use babel-plugin-transform-react-remove-prop-types to remove propTypes from their components in production builds, as an optimization. The `forbib-foreign-prop-types` rule forbids using another component's prop types unless they are explicitly imported/exported, which makes that optimization less prone to error. Fixes #696
1 parent 5827897 commit d7f5e49

File tree

5 files changed

+184
-0
lines changed

5 files changed

+184
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
8383
* [react/display-name](docs/rules/display-name.md): Prevent missing `displayName` in a React component definition
8484
* [react/forbid-component-props](docs/rules/forbid-component-props.md): Forbid certain props on Components
8585
* [react/forbid-prop-types](docs/rules/forbid-prop-types.md): Forbid certain propTypes
86+
* [react/forbid-foreign-prop-types](docs/rules/forbid-foreign-prop-types.md): Forbid foreign propTypes
8687
* [react/no-array-index-key](docs/rules/no-array-index-key.md): Prevent using Array index in `key` props
8788
* [react/no-children-prop](docs/rules/no-children-prop.md): Prevent passing children as props
8889
* [react/no-danger](docs/rules/no-danger.md): Prevent usage of dangerous JSX properties
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Forbid foreign propTypes (forbid-foreign-prop-types)
2+
3+
This rule forbids using another component's prop types unless they are explicitly imported/exported. This allows people who want to use babel-plugin-transform-react-remove-prop-types to remove propTypes from their components in production builds, to do so safely.
4+
5+
## Rule Details
6+
7+
This rule checks all objects and ensures that the `propTypes` property is not used.
8+
9+
The following patterns are considered warnings:
10+
11+
```js
12+
import SomeComponent from './SomeComponent';
13+
SomeComponent.propTypes;
14+
15+
var { propTypes } = SomeComponent;
16+
17+
SomeComponent['propTypes'];
18+
```
19+
20+
The following patterns are not considered warnings:
21+
22+
```js
23+
import {propTypes: someComponentPropTypes}, SomeComponent from './SomeComponent';
24+
```
25+
26+
## When not to use
27+
28+
This rule aims to make a certain production optimization, removing prop types, less prone to error. This rule may not be relevant to you if you do not wish to make use of this optimization.

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ var allRules = {
4343
'no-direct-mutation-state': require('./lib/rules/no-direct-mutation-state'),
4444
'forbid-component-props': require('./lib/rules/forbid-component-props'),
4545
'forbid-prop-types': require('./lib/rules/forbid-prop-types'),
46+
'forbid-foreign-prop-types': require('./lib/rules/forbid-foreign-prop-types'),
4647
'prefer-es6-class': require('./lib/rules/prefer-es6-class'),
4748
'jsx-key': require('./lib/rules/jsx-key'),
4849
'no-string-refs': require('./lib/rules/no-string-refs'),
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* @fileoverview Forbid using another component's propTypes
3+
* @author Ian Christian Myers
4+
*/
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Constants
9+
// ------------------------------------------------------------------------------
10+
11+
12+
// ------------------------------------------------------------------------------
13+
// Rule Definition
14+
// ------------------------------------------------------------------------------
15+
16+
module.exports = {
17+
meta: {
18+
docs: {
19+
description: 'Forbid using another component\'s propTypes',
20+
category: 'Best Practices',
21+
recommended: false
22+
}
23+
},
24+
25+
create: function(context) {
26+
27+
return {
28+
MemberExpression: function(node) {
29+
if (node.property && node.property.type === 'Identifier' && node.property.name === 'propTypes' ||
30+
node.property && node.property.type === 'Literal' && node.property.value === 'propTypes') {
31+
context.report({
32+
node: node.property,
33+
message: 'Using another component\'s propTypes is forbidden'
34+
});
35+
}
36+
},
37+
38+
ObjectPattern: function(node) {
39+
var propTypesNode = node.properties.find(function(property) {
40+
return property.type === 'Property' && property.key.name === 'propTypes';
41+
});
42+
43+
if (propTypesNode) {
44+
context.report({
45+
node: propTypesNode,
46+
message: 'Using another component\'s propTypes is forbidden'
47+
});
48+
}
49+
}
50+
};
51+
}
52+
};
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/**
2+
* @fileoverview Tests for forbid-foreign-prop-types
3+
*/
4+
'use strict';
5+
6+
// -----------------------------------------------------------------------------
7+
// Requirements
8+
// -----------------------------------------------------------------------------
9+
10+
var rule = require('../../../lib/rules/forbid-foreign-prop-types');
11+
var RuleTester = require('eslint').RuleTester;
12+
13+
var parserOptions = {
14+
ecmaVersion: 6,
15+
ecmaFeatures: {
16+
experimentalObjectRestSpread: true,
17+
jsx: true
18+
}
19+
};
20+
21+
require('babel-eslint');
22+
23+
// -----------------------------------------------------------------------------
24+
// Tests
25+
// -----------------------------------------------------------------------------
26+
27+
var ERROR_MESSAGE = 'Using another component\'s propTypes is forbidden';
28+
29+
var ruleTester = new RuleTester();
30+
ruleTester.run('forbid-foreign-prop-types', rule, {
31+
32+
valid: [{
33+
code: 'import { propTypes } from "SomeComponent";',
34+
parser: 'babel-eslint'
35+
},{
36+
code: 'import { propTypes: someComponentPropTypes } from "SomeComponent";',
37+
parser: 'babel-eslint'
38+
}],
39+
40+
invalid: [{
41+
code: [
42+
'var Foo = React.createClass({',
43+
' propTypes: Bar.propTypes,',
44+
' render: function() {',
45+
' return <Foo className="bar" />;',
46+
' }',
47+
'});'
48+
].join('\n'),
49+
parserOptions: parserOptions,
50+
errors: [{
51+
message: ERROR_MESSAGE,
52+
type: 'Identifier'
53+
}]
54+
},
55+
{
56+
code: [
57+
'var Foo = React.createClass({',
58+
' propTypes: Bar["propTypes"],',
59+
' render: function() {',
60+
' return <Foo className="bar" />;',
61+
' }',
62+
'});'
63+
].join('\n'),
64+
parserOptions: parserOptions,
65+
errors: [{
66+
message: ERROR_MESSAGE,
67+
type: 'Literal'
68+
}]
69+
},
70+
{
71+
code: [
72+
'var { propTypes } = SomeComponent',
73+
'var Foo = React.createClass({',
74+
' propTypes,',
75+
' render: function() {',
76+
' return <Foo className="bar" />;',
77+
' }',
78+
'});'
79+
].join('\n'),
80+
parserOptions: parserOptions,
81+
errors: [{
82+
message: ERROR_MESSAGE,
83+
type: 'Property'
84+
}]
85+
},
86+
{
87+
code: [
88+
'var { propTypes: typesOfProps } = SomeComponent',
89+
'var Foo = React.createClass({',
90+
' propTypes: typesOfProps,',
91+
' render: function() {',
92+
' return <Foo className="bar" />;',
93+
' }',
94+
'});'
95+
].join('\n'),
96+
parserOptions: parserOptions,
97+
errors: [{
98+
message: ERROR_MESSAGE,
99+
type: 'Property'
100+
}]
101+
}]
102+
});

0 commit comments

Comments
 (0)