Skip to content

Commit f5cc025

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 f5cc025

File tree

5 files changed

+184
-0
lines changed

5 files changed

+184
-0
lines changed

README.md

+1
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
+28
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 SomeComponent, {propTypes as someComponentPropTypes} 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

+1
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'),
+52
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+
};
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 as 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)