diff --git a/lib/repl.js b/lib/repl.js index 6b5f4803870c4a..6345c742f68f33 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -47,6 +47,10 @@ const { makeRequireFunction, addBuiltinLibsToObject } = require('internal/modules/cjs/helpers'); +const { + isIdentifierStart, + isIdentifierChar +} = require('internal/deps/acorn/dist/acorn'); const internalUtil = require('internal/util'); const { isTypedArray } = require('internal/util/types'); const util = require('util'); @@ -900,9 +904,25 @@ 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 isIdentifier(str) { + if (str === '') { + return false; + } + const first = str.codePointAt(0); + if (!isIdentifierStart(first)) { + return false; + } + const firstLen = first > 0xffff ? 2 : 1; + for (var i = firstLen; i < str.length; i += 1) { + const cp = str.codePointAt(i); + if (!isIdentifierChar(cp)) { + return false; + } + if (cp > 0xffff) { + i += 1; + } + } + return true; } const ARRAY_LENGTH_THRESHOLD = 1e6; @@ -932,7 +952,7 @@ function filteredOwnPropertyNames(obj) { return fakeProperties; } - return Object.getOwnPropertyNames(obj).filter(intFilter); + return Object.getOwnPropertyNames(obj).filter(isIdentifier); } function getGlobalLexicalScopeNames(contextId) { diff --git a/test/parallel/test-repl-tab-complete.js b/test/parallel/test-repl-tab-complete.js index 57c1615e6ffe2b..0e6c4bb654910e 100644 --- a/test/parallel/test-repl-tab-complete.js +++ b/test/parallel/test-repl-tab-complete.js @@ -369,6 +369,12 @@ putIn.run(['.clear']); testMe.complete('.b', common.mustCall((error, data) => { assert.deepStrictEqual(data, [['break'], 'b']); })); +putIn.run(['.clear']); +putIn.run(['var obj = {"hello, world!": "some string", "key": 123}']); +testMe.complete('obj.', common.mustCall((error, data) => { + assert.strictEqual(data[0].includes('obj.hello, world!'), false); + assert(data[0].includes('obj.key')); +})); // tab completion for large buffer const warningRegEx = new RegExp(