Skip to content

Commit

Permalink
Merge pull request #1412 from jseminck/no-unused-prop-types-flow-53
Browse files Browse the repository at this point in the history
Add support for Flow TypedArgument in no-unsed-prop-types rule
  • Loading branch information
yannickcr authored Sep 5, 2017
2 parents 94fbe6f + 3f03ac6 commit 9e090ed
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 0 deletions.
49 changes: 49 additions & 0 deletions lib/rules/no-unused-prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const has = require('has');
const Components = require('../util/Components');
const variable = require('../util/variable');
const annotations = require('../util/annotations');
const versionUtil = require('../util/version');

// ------------------------------------------------------------------------------
// Constants
Expand Down Expand Up @@ -133,6 +134,48 @@ module.exports = {
return false;
}

/**
* Resolve the type annotation for a given class declaration node with superTypeParameters.
*
* @param {ASTNode} node The annotation or a node containing the type annotation.
* @returns {ASTNode} The resolved type annotation for the node.
*/
function resolveSuperParameterPropsType(node) {
let propsParameterPosition;
try {
// Flow <=0.52 had 3 required TypedParameters of which the second one is the Props.
// Flow >=0.53 has 2 optional TypedParameters of which the first one is the Props.
propsParameterPosition = versionUtil.testFlowVersion(context, '0.53.0') ? 0 : 1;
} catch (e) {
// In case there is no flow version defined, we can safely assume that when there are 3 Props we are dealing with version <= 0.52
propsParameterPosition = node.superTypeParameters.params.length <= 2 ? 0 : 1;
}

let annotation = node.superTypeParameters.params[propsParameterPosition];
while (annotation && (annotation.type === 'TypeAnnotation' || annotation.type === 'NullableTypeAnnotation')) {
annotation = annotation.typeAnnotation;
}
if (annotation.type === 'GenericTypeAnnotation' && typeScope(annotation.id.name)) {
return typeScope(annotation.id.name);
}
return annotation;
}

/**
* Checks if we are declaring a props as a generic type in a flow-annotated class.
*
* @param {ASTNode} node the AST node being checked.
* @returns {Boolean} True if the node is a class with generic prop types, false if not.
*/
function isSuperTypeParameterPropsDeclaration(node) {
if (node && node.type === 'ClassDeclaration') {
if (node.superTypeParameters && node.superTypeParameters.params.length > 0) {
return true;
}
}
return false;
}

/**
* Checks if we are declaring a prop
* @param {ASTNode} node The AST node being checked.
Expand Down Expand Up @@ -866,6 +909,12 @@ module.exports = {
// --------------------------------------------------------------------------

return {
ClassDeclaration: function(node) {
if (isSuperTypeParameterPropsDeclaration(node)) {
markPropTypesAsDeclared(node, resolveSuperParameterPropsType(node));
}
},

ClassProperty: function(node) {
if (isAnnotatedClassPropsDeclaration(node)) {
markPropTypesAsDeclared(node, resolveTypeAnnotation(node));
Expand Down
1 change: 1 addition & 0 deletions lib/rules/prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const Components = require('../util/Components');
const variable = require('../util/variable');
const annotations = require('../util/annotations');
const versionUtil = require('../util/version');

// ------------------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------------------
Expand Down
116 changes: 116 additions & 0 deletions tests/lib/rules/no-unused-prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -2069,6 +2069,56 @@ ruleTester.run('no-unused-prop-types', rule, {
};
`,
parser: 'babel-eslint'
}, {
code: `
type Person = {
firstname: string
}
class MyComponent extends React.Component<void, Props, void> {
render() {
return <div>Hello {this.props.firstname}</div>
}
}
`,
parser: 'babel-eslint'
}, {
code: `
type Person = {
firstname: string
}
class MyComponent extends React.Component<void, Props, void> {
render() {
return <div>Hello {this.props.firstname}</div>
}
}
`,
settings: {react: {flowVersion: '0.52'}},
parser: 'babel-eslint'
}, {
code: `
type Person = {
firstname: string
}
class MyComponent extends React.Component<Props> {
render() {
return <div>Hello {this.props.firstname}</div>
}
}
`,
parser: 'babel-eslint'
}, {
code: `
type Person = {
firstname: string
}
class MyComponent extends React.Component<Props> {
render() {
return <div>Hello {this.props.firstname}</div>
}
}
`,
settings: {react: {flowVersion: '0.53'}},
parser: 'babel-eslint'
}
],

Expand Down Expand Up @@ -3469,6 +3519,72 @@ ruleTester.run('no-unused-prop-types', rule, {
errors: [{
message: '\'aProp\' PropType is defined but prop is never used'
}]
}, {
code: `
type Props = {
firstname: string,
lastname: string,
}
class MyComponent extends React.Component<void, Props, void> {
render() {
return <div>Hello {this.props.firstname}</div>
}
}
`,
parser: 'babel-eslint',
errors: [{
message: '\'lastname\' PropType is defined but prop is never used'
}]
}, {
code: `
type Props = {
firstname: string,
lastname: string,
}
class MyComponent extends React.Component<void, Props, void> {
render() {
return <div>Hello {this.props.firstname}</div>
}
}
`,
settings: {react: {flowVersion: '0.52'}},
parser: 'babel-eslint',
errors: [{
message: '\'lastname\' PropType is defined but prop is never used'
}]
}, {
code: `
type Props = {
firstname: string,
lastname: string,
}
class MyComponent extends React.Component<Props> {
render() {
return <div>Hello {this.props.firstname}</div>
}
}
`,
parser: 'babel-eslint',
errors: [{
message: '\'lastname\' PropType is defined but prop is never used'
}]
}, {
code: `
type Props = {
firstname: string,
lastname: string,
}
class MyComponent extends React.Component<Props> {
render() {
return <div>Hello {this.props.firstname}</div>
}
}
`,
settings: {react: {flowVersion: '0.53'}},
parser: 'babel-eslint',
errors: [{
message: '\'lastname\' PropType is defined but prop is never used'
}]
}

/* , {
Expand Down

0 comments on commit 9e090ed

Please sign in to comment.