diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 0f8cb859d6822..7a5e6592cf796 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,21 @@ 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 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 }; - }); + entries.push({ name, kind: ScriptElementKind.parameterElement, kindModifiers: "", sortText: Completions.SortText.LocationPriority }); + } + 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..1cb718af663d5 --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_filterAlreadyDocumented.ts @@ -0,0 +1,12 @@ +/// + +// 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"] }); + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts b/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts new file mode 100644 index 0000000000000..b968638f26732 --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_jsFile.ts @@ -0,0 +1,14 @@ +/// +// @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"] }); + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts b/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts new file mode 100644 index 0000000000000..984aea8ad0556 --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_optionalAndRest.ts @@ -0,0 +1,11 @@ +/// + +// 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"] }); + + 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..bcbe1f259b5f9 --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_overloadsUseImplementation.ts @@ -0,0 +1,12 @@ +/// + +// 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"] }); + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts b/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts new file mode 100644 index 0000000000000..c777e9f340902 --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_prefixFiltering.ts @@ -0,0 +1,11 @@ +/// + +// 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"] }); + + diff --git a/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts b/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts new file mode 100644 index 0000000000000..93a4b0876d3a8 --- /dev/null +++ b/tests/cases/fourslash/jsDocParamCompletion_skipDestructured.ts @@ -0,0 +1,11 @@ +/// + +// 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"] }); + +