@@ -33,7 +33,14 @@ function isJSXElementOrReactCall(path) {
3333 ) ;
3434}
3535
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+
3744 // Is the path is already a JSX element or a call to one of the React.* functions
3845 if ( isJSXElementOrReactCall ( path ) ) {
3946 return true ;
@@ -45,17 +52,17 @@ function resolvesToJSXElementOrReactCall(path) {
4552 // the two possible paths
4653 if ( resolvedPath . node . type === 'ConditionalExpression' ) {
4754 return (
48- resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'consequent' ) ) ||
49- resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'alternate' ) )
55+ resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'consequent' ) , seen ) ||
56+ resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'alternate' ) , seen )
5057 ) ;
5158 }
5259
5360 // If the path points to a logical expression (AND, OR, ...), then we need to look only at
5461 // the two possible paths
5562 if ( resolvedPath . node . type === 'LogicalExpression' ) {
5663 return (
57- resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'left' ) ) ||
58- resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'right' ) )
64+ resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'left' ) , seen ) ||
65+ resolvesToJSXElementOrReactCall ( resolvedPath . get ( 'right' ) , seen )
5966 ) ;
6067 }
6168
@@ -69,7 +76,7 @@ function resolvesToJSXElementOrReactCall(path) {
6976 if ( resolvedPath . node . type === 'CallExpression' ) {
7077 let calleeValue = resolveToValue ( resolvedPath . get ( 'callee' ) ) ;
7178
72- if ( returnsJSXElementOrReactCall ( calleeValue ) ) {
79+ if ( returnsJSXElementOrReactCall ( calleeValue , seen ) ) {
7380 return true ;
7481 }
7582
@@ -110,7 +117,7 @@ function resolvesToJSXElementOrReactCall(path) {
110117
111118 if (
112119 ! resolvedMemberExpression ||
113- returnsJSXElementOrReactCall ( resolvedMemberExpression )
120+ returnsJSXElementOrReactCall ( resolvedMemberExpression , seen )
114121 ) {
115122 return true ;
116123 }
@@ -120,14 +127,14 @@ function resolvesToJSXElementOrReactCall(path) {
120127 return false ;
121128}
122129
123- function returnsJSXElementOrReactCall ( path ) {
130+ function returnsJSXElementOrReactCall ( path , seen = new WeakSet ( ) ) {
124131 let visited = false ;
125132
126133 // early exit for ArrowFunctionExpressions
127134 if (
128135 path . node . type === 'ArrowFunctionExpression' &&
129136 path . get ( 'body' ) . node . type !== 'BlockStatement' &&
130- resolvesToJSXElementOrReactCall ( path . get ( 'body' ) )
137+ resolvesToJSXElementOrReactCall ( path . get ( 'body' ) , seen )
131138 ) {
132139 return true ;
133140 }
@@ -143,7 +150,7 @@ function returnsJSXElementOrReactCall(path) {
143150 // Only check return statements which are part of the checked function scope
144151 if ( returnPath . scope !== scope ) return false ;
145152
146- if ( resolvesToJSXElementOrReactCall ( returnPath . get ( 'argument' ) ) ) {
153+ if ( resolvesToJSXElementOrReactCall ( returnPath . get ( 'argument' ) , seen ) ) {
147154 visited = true ;
148155 return false ;
149156 }
0 commit comments