diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 0f8cb859d6822..2fef89e2207af 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -420,7 +420,7 @@ export function getJSDocParameterNameCompletions(tag: JSDocParameterTag): Comple const fn = jsdoc.parent; if (!isFunctionLike(fn)) return []; - return mapDefined(fn.parameters, param => { + return mapDefined(fn.parameters, (param, index) => { if (!isIdentifier(param.name)) return undefined; const name = param.name.text; @@ -431,7 +431,9 @@ export function getJSDocParameterNameCompletions(tag: JSDocParameterTag): Comple return undefined; } - return { name, kind: ScriptElementKind.parameterElement, kindModifiers: "", sortText: Completions.SortText.LocationPriority }; + // Use parameter index as sortText suffix to maintain argument order in completions + const sortText = (Completions.SortText.LocationPriority + String(index).padStart(4, "0")) as Completions.SortText; + return { name, kind: ScriptElementKind.parameterElement, kindModifiers: "", sortText }; }); } diff --git a/tests/cases/fourslash/jsdocParameterNameCompletion.ts b/tests/cases/fourslash/jsdocParameterNameCompletion.ts index 05aa388009b47..2fa7452a84e0d 100644 --- a/tests/cases/fourslash/jsdocParameterNameCompletion.ts +++ b/tests/cases/fourslash/jsdocParameterNameCompletion.ts @@ -1,5 +1,8 @@ /// +// Tests that @param completions are sorted by argument position (not alphabetically). +// See https://github.com/microsoft/TypeScript/issues/20183 + /////** //// * @param /*0*/ //// */ @@ -22,8 +25,27 @@ //// */ ////function i(foo, bar) {} +// sortText uses LocationPriority ("11") + zero-padded index to maintain argument order +const locationPriority = completion.SortText.LocationPriority; verify.completions( - { marker: ["0", "3", "4"], exact: ["foo", "bar"] }, - { marker: "1", exact: "bar" }, - { marker: "2", exact: ["canary", "canoodle"] }, + { + marker: ["0", "3", "4"], + exact: [ + { name: "foo", sortText: locationPriority + "0000" }, + { name: "bar", sortText: locationPriority + "0001" }, + ], + }, + { + marker: "1", + // bar is the second parameter (index 1), already documented foo is filtered out + exact: { name: "bar", sortText: locationPriority + "0001" }, + }, + { + marker: "2", + // canary is index 1, canoodle is index 2 (cat=0, cantaloupe=3 filtered) + exact: [ + { name: "canary", sortText: locationPriority + "0001" }, + { name: "canoodle", sortText: locationPriority + "0002" }, + ], + }, );