Repository: prettier/prettier (JavaScript)
Date: 2020-11-18 10:00:19+00:00
Task type: Bug Fix

Issue:
Output of comment before slash in JSX end tag fails to parse
**Prettier 2.0.4**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAeAhgPlQehwHShy0JABoQIAHGAS2gGdlR0AnViAdwAU2EmU6ADad0ATyYUARq3RgA1nBgBlKnNpQA5shisArnAoALGAFshAdSO14DNWDjL+N2gDcbY5OAaSQGhnCsMNyymqboyABmwgEUAFYMAB4AQrIKSsropnAAMhpwUTGGIAmJyhqaQnAAinoQ8IVCsSBqrAGsXlLoUnBC5C2sGjAWtAAmMEbIABwADBRUHAEWslReC3DtrgUUAI518CHUAiDoDAC0UHBwo9f9rHB7tPch6GERSNFNxQGmtDr63wqVVq9QKHyKFBg3RG40mSAATJDZLQhBUAMIQUzhLwbACs-T0AQAKt0BJ9mq4DABJKA3WDKMCDGgAQVpyhgYiqjQCAF8eUA)
```sh
--parser babel
```

**Input:**
```jsx
<a><//
/a>

```

**Output:**
```jsx
<a><///
a>;

```

**Second Output:**
```jsx
SyntaxError: Unterminated JSX contents (2:3)
  1 | <a><///
> 2 | a>;
    |   ^
  3 | 
```

**Expected behavior:**
Add a space before the comment, or move the comment somewhere. This parses:

```jsx
<a></ //
a>;
```


Issue discussion:
Also happens for `/**/` comment.

**Prettier 2.0.4**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAeAhgPlQegFR44A6UOWJIANCBAA4wCW0AzsqOgE4cQDuACpwSsU6ADY90AT1bUARh3RgA1nBgBlWooZQA5shgcArnGoALGAFtRAdVMN4zTWDhqh9hgDd7k5OGYyQbWY4Dhg+BR0LdGQAMzFg6gArZgAPACEFZVU1dAs4ABltOFj4kxBklLVtHVE4AEVDCHgS0QSQTQ5gjl9ZdFk4USp2jm0YawYAExhTZAAOAAZqWm5g6wVaX2W4Lo9i6gBHRvhwumEQdGYAWig4OAm7oY44Q4Yn8PRI6KQ41rLgiwY+iMf2qtQaTWK31K1BgfXGUxmSAATDCFAxRNUAMIQCxRXzbACsQ0MwQAKn1hD82h5jABJKD3WBqMAjegAQQZahgklqLWCAF9+UA)
```sh
--parser babel
```

**Input:**
```jsx
<a></**/
/a>

```

**Output:**
```jsx
<a><//**/
a>;

```

**Second Output:**
```jsx
SyntaxError: Unterminated JSX contents (2:3)
  1 | <a><//**/
> 2 | a>;
    |   ^
  3 | 
```

And for comment _after_ the slash:

**Prettier 2.0.4**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAeAhgPlQegAQ4BUhOWAOlCADQgQAOMAltAM7KjoBOnEA7gApcEbFOgA2vdAE82NAEad0YANZwYAZTpLGUAObIYnAK5waACxgBbMQHUzjeCy1g464Q8YA3B1OTgWsiA6LHCcMPyKupboyABm4iE0AFYsAB4AQooqaurolnAAMjpwcQmmICmp6jq6YnAAikYQ8KViiSBanCGcfnLocnBi1B2cOjA2jAAmMGbIABwADDR0PCE2inR+K3DdniU0AI5N8BH0IiDoLAC0UHBwk-fDnHBHjM8R6FExSPFt5SGWRgGYz-Gp1RrNEo-Mo0GD9CbTWZIABMsMUjDENQAwhBLNE-DsAKzDIwhAAq-REv3anhMAEkoA9YOowKMGABBRnqGBSOqtEIAXwFQA)
```sh
--parser babel
```

**Input:**
```jsx
<a></ /**/a>

```

**Output:**
```jsx
<a><//**/ a>;

```

**Second Output:**
```jsx
SyntaxError: Unexpected token (2:1)
  1 | <a><//**/ a>;
> 2 | 
    | ^
```
This is how fragment is printed

**Prettier 2.1.2**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAeAfKg9FgOlLdAbnxABoQIAHGAS2gGdlQBDAJzYgHcAFdhJihYAbLiwCeTCgCM2LMAGs4MAMpV5tKAHNkMNgFc4FOAFtpcACYXLAGRbb9LLXABiENiZYw625CBb6MBDkIAAWMCbCAOqhtPAM6mBwKgJxtABuceJ+YAxSIJoMcGwwPHJansgAZiJFFABWDAAeAEJyisoqLCZwNppw1bVGII1NKppawnAAivoQ8IPCdSDqbEVsftIs5sIhVGyaMFG0FjChyAAcAAwU+xBFUXJUfvtw6+kDFACOc-Bl1IJ-AwALRQOCWSwhNhwH60aFlJyVJA1JbDIomWi6AxoiZTWbzAbIoYUGDbY6nc5IABMJLktGEEwAwhATEiQG8AKwhfRFAAq20EKOW6UMAEkoNZYCowAcaABBCUqGDiKaLIoAX3VQA)
```sh
--parser babel
```

**Input:**
```jsx
<><//
/>;

```

**Output:**
```jsx
<></
  //
>;

```

Solution patch:
diff --git a/changelog_unreleased/javascript/9711.md b/changelog_unreleased/javascript/9711.md
new file mode 100644
index 000000000000..3793f3c308a1
--- /dev/null
+++ b/changelog_unreleased/javascript/9711.md
@@ -0,0 +1,18 @@
+#### Fix comments inside JSX end tag (#9711 by @fisker)
+
+<!-- prettier-ignore -->
+```jsx
+// Input
+<a><// comment
+/a>;
+
+// Prettier stable
+<a></// comment
+a>;
+
+// Prettier master
+<a></
+  // comment
+  a
+>;
+```
diff --git a/src/language-js/print/jsx.js b/src/language-js/print/jsx.js
index 4c21a063e7cd..2fdadf2d44e1 100644
--- a/src/language-js/print/jsx.js
+++ b/src/language-js/print/jsx.js
@@ -31,6 +31,7 @@ const {
   isStringLiteral,
   isBinaryish,
   isBlockComment,
+  isLineComment,
 } = require("../utils");
 const pathNeedsParens = require("../needs-parens");
 const { willPrintOwnComments } = require("../comments");
@@ -638,7 +639,31 @@ function printJsxOpeningElement(path, options, print) {
 }
 
 function printJsxClosingElement(path, options, print) {
-  return concat(["</", path.call(print, "name"), ">"]);
+  const n = path.getValue();
+  const parts = [];
+
+  parts.push("</");
+
+  const printed = path.call(print, "name");
+  if (
+    Array.isArray(n.name.comments) &&
+    n.name.comments.some((comment) => comment.leading && isLineComment(comment))
+  ) {
+    parts.push(indent(concat([hardline, printed])), hardline);
+  } else if (
+    Array.isArray(n.name.comments) &&
+    n.name.comments.some(
+      (comment) => comment.leading && isBlockComment(comment)
+    )
+  ) {
+    parts.push(" ", printed);
+  } else {
+    parts.push(printed);
+  }
+
+  parts.push(">");
+
+  return concat(parts);
 }
 
 function printJsxOpeningClosingFragment(path, options /*, print*/) {


Test patch:
diff --git a/tests/jsx/comments/__snapshots__/jsfmt.spec.js.snap b/tests/jsx/comments/__snapshots__/jsfmt.spec.js.snap
index a67f885374e6..cd3f81c5dd7c 100644
--- a/tests/jsx/comments/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/jsx/comments/__snapshots__/jsfmt.spec.js.snap
@@ -27,6 +27,134 @@ const render = (items) => (
 ================================================================================
 `;
 
+exports[`in-end-tag.js - {"jsxBracketSameLine":true} [typescript] format 1`] = `
+"Identifier expected. (2:6)
+  1 | /* =========== before slash =========== */
+> 2 | <a><// line
+    |      ^
+  3 | /a>;
+  4 | <a></* block */
+  5 | /a>;"
+`;
+
+exports[`in-end-tag.js - {"jsxBracketSameLine":true} format 1`] = `
+====================================options=====================================
+jsxBracketSameLine: true
+parsers: ["flow", "babel", "typescript"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+/* =========== before slash =========== */
+<a><// line
+/a>;
+<a></* block */
+/a>;
+
+<><// line
+/>;
+<></* block */
+/>;
+
+/* =========== after slash =========== */
+<a></ // line
+a>;
+<a></ /* block */
+a>;
+
+<></ // line
+>;
+<></ /* block */
+>;
+
+/* =========== after name =========== */
+<a></a // line
+>;
+<a></a /* block */
+>;
+
+
+/* =========== block =========== */
+<a></a /* block */>;
+<></ /* block */>;
+
+/* =========== multiple ===========  */
+<a><// line 1
+// line 2
+/a>;
+<a></* block1 */ /* block2 */
+/a>;
+<a></* block */ // line
+/a>;
+
+<><// line 1
+// line 2
+/>;
+<></* block1 */ /* block2 */
+/>;
+<></* block */ // line
+/>;
+=====================================output=====================================
+/* =========== before slash =========== */
+<a></
+  // line
+  a
+>;
+<a></ /* block */
+a>;
+
+<></
+  // line
+>;
+<></ /* block */>;
+
+/* =========== after slash =========== */
+<a></
+  // line
+  a
+>;
+<a></ /* block */
+a>;
+
+<></
+  // line
+>;
+<></ /* block */>;
+
+/* =========== after name =========== */
+<a></a>; // line
+<a></a /* block */>;
+
+/* =========== block =========== */
+<a></a /* block */>;
+<></ /* block */>;
+
+/* =========== multiple ===========  */
+<a></
+  // line 1
+  // line 2
+  a
+>;
+<a></ /* block1 */ /* block2 */
+a>;
+<a></
+  /* block */ // line
+  a
+>;
+
+<></
+  // line 1
+  // line 2
+>;
+<></ /* block1 */
+  /* block2 */>;
+<></
+  /* block */
+  // line
+>;
+
+================================================================================
+`;
+
 exports[`in-tags.js - {"jsxBracketSameLine":true} format 1`] = `
 ====================================options=====================================
 jsxBracketSameLine: true
diff --git a/tests/jsx/comments/in-end-tag.js b/tests/jsx/comments/in-end-tag.js
new file mode 100644
index 000000000000..6c0cb6efe47e
--- /dev/null
+++ b/tests/jsx/comments/in-end-tag.js
@@ -0,0 +1,49 @@
+/* =========== before slash =========== */
+<a><// line
+/a>;
+<a></* block */
+/a>;
+
+<><// line
+/>;
+<></* block */
+/>;
+
+/* =========== after slash =========== */
+<a></ // line
+a>;
+<a></ /* block */
+a>;
+
+<></ // line
+>;
+<></ /* block */
+>;
+
+/* =========== after name =========== */
+<a></a // line
+>;
+<a></a /* block */
+>;
+
+
+/* =========== block =========== */
+<a></a /* block */>;
+<></ /* block */>;
+
+/* =========== multiple ===========  */
+<a><// line 1
+// line 2
+/a>;
+<a></* block1 */ /* block2 */
+/a>;
+<a></* block */ // line
+/a>;
+
+<><// line 1
+// line 2
+/>;
+<></* block1 */ /* block2 */
+/>;
+<></* block */ // line
+/>;
\ No newline at end of file
diff --git a/tests/jsx/comments/jsfmt.spec.js b/tests/jsx/comments/jsfmt.spec.js
index 7cec7031429c..39e36879a210 100644
--- a/tests/jsx/comments/jsfmt.spec.js
+++ b/tests/jsx/comments/jsfmt.spec.js
@@ -1,3 +1,6 @@
 run_spec(__dirname, ["flow", "babel", "typescript"], {
   jsxBracketSameLine: true,
+  errors: {
+    typescript: ["in-end-tag.js"],
+  },
 });