fix(193523): JSDoc optional parameters don't display in functions (#202963)

* Issue193523: Brought back optional params to autocompletion preview

* #193523: Hided end-of-list optional params

* #193523: Added unit tests

* #193523: Fixed integration tests

* Update extensions/typescript-language-features/src/languageFeatures/util/snippetForFunctionCall.ts

---------

Co-authored-by: Matt Bierner <matb@microsoft.com>
This commit is contained in:
Yves Daaboul 2024-02-06 05:59:23 +02:00 committed by GitHub
parent e7b03742b5
commit 0786b4d2fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 42 additions and 0 deletions

View file

@ -50,6 +50,7 @@ function getParameterListParts(
displayParts: ReadonlyArray<Proto.SymbolDisplayPart>
): ParamterListParts {
const parts: Proto.SymbolDisplayPart[] = [];
let optionalParams: Proto.SymbolDisplayPart[] = [];
let isInMethod = false;
let hasOptionalParameters = false;
let parenCount = 0;
@ -75,6 +76,17 @@ function getParameterListParts(
const nameIsFollowedByOptionalIndicator = next && next.text === '?';
// Skip this parameter
const nameIsThis = part.text === 'this';
/* Add optional param to temp array. Once a non-optional param is encountered,
this means that previous optional params were mid-list ones, thus they should
be displayed */
if (nameIsFollowedByOptionalIndicator) {
optionalParams.push(part);
} else {
parts.push(...optionalParams);
optionalParams = [];
}
if (!nameIsFollowedByOptionalIndicator && !nameIsThis) {
parts.push(part);
}

View file

@ -134,4 +134,34 @@ suite('typescript function call snippets', () => {
).snippet.value,
'foobar(${1:param})$0');
});
test('Should not skip mid-list optional parameter', async () => {
assert.strictEqual(
snippetForFunctionCall(
{ label: 'foobar', },
[{ "text": "function", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "foobar", "kind": "functionName" }, { "text": "(", "kind": "punctuation" }, { "text": "alpha", "kind": "parameterName" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "string", "kind": "keyword" }, { "text": ",", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "beta", "kind": "parameterName" }, { "text": "?", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "number", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "|", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "undefined", "kind": "keyword" }, { "text": ",", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "gamma", "kind": "parameterName" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "string", "kind": "keyword" }, { "text": ")", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "void", "kind": "keyword" }]
).snippet.value,
'foobar(${1:alpha}, ${2:beta}, ${3:gamma}$4)$0');
});
test('Should skip end-of-list optional parameters', async () => {
assert.strictEqual(
snippetForFunctionCall(
{ label: 'foobar', },
[{ "text": "function", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "foobar", "kind": "functionName" }, { "text": "(", "kind": "punctuation" }, { "text": "alpha", "kind": "parameterName" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "string", "kind": "keyword" }, { "text": ",", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "beta", "kind": "parameterName" }, { "text": "?", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "number", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "|", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "undefined", "kind": "keyword" }, { "text": ",", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "gamma", "kind": "parameterName" }, { "text": "?", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "number", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "|", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "undefined", "kind": "keyword" }, { "text": ")", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "void", "kind": "keyword" }]
).snippet.value,
'foobar(${1:alpha}$2)$0');
});
// A more complex case
test('Should skip end-of-list optional params but should not skip start-of-list and mid-list ones', async () => {
assert.strictEqual(
snippetForFunctionCall(
{ label: 'foobar', },
[{ "text": "function", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "foobar", "kind": "functionName" }, { "text": "(", "kind": "punctuation" }, { "text": "a", "kind": "parameterName" }, { "text": "?", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "number", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "|", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "undefined", "kind": "keyword" }, { "text": ",", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "b", "kind": "parameterName" }, { "text": "?", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "number", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "|", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "undefined", "kind": "keyword" }, { "text": ",", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "c", "kind": "parameterName" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "string", "kind": "keyword" }, { "text": ",", "kind": "punctuation" }, { "text": " ", "kind": "space" },
{ "text": "d", "kind": "parameterName" }, { "text": "?", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "number", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "|", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "undefined", "kind": "keyword" }, { "text": ",", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "e", "kind": "parameterName" }, { "text": "?", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "number", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "|", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "undefined", "kind": "keyword" }, { "text": ",", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "f", "kind": "parameterName" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "string", "kind": "keyword" }, { "text": ",", "kind": "punctuation" }, { "text": " ", "kind": "space" },
{ "text": "g", "kind": "parameterName" }, { "text": "?", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "number", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "|", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "undefined", "kind": "keyword" }, { "text": ",", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "h", "kind": "parameterName" }, { "text": "?", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "number", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "|", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "undefined", "kind": "keyword" }, { "text": ")", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "void", "kind": "keyword" }]
).snippet.value,
'foobar(${1:a}, ${2:b}, ${3:c}, ${4:d}, ${5:e}, ${6:f}$7)$0');
});
});