Skip to content

Commit 815fbec

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 <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Tobias Nießen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent 93bbaa0 commit 815fbec

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

Diff for: lib/repl.js

+22-2
Original file line numberDiff line numberDiff line change
@@ -1188,11 +1188,31 @@ function isIdentifier(str) {
11881188
return true;
11891189
}
11901190

1191+
function isNotLegacyObjectPrototypeMethod(str) {
1192+
return isIdentifier(str) &&
1193+
str !== '__defineGetter__' &&
1194+
str !== '__defineSetter__' &&
1195+
str !== '__lookupGetter__' &&
1196+
str !== '__lookupSetter__';
1197+
}
1198+
11911199
function filteredOwnPropertyNames(obj) {
11921200
if (!obj) return [];
1201+
// `Object.prototype` is the only non-contrived object that fulfills
1202+
// `Object.getPrototypeOf(X) === null &&
1203+
// Object.getPrototypeOf(Object.getPrototypeOf(X.constructor)) === X`.
1204+
let isObjectPrototype = false;
1205+
if (ObjectGetPrototypeOf(obj) === null) {
1206+
const ctorDescriptor = ObjectGetOwnPropertyDescriptor(obj, 'constructor');
1207+
if (ctorDescriptor && ctorDescriptor.value) {
1208+
const ctorProto = ObjectGetPrototypeOf(ctorDescriptor.value);
1209+
isObjectPrototype = ctorProto && ObjectGetPrototypeOf(ctorProto) === obj;
1210+
}
1211+
}
11931212
const filter = ALL_PROPERTIES | SKIP_SYMBOLS;
1194-
return ArrayPrototypeFilter(getOwnNonIndexProperties(obj, filter),
1195-
isIdentifier);
1213+
return ArrayPrototypeFilter(
1214+
getOwnNonIndexProperties(obj, filter),
1215+
isObjectPrototype ? isNotLegacyObjectPrototypeMethod : isIdentifier);
11961216
}
11971217

11981218
function getGlobalLexicalScopeNames(contextId) {

Diff for: test/parallel/test-repl-tab-complete.js

+12
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)