Repository: prettier/prettier (JavaScript)
Date: 2018-12-18 15:21:46+00:00
Task type: Bug Fix

Issue:
`html` in `.ts/.tsx` is not formatted
**Prettier 1.15.3**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuc0DOMAEALGBbAG0wF5MB6AKkwAkAVAWQBlMKzMADAHgEIARAeQDCtAJoAFAKI58BAHwAdKJzpNMgxgEEAyluLyQUCAFoAVmkx4RRwQQ1ot+hVEyZlEjbycuXnehNoaatQaAEpa-nogAK4wAGZGAByOit6utACStIwSsvQAnpgwmQQSnGQZWTkp3r7+gQByGn6RACZwaGAATgCWAA4w3dD6mJCwCDCR+WoQ9TASULTJzq5k1O6e1ZwARhAteV41YrLUcAQEEJgA7hCdBC3cnABCIbKYtNjd5p80DIwArJhHhBugQ4J1egQAIbwAB0ZSO1R8WkEIXSYloB1Sl26UBaEEuMIA5pCSJhYlEoGABtBMAAKACUmGAmGJMIAjjDelE0NhaZDOoSonhxmhGQBfADcLMh7NJAG0ALpS1lEUgAaigcEumF40LgEsR3mJtIA5F04HqTQAaTAmgCqGiMAA0XS6jCJrbbITEICb6crIaa0AgWp6Tb1IYS4AA3bpav2GsodHr9TGuZGo9GYNCdMCRXAwXpoJBkMiXctEiAQQmgoyQqCQgh5AZgNAwyB4Mj1xvN7qtmFmYbaET1QQ6iQAMQkLyTXT6MAOZR2eycZRUjFk7BAVpAEH6gygaGQoH5nXxYn5CCPKEh0eBLW3IC2nUhYAA1nAYFoI2AcYTkDAnRRHAO64IQADqHzwGgP5wFoV7dAMsYwHkyDgGgR47jiwadDAYgvoSeCQsgsSNsGO5mAAHo8L7vp+WiQsKjA4nAJFkSBIBUVof6ggAilEEDwGxBDkSAEadDhaEob07Rzv0j69D0sDgd0LQwNgyAJAADDuikQMG4Evr0aGKe0YLRqxO6dHAbJRN01n4ZGRHCaJwZ4N0AFARxaA8XA-GCaxSCkSJHEwJCWwqWpGlIAATDugGQiCf6CBAeDOSghiao+3JwLQ4XXsFwZimKQA)
```sh
--parser typescript
```

**Input:**
```tsx
const html = /* HTML */ `<!DOCTYPE html>
<HTML CLASS="no-js mY-ClAsS">
  <HEAD>
    <META CHARSET="utf-8">
    <TITLE>My tITlE</TITLE>
    <META NAME="description" content="My CoNtEnT">
  </HEAD>
  <body>
    <P>Hello world!<BR> This is HTML5 Boilerplate.</P>
    <SCRIPT>
      window.ga = function () { ga.q.push(arguments) }; ga.q = []; ga.l = +new Date;
      ga('create', 'UA-XXXXX-Y', 'auto'); ga('send', 'pageview')
    </script>
    <SCRIPT src="https://www.google-analytics.com/analytics.js" ASYNC DEFER></script>
  </body>
</HTML>`
```

**Output:**
```tsx
const html = /* HTML */ `<!DOCTYPE html>
<HTML CLASS="no-js mY-ClAsS">
  <HEAD>
    <META CHARSET="utf-8">
    <TITLE>My tITlE</TITLE>
    <META NAME="description" content="My CoNtEnT">
  </HEAD>
  <body>
    <P>Hello world!<BR> This is HTML5 Boilerplate.</P>
    <SCRIPT>
      window.ga = function () { ga.q.push(arguments) }; ga.q = []; ga.l = +new Date;
      ga('create', 'UA-XXXXX-Y', 'auto'); ga('send', 'pageview')
    </script>
    <SCRIPT src="https://www.google-analytics.com/analytics.js" ASYNC DEFER></script>
  </body>
</HTML>`;

```

**Expected behavior:**
format html correctly like [JavaScript](https://prettier.io/playground/#N4Igxg9gdgLgprEAuc0DOMAEALGBbAG0wF5MB6AKkwAkAVAWQBlMKzMADAHgEIARAeQDCtAJoAFAKI58BAHwAdKJzpNMgxgEEAyluLyQUCAFoAVmkx4RRwQQ1ot+hVEyZlEjbycuXnehNoaatQaAEpa-nogAK4wAGZGAByOit6utACStIwSsvQAnpgwmQQSnGQZWTkp3r7+gQByGn6RACZwaGAATgCWAA4w3dD6mJCwCDCR+WoQ9TASULTJzq5k1O6e1ZwARhAteV41YrLUcAQEEJgA7hCdBC3cnABCIbKYtNjd5p80DIwArJhHhBugQ4J1egQAIbwAB0ZSO1R8WkEIXSYloB1Sl26UBaEEuMIA5pCSJhYlEoGABtBMAAKACUmGAmGJMIAjjDelE0NhaZDOoSonhxmhGQBfADcLMh7NJAG0ALpS1lEUgAaigcEumF40LgEsR3mJtIA5F04HqTQAaTAmgCqGiMAA0XS6jCJrbbITEICb6crIaa0AgWp6Tb1IYS4AA3bpav2GsodHr9TGuZGo9GYNCdMCRXAwXpoJBkMiXctEiAQQmgoyQqCQgh5AZgNAwyB4Mj1xvN7qtmFmYbaET1QQ6iQAMQkLyTXT6MAOZR2eycZRUjFk7BAVpAEH6gygaGQoH5nXxYn5CCPKEh0eBLW3IC2nUhYAA1nAYFoI2AcYTkDAnRRHAO64IQADqHzwGgP5wFoV7dAMsYwHkyDgGgR47jiwadDAYgvoSeCQsgsSNsGO5mAAHo8L7vp+WiQsKjA4nAJFkSBIBUVof6ggAilEEDwGxBDkSAEadDhaFbJCWx5OcUCPr0PSwOB3QtDA2DIAkAAMO5KRAwbgS+vRoUp7RgtGrE7p0cBslE3Q2fhkZEcJonBng3QAUBHFoDxcD8YJrFIKRIkcTAMmqepmlIAATDugGQiCf6CBAeAuSghiao+3JwLQMnXiFwZimKQA)


Issue discussion:
The issue here is that the `/* HTML */` comment is somehow not attached to the template literal.
This seems to be related to #5588, relevant code: https://github.com/prettier/prettier/blob/6a45924379d919a17b072e38114745053ab808ef/src/language-js/embed.js#L555
Also happens with Flow, i.e. only works with babylon.

Solution patch:
diff --git a/src/language-js/comments.js b/src/language-js/comments.js
index 50ee0e9e2942..be1394e0058a 100644
--- a/src/language-js/comments.js
+++ b/src/language-js/comments.js
@@ -858,9 +858,20 @@ function isBlockComment(comment) {
   return comment.type === "Block" || comment.type === "CommentBlock";
 }
 
+function hasLeadingComment(node, fn = () => true) {
+  if (node.leadingComments) {
+    return node.leadingComments.some(fn);
+  }
+  if (node.comments) {
+    return node.comments.some(comment => comment.leading && fn(comment));
+  }
+  return false;
+}
+
 module.exports = {
   handleOwnLineComment,
   handleEndOfLineComment,
   handleRemainingComment,
+  hasLeadingComment,
   isBlockComment
 };
diff --git a/src/language-js/embed.js b/src/language-js/embed.js
index 26b4186e1eef..fa96ede479e7 100644
--- a/src/language-js/embed.js
+++ b/src/language-js/embed.js
@@ -1,5 +1,7 @@
 "use strict";
 
+const { isBlockComment, hasLeadingComment } = require("./comments");
+
 const {
   builders: {
     indent,
@@ -508,12 +510,9 @@ function hasLanguageComment(node, languageName) {
   // we will not trim the comment value and we will expect exactly one space on
   // either side of the GraphQL string
   // Also see ./clean.js
-  return (
-    node.leadingComments &&
-    node.leadingComments.some(
-      comment =>
-        comment.type === "CommentBlock" && comment.value === ` ${languageName} `
-    )
+  return hasLeadingComment(
+    node,
+    comment => isBlockComment(comment) && comment.value === ` ${languageName} `
   );
 }
 


Test patch:
diff --git a/tests/multiparser_js_html/__snapshots__/jsfmt.spec.js.snap b/tests/multiparser_js_html/__snapshots__/jsfmt.spec.js.snap
index ac3e5057945e..98f22416d728 100644
--- a/tests/multiparser_js_html/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/multiparser_js_html/__snapshots__/jsfmt.spec.js.snap
@@ -2,7 +2,7 @@
 
 exports[`lit-html.js 1`] = `
 ====================================options=====================================
-parsers: ["babylon"]
+parsers: ["babylon", "flow", "typescript"]
 printWidth: 80
                                                                                 | printWidth
 =====================================input======================================
diff --git a/tests/multiparser_js_html/jsfmt.spec.js b/tests/multiparser_js_html/jsfmt.spec.js
index 968651cdbc2c..c0e8f2eb217b 100644
--- a/tests/multiparser_js_html/jsfmt.spec.js
+++ b/tests/multiparser_js_html/jsfmt.spec.js
@@ -1,1 +1,1 @@
-run_spec(__dirname, ["babylon"]);
+run_spec(__dirname, ["babylon", "flow", "typescript"]);