Skip to content

Commit 1894d6c

Browse files
starkwangtargos
authored andcommitted
repl: fix tab completion for object properties with special char
The old RegExp will pass property names like `"hello world!"` when filtering the results of tab complete. This change is to fix it. Fixes: #21201 PR-URL: #21556 Fixes: #21201 Reviewed-By: Tiancheng "Timothy" Gu <[email protected]> Reviewed-By: John-David Dalton <[email protected]>
1 parent 24bc6ab commit 1894d6c

File tree

2 files changed

+30
-4
lines changed

2 files changed

+30
-4
lines changed

lib/repl.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ const {
4747
makeRequireFunction,
4848
addBuiltinLibsToObject
4949
} = require('internal/modules/cjs/helpers');
50+
const {
51+
isIdentifierStart,
52+
isIdentifierChar
53+
} = require('internal/deps/acorn/dist/acorn');
5054
const internalUtil = require('internal/util');
5155
const { isTypedArray } = require('internal/util/types');
5256
const util = require('util');
@@ -900,9 +904,25 @@ const requireRE = /\brequire\s*\(['"](([\w@./-]+\/)?(?:[\w@./-]*))/;
900904
const simpleExpressionRE =
901905
/(?:[a-zA-Z_$](?:\w|\$)*\.)*[a-zA-Z_$](?:\w|\$)*\.?$/;
902906

903-
function intFilter(item) {
904-
// filters out anything not starting with A-Z, a-z, $ or _
905-
return /^[A-Za-z_$]/.test(item);
907+
function isIdentifier(str) {
908+
if (str === '') {
909+
return false;
910+
}
911+
const first = str.codePointAt(0);
912+
if (!isIdentifierStart(first)) {
913+
return false;
914+
}
915+
const firstLen = first > 0xffff ? 2 : 1;
916+
for (var i = firstLen; i < str.length; i += 1) {
917+
const cp = str.codePointAt(i);
918+
if (!isIdentifierChar(cp)) {
919+
return false;
920+
}
921+
if (cp > 0xffff) {
922+
i += 1;
923+
}
924+
}
925+
return true;
906926
}
907927

908928
const ARRAY_LENGTH_THRESHOLD = 1e6;
@@ -932,7 +952,7 @@ function filteredOwnPropertyNames(obj) {
932952

933953
return fakeProperties;
934954
}
935-
return Object.getOwnPropertyNames(obj).filter(intFilter);
955+
return Object.getOwnPropertyNames(obj).filter(isIdentifier);
936956
}
937957

938958
function getGlobalLexicalScopeNames(contextId) {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,12 @@ putIn.run(['.clear']);
369369
testMe.complete('.b', common.mustCall((error, data) => {
370370
assert.deepStrictEqual(data, [['break'], 'b']);
371371
}));
372+
putIn.run(['.clear']);
373+
putIn.run(['var obj = {"hello, world!": "some string", "key": 123}']);
374+
testMe.complete('obj.', common.mustCall((error, data) => {
375+
assert.strictEqual(data[0].includes('obj.hello, world!'), false);
376+
assert(data[0].includes('obj.key'));
377+
}));
372378

373379
// tab completion for large buffer
374380
const warningRegEx = new RegExp(

0 commit comments

Comments
 (0)