Skip to content

Commit 9264cae

Browse files
addaleaxtargos
authored andcommitted
repl: do not include legacy getter/setter methods in completion
For every object that inherits from `Object.prototype`, the REPL includes the `Object.prototype` methods in its autocompletion. This is already a little noisy, but in particular, this also includes the legacy `__defineGetter__` family of methods; since those are deprecated and not in practical use anymore, it helps reduce noise a bit to remove them. This commit does not remove `__proto__` as it is a little more popular and, despite its downsides, a slightly more convenient way to access the prototype of an object in the REPL than `Object.getPrototypeOf(...)`. PR-URL: #39576 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
1 parent 3482bca commit 9264cae

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

lib/repl.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,11 +1213,31 @@ function isIdentifier(str) {
12131213
return true;
12141214
}
12151215

1216+
function isNotLegacyObjectPrototypeMethod(str) {
1217+
return isIdentifier(str) &&
1218+
str !== '__defineGetter__' &&
1219+
str !== '__defineSetter__' &&
1220+
str !== '__lookupGetter__' &&
1221+
str !== '__lookupSetter__';
1222+
}
1223+
12161224
function filteredOwnPropertyNames(obj) {
12171225
if (!obj) return [];
1226+
// `Object.prototype` is the only non-contrived object that fulfills
1227+
// `Object.getPrototypeOf(X) === null &&
1228+
// Object.getPrototypeOf(Object.getPrototypeOf(X.constructor)) === X`.
1229+
let isObjectPrototype = false;
1230+
if (ObjectGetPrototypeOf(obj) === null) {
1231+
const ctorDescriptor = ObjectGetOwnPropertyDescriptor(obj, 'constructor');
1232+
if (ctorDescriptor && ctorDescriptor.value) {
1233+
const ctorProto = ObjectGetPrototypeOf(ctorDescriptor.value);
1234+
isObjectPrototype = ctorProto && ObjectGetPrototypeOf(ctorProto) === obj;
1235+
}
1236+
}
12181237
const filter = ALL_PROPERTIES | SKIP_SYMBOLS;
1219-
return ArrayPrototypeFilter(getOwnNonIndexProperties(obj, filter),
1220-
isIdentifier);
1238+
return ArrayPrototypeFilter(
1239+
getOwnNonIndexProperties(obj, filter),
1240+
isObjectPrototype ? isNotLegacyObjectPrototypeMethod : isIdentifier);
12211241
}
12221242

12231243
function getGlobalLexicalScopeNames(contextId) {

test/parallel/test-repl-tab-complete.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,18 @@ testMe.complete('obj.', common.mustCall((error, data) => {
443443
assert(data[0].includes('obj.key'));
444444
}));
445445

446+
// Make sure tab completion does not include __defineSetter__ and friends.
447+
putIn.run(['.clear']);
448+
449+
putIn.run(['var obj = {};']);
450+
testMe.complete('obj.', common.mustCall(function(error, data) {
451+
assert.strictEqual(data[0].includes('obj.__defineGetter__'), false);
452+
assert.strictEqual(data[0].includes('obj.__defineSetter__'), false);
453+
assert.strictEqual(data[0].includes('obj.__lookupGetter__'), false);
454+
assert.strictEqual(data[0].includes('obj.__lookupSetter__'), false);
455+
assert.strictEqual(data[0].includes('obj.__proto__'), true);
456+
}));
457+
446458
// Tab completion for files/directories
447459
{
448460
putIn.run(['.clear']);

0 commit comments

Comments
 (0)