@@ -33,7 +33,14 @@ function isJSXElementOrReactCall(path) {
33
33
) ;
34
34
}
35
35
36
- function resolvesToJSXElementOrReactCall ( path ) {
36
+ function resolvesToJSXElementOrReactCall ( path , seen ) {
37
+ // avoid returns with recursive function calls
38
+ if ( seen . has ( path ) ) {
39
+ return false ;
40
+ }
41
+
42
+ seen . add ( path ) ;
43
+
37
44
// Is the path is already a JSX element or a call to one of the React.* functions
38
45
if ( isJSXElementOrReactCall ( path ) ) {
39
46
return true ;
@@ -45,17 +52,17 @@ function resolvesToJSXElementOrReactCall(path) {
45
52
// the two possible paths
46
53
if ( resolvedPath . node . type === 'ConditionalExpression' ) {
47
54
return (
48
- resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'consequent' ) ) ||
49
- resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'alternate' ) )
55
+ resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'consequent' ) , seen ) ||
56
+ resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'alternate' ) , seen )
50
57
) ;
51
58
}
52
59
53
60
// If the path points to a logical expression (AND, OR, ...), then we need to look only at
54
61
// the two possible paths
55
62
if ( resolvedPath . node . type === 'LogicalExpression' ) {
56
63
return (
57
- resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'left' ) ) ||
58
- resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'right' ) )
64
+ resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'left' ) , seen ) ||
65
+ resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'right' ) , seen )
59
66
) ;
60
67
}
61
68
@@ -69,7 +76,7 @@ function resolvesToJSXElementOrReactCall(path) {
69
76
if ( resolvedPath . node . type === 'CallExpression' ) {
70
77
let calleeValue = resolveToValue ( resolvedPath . get ( 'callee' ) ) ;
71
78
72
- if ( returnsJSXElementOrReactCall ( calleeValue ) ) {
79
+ if ( returnsJSXElementOrReactCall ( calleeValue , seen ) ) {
73
80
return true ;
74
81
}
75
82
@@ -110,7 +117,7 @@ function resolvesToJSXElementOrReactCall(path) {
110
117
111
118
if (
112
119
! resolvedMemberExpression ||
113
- returnsJSXElementOrReactCall ( resolvedMemberExpression )
120
+ returnsJSXElementOrReactCall ( resolvedMemberExpression , seen )
114
121
) {
115
122
return true ;
116
123
}
@@ -120,14 +127,14 @@ function resolvesToJSXElementOrReactCall(path) {
120
127
return false ;
121
128
}
122
129
123
- function returnsJSXElementOrReactCall ( path ) {
130
+ function returnsJSXElementOrReactCall ( path , seen = new WeakSet ( ) ) {
124
131
let visited = false ;
125
132
126
133
// early exit for ArrowFunctionExpressions
127
134
if (
128
135
path . node . type === 'ArrowFunctionExpression' &&
129
136
path . get ( 'body' ) . node . type !== 'BlockStatement' &&
130
- resolvesToJSXElementOrReactCall ( path . get ( 'body' ) )
137
+ resolvesToJSXElementOrReactCall ( path . get ( 'body' ) , seen )
131
138
) {
132
139
return true ;
133
140
}
@@ -143,7 +150,7 @@ function returnsJSXElementOrReactCall(path) {
143
150
// Only check return statements which are part of the checked function scope
144
151
if ( returnPath . scope !== scope ) return false ;
145
152
146
- if ( resolvesToJSXElementOrReactCall ( returnPath . get ( 'argument' ) ) ) {
153
+ if ( resolvesToJSXElementOrReactCall ( returnPath . get ( 'argument' ) , seen ) ) {
147
154
visited = true ;
148
155
return false ;
149
156
}
0 commit comments