From 9500403c1df4a2f27ac1699f4be1514868c1ea6b Mon Sep 17 00:00:00 2001 From: Seiya <20365512+seiyab@users.noreply.github.com> Date: Wed, 29 Mar 2023 10:12:38 +0900 Subject: [PATCH] Fix a bug: css urls are incorrectly stripped of commas (#14476) Co-authored-by: fisker Cheung --- changelog_unreleased/css/14476.md | 19 +++++++ src/language-css/parse/parse-value.js | 18 ++----- .../utils/get-function-arguments-text.js | 13 +++++ src/language-css/utils/get-value-root.js | 9 ++++ .../utils/has-string-or-function.js | 6 ++- .../css/url/__snapshots__/jsfmt.spec.js.snap | 52 +++++++++++++++++++ tests/format/css/url/url.css | 27 ++++++++++ 7 files changed, 129 insertions(+), 15 deletions(-) create mode 100644 changelog_unreleased/css/14476.md create mode 100644 src/language-css/utils/get-function-arguments-text.js create mode 100644 src/language-css/utils/get-value-root.js diff --git a/changelog_unreleased/css/14476.md b/changelog_unreleased/css/14476.md new file mode 100644 index 000000000..4a5fbde7b --- /dev/null +++ b/changelog_unreleased/css/14476.md @@ -0,0 +1,19 @@ +#### Fix url contains comma (#14476 by @seiyab) + + +```css +/* Input */ +@font-face { + src: url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf); +} + +/* Prettier stable */ +@font-face { + src: url(RobotoFlex-VariableFont_GRADXTRAYOPQYTASYTDEYTFIYTLCYTUCopszslntwdthwght.ttf); +} + +/* Prettier main */ +@font-face { + src: url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf); +} +``` diff --git a/src/language-css/parse/parse-value.js b/src/language-css/parse/parse-value.js index f4a0e6501..df66908be 100644 --- 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 index 000000000..d67ce279c --- /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 index 000000000..fb0809ec6 --- /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 index 085d20a66..d0ff332ad 100644 --- 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("\\")) ); } diff --git a/tests/format/css/url/__snapshots__/jsfmt.spec.js.snap b/tests/format/css/url/__snapshots__/jsfmt.spec.js.snap index ff0a122da..8f0b9dc29 100644 --- 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 index db4e23140..d31282c7e 100644 --- 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); + ; +}