Skip to content

Commit 3e125ca

Browse files
authored
Merge pull request #45 from RunDevelopment/fix-rest-parameter
feat(type-formatter): support rest parameters
2 parents c907408 + 9952ab8 commit 3e125ca

File tree

3 files changed

+55
-2
lines changed

3 files changed

+55
-2
lines changed

src/utils.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,41 @@ function formatType(type: string, options?: Options): string {
7474
try {
7575
const TYPE_START = "type name = ";
7676

77-
let pretty = format(`${TYPE_START}${type}`, {
77+
let pretty = type;
78+
79+
// Rest parameter types start with "...". This is supported by TS and JSDoc
80+
// but it's implemented in a weird way in TS. TS will only acknowledge the
81+
// "..." if the function parameter is a rest parameter. In this case, TS
82+
// will interpret `...T` as `T[]`. But we can't just convert "..." to arrays
83+
// because of @callback types. In @callback types `...T` and `T[]` are not
84+
// equivalent, so we have to support "..." as is.
85+
//
86+
// This formatting itself is rather simple. If `...T` is detected, it will
87+
// be replaced with `T[]` and formatted. At the end, the outer array will
88+
// be removed and "..." will be added again.
89+
//
90+
// As a consequence, union types will get an additional pair of parentheses
91+
// (e.g. `...A|B` -> `...(A|B)`). This is technically unnecessary but it
92+
// makes the operator precedence very clear.
93+
//
94+
// https://www.typescriptlang.org/docs/handbook/functions.html#rest-parameters
95+
let rest = false;
96+
if (pretty.startsWith("...")) {
97+
rest = true;
98+
pretty = `(${pretty.slice(3)})[]`;
99+
}
100+
101+
pretty = format(`${TYPE_START}${pretty}`, {
78102
...options,
79103
parser: "typescript",
80104
});
81105
pretty = pretty.slice(TYPE_START.length);
82-
83106
pretty = pretty.replace(/[;\n]*$/g, "");
84107

108+
if (rest) {
109+
pretty = "..." + pretty.replace(/\[\s*\]$/, "");
110+
}
111+
85112
return pretty;
86113
} catch (error) {
87114
// console.log("jsdoc-parser", error);

tests/__snapshots__/main.test.js.snap

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ exports[`Empty comment 1`] = `
3737
"
3838
`;
3939

40+
exports[`Format rest parameters properly 1`] = `
41+
"/**
42+
* @param {...any} arg1
43+
* @param {...number} arg2
44+
* @param {...(string | number)} arg3
45+
* @param {...(string | number)} arg4 This is equivalent to arg3
46+
*/
47+
function a() {}
48+
"
49+
`;
50+
4051
exports[`Hyphen at the start of description 1`] = `
4152
"/**
4253
* Assign the project to an employee.

tests/main.test.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,3 +427,18 @@ test("Non-jsdoc comment", () => {
427427

428428
expect(result).toMatchSnapshot();
429429
});
430+
431+
test("Format rest parameters properly", () => {
432+
const result = subject(`
433+
/**
434+
* @param {... *} arg1
435+
* @param {... number} arg2
436+
* @param {... (string|number)} arg3
437+
* @param {... string|number} arg4 This is equivalent to arg3
438+
*
439+
*/
440+
function a(){}
441+
`);
442+
443+
expect(result).toMatchSnapshot();
444+
});

0 commit comments

Comments
 (0)