Repository: prettier/prettier (JavaScript)
Date: 2023-05-17 03:57:50+00:00
Task type: Bug Fix

Issue:
Bug report: using `// prettier-ignore` on a call signature line leads to broken code on format
**Prettier 2.8.8**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEMCeAHOACAYhCbAXm2AB0ptsAKASiWwDcIBLAEwG5sB6b7DAE5wYMFnAEBaFgHMoEIRSoBnOJChsGSmAJZRpHCgF8DUEABoQEDKOhLkoAIYCBEAO4AFJwjsoHAG1cHNDsLACMBBzAAa2EAZQcAWzgAGV04ZAAzfxUwiOi4jEjdaWRtAFc4CzgE0Lg2Njrkhz0yh2k4fAEEhxFi5BAHMpgIcxAACxgEvwB1MZZ4JUKwOFjveZZGebR+sCUQkF0VARh3COluzOzKkAArJQAPWOK-OABFMoh4S78ckEKBI79dBYJRgHTWUaCXQwabsGBjZAADgADBZBBAVNMIhh+oI4EdGOkLABHD7wU5WHwDJQSKBwOp1UZCUksISnNoXJBZH7XFQJFilAQVCxKZ5wACCIh0oSGcHc4lSdO+v1Fehe70+6S5VwsMAcoVhbHhyAATLqIiw-MUAMIQBKckD4gCsozKKgAKvqfNzfowKgBJdQIGCxMEsazi9SxdAvZVwQyGIA)
<!-- prettier-ignore -->
```sh
--parser typescript
```

**Input:**
<!-- prettier-ignore -->
```tsx
type Foo = {
  (): void; // prettier-ignore
  second: string;
};
```

This is for the `typescript` parser only, the `babel` parser seems unaffected.

Key parts to reproduce:

1. Create a type definition (or an interface type, it has the same bug);
2. Add a call signature property (e.g. the `(): void` part in the linked playground), and `prettier-ignore` that line;
3. Add another property below it. The bug does not occur if the call signature is the last property in the type.

**Output:**
<!-- prettier-ignore -->
```tsx
type Foo = {
  (): void;; // prettier-ignore
  second: string;
};
```

Due to the `;;` part, the code actually breaks and becomes invalid TypeScript on save.

**Expected behavior:**

The output contains no double semicolon, i.e. the `;;` part.



Issue discussion:
Hello, I don't have prior experience contributing to this project, but I would like to work on this issue as a good first issue.

If I find a solution, I plan to submit a pull request.

Solution patch:
diff --git a/changelog_unreleased/typescript/14830.md b/changelog_unreleased/typescript/14830.md
new file mode 100644
index 000000000000..f8f3b7235624
--- /dev/null
+++ b/changelog_unreleased/typescript/14830.md
@@ -0,0 +1,22 @@
+#### Fix issue with double semicolon caused by `// prettier-ignore` on a call signature line (#14830 by @ot07)
+
+<!-- prettier-ignore -->
+```ts
+// Input
+type Foo = {
+  (): void; // prettier-ignore
+  second: string;
+};
+
+// Prettier stable
+type Foo = {
+  (): void;; // prettier-ignore
+  second: string;
+};
+
+// Prettier main
+type Foo = {
+  (): void; // prettier-ignore
+  second: string;
+};
+```
diff --git a/src/language-js/print/object.js b/src/language-js/print/object.js
index 4122a8d4a61b..d0d273c4c7eb 100644
--- a/src/language-js/print/object.js
+++ b/src/language-js/print/object.js
@@ -118,7 +118,8 @@ function printObject(path, options, print) {
     if (
       (prop.node.type === "TSPropertySignature" ||
         prop.node.type === "TSMethodSignature" ||
-        prop.node.type === "TSConstructSignatureDeclaration") &&
+        prop.node.type === "TSConstructSignatureDeclaration" ||
+        prop.node.type === "TSCallSignatureDeclaration") &&
       hasComment(prop.node, CommentCheckFlags.PrettierIgnore)
     ) {
       separatorParts.shift();


Test patch:
diff --git a/tests/format/typescript/call-signature/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/call-signature/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 000000000000..4dacb6c0f423
--- /dev/null
+++ b/tests/format/typescript/call-signature/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,131 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`call-signature.ts format 1`] = `
+====================================options=====================================
+parsers: ["typescript"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+type T = {
+  (): void;
+  second: string;
+};
+
+type T = {
+  (): void; // prettier-ignore
+  second: string;
+};
+
+type T = {
+  (): void; // comment
+  second: string;
+};
+
+type T = {
+  first: string;
+  (): void;
+};
+
+type T = {
+  first: string;
+  (): void; // prettier-ignore
+};
+
+type T = {
+  first: string;
+  (): void; // comment
+};
+
+interface I {
+  (): void;
+  second: string;
+}
+
+interface I {
+  (): void; // prettier-ignore
+  second: string;
+}
+
+interface I {
+  (): void; // comment
+  second: string;
+}
+
+interface I {
+  first: string;
+  (): void;
+}
+
+interface I {
+  first: string;
+  (): void; // prettier-ignore
+}
+
+interface I {
+  first: string;
+  (): void; // comment
+}
+
+=====================================output=====================================
+type T = {
+  (): void;
+  second: string;
+};
+
+type T = {
+  (): void; // prettier-ignore
+  second: string;
+};
+
+type T = {
+  (): void; // comment
+  second: string;
+};
+
+type T = {
+  first: string;
+  (): void;
+};
+
+type T = {
+  first: string;
+  (): void; // prettier-ignore
+};
+
+type T = {
+  first: string;
+  (): void; // comment
+};
+
+interface I {
+  (): void;
+  second: string;
+}
+
+interface I {
+  (): void; // prettier-ignore
+  second: string;
+}
+
+interface I {
+  (): void; // comment
+  second: string;
+}
+
+interface I {
+  first: string;
+  (): void;
+}
+
+interface I {
+  first: string;
+  (): void; // prettier-ignore
+}
+
+interface I {
+  first: string;
+  (): void; // comment
+}
+
+================================================================================
+`;
diff --git a/tests/format/typescript/call-signature/call-signature.ts b/tests/format/typescript/call-signature/call-signature.ts
new file mode 100644
index 000000000000..26a328f2fcb4
--- /dev/null
+++ b/tests/format/typescript/call-signature/call-signature.ts
@@ -0,0 +1,59 @@
+type T = {
+  (): void;
+  second: string;
+};
+
+type T = {
+  (): void; // prettier-ignore
+  second: string;
+};
+
+type T = {
+  (): void; // comment
+  second: string;
+};
+
+type T = {
+  first: string;
+  (): void;
+};
+
+type T = {
+  first: string;
+  (): void; // prettier-ignore
+};
+
+type T = {
+  first: string;
+  (): void; // comment
+};
+
+interface I {
+  (): void;
+  second: string;
+}
+
+interface I {
+  (): void; // prettier-ignore
+  second: string;
+}
+
+interface I {
+  (): void; // comment
+  second: string;
+}
+
+interface I {
+  first: string;
+  (): void;
+}
+
+interface I {
+  first: string;
+  (): void; // prettier-ignore
+}
+
+interface I {
+  first: string;
+  (): void; // comment
+}
diff --git a/tests/format/typescript/call-signature/jsfmt.spec.js b/tests/format/typescript/call-signature/jsfmt.spec.js
new file mode 100644
index 000000000000..29084a9c8a10
--- /dev/null
+++ b/tests/format/typescript/call-signature/jsfmt.spec.js
@@ -0,0 +1,1 @@
+run_spec(import.meta, ["typescript"]);