@@ -96,6 +96,10 @@ const {
96
96
globalThis,
97
97
} = primordials;
98
98
99
+
const {
100
+
isProxy,
101
+
} = require('internal/util/types');
102
+
99
103
const { BuiltinModule } = require('internal/bootstrap/realm');
100
104
const {
101
105
makeRequireFunction,
@@ -1328,8 +1332,10 @@ function completeFSFunctions(match) {
1328
1332
// -> [['util.print', 'util.debug', 'util.log', 'util.inspect'],
1329
1333
// 'util.' ]
1330
1334
//
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).
1333
1339
function complete(line, callback) {
1334
1340
// List of completion lists, one for each inheritance "level"
1335
1341
let completionGroups = [];
@@ -1525,50 +1531,61 @@ function complete(line, callback) {
1525
1531
return;
1526
1532
}
1527
1533
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();
1545
1543
}
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 = '?.';
1551
1549
}
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
-
}
1558
1550
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
+
}
1568
1575
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
+
});
1572
1589
}
1573
1590
1574
1591
return completionGroupsLoaded();
@@ -1626,6 +1643,34 @@ function complete(line, callback) {
1626
1643
}
1627
1644
}
1628
1645
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
+
1629
1674
REPLServer.prototype.completeOnEditorMode = (callback) => (err, results) => {
1630
1675
if (err) return callback(err);
1631
1676
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4