Skip to content

Commit 5d74869

Browse files
jasnellrvagg
authored andcommitted
repl: filter integer keys from repl tab complete list
Refactored version of nodejs/node-v0.x-archive#25819 Removes integer keys (and keys starting with numbers) from candidate list on repl tab complete. Refactored the originally submitted change to simplify and ensure that the integer keys do not show up on objects either. Reviewed By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com> PR-URL: #2409
1 parent 1cd794f commit 5d74869

File tree

2 files changed

+83
-4
lines changed

2 files changed

+83
-4
lines changed

lib/repl.js

+13-4
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,15 @@ const requireRE = /\brequire\s*\(['"](([\w\.\/-]+\/)?([\w\.\/-]*))/;
561561
const simpleExpressionRE =
562562
/(([a-zA-Z_$](?:\w|\$)*)\.)*([a-zA-Z_$](?:\w|\$)*)\.?$/;
563563

564+
function intFilter(item) {
565+
// filters out anything not starting with A-Z, a-z, $ or _
566+
return /^[A-Za-z_$]/.test(item);
567+
}
568+
569+
function filteredOwnPropertyNames(obj) {
570+
if (!obj) return [];
571+
return Object.getOwnPropertyNames(obj).filter(intFilter);
572+
}
564573

565574
// Provide a list of completions for the given leading text. This is
566575
// given to the readline interface for handling tab completion.
@@ -705,9 +714,9 @@ REPLServer.prototype.complete = function(line, callback) {
705714
if (this.useGlobal || vm.isContext(this.context)) {
706715
var contextProto = this.context;
707716
while (contextProto = Object.getPrototypeOf(contextProto)) {
708-
completionGroups.push(Object.getOwnPropertyNames(contextProto));
717+
completionGroups.push(filteredOwnPropertyNames(contextProto));
709718
}
710-
completionGroups.push(Object.getOwnPropertyNames(this.context));
719+
completionGroups.push(filteredOwnPropertyNames(this.context));
711720
addStandardGlobals(completionGroups, filter);
712721
completionGroupsLoaded();
713722
} else {
@@ -733,7 +742,7 @@ REPLServer.prototype.complete = function(line, callback) {
733742
if (obj != null) {
734743
if (typeof obj === 'object' || typeof obj === 'function') {
735744
try {
736-
memberGroups.push(Object.getOwnPropertyNames(obj));
745+
memberGroups.push(filteredOwnPropertyNames(obj));
737746
} catch (ex) {
738747
// Probably a Proxy object without `getOwnPropertyNames` trap.
739748
// We simply ignore it here, as we don't want to break the
@@ -751,7 +760,7 @@ REPLServer.prototype.complete = function(line, callback) {
751760
p = obj.constructor ? obj.constructor.prototype : null;
752761
}
753762
while (p !== null) {
754-
memberGroups.push(Object.getOwnPropertyNames(p));
763+
memberGroups.push(filteredOwnPropertyNames(p));
755764
p = Object.getPrototypeOf(p);
756765
// Circular refs possible? Let's guard against that.
757766
sentinel--;

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

+70
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,73 @@ testMe.complete('proxy.', common.mustCall(function(error, data) {
248248
assert.strictEqual(error, null);
249249
assert.deepEqual(data, [[], 'proxy.']);
250250
}));
251+
252+
// Make sure tab completion does not include integer members of an Array
253+
var array_elements = [ [
254+
'ary.__defineGetter__',
255+
'ary.__defineSetter__',
256+
'ary.__lookupGetter__',
257+
'ary.__lookupSetter__',
258+
'ary.__proto__',
259+
'ary.constructor',
260+
'ary.hasOwnProperty',
261+
'ary.isPrototypeOf',
262+
'ary.propertyIsEnumerable',
263+
'ary.toLocaleString',
264+
'ary.toString',
265+
'ary.valueOf',
266+
'',
267+
'ary.concat',
268+
'ary.entries',
269+
'ary.every',
270+
'ary.filter',
271+
'ary.forEach',
272+
'ary.indexOf',
273+
'ary.join',
274+
'ary.keys',
275+
'ary.lastIndexOf',
276+
'ary.length',
277+
'ary.map',
278+
'ary.pop',
279+
'ary.push',
280+
'ary.reduce',
281+
'ary.reduceRight',
282+
'ary.reverse',
283+
'ary.shift',
284+
'ary.slice',
285+
'ary.some',
286+
'ary.sort',
287+
'ary.splice',
288+
'ary.unshift' ],
289+
'ary.'];
290+
291+
putIn.run(['.clear']);
292+
293+
putIn.run(['var ary = [1,2,3];']);
294+
testMe.complete('ary.', common.mustCall(function(error, data) {
295+
assert.deepEqual(data, array_elements);
296+
}));
297+
298+
// Make sure tab completion does not include integer keys in an object
299+
var obj_elements = [ [
300+
'obj.__defineGetter__',
301+
'obj.__defineSetter__',
302+
'obj.__lookupGetter__',
303+
'obj.__lookupSetter__',
304+
'obj.__proto__',
305+
'obj.constructor',
306+
'obj.hasOwnProperty',
307+
'obj.isPrototypeOf',
308+
'obj.propertyIsEnumerable',
309+
'obj.toLocaleString',
310+
'obj.toString',
311+
'obj.valueOf',
312+
'',
313+
'obj.a' ],
314+
'obj.' ];
315+
putIn.run(['.clear']);
316+
putIn.run(['var obj = {1:"a","1a":"b",a:"b"};']);
317+
318+
testMe.complete('obj.', common.mustCall(function(error, data) {
319+
assert.deepEqual(data, obj_elements);
320+
}));

0 commit comments

Comments
 (0)