Skip to content

Commit

Permalink
Aadd support also for no-unused-prop-types
Browse files Browse the repository at this point in the history
  • Loading branch information
Joachim Seminck committed Sep 6, 2017
1 parent 19a2911 commit 3e4d184
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 44 deletions.
87 changes: 47 additions & 40 deletions lib/rules/no-unused-prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -725,49 +725,69 @@ module.exports = {
}

/**
* Marks all props found inside IntersectionTypeAnnotation as declared.
* Since InterSectionTypeAnnotations can be nested, this handles recursively.
* Marks all props found inside ObjectTypeAnnotaiton as declared.
*
* Modifies the declaredPropTypes object
* Modifies the declaredProperties object
* @param {ASTNode} propTypes
* @param {Object} declaredPropTypes
* @returns {Boolean} True if propTypes should be ignored (e.g. when a type can't be resolved, when it is imported)
*/
function declarePropTypesForIntersectionTypeAnnotation(propTypes, declaredPropTypes) {
function declarePropTypesForObjectTypeAnnotation(propTypes, declaredPropTypes) {
let ignorePropsValidation = false;

propTypes.types.forEach(annotation => {
const typeNode = typeScope(annotation.id.name);

if (!typeNode) {
iterateProperties(propTypes.properties, (key, value) => {
if (!value) {
ignorePropsValidation = true;
return;
}

if (typeNode.type === 'IntersectionTypeAnnotation') {
ignorePropsValidation = declarePropTypesForIntersectionTypeAnnotation(typeNode, declaredPropTypes);
} else {
iterateProperties(typeNode.properties, (key, value) => {
if (!value) {
ignorePropsValidation = true;
return;
}

let types = buildTypeAnnotationDeclarationTypes(value, key);
if (types === true) {
types = {};
}
types.fullName = key;
types.name = key;
types.node = value;
declaredPropTypes.push(types);
});
let types = buildTypeAnnotationDeclarationTypes(value, key);
if (types === true) {
types = {};
}
types.fullName = key;
types.name = key;
types.node = value;
declaredPropTypes.push(types);
});

return ignorePropsValidation;
}

/**
* Marks all props found inside IntersectionTypeAnnotation as declared.
* Since InterSectionTypeAnnotations can be nested, this handles recursively.
*
* Modifies the declaredPropTypes object
* @param {ASTNode} propTypes
* @param {Object} declaredPropTypes
* @returns {Boolean} True if propTypes should be ignored (e.g. when a type can't be resolved, when it is imported)
*/
function declarePropTypesForIntersectionTypeAnnotation(propTypes, declaredPropTypes) {
return propTypes.types.reduce((ignorePropsValidation, annotation) => {
// If we already decided to skip props validation then we don't have to continue processing anything else
if (ignorePropsValidation) {
return ignorePropsValidation;
}

if (annotation.type === 'ObjectTypeAnnotation') {
ignorePropsValidation = declarePropTypesForObjectTypeAnnotation(annotation, declaredPropTypes);
} else {
const typeNode = typeScope(annotation.id.name);

if (!typeNode) {
ignorePropsValidation = true;
} else if (typeNode.type === 'IntersectionTypeAnnotation') {
ignorePropsValidation = declarePropTypesForIntersectionTypeAnnotation(typeNode, declaredPropTypes);
} else {
ignorePropsValidation = declarePropTypesForObjectTypeAnnotation(typeNode, declaredPropTypes);
}
}

return ignorePropsValidation;
}, false);
}

/**
* Mark a prop type as declared
* @param {ASTNode} node The AST node being checked.
Expand All @@ -780,20 +800,7 @@ module.exports = {

switch (propTypes && propTypes.type) {
case 'ObjectTypeAnnotation':
iterateProperties(propTypes.properties, (key, value) => {
if (!value) {
ignorePropsValidation = true;
return;
}
let types = buildTypeAnnotationDeclarationTypes(value, key);
if (types === true) {
types = {};
}
types.fullName = key;
types.name = key;
types.node = value;
declaredPropTypes.push(types);
});
ignorePropsValidation = declarePropTypesForObjectTypeAnnotation(propTypes, declaredPropTypes);
break;
case 'ObjectExpression':
iterateProperties(propTypes.properties, (key, value) => {
Expand Down
5 changes: 1 addition & 4 deletions lib/rules/prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -762,10 +762,7 @@ module.exports = {
}
}

// Return early if we have to ignore props validation. No point to continue processing.
if (ignorePropsValidation) {
return ignorePropsValidation;
}
return ignorePropsValidation;
}, false);
}

Expand Down
37 changes: 37 additions & 0 deletions tests/lib/rules/no-unused-prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,23 @@ ruleTester.run('no-unused-prop-types', rule, {
}
`,
parser: 'babel-eslint'
}, {
code: `
type PropsB = { foo: string };
type PropsC = { bar: string };
type Props = PropsB & {
zap: string
};
class Bar extends React.Component {
props: Props & PropsC;
render() {
return <div>{this.props.foo} - {this.props.bar} - {this.props.zap}</div>
}
}
`,
parser: 'babel-eslint'
}, {
code: [
'import type Props from "fake";',
Expand Down Expand Up @@ -2794,6 +2811,26 @@ ruleTester.run('no-unused-prop-types', rule, {
errors: [
{message: '\'zap\' PropType is defined but prop is never used'}
]
}, {
code: `
type PropsB = { foo: string };
type PropsC = { bar: string };
type Props = PropsB & {
zap: string
};
class Bar extends React.Component {
props: Props & PropsC;
render() {
return <div>{this.props.foo} - {this.props.bar}</div>
}
}
`,
errors: [
{message: '\'zap\' PropType is defined but prop is never used'}
],
parser: 'babel-eslint'
}, {
code: [
'class Hello extends React.Component {',
Expand Down

0 comments on commit 3e4d184

Please sign in to comment.