forked from jsx-eslint/eslint-plugin-react
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 jsx-eslint#696
- Loading branch information
Showing
5 changed files
with
251 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Forbid foreign propTypes (forbid-foreign-prop-types) | ||
|
||
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](https://github.com/oliviertassinari/babel-plugin-transform-react-remove-prop-types) to remove propTypes from their components in production builds, to do so safely. | ||
|
||
In order to ensure that imports are explicitly exported it is recommended to use the ["named" rule in eslint-plugin-import](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/named.md) in conjunction with this rule. | ||
|
||
## Rule Details | ||
|
||
This rule checks all objects and ensures that the `propTypes` property is not used. | ||
|
||
The following patterns are considered warnings: | ||
|
||
```js | ||
import SomeComponent from './SomeComponent'; | ||
SomeComponent.propTypes; | ||
|
||
var { propTypes } = SomeComponent; | ||
|
||
SomeComponent['propTypes']; | ||
``` | ||
|
||
The following patterns are not considered warnings: | ||
|
||
```js | ||
import SomeComponent, {propTypes as someComponentPropTypes} from './SomeComponent'; | ||
``` | ||
|
||
## When not to use | ||
|
||
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/** | ||
* @fileoverview Forbid using another component's propTypes | ||
* @author Ian Christian Myers | ||
*/ | ||
'use strict'; | ||
|
||
var find = require('array.prototype.find'); | ||
|
||
// ------------------------------------------------------------------------------ | ||
// Constants | ||
// ------------------------------------------------------------------------------ | ||
|
||
|
||
// ------------------------------------------------------------------------------ | ||
// Rule Definition | ||
// ------------------------------------------------------------------------------ | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: 'Forbid using another component\'s propTypes', | ||
category: 'Best Practices', | ||
recommended: false | ||
} | ||
}, | ||
|
||
create: function(context) { | ||
// -------------------------------------------------------------------------- | ||
// Helpers | ||
// -------------------------------------------------------------------------- | ||
|
||
function isLeftSideOfAssignment(node) { | ||
return node.parent.type === 'AssignmentExpression' && node.parent.left === node; | ||
} | ||
|
||
return { | ||
MemberExpression: function(node) { | ||
if (!node.computed && node.property && node.property.type === 'Identifier' && | ||
node.property.name === 'propTypes' && !isLeftSideOfAssignment(node) || | ||
node.property && node.property.type === 'Literal' && | ||
node.property.value === 'propTypes' && !isLeftSideOfAssignment(node)) { | ||
context.report({ | ||
node: node.property, | ||
message: 'Using another component\'s propTypes is forbidden' | ||
}); | ||
} | ||
}, | ||
|
||
ObjectPattern: function(node) { | ||
var propTypesNode = find(node.properties, function(property) { | ||
return property.type === 'Property' && property.key.name === 'propTypes'; | ||
}); | ||
|
||
if (propTypesNode) { | ||
context.report({ | ||
node: propTypesNode, | ||
message: 'Using another component\'s propTypes is forbidden' | ||
}); | ||
} | ||
} | ||
}; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
/** | ||
* @fileoverview Tests for forbid-foreign-prop-types | ||
*/ | ||
'use strict'; | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Requirements | ||
// ----------------------------------------------------------------------------- | ||
|
||
var rule = require('../../../lib/rules/forbid-foreign-prop-types'); | ||
var RuleTester = require('eslint').RuleTester; | ||
|
||
var parserOptions = { | ||
ecmaVersion: 6, | ||
sourceType: 'module', | ||
ecmaFeatures: { | ||
jsx: true | ||
} | ||
}; | ||
|
||
require('babel-eslint'); | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Tests | ||
// ----------------------------------------------------------------------------- | ||
|
||
var ERROR_MESSAGE = 'Using another component\'s propTypes is forbidden'; | ||
|
||
var ruleTester = new RuleTester(); | ||
ruleTester.run('forbid-foreign-prop-types', rule, { | ||
|
||
valid: [{ | ||
code: 'import { propTypes } from "SomeComponent";', | ||
parserOptions: parserOptions | ||
}, { | ||
code: 'import { propTypes as someComponentPropTypes } from "SomeComponent";', | ||
parserOptions: parserOptions | ||
}, { | ||
code: 'const foo = propTypes', | ||
parserOptions: parserOptions | ||
}, { | ||
code: 'foo(propTypes)', | ||
parserOptions: parserOptions | ||
}, { | ||
code: 'foo + propTypes', | ||
parserOptions: parserOptions | ||
}, { | ||
code: 'const foo = [propTypes]', | ||
parserOptions: parserOptions | ||
}, { | ||
code: 'const foo = { propTypes }', | ||
parserOptions: parserOptions | ||
}, { | ||
code: 'Foo.propTypes = propTypes', | ||
parserOptions: parserOptions | ||
}, { | ||
code: 'Foo["propTypes"] = propTypes', | ||
parserOptions: parserOptions | ||
}, { | ||
code: 'const propTypes = "bar"; Foo[propTypes];', | ||
parserOptions: parserOptions | ||
}], | ||
|
||
invalid: [{ | ||
code: [ | ||
'var Foo = React.createClass({', | ||
' propTypes: Bar.propTypes,', | ||
' render: function() {', | ||
' return <Foo className="bar" />;', | ||
' }', | ||
'});' | ||
].join('\n'), | ||
parserOptions: parserOptions, | ||
errors: [{ | ||
message: ERROR_MESSAGE, | ||
type: 'Identifier' | ||
}] | ||
}, | ||
{ | ||
code: [ | ||
'var Foo = React.createClass({', | ||
' propTypes: Bar["propTypes"],', | ||
' render: function() {', | ||
' return <Foo className="bar" />;', | ||
' }', | ||
'});' | ||
].join('\n'), | ||
parserOptions: parserOptions, | ||
errors: [{ | ||
message: ERROR_MESSAGE, | ||
type: 'Literal' | ||
}] | ||
}, | ||
{ | ||
code: [ | ||
'var { propTypes } = SomeComponent', | ||
'var Foo = React.createClass({', | ||
' propTypes,', | ||
' render: function() {', | ||
' return <Foo className="bar" />;', | ||
' }', | ||
'});' | ||
].join('\n'), | ||
parserOptions: parserOptions, | ||
errors: [{ | ||
message: ERROR_MESSAGE, | ||
type: 'Property' | ||
}] | ||
}, | ||
{ | ||
code: [ | ||
'var { propTypes: things, ...foo } = SomeComponent', | ||
'var Foo = React.createClass({', | ||
' propTypes,', | ||
' render: function() {', | ||
' return <Foo className="bar" />;', | ||
' }', | ||
'});' | ||
].join('\n'), | ||
parser: 'babel-eslint', | ||
errors: [{ | ||
message: ERROR_MESSAGE, | ||
type: 'Property' | ||
}] | ||
}, | ||
{ | ||
code: [ | ||
'class MyComponent extends React.Component {', | ||
' static fooBar = {', | ||
' baz: Qux.propTypes.baz', | ||
' };', | ||
'}' | ||
].join('\n'), | ||
parser: 'babel-eslint', | ||
errors: [{ | ||
message: ERROR_MESSAGE, | ||
type: 'Identifier' | ||
}] | ||
}, | ||
{ | ||
code: [ | ||
'var { propTypes: typesOfProps } = SomeComponent', | ||
'var Foo = React.createClass({', | ||
' propTypes: typesOfProps,', | ||
' render: function() {', | ||
' return <Foo className="bar" />;', | ||
' }', | ||
'});' | ||
].join('\n'), | ||
parserOptions: parserOptions, | ||
errors: [{ | ||
message: ERROR_MESSAGE, | ||
type: 'Property' | ||
}] | ||
}] | ||
}); |