@@ -96,6 +96,10 @@ const {
9696 globalThis, 
9797}  =  primordials ; 
9898
99+ const  { 
100+  isProxy, 
101+ }  =  require ( 'internal/util/types' ) ; 
102+ 
99103const  {  BuiltinModule }  =  require ( 'internal/bootstrap/realm' ) ; 
100104const  { 
101105 makeRequireFunction, 
@@ -1328,8 +1332,10 @@ function completeFSFunctions(match) {
13281332// -> [['util.print', 'util.debug', 'util.log', 'util.inspect'], 
13291333// 'util.' ] 
13301334// 
1331- // Warning: This eval's code like "foo.bar.baz", so it will run property 
1332- // getter code. 
1335+ // Warning: This evals code like "foo.bar.baz", so it could run property 
1336+ // getter code. To avoid potential triggering side-effects with getters the completion 
1337+ // logic is skipped when getters or proxies are involved in the expression. 
1338+ // (see: https://github.com/nodejs/node/issues/57829). 
13331339function  complete ( line ,  callback )  { 
13341340 // List of completion lists, one for each inheritance "level" 
13351341 let  completionGroups  =  [ ] ; 
@@ -1525,50 +1531,61 @@ function complete(line, callback) {
15251531 return ; 
15261532 } 
15271533
1528-  let  chaining  =  '.' ; 
1529-  if  ( StringPrototypeEndsWith ( expr ,  '?' ) )  { 
1530-  expr  =  StringPrototypeSlice ( expr ,  0 ,  - 1 ) ; 
1531-  chaining  =  '?.' ; 
1532-  } 
1533- 
1534-  const  memberGroups  =  [ ] ; 
1535-  const  evalExpr  =  `try { ${ expr }   } catch {}` ; 
1536-  this . eval ( evalExpr ,  this . context ,  getREPLResourceName ( ) ,  ( e ,  obj )  =>  { 
1537-  try  { 
1538-  let  p ; 
1539-  if  ( ( typeof  obj  ===  'object'  &&  obj  !==  null )  || 
1540-  typeof  obj  ===  'function' )  { 
1541-  ArrayPrototypePush ( memberGroups ,  filteredOwnPropertyNames ( obj ) ) ; 
1542-  p  =  ObjectGetPrototypeOf ( obj ) ; 
1543-  }  else  { 
1544-  p  =  obj . constructor  ? obj . constructor . prototype  : null ; 
1534+  return  includesProxiesOrGetters ( 
1535+  StringPrototypeSplit ( match ,  '.' ) , 
1536+  this . eval , 
1537+  this . context , 
1538+  ( includes )  =>  { 
1539+  if  ( includes )  { 
1540+  // The expression involves proxies or getters, meaning that it 
1541+  // can trigger side-effectful behaviors, so bail out 
1542+  return  completionGroupsLoaded ( ) ; 
15451543 } 
1546-   // Circular refs possible? Let's guard against that. 
1547-  let  sentinel  =  5 ; 
1548-  while   ( p   !==   null   &&   sentinel --   !==   0 )  { 
1549-  ArrayPrototypePush ( memberGroups ,   filteredOwnPropertyNames ( p ) ) ; 
1550-  p  =  ObjectGetPrototypeOf ( p ) ; 
1544+ 
1545+  let  chaining  =  '.' ; 
1546+  if   ( StringPrototypeEndsWith ( expr ,   '?' ) )  { 
1547+  expr   =   StringPrototypeSlice ( expr ,   0 ,   - 1 ) ; 
1548+  chaining  =  '?.' ; 
15511549 } 
1552-  }  catch  { 
1553-  // Maybe a Proxy object without `getOwnPropertyNames` trap. 
1554-  // We simply ignore it here, as we don't want to break the 
1555-  // autocompletion. Fixes the bug 
1556-  // https://github.com/nodejs/node/issues/2119 
1557-  } 
15581550
1559-  if  ( memberGroups . length )  { 
1560-  expr  +=  chaining ; 
1561-  ArrayPrototypeForEach ( memberGroups ,  ( group )  =>  { 
1562-  ArrayPrototypePush ( completionGroups , 
1563-  ArrayPrototypeMap ( group , 
1564-  ( member )  =>  `${ expr } ${ member }  ` ) ) ; 
1565-  } ) ; 
1566-  filter  &&=  `${ expr } ${ filter }  ` ; 
1567-  } 
1551+  const  memberGroups  =  [ ] ; 
1552+  const  evalExpr  =  `try { ${ expr }   } catch {}` ; 
1553+  this . eval ( evalExpr ,  this . context ,  getREPLResourceName ( ) ,  ( e ,  obj )  =>  { 
1554+  try  { 
1555+  let  p ; 
1556+  if  ( ( typeof  obj  ===  'object'  &&  obj  !==  null )  || 
1557+  typeof  obj  ===  'function' )  { 
1558+  ArrayPrototypePush ( memberGroups ,  filteredOwnPropertyNames ( obj ) ) ; 
1559+  p  =  ObjectGetPrototypeOf ( obj ) ; 
1560+  }  else  { 
1561+  p  =  obj . constructor  ? obj . constructor . prototype  : null ; 
1562+  } 
1563+  // Circular refs possible? Let's guard against that. 
1564+  let  sentinel  =  5 ; 
1565+  while  ( p  !==  null  &&  sentinel --  !==  0 )  { 
1566+  ArrayPrototypePush ( memberGroups ,  filteredOwnPropertyNames ( p ) ) ; 
1567+  p  =  ObjectGetPrototypeOf ( p ) ; 
1568+  } 
1569+  }  catch  { 
1570+  // Maybe a Proxy object without `getOwnPropertyNames` trap. 
1571+  // We simply ignore it here, as we don't want to break the 
1572+  // autocompletion. Fixes the bug 
1573+  // https://github.com/nodejs/node/issues/2119 
1574+  } 
15681575
1569-  completionGroupsLoaded ( ) ; 
1570-  } ) ; 
1571-  return ; 
1576+  if  ( memberGroups . length )  { 
1577+  expr  +=  chaining ; 
1578+  ArrayPrototypeForEach ( memberGroups ,  ( group )  =>  { 
1579+  ArrayPrototypePush ( completionGroups , 
1580+  ArrayPrototypeMap ( group , 
1581+  ( member )  =>  `${ expr } ${ member }  ` ) ) ; 
1582+  } ) ; 
1583+  filter  &&=  `${ expr } ${ filter }  ` ; 
1584+  } 
1585+ 
1586+  completionGroupsLoaded ( ) ; 
1587+  } ) ; 
1588+  } ) ; 
15721589 } 
15731590
15741591 return  completionGroupsLoaded ( ) ; 
@@ -1626,6 +1643,34 @@ function complete(line, callback) {
16261643 } 
16271644} 
16281645
1646+ function  includesProxiesOrGetters ( exprSegments ,  evalFn ,  context ,  callback ,  currentExpr  =  '' ,  idx  =  0 )  { 
1647+  const  currentSegment  =  exprSegments [ idx ] ; 
1648+  currentExpr  +=  `${ currentExpr . length  ===  0  ? ''  : '.' } ${ currentSegment }  ` ; 
1649+  evalFn ( `try { ${ currentExpr }   } catch { }` ,  context ,  getREPLResourceName ( ) ,  ( _ ,  currentObj )  =>  { 
1650+  if  ( typeof  currentObj  !==  'object'  ||  currentObj  ===  null )  { 
1651+  return  callback ( false ) ; 
1652+  } 
1653+ 
1654+  if  ( isProxy ( currentObj ) )  { 
1655+  return  callback ( true ) ; 
1656+  } 
1657+ 
1658+  const  nextIdx  =  idx  +  1 ; 
1659+ 
1660+  if  ( nextIdx  >=  exprSegments . length )  { 
1661+  return  callback ( false ) ; 
1662+  } 
1663+ 
1664+  const  nextSegmentProp  =  ObjectGetOwnPropertyDescriptor ( currentObj ,  exprSegments [ nextIdx ] ) ; 
1665+  const  nextSegmentPropHasGetter  =  typeof  nextSegmentProp ?. get  ===  'function' ; 
1666+  if  ( nextSegmentPropHasGetter )  { 
1667+  return  callback ( true ) ; 
1668+  } 
1669+ 
1670+  return  includesProxiesOrGetters ( exprSegments ,  evalFn ,  context ,  callback ,  currentExpr ,  nextIdx ) ; 
1671+  } ) ; 
1672+ } 
1673+ 
16291674REPLServer . prototype . completeOnEditorMode  =  ( callback )  =>  ( err ,  results )  =>  { 
16301675 if  ( err )  return  callback ( err ) ; 
16311676
0 commit comments