mirror of
https://github.com/nodejs/node.git
synced 2025-08-15 13:48:44 +02:00

improve the tab completion capabilities around computed properties by replacing the use of brittle and error prone Regex checks with more robust AST based analysis PR-URL: https://github.com/nodejs/node/pull/58775 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
159 lines
4.5 KiB
JavaScript
159 lines
4.5 KiB
JavaScript
'use strict';
|
|
|
|
const common = require('../common');
|
|
const ArrayStream = require('../common/arraystream');
|
|
const { describe, it, before, after } = require('node:test');
|
|
const assert = require('assert');
|
|
|
|
const repl = require('repl');
|
|
|
|
function prepareREPL() {
|
|
const input = new ArrayStream();
|
|
const replServer = repl.start({
|
|
prompt: '',
|
|
input,
|
|
output: process.stdout,
|
|
allowBlockingCompletions: true,
|
|
});
|
|
|
|
// Some errors are passed to the domain, but do not callback
|
|
replServer._domain.on('error', assert.ifError);
|
|
|
|
return { replServer, input };
|
|
}
|
|
|
|
function testCompletion(replServer, { input, expectedCompletions }) {
|
|
replServer.complete(
|
|
input,
|
|
common.mustCall((_error, data) => {
|
|
assert.deepStrictEqual(data, [expectedCompletions, input]);
|
|
}),
|
|
);
|
|
};
|
|
|
|
describe('REPL tab object completion on computed properties', () => {
|
|
describe('simple string cases', () => {
|
|
let replServer;
|
|
|
|
before(() => {
|
|
const { replServer: server, input } = prepareREPL();
|
|
replServer = server;
|
|
|
|
input.run([
|
|
`
|
|
const obj = {
|
|
one: 1,
|
|
innerObj: { two: 2 },
|
|
'inner object': { three: 3 },
|
|
};
|
|
|
|
const oneStr = 'one';
|
|
`,
|
|
]);
|
|
});
|
|
|
|
after(() => {
|
|
replServer.close();
|
|
});
|
|
|
|
it('works with double quoted strings', () => testCompletion(replServer, {
|
|
input: 'obj["one"].toFi',
|
|
expectedCompletions: ['obj["one"].toFixed'],
|
|
}));
|
|
|
|
it('works with single quoted strings', () => testCompletion(replServer, {
|
|
input: "obj['one'].toFi",
|
|
expectedCompletions: ["obj['one'].toFixed"],
|
|
}));
|
|
|
|
it('works with template strings', () => testCompletion(replServer, {
|
|
input: 'obj[`one`].toFi',
|
|
expectedCompletions: ['obj[`one`].toFixed'],
|
|
}));
|
|
|
|
it('works with nested objects', () => {
|
|
testCompletion(replServer, {
|
|
input: 'obj["innerObj"].tw',
|
|
expectedCompletions: ['obj["innerObj"].two'],
|
|
});
|
|
testCompletion(replServer, {
|
|
input: 'obj["innerObj"].two.tofi',
|
|
expectedCompletions: ['obj["innerObj"].two.toFixed'],
|
|
});
|
|
});
|
|
|
|
it('works with nested objects combining different type of strings', () => testCompletion(replServer, {
|
|
input: 'obj["innerObj"][`two`].tofi',
|
|
expectedCompletions: ['obj["innerObj"][`two`].toFixed'],
|
|
}));
|
|
|
|
it('works with strings with spaces', () => testCompletion(replServer, {
|
|
input: 'obj["inner object"].th',
|
|
expectedCompletions: ['obj["inner object"].three'],
|
|
}));
|
|
});
|
|
|
|
describe('variables as indexes', () => {
|
|
let replServer;
|
|
|
|
before(() => {
|
|
const { replServer: server, input } = prepareREPL();
|
|
replServer = server;
|
|
|
|
input.run([
|
|
`
|
|
const oneStr = 'One';
|
|
const helloWorldStr = 'Hello' + ' ' + 'World';
|
|
|
|
const obj = {
|
|
[oneStr]: 1,
|
|
['Hello World']: 'hello world!',
|
|
};
|
|
|
|
const lookupObj = {
|
|
stringLookup: helloWorldStr,
|
|
['number lookup']: oneStr,
|
|
};
|
|
`,
|
|
]);
|
|
});
|
|
|
|
after(() => {
|
|
replServer.close();
|
|
});
|
|
|
|
it('works with a simple variable', () => testCompletion(replServer, {
|
|
input: 'obj[oneStr].toFi',
|
|
expectedCompletions: ['obj[oneStr].toFixed'],
|
|
}));
|
|
|
|
it('works with a computed variable', () => testCompletion(replServer, {
|
|
input: 'obj[helloWorldStr].tolocaleup',
|
|
expectedCompletions: ['obj[helloWorldStr].toLocaleUpperCase'],
|
|
}));
|
|
|
|
it('works with a simple inlined computed property', () => testCompletion(replServer, {
|
|
input: 'obj["Hello " + "World"].tolocaleup',
|
|
expectedCompletions: ['obj["Hello " + "World"].toLocaleUpperCase'],
|
|
}));
|
|
|
|
it('works with a ternary inlined computed property', () => testCompletion(replServer, {
|
|
input: 'obj[(1 + 2 > 5) ? oneStr : "Hello " + "World"].toLocaleUpperCase',
|
|
expectedCompletions: ['obj[(1 + 2 > 5) ? oneStr : "Hello " + "World"].toLocaleUpperCase'],
|
|
}));
|
|
|
|
it('works with an inlined computed property with a nested property lookup', () =>
|
|
testCompletion(replServer, {
|
|
input: 'obj[lookupObj.stringLookup].tolocaleupp',
|
|
expectedCompletions: ['obj[lookupObj.stringLookup].toLocaleUpperCase'],
|
|
})
|
|
);
|
|
|
|
it('works with an inlined computed property with a nested inlined computer property lookup', () =>
|
|
testCompletion(replServer, {
|
|
input: 'obj[lookupObj["number" + " lookup"]].toFi',
|
|
expectedCompletions: ['obj[lookupObj["number" + " lookup"]].toFixed'],
|
|
})
|
|
);
|
|
});
|
|
});
|