From d37bc08425d390dc569d28f082bd87a155d35228 Mon Sep 17 00:00:00 2001 From: Jay <140453707+jayinmt@users.noreply.github.com> Date: Sun, 26 Oct 2025 19:23:28 -0700 Subject: [PATCH 1/3] 20183 - Sort jsdoc parameter suggestions by argument position --- src/services/jsDoc.ts | 16 ++++++++----- ...ParamCompletion_filterAlreadyDocumented.ts | 22 ++++++++++++++++++ .../fourslash/jsDocParamCompletion_jsFile.ts | 23 +++++++++++++++++++ .../jsDocParamCompletion_optionalAndRest.ts | 20 ++++++++++++++++ .../fourslash/jsDocParamCompletion_order.ts | 16 +++++++++++++ ...amCompletion_overloadsUseImplementation.ts | 22 ++++++++++++++++++ .../jsDocParamCompletion_prefixFiltering.ts | 20 ++++++++++++++++ .../jsDocParamCompletion_skipDestructured.ts | 20 ++++++++++++++++ 8 files changed, 153 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts create mode 100644 tests/cases/fourslash/jsDocParamCompletion_jsFile.ts create mode 100644 tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts create mode 100644 tests/cases/fourslash/jsDocParamCompletion_order.ts create mode 100644 tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts create mode 100644 tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts create mode 100644 tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 0f8cb859d6822..e696ac58ef655 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -68,7 +68,6 @@ import { length, lineBreakPart, map, - mapDefined, MethodDeclaration, MethodSignature, Node, @@ -420,19 +419,24 @@ export function getJSDocParameterNameCompletions(tag: JSDocParameterTag): Comple const fn = jsdoc.parent; if (!isFunctionLike(fn)) return []; - return mapDefined(fn.parameters, param => { - if (!isIdentifier(param.name)) return undefined; + const baseSort = Completions.SortText.LocationPriority; + const entries: CompletionEntry[] = []; + for (const param of fn.parameters) { + if (!isIdentifier(param.name)) continue; const name = param.name.text; if ( jsdoc.tags!.some(t => t !== tag && isJSDocParameterTag(t) && isIdentifier(t.name) && t.name.escapedText === name) // TODO: GH#18217 || nameThusFar !== undefined && !startsWith(name, nameThusFar) ) { - return undefined; + continue; } - return { name, kind: ScriptElementKind.parameterElement, kindModifiers: "", sortText: Completions.SortText.LocationPriority }; - }); + const index = fn.parameters.indexOf(param); + const sortText = baseSort + index.toString().padStart(4, "0"); + entries.push({ name, kind: ScriptElementKind.parameterElement, kindModifiers: "", sortText }); + } + return entries; } /** @internal */ diff --git a/tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts b/tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts new file mode 100644 index 0000000000000..a01060ee49d47 --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts @@ -0,0 +1,22 @@ +/// + +// Expectation: Only 'a' is suggested because 'z' is already documented. +//// /** +//// * @param z +//// * @param /*1*/ +//// */ +//// function foo(z: number, a: number) {} + +verify.completions({ marker: "1", exact: ["a"] }); + + +/** + * Manual check: + * Only 'a' should be suggested because 'z' is already documented. + * Place cursor after the space in '@param '. + * @param z + * @param + */ +function foo(z: number, a: number) {} + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts b/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts new file mode 100644 index 0000000000000..7bf2e837e118f --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts @@ -0,0 +1,23 @@ +/// +// @allowJs: true +// @Filename: a.js + +// Expectation (JS): Declaration order is preserved: 'z' before 'a'. +//// /** +//// * @param /*1*/ +//// */ +//// function foo(z, a) {} + +goTo.file("a.js"); +verify.completions({ marker: "1", exact: ["z", "a"] }); + + +/** + * Manual check (TS file view): + * Order preserved: 'z' before 'a'. + * Place cursor after the space in '@param '. + * @param + */ +function foo(z, a) {} + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts b/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts new file mode 100644 index 0000000000000..f8cf2cb736a63 --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts @@ -0,0 +1,20 @@ +/// + +// Expectation: Declaration order is preserved: 'a' (optional) before 'z' (rest). +//// /** +//// * @param /*1*/ +//// */ +//// function foo(a?: number, ...z: number[]) {} + +verify.completions({ marker: "1", exact: ["a", "z"] }); + + +/** + * Manual check: + * Declaration order preserved: 'a' (optional) before 'z' (rest). + * Place cursor after the space in '@param '. + * @param + */ +function foo(a?: number, ...z: number[]) {} + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_order.ts b/tests/cases/fourslash/jsDocParamCompletion_order.ts new file mode 100644 index 0000000000000..862fb9d94255e --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_order.ts @@ -0,0 +1,16 @@ +/// + +//// /** +//// * @param /*1*/ +//// */ +//// function foo(z: number, a: number) {} + +verify.completions({ + marker: "1", + exact: ["z", "a"], // expected: declaration order + }); + + /** + * @param | + */ +function foo(z: number, a: number) {} \ No newline at end of file diff --git a/tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts b/tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts new file mode 100644 index 0000000000000..9a335b011998b --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts @@ -0,0 +1,22 @@ +/// + +// Expectation: Suggestions are based on the implementation signature: 'a', then 'z'. +//// /** +//// * @param /*1*/ +//// */ +//// function foo(a: number, z: number): void; +//// function foo(a: number, z: number): void {} + +verify.completions({ marker: "1", exact: ["a", "z"] }); + + +/** + * Manual check: + * Suggestions based on implementation signature: 'a' then 'z'. + * Place cursor after the space in '@param '. + * @param + */ +function foo(a: number, z: number): void; +function foo(a: number, z: number): void {} + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts b/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts new file mode 100644 index 0000000000000..55f39b5a91597 --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts @@ -0,0 +1,20 @@ +/// + +// Expectation: Only 'a' is suggested due to prefix filtering after '@param a'. +//// /** +//// * @param a/*1*/ +//// */ +//// function foo(z: number, a: number) {} + +verify.completions({ marker: "1", exact: ["a"] }); + + +/** + * Manual check: + * Only 'a' should be suggested due to prefix filtering after '@param a'. + * Place cursor right after the 'a'. + * @param a + */ +function foo(z: number, a: number) {} + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts b/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts new file mode 100644 index 0000000000000..39f2691cf6a9f --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts @@ -0,0 +1,20 @@ +/// + +// Expectation: Destructured parameter is skipped; only identifier param 'z' is suggested. +//// /** +//// * @param /*1*/ +//// */ +//// function foo({ x }: any, z: number) {} + +verify.completions({ marker: "1", exact: ["z"] }); + + +/** + * Manual check: + * Destructured parameter is skipped; only 'z' is suggested. + * Place cursor after the space in '@param '. + * @param + */ +function foo({ x }: any, z: number) {} + + From 629f5b241c6e510e3fe9f2fa01157aad22421117 Mon Sep 17 00:00:00 2001 From: Jay <140453707+jayinmt@users.noreply.github.com> Date: Sun, 26 Oct 2025 20:29:32 -0700 Subject: [PATCH 2/3] 20183 - Sort jsdoc parameter suggestions by argument position --- src/services/jsDoc.ts | 5 +- ...ParamCompletion_filterAlreadyDocumented.ts | 44 +++++++++--------- .../fourslash/jsDocParamCompletion_jsFile.ts | 46 +++++++++---------- .../jsDocParamCompletion_optionalAndRest.ts | 40 ++++++++-------- ...amCompletion_overloadsUseImplementation.ts | 44 +++++++++--------- .../jsDocParamCompletion_prefixFiltering.ts | 40 ++++++++-------- .../jsDocParamCompletion_skipDestructured.ts | 40 ++++++++-------- 7 files changed, 128 insertions(+), 131 deletions(-) diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index e696ac58ef655..7a5e6592cf796 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -419,7 +419,6 @@ export function getJSDocParameterNameCompletions(tag: JSDocParameterTag): Comple const fn = jsdoc.parent; if (!isFunctionLike(fn)) return []; - const baseSort = Completions.SortText.LocationPriority; const entries: CompletionEntry[] = []; for (const param of fn.parameters) { if (!isIdentifier(param.name)) continue; @@ -432,9 +431,7 @@ export function getJSDocParameterNameCompletions(tag: JSDocParameterTag): Comple continue; } - const index = fn.parameters.indexOf(param); - const sortText = baseSort + index.toString().padStart(4, "0"); - entries.push({ name, kind: ScriptElementKind.parameterElement, kindModifiers: "", sortText }); + entries.push({ name, kind: ScriptElementKind.parameterElement, kindModifiers: "", sortText: Completions.SortText.LocationPriority }); } return entries; } diff --git a/tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts b/tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts index a01060ee49d47..d2ff7aa8910ad 100644 --- a/tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts +++ b/tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts @@ -1,22 +1,22 @@ -/// - -// Expectation: Only 'a' is suggested because 'z' is already documented. -//// /** -//// * @param z -//// * @param /*1*/ -//// */ -//// function foo(z: number, a: number) {} - -verify.completions({ marker: "1", exact: ["a"] }); - - -/** - * Manual check: - * Only 'a' should be suggested because 'z' is already documented. - * Place cursor after the space in '@param '. - * @param z - * @param - */ -function foo(z: number, a: number) {} - - +/// + +// Expectation: Only 'a' is suggested because 'z' is already documented. +//// /** +//// * @param z +//// * @param /*1*/ +//// */ +//// function foo(z: number, a: number) {} + +verify.completions({ marker: "1", exact: ["a"] }); + + +/** + * Manual check: + * Only 'a' should be suggested because 'z' is already documented. + * Place cursor after the space in '@param '. + * @param z + * @param + */ +function foo(z: number, a: number) {} + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts b/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts index 7bf2e837e118f..8eba36e07d4d2 100644 --- a/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts +++ b/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts @@ -1,23 +1,23 @@ -/// -// @allowJs: true -// @Filename: a.js - -// Expectation (JS): Declaration order is preserved: 'z' before 'a'. -//// /** -//// * @param /*1*/ -//// */ -//// function foo(z, a) {} - -goTo.file("a.js"); -verify.completions({ marker: "1", exact: ["z", "a"] }); - - -/** - * Manual check (TS file view): - * Order preserved: 'z' before 'a'. - * Place cursor after the space in '@param '. - * @param - */ -function foo(z, a) {} - - +/// +// @allowJs: true +// @Filename: a.js + +// Expectation (JS): Declaration order is preserved: 'z' before 'a'. +//// /** +//// * @param /*1*/ +//// */ +//// function foo(z, a) {} + +goTo.file("a.js"); +verify.completions({ marker: "1", exact: ["z", "a"] }); + + +/** + * Manual check (TS file view): + * Order preserved: 'z' before 'a'. + * Place cursor after the space in '@param '. + * @param + */ +function foo(z, a) {} + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts b/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts index f8cf2cb736a63..3a9f4d40e3857 100644 --- a/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts +++ b/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts @@ -1,20 +1,20 @@ -/// - -// Expectation: Declaration order is preserved: 'a' (optional) before 'z' (rest). -//// /** -//// * @param /*1*/ -//// */ -//// function foo(a?: number, ...z: number[]) {} - -verify.completions({ marker: "1", exact: ["a", "z"] }); - - -/** - * Manual check: - * Declaration order preserved: 'a' (optional) before 'z' (rest). - * Place cursor after the space in '@param '. - * @param - */ -function foo(a?: number, ...z: number[]) {} - - +/// + +// Expectation: Declaration order is preserved: 'a' (optional) before 'z' (rest). +//// /** +//// * @param /*1*/ +//// */ +//// function foo(a?: number, ...z: number[]) {} + +verify.completions({ marker: "1", exact: ["a", "z"] }); + + +/** + * Manual check: + * Declaration order preserved: 'a' (optional) before 'z' (rest). + * Place cursor after the space in '@param '. + * @param + */ +function foo(a?: number, ...z: number[]) {} + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts b/tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts index 9a335b011998b..dff3b665d818e 100644 --- a/tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts +++ b/tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts @@ -1,22 +1,22 @@ -/// - -// Expectation: Suggestions are based on the implementation signature: 'a', then 'z'. -//// /** -//// * @param /*1*/ -//// */ -//// function foo(a: number, z: number): void; -//// function foo(a: number, z: number): void {} - -verify.completions({ marker: "1", exact: ["a", "z"] }); - - -/** - * Manual check: - * Suggestions based on implementation signature: 'a' then 'z'. - * Place cursor after the space in '@param '. - * @param - */ -function foo(a: number, z: number): void; -function foo(a: number, z: number): void {} - - +/// + +// Expectation: Suggestions are based on the implementation signature: 'a', then 'z'. +//// /** +//// * @param /*1*/ +//// */ +//// function foo(a: number, z: number): void; +//// function foo(a: number, z: number): void {} + +verify.completions({ marker: "1", exact: ["a", "z"] }); + + +/** + * Manual check: + * Suggestions based on implementation signature: 'a' then 'z'. + * Place cursor after the space in '@param '. + * @param + */ +function foo(a: number, z: number): void; +function foo(a: number, z: number): void {} + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts b/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts index 55f39b5a91597..72e65cdf49bea 100644 --- a/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts +++ b/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts @@ -1,20 +1,20 @@ -/// - -// Expectation: Only 'a' is suggested due to prefix filtering after '@param a'. -//// /** -//// * @param a/*1*/ -//// */ -//// function foo(z: number, a: number) {} - -verify.completions({ marker: "1", exact: ["a"] }); - - -/** - * Manual check: - * Only 'a' should be suggested due to prefix filtering after '@param a'. - * Place cursor right after the 'a'. - * @param a - */ -function foo(z: number, a: number) {} - - +/// + +// Expectation: Only 'a' is suggested due to prefix filtering after '@param a'. +//// /** +//// * @param a/*1*/ +//// */ +//// function foo(z: number, a: number) {} + +verify.completions({ marker: "1", exact: ["a"] }); + + +/** + * Manual check: + * Only 'a' should be suggested due to prefix filtering after '@param a'. + * Place cursor right after the 'a'. + * @param a + */ +function foo(z: number, a: number) {} + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts b/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts index 39f2691cf6a9f..e7b6132f3bbd0 100644 --- a/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts +++ b/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts @@ -1,20 +1,20 @@ -/// - -// Expectation: Destructured parameter is skipped; only identifier param 'z' is suggested. -//// /** -//// * @param /*1*/ -//// */ -//// function foo({ x }: any, z: number) {} - -verify.completions({ marker: "1", exact: ["z"] }); - - -/** - * Manual check: - * Destructured parameter is skipped; only 'z' is suggested. - * Place cursor after the space in '@param '. - * @param - */ -function foo({ x }: any, z: number) {} - - +/// + +// Expectation: Destructured parameter is skipped; only identifier param 'z' is suggested. +//// /** +//// * @param /*1*/ +//// */ +//// function foo({ x }: any, z: number) {} + +verify.completions({ marker: "1", exact: ["z"] }); + + +/** + * Manual check: + * Destructured parameter is skipped; only 'z' is suggested. + * Place cursor after the space in '@param '. + * @param + */ +function foo({ x }: any, z: number) {} + + From e3ac58fb425590d7aec6890084f9463e11e95f48 Mon Sep 17 00:00:00 2001 From: Jay <140453707+jayinmt@users.noreply.github.com> Date: Sun, 26 Oct 2025 20:34:59 -0700 Subject: [PATCH 3/3] 20183 - Sort jsdoc parameter suggestions by argument position --- .../jsDocParamCompletion_filterAlreadyDocumented.ts | 10 ---------- tests/cases/fourslash/jsDocParamCompletion_jsFile.ts | 9 --------- .../fourslash/jsDocParamCompletion_optionalAndRest.ts | 9 --------- .../jsDocParamCompletion_overloadsUseImplementation.ts | 10 ---------- .../fourslash/jsDocParamCompletion_prefixFiltering.ts | 9 --------- .../fourslash/jsDocParamCompletion_skipDestructured.ts | 9 --------- 6 files changed, 56 deletions(-) diff --git a/tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts b/tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts index d2ff7aa8910ad..1cb718af663d5 100644 --- a/tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts +++ b/tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts @@ -10,13 +10,3 @@ verify.completions({ marker: "1", exact: ["a"] }); -/** - * Manual check: - * Only 'a' should be suggested because 'z' is already documented. - * Place cursor after the space in '@param '. - * @param z - * @param - */ -function foo(z: number, a: number) {} - - diff --git a/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts b/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts index 8eba36e07d4d2..b968638f26732 100644 --- a/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts +++ b/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts @@ -12,12 +12,3 @@ goTo.file("a.js"); verify.completions({ marker: "1", exact: ["z", "a"] }); -/** - * Manual check (TS file view): - * Order preserved: 'z' before 'a'. - * Place cursor after the space in '@param '. - * @param - */ -function foo(z, a) {} - - diff --git a/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts b/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts index 3a9f4d40e3857..984aea8ad0556 100644 --- a/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts +++ b/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts @@ -9,12 +9,3 @@ verify.completions({ marker: "1", exact: ["a", "z"] }); -/** - * Manual check: - * Declaration order preserved: 'a' (optional) before 'z' (rest). - * Place cursor after the space in '@param '. - * @param - */ -function foo(a?: number, ...z: number[]) {} - - diff --git a/tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts b/tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts index dff3b665d818e..bcbe1f259b5f9 100644 --- a/tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts +++ b/tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts @@ -10,13 +10,3 @@ verify.completions({ marker: "1", exact: ["a", "z"] }); -/** - * Manual check: - * Suggestions based on implementation signature: 'a' then 'z'. - * Place cursor after the space in '@param '. - * @param - */ -function foo(a: number, z: number): void; -function foo(a: number, z: number): void {} - - diff --git a/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts b/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts index 72e65cdf49bea..c777e9f340902 100644 --- a/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts +++ b/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts @@ -9,12 +9,3 @@ verify.completions({ marker: "1", exact: ["a"] }); -/** - * Manual check: - * Only 'a' should be suggested due to prefix filtering after '@param a'. - * Place cursor right after the 'a'. - * @param a - */ -function foo(z: number, a: number) {} - - diff --git a/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts b/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts index e7b6132f3bbd0..93a4b0876d3a8 100644 --- a/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts +++ b/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts @@ -9,12 +9,3 @@ verify.completions({ marker: "1", exact: ["z"] }); -/** - * Manual check: - * Destructured parameter is skipped; only 'z' is suggested. - * Place cursor after the space in '@param '. - * @param - */ -function foo({ x }: any, z: number) {} - -