Repository: prettier/prettier (JavaScript)

Issue:
Using inline comments (/* */) before an element attribute's value in JSX causes document to not be formatted
**Prettier 2.3.2**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAzArlMMCW0AEAsgJ4Bim2eUAwhALYAO0CMAFAJT7AA6U3MAHgBG6GDAIAbAIZC4EgLwB6AFRxli7iDiaAfCLHQBi-eKg7eAXxAAaEBAa5oAZ2SgpAJ3cQA7gAUPCC4oUhLeUsQutkLuUmAA1nAwAMoMsThQAObIMO7ocLZwdLIAJsVwxQAyUpnoUhlwpBDudFJi6VnBohA2IAAWMHQSAOq9OPBOqWBwSYFjOABuY8TI4E6RIOlOcO4wvjEZLcioIVu2AFZOAB4AQjHxiUlSdHAV6XBHJ-kgF5dJ7RJwACK6Ag8A+ElOIFS7i27hWQhkch6DHc6RgQxwxRgvWQAA4AAy2FEQLZDGIMFYouCw+bvWwARxB8D29iCICkTgAtFA4OVyj13HBGThBXs6ockMcIV8tnQcNlcjL-kCme9JZ9bDAZBisTikAAmTUxHASdq0OgSrROACsPXQWwAKjIglLIfM8gBJKBlWBJMCohwAQW9SRgxAB4K2FgsQA)
<!-- prettier-ignore -->
```sh
--parser babel
```

**Input:**
<!-- prettier-ignore -->
```jsx
function MyFunctionComponent() {
	<button label=/*old*/"new">button</button>
}
```

**Output:**
<!-- prettier-ignore -->
```jsx
Error: Comment "old" was not printed. Please report this error!
    at Object.ensureAllCommentsPrinted (https://prettier.io/lib/standalone.js:36:119166)
    at Sd (https://prettier.io/lib/standalone.js:36:125590)
    at Nd (https://prettier.io/lib/standalone.js:36:128103)
    at Object.formatWithCursor (https://prettier.io/lib/standalone.js:76:38121)
    at formatCode (https://prettier.io/worker.js:141:21)
    at handleMessage (https://prettier.io/worker.js:78:26)
    at self.onmessage (https://prettier.io/worker.js:36:14)
```

**Expected behaviour:**
The document should be formatted as usual



Hints:
Workaround
**Prettier 2.3.2**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAzArlMMCW0AEAsgJ4Bim2eUAwhALYAO0CMAFAJT7AA6U3MAHgBG6GDAIAbAIZC4EgLwB6AFRxliniDjcQAXwB8IsdAGKj4qPt66QAGhAQGuaAGdkoKQCdPEAO4AFLwQ3FCkJXyliN3shTykwAGs4GABlBnicKABzZBhPdDh7ODpZABNSuFKAGSls9CksuFIITzopMUyc0NEIOxAACxg6CQB1fpx4F3SwOBTgiZwANwniZHAXaJBMlzhPGH84rLbkVDCd+wArFwAPACE4xOSUqTo4Ksy4E7PCkCvrlM6EjgAEV0BB4F8JOcQOlPDtPGshDI5H0GJ5MjARjhSjB+sgABwABnsaIgOxGcQYazRcHhi0+9gAjmD4AdHCEQFIXABaKBwSqVPqeODMnDCg4NY5IU5Qn47Og4XL5OWAkEsz7S772GAyLE4vFIABM2riOAknVodClWhcAFY+ugdgAVGQhGXQxYFACSUAqsBSYHRTgAgr6UjBiEDITtdLogA)
<!-- prettier-ignore -->
```sh
--parser babel
```

**Input:**
<!-- prettier-ignore -->
```jsx
function MyFunctionComponent() {
	<button label=/*e*/{"e"}>button</button>
}
```

**Output:**
<!-- prettier-ignore -->
```jsx
function MyFunctionComponent() {
  <button label=/*e*/ {"e"}>button</button>;
}

```

Patch:
diff --git a/src/language-js/print/jsx.js b/src/language-js/print/jsx.js
--- a/src/language-js/print/jsx.js
+++ b/src/language-js/print/jsx.js
@@ -3,6 +3,7 @@
 const {
   printComments,
   printDanglingComments,
+  printCommentsSeparately,
 } = require("../../main/comments.js");
 const {
   builders: {
@@ -490,7 +491,11 @@ function printJsxAttribute(path, options, print) {
         options.jsxSingleQuote ? "'" : '"'
       );
       final = final.replace(regex, escaped);
-      res = [quote, final, quote];
+      const { leading, trailing } = path.call(
+        () => printCommentsSeparately(path, options),
+        "value"
+      );
+      res = [leading, quote, final, quote, trailing];
     } else {
       res = print("value");
     }
@@ -766,7 +771,7 @@ function printJsx(path, options, print) {
       return printJsxEmptyExpression(path, options /*, print*/);
     case "JSXText":
       /* istanbul ignore next */
-      throw new Error("JSXTest should be handled by JSXElement");
+      throw new Error("JSXText should be handled by JSXElement");
     default:
       /* istanbul ignore next */
       throw new Error(`Unknown JSX node type: ${JSON.stringify(node.type)}.`);


Test patch:
diff --git a/tests/config/format-test.js b/tests/config/format-test.js
--- a/tests/config/format-test.js
+++ b/tests/config/format-test.js
@@ -42,6 +42,7 @@ const unstableTests = new Map(
     "js/for/continue-and-break-comment-without-blocks.js",
     "typescript/satisfies-operators/comments-unstable.ts",
     ["js/identifier/parentheses/let.js", (options) => options.semi === false],
+    "jsx/comments/in-attributes.js",
   ].map((fixture) => {
     const [file, isUnstable = () => true] = Array.isArray(fixture)
       ? fixture
diff --git a/tests/format/jsx/comments/__snapshots__/jsfmt.spec.js.snap b/tests/format/jsx/comments/__snapshots__/jsfmt.spec.js.snap
--- a/tests/format/jsx/comments/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/jsx/comments/__snapshots__/jsfmt.spec.js.snap
@@ -27,6 +27,62 @@ const render = (items) => (
 ================================================================================
 `;
 
+exports[`in-attributes.js - {"bracketSameLine":true} format 1`] = `
+====================================options=====================================
+bracketSameLine: true
+parsers: ["flow", "babel", "typescript"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+<div
+  attr=/* comment */"foo"
+></div>;
+
+<div
+  attr=
+  /* comment */
+  "foo"
+></div>;
+
+<div
+  attr= /* comment */
+  "foo"
+></div>;
+
+<div
+  attr=
+  /* comment */ "foo"
+></div>;
+
+<div
+  attr=
+  // comment
+  "foo"
+></div>;
+
+<div
+  attr= // comment
+  "foo"
+></div>;
+
+=====================================output=====================================
+<div attr=/* comment */ "foo"></div>;
+
+<div attr=/* comment */
+"foo"></div>;
+
+<div attr /* comment */="foo"></div>;
+
+<div attr=/* comment */ "foo"></div>;
+
+<div attr=// comment
+"foo"></div>;
+
+<div attr="foo"></div>; // comment
+
+================================================================================
+`;
+
 exports[`in-end-tag.js - {"bracketSameLine":true} [typescript] format 1`] = `
 "Identifier expected. (2:6)
   1 | /* =========== before slash =========== */
diff --git a/tests/format/jsx/comments/in-attributes.js b/tests/format/jsx/comments/in-attributes.js
new file mode 100644
--- /dev/null
+++ b/tests/format/jsx/comments/in-attributes.js
@@ -0,0 +1,30 @@
+<div
+  attr=/* comment */"foo"
+></div>;
+
+<div
+  attr=
+  /* comment */
+  "foo"
+></div>;
+
+<div
+  attr= /* comment */
+  "foo"
+></div>;
+
+<div
+  attr=
+  /* comment */ "foo"
+></div>;
+
+<div
+  attr=
+  // comment
+  "foo"
+></div>;
+
+<div
+  attr= // comment
+  "foo"
+></div>;