Repository: prettier/prettier (JavaScript)

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.



Hints:
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.

Patch:
diff --git a/src/language-js/print/object.js b/src/language-js/print/object.js
--- 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
--- /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
--- /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
--- /dev/null
+++ b/tests/format/typescript/call-signature/jsfmt.spec.js
@@ -0,0 +1 @@
+run_spec(import.meta, ["typescript"]);