Repository: prettier/prettier (JavaScript)
Date: 2020-08-25 10:10:06+00:00
Task type: Bug Fix

Issue:
Prettier 2.1.0 and Sass rules with single mixin inclusion
Having just upgraded from prettier 2.0.5 to 2.1.0. 
I have a `.vue` Single File Components with SASS style where I apply a mixin to a selector

For example, something like:
```
// Works with Prettier 2.0.5
<style lang="sass">
.hero
  @include background-centered
</style>
```

Was acceptable for Prettier 2.0.5, but now 2.1.0 suggests me to delete the newline and insert a semicolon at the end, like this:
```
// Fix suggested by prettier 2.1.0
<style lang="sass">
.hero @include background-centered;
</style>
```
This produces a Sass compilation error.

Using the mixin shorthand `+` also confuses Prettier when there are not other rules:
```
// Works with Prettier 2.0.5
<style lang="sass">
.hero
  +background-centered
</style>
```

Prettier will suggest this edit:
```
// Fix suggested by prettier 2.1.0
<style lang="sass" scoped>
.hero + background-centered;
</style>
```

When there are actual rules preceding or following, there are no problems:
```
// Works with Prettier 2.0.5 and Prettier 2.1.0
<style lang="sass">
.hero
  +background-centered

.another-selector
  margin: 0 auto
</style>
```

So the problem seems to be pulled up by having selectors with only mixins applied and no actual rules. As soon as the .sass file includes an actual CSS rule, having a selector with just a mixin is nice for Prettier, not before ^^


Issue discussion:
It's a bug. Prettier should keep `style` blocks with unsupported `lang` as is.
I'll work on this

Solution patch:
diff --git a/changelog_unreleased/TEMPLATE.md b/changelog_unreleased/TEMPLATE.md
index a7ebe3c0aaa9..268377304b92 100644
--- a/changelog_unreleased/TEMPLATE.md
+++ b/changelog_unreleased/TEMPLATE.md
@@ -24,7 +24,7 @@
 
 #### Title ([#XXXX](https://github.com/prettier/prettier/pull/XXXX) by [@user](https://github.com/user))
 
-Optional description if it makes sense.
+<!-- Optional description if it makes sense. -->
 
 <!-- prettier-ignore -->
 ```jsx
diff --git a/changelog_unreleased/html/pr-9051.md b/changelog_unreleased/html/pr-9051.md
new file mode 100644
index 000000000000..63c99d04719b
--- /dev/null
+++ b/changelog_unreleased/html/pr-9051.md
@@ -0,0 +1,21 @@
+#### Fix format on `style[lang="sass"]` ([#9051](https://github.com/prettier/prettier/pull/9051) by [@fisker](https://github.com/fisker))
+
+<!-- prettier-ignore -->
+```jsx
+<!-- Input -->
+<style lang="sass">
+.hero
+  @include background-centered
+</style>
+
+<!-- Prettier stable -->
+<style lang="sass">
+.hero @include background-centered;
+</style>
+
+<!-- Prettier master -->
+<style lang="sass">
+  .hero
+    @include background-centered
+</style>
+```
diff --git a/src/language-html/utils.js b/src/language-html/utils.js
index cd6540c7a4fd..e79715793c02 100644
--- a/src/language-html/utils.js
+++ b/src/language-html/utils.js
@@ -399,7 +399,7 @@ function _inferScriptParser(node) {
 
 function inferStyleParser(node) {
   const { lang } = node.attrMap;
-  if (lang === "postcss" || lang === "css") {
+  if (!lang || lang === "postcss" || lang === "css") {
     return "css";
   }
 
@@ -421,13 +421,12 @@ function inferScriptParser(node, options) {
   }
 
   if (node.name === "style") {
-    return inferStyleParser(node) || "css";
+    return inferStyleParser(node);
   }
 
   if (options && isVueNonHtmlBlock(node, options)) {
     return (
       _inferScriptParser(node) ||
-      inferStyleParser(node) ||
       (!("src" in node.attrMap) && getParserName(node.attrMap.lang, options))
     );
   }


Test patch:
diff --git a/tests/html/multiparser-css/__snapshots__/jsfmt.spec.js.snap b/tests/html/multiparser/css/__snapshots__/jsfmt.spec.js.snap
similarity index 100%
rename from tests/html/multiparser-css/__snapshots__/jsfmt.spec.js.snap
rename to tests/html/multiparser/css/__snapshots__/jsfmt.spec.js.snap
diff --git a/tests/html/multiparser-css/html-with-css-style.html b/tests/html/multiparser/css/html-with-css-style.html
similarity index 100%
rename from tests/html/multiparser-css/html-with-css-style.html
rename to tests/html/multiparser/css/html-with-css-style.html
diff --git a/tests/html/multiparser-css/jsfmt.spec.js b/tests/html/multiparser/css/jsfmt.spec.js
similarity index 100%
rename from tests/html/multiparser-css/jsfmt.spec.js
rename to tests/html/multiparser/css/jsfmt.spec.js
diff --git a/tests/html/multiparser-js/__snapshots__/jsfmt.spec.js.snap b/tests/html/multiparser/js/__snapshots__/jsfmt.spec.js.snap
similarity index 100%
rename from tests/html/multiparser-js/__snapshots__/jsfmt.spec.js.snap
rename to tests/html/multiparser/js/__snapshots__/jsfmt.spec.js.snap
diff --git a/tests/html/multiparser-js/html-with-js-script.html b/tests/html/multiparser/js/html-with-js-script.html
similarity index 100%
rename from tests/html/multiparser-js/html-with-js-script.html
rename to tests/html/multiparser/js/html-with-js-script.html
diff --git a/tests/html/multiparser-js/jsfmt.spec.js b/tests/html/multiparser/js/jsfmt.spec.js
similarity index 100%
rename from tests/html/multiparser-js/jsfmt.spec.js
rename to tests/html/multiparser/js/jsfmt.spec.js
diff --git a/tests/html/multiparser-js/script-tag-escaping.html b/tests/html/multiparser/js/script-tag-escaping.html
similarity index 100%
rename from tests/html/multiparser-js/script-tag-escaping.html
rename to tests/html/multiparser/js/script-tag-escaping.html
diff --git a/tests/html/multiparser-markdown/__snapshots__/jsfmt.spec.js.snap b/tests/html/multiparser/markdown/__snapshots__/jsfmt.spec.js.snap
similarity index 100%
rename from tests/html/multiparser-markdown/__snapshots__/jsfmt.spec.js.snap
rename to tests/html/multiparser/markdown/__snapshots__/jsfmt.spec.js.snap
diff --git a/tests/html/multiparser-markdown/html-with-markdown-script.html b/tests/html/multiparser/markdown/html-with-markdown-script.html
similarity index 100%
rename from tests/html/multiparser-markdown/html-with-markdown-script.html
rename to tests/html/multiparser/markdown/html-with-markdown-script.html
diff --git a/tests/html/multiparser-markdown/jsfmt.spec.js b/tests/html/multiparser/markdown/jsfmt.spec.js
similarity index 100%
rename from tests/html/multiparser-markdown/jsfmt.spec.js
rename to tests/html/multiparser/markdown/jsfmt.spec.js
diff --git a/tests/html/multiparser-ts/__snapshots__/jsfmt.spec.js.snap b/tests/html/multiparser/ts/__snapshots__/jsfmt.spec.js.snap
similarity index 100%
rename from tests/html/multiparser-ts/__snapshots__/jsfmt.spec.js.snap
rename to tests/html/multiparser/ts/__snapshots__/jsfmt.spec.js.snap
diff --git a/tests/html/multiparser-ts/html-with-ts-script.html b/tests/html/multiparser/ts/html-with-ts-script.html
similarity index 100%
rename from tests/html/multiparser-ts/html-with-ts-script.html
rename to tests/html/multiparser/ts/html-with-ts-script.html
diff --git a/tests/html/multiparser-ts/jsfmt.spec.js b/tests/html/multiparser/ts/jsfmt.spec.js
similarity index 100%
rename from tests/html/multiparser-ts/jsfmt.spec.js
rename to tests/html/multiparser/ts/jsfmt.spec.js
diff --git a/tests/html/multiparser/unknown/__snapshots__/jsfmt.spec.js.snap b/tests/html/multiparser/unknown/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 000000000000..160a944843b7
--- /dev/null
+++ b/tests/html/multiparser/unknown/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,81 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`unknown-lang.html format 1`] = `
+====================================options=====================================
+parsers: ["html"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>Document</title>
+</head>
+<body>
+  <style lang="unknown">
+.prettier {
+content:
+"awesome"
+          }
+</style>
+
+<script lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown" lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+</body>
+</html>
+
+=====================================output=====================================
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Document</title>
+  </head>
+  <body>
+    <style lang="unknown">
+      .prettier {
+      content:
+      "awesome"
+                }
+    </style>
+
+    <script lang="unknown">
+      prettier.is
+                        .awesome(
+      )
+    </script>
+
+    <script type="unknown">
+      prettier.is
+                        .awesome(
+      )
+    </script>
+
+    <script type="unknown" lang="unknown">
+      prettier.is
+                        .awesome(
+      )
+    </script>
+  </body>
+</html>
+
+================================================================================
+`;
diff --git a/tests/html/multiparser/unknown/jsfmt.spec.js b/tests/html/multiparser/unknown/jsfmt.spec.js
new file mode 100644
index 000000000000..53763df9b20b
--- /dev/null
+++ b/tests/html/multiparser/unknown/jsfmt.spec.js
@@ -0,0 +1,1 @@
+run_spec(__dirname, ["html"]);
diff --git a/tests/html/multiparser/unknown/unknown-lang.html b/tests/html/multiparser/unknown/unknown-lang.html
new file mode 100644
index 000000000000..8d1f258f0720
--- /dev/null
+++ b/tests/html/multiparser/unknown/unknown-lang.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>Document</title>
+</head>
+<body>
+  <style lang="unknown">
+.prettier {
+content:
+"awesome"
+          }
+</style>
+
+<script lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown" lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+</body>
+</html>
diff --git a/tests/vue/multiparser/unknown/__snapshots__/jsfmt.spec.js.snap b/tests/vue/multiparser/unknown/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 000000000000..fad52a02b0bf
--- /dev/null
+++ b/tests/vue/multiparser/unknown/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,219 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`unknown.vue - {"embeddedLanguageFormatting":"off"} format 1`] = `
+====================================options=====================================
+embeddedLanguageFormatting: "off"
+parsers: ["vue"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+<style lang="unknown">
+.prettier {
+content:
+"awesome"
+          }
+</style>
+
+<script lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown" lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<template lang="unknown">
+    <prettier>
+      awesome
+</prettier>
+</template>
+
+=====================================output=====================================
+<style lang="unknown">
+.prettier {
+content:
+"awesome"
+          }
+</style>
+
+<script lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown" lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<template lang="unknown">
+    <prettier>
+      awesome
+</prettier>
+</template>
+
+================================================================================
+`;
+
+exports[`unknown.vue - {"vueIndentScriptAndStyle":true} format 1`] = `
+====================================options=====================================
+parsers: ["vue"]
+printWidth: 80
+vueIndentScriptAndStyle: true
+                                                                                | printWidth
+=====================================input======================================
+<style lang="unknown">
+.prettier {
+content:
+"awesome"
+          }
+</style>
+
+<script lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown" lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<template lang="unknown">
+    <prettier>
+      awesome
+</prettier>
+</template>
+
+=====================================output=====================================
+<style lang="unknown">
+  .prettier {
+  content:
+  "awesome"
+            }
+</style>
+
+<script lang="unknown">
+  prettier.is
+                    .awesome(
+  )
+</script>
+
+<script type="unknown">
+  prettier.is
+                    .awesome(
+  )
+</script>
+
+<script type="unknown" lang="unknown">
+  prettier.is
+                    .awesome(
+  )
+</script>
+
+<template lang="unknown">
+    <prettier>
+      awesome
+</prettier>
+</template>
+
+================================================================================
+`;
+
+exports[`unknown.vue format 1`] = `
+====================================options=====================================
+parsers: ["vue"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+<style lang="unknown">
+.prettier {
+content:
+"awesome"
+          }
+</style>
+
+<script lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown" lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<template lang="unknown">
+    <prettier>
+      awesome
+</prettier>
+</template>
+
+=====================================output=====================================
+<style lang="unknown">
+.prettier {
+content:
+"awesome"
+          }
+</style>
+
+<script lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown" lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<template lang="unknown">
+    <prettier>
+      awesome
+</prettier>
+</template>
+
+================================================================================
+`;
diff --git a/tests/vue/multiparser/unknown/jsfmt.spec.js b/tests/vue/multiparser/unknown/jsfmt.spec.js
new file mode 100644
index 000000000000..e188873aa9d8
--- /dev/null
+++ b/tests/vue/multiparser/unknown/jsfmt.spec.js
@@ -0,0 +1,3 @@
+run_spec(__dirname, ["vue"]);
+run_spec(__dirname, ["vue"], { vueIndentScriptAndStyle: true });
+run_spec(__dirname, ["vue"], { embeddedLanguageFormatting: "off" });
diff --git a/tests/vue/multiparser/unknown/unknown.vue b/tests/vue/multiparser/unknown/unknown.vue
new file mode 100644
index 000000000000..86dca0de51c0
--- /dev/null
+++ b/tests/vue/multiparser/unknown/unknown.vue
@@ -0,0 +1,30 @@
+<style lang="unknown">
+.prettier {
+content:
+"awesome"
+          }
+</style>
+
+<script lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<script type="unknown" lang="unknown">
+prettier.is
+                  .awesome(
+)
+</script>
+
+<template lang="unknown">
+    <prettier>
+      awesome
+</prettier>
+</template>
diff --git a/tests_config/run_spec.js b/tests_config/run_spec.js
index 75cd10327db0..795b2d0912ef 100644
--- a/tests_config/run_spec.js
+++ b/tests_config/run_spec.js
@@ -36,7 +36,7 @@ const unstableTests = new Map(
     "js/comments-closure-typecast/iife.js",
     "markdown/spec/example-234.md",
     "markdown/spec/example-235.md",
-    "html/multiparser-js/script-tag-escaping.html",
+    "html/multiparser/js/script-tag-escaping.html",
     [
       "js/multiparser-markdown/codeblock.js",
       (options) => options.proseWrap === "always",