Skip to content

Commit

Permalink
Support recursive type annotations, fixes #913
Browse files Browse the repository at this point in the history
Originally written by @phpnode as part of #1138
  • Loading branch information
jetpacmonkey committed Jan 22, 2018
1 parent 692cdc8 commit 614d3bd
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 5 deletions.
21 changes: 16 additions & 5 deletions lib/rules/prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -466,11 +466,22 @@ module.exports = {
* @return {Object} The representation of the declaration, empty object means
* the property is declared without the need for further analysis.
*/
function buildTypeAnnotationDeclarationTypes(annotation) {
function buildTypeAnnotationDeclarationTypes(annotation, seen) {
if (seen === void 0) {
// Keeps track of annotations we've already seen to
// prevent problems with recursive types.
seen = new Set();
}
if (seen.has(annotation)) {
// This must be a recursive type annotation, so just accept anything.
return true;
}
seen.add(annotation);

switch (annotation.type) {
case 'GenericTypeAnnotation':
if (typeScope(annotation.id.name)) {
return buildTypeAnnotationDeclarationTypes(typeScope(annotation.id.name));
return buildTypeAnnotationDeclarationTypes(typeScope(annotation.id.name), seen);
}
return {};
case 'ObjectTypeAnnotation':
Expand All @@ -483,7 +494,7 @@ module.exports = {
if (!childKey && !childValue) {
containsObjectTypeSpread = true;
} else {
shapeTypeDefinition.children[childKey] = buildTypeAnnotationDeclarationTypes(childValue);
shapeTypeDefinition.children[childKey] = buildTypeAnnotationDeclarationTypes(childValue, seen);
}
});

Expand All @@ -498,7 +509,7 @@ module.exports = {
children: []
};
for (let i = 0, j = annotation.types.length; i < j; i++) {
const type = buildTypeAnnotationDeclarationTypes(annotation.types[i]);
const type = buildTypeAnnotationDeclarationTypes(annotation.types[i], seen);
// keep only complex type
if (Object.keys(type).length > 0) {
if (type.children === true) {
Expand All @@ -519,7 +530,7 @@ module.exports = {
return {
type: 'object',
children: {
__ANY_KEY__: buildTypeAnnotationDeclarationTypes(annotation.elementType)
__ANY_KEY__: buildTypeAnnotationDeclarationTypes(annotation.elementType, seen)
}
};
default:
Expand Down
14 changes: 14 additions & 0 deletions tests/lib/rules/prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -1581,6 +1581,20 @@ ruleTester.run('prop-types', rule, {
].join('\n'),
settings: {react: {flowVersion: '0.52'}},
parser: 'babel-eslint'
}, {
code: [
'type Note = {text: string, children?: Note[]};',
'type Props = {',
' notes: Note[];',
'};',
'class Hello extends React.Component<void, Props, void> {',
' render () {',
' return <div>Hello {this.props.notes[0].text}</div>;',
' }',
'}'
].join('\n'),
settings: {react: {flowVersion: '0.52'}},
parser: 'babel-eslint'
}, {
code: [
'import type Props from "fake";',
Expand Down

0 comments on commit 614d3bd

Please sign in to comment.