From ce145bf3581f3bcff71e9b069d2620783c2a6466 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 17 Aug 2015 12:03:32 -0700 Subject: [PATCH] repl: filter integer keys from repl tab complete list Refactored version of https://github.com/joyent/node/pull/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 PR-URL: https://github.com/nodejs/node/pull/2409 --- lib/repl.js | 17 ++++-- test/parallel/test-repl-tab-complete.js | 70 +++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/lib/repl.js b/lib/repl.js index 366b2b7b0a..d099725bc1 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -561,6 +561,15 @@ const requireRE = /\brequire\s*\(['"](([\w\.\/-]+\/)?([\w\.\/-]*))/; const simpleExpressionRE = /(([a-zA-Z_$](?:\w|\$)*)\.)*([a-zA-Z_$](?:\w|\$)*)\.?$/; +function intFilter(item) { + // filters out anything not starting with A-Z, a-z, $ or _ + return /^[A-Za-z_$]/.test(item); +} + +function filteredOwnPropertyNames(obj) { + if (!obj) return []; + return Object.getOwnPropertyNames(obj).filter(intFilter); +} // Provide a list of completions for the given leading text. This is // given to the readline interface for handling tab completion. @@ -705,9 +714,9 @@ REPLServer.prototype.complete = function(line, callback) { if (this.useGlobal || vm.isContext(this.context)) { var contextProto = this.context; while (contextProto = Object.getPrototypeOf(contextProto)) { - completionGroups.push(Object.getOwnPropertyNames(contextProto)); + completionGroups.push(filteredOwnPropertyNames(contextProto)); } - completionGroups.push(Object.getOwnPropertyNames(this.context)); + completionGroups.push(filteredOwnPropertyNames(this.context)); addStandardGlobals(completionGroups, filter); completionGroupsLoaded(); } else { @@ -733,7 +742,7 @@ REPLServer.prototype.complete = function(line, callback) { if (obj != null) { if (typeof obj === 'object' || typeof obj === 'function') { try { - memberGroups.push(Object.getOwnPropertyNames(obj)); + memberGroups.push(filteredOwnPropertyNames(obj)); } catch (ex) { // Probably a Proxy object without `getOwnPropertyNames` trap. // We simply ignore it here, as we don't want to break the @@ -751,7 +760,7 @@ REPLServer.prototype.complete = function(line, callback) { p = obj.constructor ? obj.constructor.prototype : null; } while (p !== null) { - memberGroups.push(Object.getOwnPropertyNames(p)); + memberGroups.push(filteredOwnPropertyNames(p)); p = Object.getPrototypeOf(p); // Circular refs possible? Let's guard against that. sentinel--; diff --git a/test/parallel/test-repl-tab-complete.js b/test/parallel/test-repl-tab-complete.js index 856fd9b041..aca26648cf 100644 --- a/test/parallel/test-repl-tab-complete.js +++ b/test/parallel/test-repl-tab-complete.js @@ -248,3 +248,73 @@ testMe.complete('proxy.', common.mustCall(function(error, data) { assert.strictEqual(error, null); assert.deepEqual(data, [[], 'proxy.']); })); + +// Make sure tab completion does not include integer members of an Array +var array_elements = [ [ + 'ary.__defineGetter__', + 'ary.__defineSetter__', + 'ary.__lookupGetter__', + 'ary.__lookupSetter__', + 'ary.__proto__', + 'ary.constructor', + 'ary.hasOwnProperty', + 'ary.isPrototypeOf', + 'ary.propertyIsEnumerable', + 'ary.toLocaleString', + 'ary.toString', + 'ary.valueOf', + '', + 'ary.concat', + 'ary.entries', + 'ary.every', + 'ary.filter', + 'ary.forEach', + 'ary.indexOf', + 'ary.join', + 'ary.keys', + 'ary.lastIndexOf', + 'ary.length', + 'ary.map', + 'ary.pop', + 'ary.push', + 'ary.reduce', + 'ary.reduceRight', + 'ary.reverse', + 'ary.shift', + 'ary.slice', + 'ary.some', + 'ary.sort', + 'ary.splice', + 'ary.unshift' ], + 'ary.']; + +putIn.run(['.clear']); + +putIn.run(['var ary = [1,2,3];']); +testMe.complete('ary.', common.mustCall(function(error, data) { + assert.deepEqual(data, array_elements); +})); + +// Make sure tab completion does not include integer keys in an object +var obj_elements = [ [ + 'obj.__defineGetter__', + 'obj.__defineSetter__', + 'obj.__lookupGetter__', + 'obj.__lookupSetter__', + 'obj.__proto__', + 'obj.constructor', + 'obj.hasOwnProperty', + 'obj.isPrototypeOf', + 'obj.propertyIsEnumerable', + 'obj.toLocaleString', + 'obj.toString', + 'obj.valueOf', + '', + 'obj.a' ], + 'obj.' ]; +putIn.run(['.clear']); +putIn.run(['var obj = {1:"a","1a":"b",a:"b"};']); + +testMe.complete('obj.', common.mustCall(function(error, data) { + assert.deepEqual(data, obj_elements); +}));