Skip to content

Commit

Permalink
Add invalid test cases, defer class expressions till program exit
Browse files Browse the repository at this point in the history
  • Loading branch information
Joachim Seminck committed Aug 27, 2017
1 parent 8a56b01 commit b92f2c6
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 3 deletions.
23 changes: 20 additions & 3 deletions lib/rules/prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ module.exports = {
// Used to track the type annotations in scope.
// Necessary because babel's scopes do not track type annotations.
let stack = null;
const classExpressions = [];

const MISSING_MESSAGE = '\'{{name}}\' is missing in props validation';

Expand Down Expand Up @@ -872,6 +873,7 @@ module.exports = {
while (annotation && (annotation.type === 'TypeAnnotation' || annotation.type === 'NullableTypeAnnotation')) {
annotation = annotation.typeAnnotation;
}

if (annotation.type === 'GenericTypeAnnotation' && typeScope(annotation.id.name)) {
return typeScope(annotation.id.name);
}
Expand Down Expand Up @@ -921,9 +923,10 @@ module.exports = {
},

ClassExpression: function(node) {
if (isSuperTypeParameterPropsDeclaration(node)) {
markPropTypesAsDeclared(node, resolveSuperParameterPropsType(node));
}
// TypeParameterDeclaration need to be added to typeScope in order to handle ClassExpressions.
// This visitor is executed before TypeParameterDeclaration are scoped, therefore we postpone
// processing class expressions until when the program exists.
classExpressions.push(node);
},

ClassProperty: function(node) {
Expand Down Expand Up @@ -1017,6 +1020,14 @@ module.exports = {
typeScope(node.id.name, node.right);
},

TypeParameterDeclaration: function(node) {
const identifier = node.params[0];

if (identifier.typeAnnotation) {
typeScope(identifier.name, identifier.typeAnnotation.typeAnnotation);
}
},

Program: function() {
stack = [{}];
},
Expand All @@ -1030,6 +1041,12 @@ module.exports = {
},

'Program:exit': function() {
classExpressions.forEach(node => {
if (isSuperTypeParameterPropsDeclaration(node)) {
markPropTypesAsDeclared(node, resolveSuperParameterPropsType(node));
}
});

stack = null;
const list = components.list();
// Report undeclared proptypes for all classes
Expand Down
29 changes: 29 additions & 0 deletions tests/lib/rules/prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -3295,6 +3295,35 @@ ruleTester.run('prop-types', rule, {
type: 'Identifier'
}],
parser: 'babel-eslint'
}, {
code: `
type Props = { foo: string }
function higherOrderComponent<Props>() {
return class extends React.Component<Props> {
render() {
return <div>{this.props.foo} - {this.props.bar}</div>
}
}
}
`,
errors: [{
message: '\'bar\' is missing in props validation'
}],
parser: 'babel-eslint'
}, {
code: `
function higherOrderComponent<P: { foo: string }>() {
return class extends React.Component<P> {
render() {
return <div>{this.props.foo} - {this.props.bar}</div>
}
}
}
`,
errors: [{
message: '\'bar\' is missing in props validation'
}],
parser: 'babel-eslint'
}
]
});

0 comments on commit b92f2c6

Please sign in to comment.