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"] });
+
+