Repository: prettier/prettier (JavaScript)

Issue:
@font-face urls are incorrectly stripped of commas
**Prettier 2.8.3**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAeAzjAngGzgPgB0oACEgAQDNoYBaSgQzDhOGLI4+tnoYFsAljixISAJwgAjANyc58hYqXKVqxewXoxYUQFcxOABQAlKRBgQAYngAetAGoMxAhpLyWaAfQDixgIIAIgA0ABoAKv5BAJoA8gAKAIrRYX4AyskBAKLJlgCSyQAyAMLJAKolEAAO6ABeQeg4sEEA7gAmMAAWLQDmHTAAdDAwlACU0hokAL5yxKgA9Ji4BBMkIEEgVTAC0OjIoE4SzXFOCLsoDDjNDFi765JiTADWcDCp-HAFAlBwyIw46HA7g8wM9XpUmF9usgYGJdICQHA+JI4K1WiiCgwoN1dAxunAPGI+AwhpDkCAGLoLGsQH0+DgAOodATwdDg5ipU7MgQAN2ZWDJYHQtxAXwBYhgcQe3SJvwuAPWACt0DZUpC8AldOYfkg-vKQOCxGKybScNTKs5YPSBO0OsgABwABnW5ogAPpD0qZPNcDF3J+6wAjpr4JKqmdyehaN8USjqWI4EGBPHJbiZTq5fCAYJobDM2q4H4hs5JJS4HE4GJPt9Zf881j1cHtbr4TBXFabcgAEzrGEMISQooQPhphHoACs1N0ALCrjOzfW3LhuSgaNgqTAzkqMD8K9S2DwNYBk0mQA)
<!-- prettier-ignore -->
```sh
--parser html
```

**Input:**
<!-- prettier-ignore -->
```html
<style>
  @font-face {
        font-family: rob;                                                                                
        src: url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);
   }     
</style>
    
```

**Output:**
<!-- prettier-ignore -->
```html
<style>
  @font-face {
    font-family: rob;
    src: url(RobotoFlex-VariableFont_GRADXTRAYOPQYTASYTDEYTFIYTLCYTUCopszslntwdthwght.ttf);
  }
</style>

```

**Expected behavior:**

Commas in filename should be kept - I don't see why they would be invalid inside a url() CSS function.


@font-face urls are incorrectly stripped of commas
**Prettier 2.8.3**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAeAzjAngGzgPgB0oACEgAQDNoYBaSgQzDhOGLI4+tnoYFsAljixISAJwgAjANyc58hYqXKVqxewXoxYUQFcxOABQAlKRBgQAYngAetAGoMxAhpLyWaAfQDixgIIAIgA0ABoAKv5BAJoA8gAKAIrRYX4AyskBAKLJlgCSyQAyAMLJAKolEAAO6ABeQeg4sEEA7gAmMAAWLQDmHTAAdDAwlACU0hokAL5yxKgA9Ji4BBMkIEEgVTAC0OjIoE4SzXFOCLsoDDjNDFi765JiTADWcDCp-HAFAlBwyIw46HA7g8wM9XpUmF9usgYGJdICQHA+JI4K1WiiCgwoN1dAxunAPGI+AwhpDkCAGLoLGsQH0+DgAOodATwdDg5ipU7MgQAN2ZWDJYHQtxAXwBYhgcQe3SJvwuAPWACt0DZUpC8AldOYfkg-vKQOCxGKybScNTKs5YPSBO0OsgABwABnW5ogAPpD0qZPNcDF3J+6wAjpr4JKqmdyehaN8USjqWI4EGBPHJbiZTq5fCAYJobDM2q4H4hs5JJS4HE4GJPt9Zf881j1cHtbr4TBXFabcgAEzrGEMISQooQPhphHoACs1N0ALCrjOzfW3LhuSgaNgqTAzkqMD8K9S2DwNYBk0mQA)
<!-- prettier-ignore -->
```sh
--parser html
```

**Input:**
<!-- prettier-ignore -->
```html
<style>
  @font-face {
        font-family: rob;                                                                                
        src: url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);
   }     
</style>
    
```

**Output:**
<!-- prettier-ignore -->
```html
<style>
  @font-face {
    font-family: rob;
    src: url(RobotoFlex-VariableFont_GRADXTRAYOPQYTASYTDEYTFIYTLCYTUCopszslntwdthwght.ttf);
  }
</style>

```

**Expected behavior:**

Commas in filename should be kept - I don't see why they would be invalid inside a url() CSS function.




Hints:
Thank you for reporting this! This is a CSS formatting problem, not for HTML!

**Prettier 2.8.3**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEACVABAZtGBaLAQzDlWAB0p1rqdYDCBbASwBsBPJVAJwgCMA3DWEjRY8RMlSxlMQGduYLgFdurABQAlfhBgQAYqzgAPPADVC3ZoT5H9uAPoBxTQEEAIgBoAGgBU3ngCaAPIACgCKQb6uAMpR7gCiUfoAklEAMgDCUQCq2RAADnIAXp5yrLCeAO4AJjAAFtUA5vUwAHQwMFgAlAKy6AC+wv3oIJ4ghTDM0HLIoJa8VaGWCLMohKxVhOyz43zcxADWcDAxTHDpzFBwyESscnB7B2DHpwXEV03IMNzKjyBwRh8OA1Gog9KEKBNZSEJpwezcRiETqfZAgQjKPRjECtRisADq9WY8Dk7xIMVWxOYADdiew0WA5LsQFcHtwYKEDk0kbcNg9xgArOTGGKfIzhZS6G5IO78kDvbhshlM7EFKywfHMOr1ZAADgADOM1RAHviDgU0Wq4GzqTdxgBHSXwTmFNbouR4a4gkHY7hwR3MP2c2E8mV8-4PFjfX4RsVwVydKx8TFwUJwbiXa68+6xqHip3S2X-GA2TXa5AAJnGP0IbE+mQgjFDALkAFZscoHr4bGsi+NqX8UlAwbAYmArAUYK5hzEYOwjNmHgMBkA)
<!-- prettier-ignore -->
```sh
--parser css
```

**Input:**
<!-- prettier-ignore -->
```css
  @font-face {
        font-family: rob;                                                                                
        src: url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);
   }     
    
```

**Output:**
<!-- prettier-ignore -->
```css
@font-face {
  font-family: rob;
  src: url(RobotoFlex-VariableFont_GRADXTRAYOPQYTASYTDEYTFIYTLCYTUCopszslntwdthwght.ttf);
}

```
Thank you for reporting this! This is a CSS formatting problem, not for HTML!

**Prettier 2.8.3**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEACVABAZtGBaLAQzDlWAB0p1rqdYDCBbASwBsBPJVAJwgCMA3DWEjRY8RMlSxlMQGduYLgFdurABQAlfhBgQAYqzgAPPADVC3ZoT5H9uAPoBxTQEEAIgBoAGgBU3ngCaAPIACgCKQb6uAMpR7gCiUfoAklEAMgDCUQCq2RAADnIAXp5yrLCeAO4AJjAAFtUA5vUwAHQwMFgAlAKy6AC+wv3oIJ4ghTDM0HLIoJa8VaGWCLMohKxVhOyz43zcxADWcDAxTHDpzFBwyESscnB7B2DHpwXEV03IMNzKjyBwRh8OA1Gog9KEKBNZSEJpwezcRiETqfZAgQjKPRjECtRisADq9WY8Dk7xIMVWxOYADdiew0WA5LsQFcHtwYKEDk0kbcNg9xgArOTGGKfIzhZS6G5IO78kDvbhshlM7EFKywfHMOr1ZAADgADOM1RAHviDgU0Wq4GzqTdxgBHSXwTmFNbouR4a4gkHY7hwR3MP2c2E8mV8-4PFjfX4RsVwVydKx8TFwUJwbiXa68+6xqHip3S2X-GA2TXa5AAJnGP0IbE+mQgjFDALkAFZscoHr4bGsi+NqX8UlAwbAYmArAUYK5hzEYOwjNmHgMBkA)
<!-- prettier-ignore -->
```sh
--parser css
```

**Input:**
<!-- prettier-ignore -->
```css
  @font-face {
        font-family: rob;                                                                                
        src: url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);
   }     
    
```

**Output:**
<!-- prettier-ignore -->
```css
@font-face {
  font-family: rob;
  src: url(RobotoFlex-VariableFont_GRADXTRAYOPQYTASYTDEYTFIYTLCYTUCopszslntwdthwght.ttf);
}

```

Patch:
diff --git a/src/language-css/parse/parse-value.js b/src/language-css/parse/parse-value.js
--- a/src/language-css/parse/parse-value.js
+++ b/src/language-css/parse/parse-value.js
@@ -1,18 +1,12 @@
 import PostcssValuesParser from "postcss-values-parser/lib/parser.js";
+import getFunctionArgumentsText from "../utils/get-function-arguments-text.js";
+import getValueRoot from "../utils/get-value-root.js";
 import hasSCSSInterpolation from "../utils/has-scss-interpolation.js";
 import hasStringOrFunction from "../utils/has-string-or-function.js";
 import isSCSSVariable from "../utils/is-scss-variable.js";
-import stringifyNode from "../utils/stringify-node.js";
 import parseSelector from "./parse-selector.js";
 import { addTypePrefix } from "./utils.js";
 
-const getHighestAncestor = (node) => {
-  while (node.parent) {
-    node = node.parent;
-  }
-  return node;
-};
-
 function parseValueNode(valueNode, options) {
   const { nodes } = valueNode;
   let parenGroup = {
@@ -48,7 +42,7 @@ function parseValueNode(valueNode, options) {
     if (node.type === "func" && node.value === "selector") {
       node.group.groups = [
         parseSelector(
-          getHighestAncestor(valueNode).text.slice(
+          getValueRoot(valueNode).text.slice(
             node.group.open.sourceIndex + 1,
             node.group.close.sourceIndex
           )
@@ -76,10 +70,7 @@ function parseValueNode(valueNode, options) {
         (!hasStringOrFunction(groupList) &&
           !isSCSSVariable(groupList[0], options))
       ) {
-        const stringifiedContent = stringifyNode({
-          groups: node.group.groups,
-        });
-        node.group.groups = [stringifiedContent.trim()];
+        node.group.groups = [getFunctionArgumentsText(node)];
       }
     }
     if (node.type === "paren" && node.value === "(") {
@@ -162,7 +153,6 @@ function parseNestedValue(node, options) {
         }
       }
     }
-    delete node.parent;
   }
   return node;
 }
diff --git a/src/language-css/utils/get-function-arguments-text.js b/src/language-css/utils/get-function-arguments-text.js
new file mode 100644
--- /dev/null
+++ b/src/language-css/utils/get-function-arguments-text.js
@@ -0,0 +1,13 @@
+import getValueRoot from "./get-value-root.js";
+
+/**
+ * @param {*} node
+ * @returns {string}
+ */
+function getFunctionArgumentsText(node) {
+  return getValueRoot(node)
+    .text.slice(node.group.open.sourceIndex + 1, node.group.close.sourceIndex)
+    .trim();
+}
+
+export default getFunctionArgumentsText;
diff --git a/src/language-css/utils/get-value-root.js b/src/language-css/utils/get-value-root.js
new file mode 100644
--- /dev/null
+++ b/src/language-css/utils/get-value-root.js
@@ -0,0 +1,9 @@
+const getValueRoot = (node) => {
+  while (node.parent) {
+    node = node.parent;
+  }
+
+  return node;
+};
+
+export default getValueRoot;
diff --git a/src/language-css/utils/has-string-or-function.js b/src/language-css/utils/has-string-or-function.js
--- a/src/language-css/utils/has-string-or-function.js
+++ b/src/language-css/utils/has-string-or-function.js
@@ -1,6 +1,10 @@
 function hasStringOrFunction(groupList) {
   return groupList.some(
-    (group) => group.type === "string" || group.type === "func"
+    (group) =>
+      group.type === "string" ||
+      (group.type === "func" &&
+        // workaround false-positive func
+        !group.value.endsWith("\\"))
   );
 }
 


Test patch:
diff --git a/tests/format/css/url/__snapshots__/jsfmt.spec.js.snap b/tests/format/css/url/__snapshots__/jsfmt.spec.js.snap
--- a/tests/format/css/url/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/css/url/__snapshots__/jsfmt.spec.js.snap
@@ -11,11 +11,63 @@ div {
   background: -fb-url(/images/bg.png);
 }
 
+@font-face {
+  src: url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);
+  src: url(foo.ttf?query=foo,bar,);
+  src: url(foo.woff2?foo=rgb\\(255,255,0\\));
+}
+
+a {
+  content: url(https://example.com/\\)\\).jpg);
+  content: url(https://example.com/\\(\\(.jpg);
+  content: url(https://example.com/\\ \\ .jpg);
+  content: url(   https://example.com/\\)\\).jpg   );
+  content: url(   https://example.com/\\(\\(.jpg   );
+  content: url(   https://example.com/\\ \\ .jpg   );
+
+  background:
+    no-repeat url(https://example.com/\\)\\).jpg),
+    no-repeat url(https://example.com/\\(\\(.jpg),
+    no-repeat url(https://example.com/\\ \\ .jpg),
+    no-repeat url(   https://example.com/\\)\\).jpg   ),
+    no-repeat url(   https://example.com/\\(\\(.jpg   ),
+    no-repeat url(   https://example.com/\\ \\ .jpg   ),
+    no-repeat url(foo.ttf?query=foo,bar,),
+    no-repeat url(foo.woff2?foo=rgb\\(255,255,0\\))
+    no-repeat url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);
+  ;
+}
+
 =====================================output=====================================
 div {
   background: url(/images/bg.png);
   background: -fb-url(/images/bg.png);
 }
 
+@font-face {
+  src: url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);
+  src: url(foo.ttf?query=foo,bar,);
+  src: url(foo.woff2?foo=rgb\\(255,255,0\\));
+}
+
+a {
+  content: url(https://example.com/\\)\\).jpg);
+  content: url(https://example.com/\\(\\(.jpg);
+  content: url(https://example.com/\\ \\ .jpg);
+  content: url(   https://example.com/\\)\\).jpg   );
+  content: url(   https://example.com/\\(\\(.jpg   );
+  content: url(https://example.com/\\ \\ .jpg);
+
+  background: no-repeat url(https://example.com/\\)\\).jpg),
+    no-repeat url(https://example.com/\\(\\(.jpg),
+    no-repeat url(https://example.com/\\ \\ .jpg),
+    no-repeat url(   https://example.com/\\)\\).jpg   ),
+    no-repeat url(   https://example.com/\\(\\(.jpg   ),
+    no-repeat url(   https://example.com/\\ \\ .jpg   ),
+    no-repeat url(foo.ttf?query=foo,bar,),
+    no-repeat url(foo.woff2?foo=rgb\\(255,255,0\\))
+    no-repeat url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);
+}
+
 ================================================================================
 `;
diff --git a/tests/format/css/url/url.css b/tests/format/css/url/url.css
--- a/tests/format/css/url/url.css
+++ b/tests/format/css/url/url.css
@@ -2,3 +2,30 @@ div {
   background: url(/images/bg.png);
   background: -fb-url(/images/bg.png);
 }
+
+@font-face {
+  src: url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);
+  src: url(foo.ttf?query=foo,bar,);
+  src: url(foo.woff2?foo=rgb\(255,255,0\));
+}
+
+a {
+  content: url(https://example.com/\)\).jpg);
+  content: url(https://example.com/\(\(.jpg);
+  content: url(https://example.com/\ \ .jpg);
+  content: url(   https://example.com/\)\).jpg   );
+  content: url(   https://example.com/\(\(.jpg   );
+  content: url(   https://example.com/\ \ .jpg   );
+
+  background:
+    no-repeat url(https://example.com/\)\).jpg),
+    no-repeat url(https://example.com/\(\(.jpg),
+    no-repeat url(https://example.com/\ \ .jpg),
+    no-repeat url(   https://example.com/\)\).jpg   ),
+    no-repeat url(   https://example.com/\(\(.jpg   ),
+    no-repeat url(   https://example.com/\ \ .jpg   ),
+    no-repeat url(foo.ttf?query=foo,bar,),
+    no-repeat url(foo.woff2?foo=rgb\(255,255,0\))
+    no-repeat url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);
+  ;
+}