From 5d7486941b7ca5df8d8bd199ffb694ae1c5e9cec 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 366b2b7b0a7c60..d099725bc1d0be 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 856fd9b041f973..aca26648cf44e1 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); +}));