Skip to content

Commit 0722023

Browse files
repl: fix tab completion not working with computer string properties
PR-URL: #58709 Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]>
1 parent ea5d37e commit 0722023

File tree

2 files changed

+131
-1
lines changed

2 files changed

+131
-1
lines changed

lib/repl.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1226,7 +1226,7 @@ const importRE = /\bimport\s*\(\s*['"`](([\w@./:-]+\/)?(?:[\w@./:-]*))(?![^'"`])
12261226
const requireRE = /\brequire\s*\(\s*['"`](([\w@./:-]+\/)?(?:[\w@./:-]*))(?![^'"`])$/;
12271227
const fsAutoCompleteRE = /fs(?:\.promises)?\.\s*[a-z][a-zA-Z]+\(\s*["'](.*)/;
12281228
const simpleExpressionRE =
1229-
/(?:[\w$'"`[{(](?:\w|\$|['"`\]})])*\??\.)*[a-zA-Z_$](?:\w|\$)*\??\.?$/;
1229+
/(?:[\w$'"`[{(](?:(\w| |\t)*?['"`]|\$|['"`\]})])*\??(?:\.|])?)*?(?:[a-zA-Z_$])?(?:\w|\$)*\??\.?$/;
12301230
const versionedFileNamesRe = /-\d+\.\d+/;
12311231

12321232
function isIdentifier(str) {
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const ArrayStream = require('../common/arraystream');
5+
const { describe, it, before, after } = require('node:test');
6+
const assert = require('assert');
7+
8+
const repl = require('repl');
9+
10+
function prepareREPL() {
11+
const input = new ArrayStream();
12+
const replServer = repl.start({
13+
prompt: '',
14+
input,
15+
output: process.stdout,
16+
allowBlockingCompletions: true,
17+
});
18+
19+
// Some errors are passed to the domain, but do not callback
20+
replServer._domain.on('error', assert.ifError);
21+
22+
return { replServer, input };
23+
}
24+
25+
function testCompletion(replServer, { input, expectedCompletions }) {
26+
replServer.complete(
27+
input,
28+
common.mustCall((_error, data) => {
29+
assert.deepStrictEqual(data, [expectedCompletions, input]);
30+
}),
31+
);
32+
};
33+
34+
describe('REPL tab object completion on computed properties', () => {
35+
describe('simple string cases', () => {
36+
let replServer;
37+
38+
before(() => {
39+
const { replServer: server, input } = prepareREPL();
40+
replServer = server;
41+
42+
input.run([
43+
`
44+
const obj = {
45+
one: 1,
46+
innerObj: { two: 2 },
47+
'inner object': { three: 3 },
48+
};
49+
50+
const oneStr = 'one';
51+
`,
52+
]);
53+
});
54+
55+
after(() => {
56+
replServer.close();
57+
});
58+
59+
it('works with double quoted strings', () => testCompletion(replServer, {
60+
input: 'obj["one"].toFi',
61+
expectedCompletions: ['obj["one"].toFixed'],
62+
}));
63+
64+
it('works with single quoted strings', () => testCompletion(replServer, {
65+
input: "obj['one'].toFi",
66+
expectedCompletions: ["obj['one'].toFixed"],
67+
}));
68+
69+
it('works with template strings', () => testCompletion(replServer, {
70+
input: 'obj[`one`].toFi',
71+
expectedCompletions: ['obj[`one`].toFixed'],
72+
}));
73+
74+
it('works with nested objects', () => {
75+
testCompletion(replServer, {
76+
input: 'obj["innerObj"].tw',
77+
expectedCompletions: ['obj["innerObj"].two'],
78+
});
79+
testCompletion(replServer, {
80+
input: 'obj["innerObj"].two.tofi',
81+
expectedCompletions: ['obj["innerObj"].two.toFixed'],
82+
});
83+
});
84+
85+
it('works with nested objects combining different type of strings', () => testCompletion(replServer, {
86+
input: 'obj["innerObj"][`two`].tofi',
87+
expectedCompletions: ['obj["innerObj"][`two`].toFixed'],
88+
}));
89+
90+
it('works with strings with spaces', () => testCompletion(replServer, {
91+
input: 'obj["inner object"].th',
92+
expectedCompletions: ['obj["inner object"].three'],
93+
}));
94+
});
95+
96+
describe('variables as indexes', () => {
97+
let replServer;
98+
99+
before(() => {
100+
const { replServer: server, input } = prepareREPL();
101+
replServer = server;
102+
103+
input.run([
104+
`
105+
const oneStr = 'One';
106+
const helloWorldStr = 'Hello' + ' ' + 'World';
107+
108+
const obj = {
109+
[oneStr]: 1,
110+
['Hello World']: 'hello world!',
111+
};
112+
`,
113+
]);
114+
});
115+
116+
after(() => {
117+
replServer.close();
118+
});
119+
120+
it('works with a simple variable', () => testCompletion(replServer, {
121+
input: 'obj[oneStr].toFi',
122+
expectedCompletions: ['obj[oneStr].toFixed'],
123+
}));
124+
125+
it('works with a computed variable', () => testCompletion(replServer, {
126+
input: 'obj[helloWorldStr].tolocaleup',
127+
expectedCompletions: ['obj[helloWorldStr].toLocaleUpperCase'],
128+
}));
129+
});
130+
});

0 commit comments

Comments
 (0)