@@ -22,20 +22,20 @@ export function has(object: any, key: string) {
2222
2323function resolve (
2424 path : NodePath ,
25- resolved : Set < NodePath > = new Set ( ) ,
25+ seen : Set < NodePath > = new Set ( ) ,
2626) : NodePath | undefined {
27- if ( resolved . has ( path ) ) return ;
28- resolved . add ( path ) ;
27+ if ( seen . has ( path ) ) return ;
28+ seen . add ( path ) ;
2929
3030 if ( path . isVariableDeclarator ( ) ) {
3131 if ( path . get ( "id" ) . isIdentifier ( ) ) {
32- return resolve ( path . get ( "init" ) , resolved ) ;
32+ return resolve ( path . get ( "init" ) , seen ) ;
3333 }
3434 } else if ( path . isReferencedIdentifier ( ) ) {
3535 const binding = path . scope . getBinding ( path . node . name ) ;
3636 if ( ! binding ) return path ;
3737 if ( ! binding . constant ) return ;
38- return resolve ( binding . path , resolved ) ;
38+ return resolve ( binding . path , seen ) ;
3939 }
4040 return path ;
4141}
@@ -104,15 +104,23 @@ export function resolveKey(
104104 }
105105}
106106
107- export function resolveInstance ( obj : NodePath ) : string | null {
108- const source = resolveSource ( obj ) ;
107+ function resolveInstance ( obj : NodePath , seen : Set < NodePath > ) : string | null {
108+ const source = resolveSource ( obj , seen ) ;
109109 return source . placement === "prototype" ? source . id : null ;
110110}
111111
112- export function resolveSource ( obj : NodePath ) : {
112+ export function resolveSource (
113+ obj : NodePath ,
114+ seen : Set < NodePath > ,
115+ ) : {
113116 id : string | null ;
114117 placement : "prototype" | "static" | null ;
115118} {
119+ if ( seen . has ( obj ) ) {
120+ return { id : null , placement : null } ;
121+ }
122+ seen . add ( obj ) ;
123+
116124 if (
117125 obj . isMemberExpression ( ) &&
118126 obj . get ( "property" ) . isIdentifier ( { name : "prototype" } )
@@ -175,6 +183,7 @@ export function resolveSource(obj: NodePath): {
175183 if ( operator === "-" || operator === "~" ) {
176184 const arg = resolveInstance (
177185 ( path as NodePath < t . UnaryExpression > ) . get ( "argument" ) ,
186+ seen ,
178187 ) ;
179188 if ( arg === "BigInt" ) return { id : "BigInt" , placement : "prototype" } ;
180189 if ( arg !== null ) return { id : "Number" , placement : "prototype" } ;
@@ -186,6 +195,7 @@ export function resolveSource(obj: NodePath): {
186195 case "UpdateExpression" : {
187196 const arg = resolveInstance (
188197 ( path as NodePath < t . UpdateExpression > ) . get ( "argument" ) ,
198+ seen ,
189199 ) ;
190200 if ( arg === "BigInt" ) return { id : "BigInt" , placement : "prototype" } ;
191201 if ( arg !== null ) return { id : "Number" , placement : "prototype" } ;
@@ -227,9 +237,11 @@ export function resolveSource(obj: NodePath): {
227237 ) {
228238 const left = resolveInstance (
229239 ( path as NodePath < t . BinaryExpression > ) . get ( "left" ) ,
240+ seen ,
230241 ) ;
231242 const right = resolveInstance (
232243 ( path as NodePath < t . BinaryExpression > ) . get ( "right" ) ,
244+ seen ,
233245 ) ;
234246 if ( left === "BigInt" && right === "BigInt" ) {
235247 return { id : "BigInt" , placement : "prototype" } ;
@@ -243,9 +255,11 @@ export function resolveSource(obj: NodePath): {
243255 if ( operator === "+" ) {
244256 const left = resolveInstance (
245257 ( path as NodePath < t . BinaryExpression > ) . get ( "left" ) ,
258+ seen ,
246259 ) ;
247260 const right = resolveInstance (
248261 ( path as NodePath < t . BinaryExpression > ) . get ( "right" ) ,
262+ seen ,
249263 ) ;
250264 if ( left === "String" || right === "String" ) {
251265 return { id : "String" , placement : "prototype" } ;
@@ -264,13 +278,14 @@ export function resolveSource(obj: NodePath): {
264278 const expressions = ( path as NodePath < t . SequenceExpression > ) . get (
265279 "expressions" ,
266280 ) ;
267- return resolveSource ( expressions [ expressions . length - 1 ] ) ;
281+ return resolveSource ( expressions [ expressions . length - 1 ] , seen ) ;
268282 }
269283 // a = b -> the result is the right side
270284 case "AssignmentExpression" : {
271285 if ( ( path . node as t . AssignmentExpression ) . operator === "=" ) {
272286 return resolveSource (
273287 ( path as NodePath < t . AssignmentExpression > ) . get ( "right" ) ,
288+ seen ,
274289 ) ;
275290 }
276291 return { id : null , placement : null } ;
@@ -279,9 +294,11 @@ export function resolveSource(obj: NodePath): {
279294 case "ConditionalExpression" : {
280295 const consequent = resolveSource (
281296 ( path as NodePath < t . ConditionalExpression > ) . get ( "consequent" ) ,
297+ seen ,
282298 ) ;
283299 const alternate = resolveSource (
284300 ( path as NodePath < t . ConditionalExpression > ) . get ( "alternate" ) ,
301+ seen ,
285302 ) ;
286303 if ( consequent . id && consequent . id === alternate . id ) {
287304 return consequent ;
@@ -292,6 +309,7 @@ export function resolveSource(obj: NodePath): {
292309 case "ParenthesizedExpression" :
293310 return resolveSource (
294311 ( path as NodePath < t . ParenthesizedExpression > ) . get ( "expression" ) ,
312+ seen ,
295313 ) ;
296314 // TypeScript / Flow type wrappers -> unwrap to the inner expression
297315 case "TSAsExpression" :
@@ -300,7 +318,7 @@ export function resolveSource(obj: NodePath): {
300318 case "TSInstantiationExpression" :
301319 case "TSTypeAssertion" :
302320 case "TypeCastExpression" :
303- return resolveSource ( path . get ( "expression" ) as NodePath ) ;
321+ return resolveSource ( path . get ( "expression" ) as NodePath , seen ) ;
304322 }
305323
306324 return { id : null , placement : null } ;
0 commit comments