diff --git a/changelog_unreleased/css/pr-8567.md b/changelog_unreleased/css/pr-8567.md index 3860e4169dbe..ca8637d99d32 100644 --- a/changelog_unreleased/css/pr-8567.md +++ b/changelog_unreleased/css/pr-8567.md @@ -1,22 +1,28 @@ -#### Fix: [Sass] Unexpectedly add extra space after function when passing arbitrary arguments ([#8567](https://github.com/prettier/prettier/pull/8567) by [@boyenn](https://github.com/boyenn)) +#### Improve Prettier handling of arbitrary arguments ([#8567](https://github.com/prettier/prettier/pull/8567), [#8566](https://github.com/prettier/prettier/pull/8566) by [@boyenn](https://github.com/boyenn)) + +Prettier no longer unexpectedly add extra space after function when passing arbitrary arguments. +Prettier no longer breaks code when inline number lists are used as arbitrary arguments. ```css /* Input */ body { test: function($list...); - test: function(return-list($list)...); + foo: bar(returns-list($list)...); + background-color: rgba(50 50 50 50...); } /* Prettier stable */ body { test: function($list...); - test: function(return-list($list) ...); + foo: bar(returns-list($list) ...); + background-color: rgba(50 50 50 50..); } /* Prettier master */ body { test: function($list...); - test: function(return-list($list)...); + foo: bar(returns-list($list)...); + background-color: rgba(50 50 50 50...); } ``` diff --git a/src/language-css/parser-postcss.js b/src/language-css/parser-postcss.js index 5fd2130b8bd8..7b25df944f53 100644 --- a/src/language-css/parser-postcss.js +++ b/src/language-css/parser-postcss.js @@ -14,7 +14,7 @@ const { } = require("./utils"); const { calculateLoc, replaceQuotesInInlineComments } = require("./loc"); -function parseValueNodes(nodes) { +function parseValueNodes(nodes, options) { let parenGroup = { open: null, close: null, @@ -32,6 +32,19 @@ function parseValueNodes(nodes) { for (let i = 0; i < nodes.length; ++i) { const node = nodes[i]; + if ( + isSCSS(options.parser, node.value) && + node.type === "number" && + node.unit === ".." && + node.value[node.value.length - 1] === "." + ) { + // Work around postcss bug parsing `50...` as `50.` with unit `..` + // Set the unit to `...` to "accidentally" have arbitrary arguments work in the same way that cases where the node already had a unit work. + // For example, 50px... is parsed as `50` with unit `px...` already by postcss-values-parser. + node.value = node.value.slice(0, -1); + node.unit = "..."; + } + if (node.type === "func" && node.value === "url") { const groups = (node.group && node.group.groups) || []; @@ -153,13 +166,13 @@ function addMissingType(node) { return node; } -function parseNestedValue(node) { +function parseNestedValue(node, options) { if (node && typeof node === "object") { delete node.parent; for (const key in node) { - parseNestedValue(node[key]); + parseNestedValue(node[key], options); if (key === "nodes") { - node.group = flattenGroups(parseValueNodes(node[key])); + node.group = flattenGroups(parseValueNodes(node[key], options)); delete node[key]; } } @@ -167,7 +180,7 @@ function parseNestedValue(node) { return node; } -function parseValue(value) { +function parseValue(value, options) { const valueParser = require("postcss-values-parser"); let result = null; @@ -183,7 +196,7 @@ function parseValue(value) { result.text = value; - const parsedResult = parseNestedValue(result); + const parsedResult = parseNestedValue(result, options); return addTypePrefix(parsedResult, "value-"); } @@ -321,7 +334,7 @@ function parseNestedCSS(node, options) { // Ignore LESS mixins if (node.mixin) { - node.selector = parseValue(selector); + node.selector = parseValue(selector, options); return node; } @@ -366,7 +379,7 @@ function parseNestedCSS(node, options) { }; } - node.value = parseValue(value); + node.value = parseValue(value, options); } if ( @@ -423,7 +436,7 @@ function parseNestedCSS(node, options) { node.variable = true; const parts = node.name.split(":"); node.name = parts[0]; - node.value = parseValue(parts.slice(1).join(":")); + node.value = parseValue(parts.slice(1).join(":"), options); } // Missing whitespace between variable and colon @@ -433,7 +446,7 @@ function parseNestedCSS(node, options) { node.params[0] === ":" ) { node.variable = true; - node.value = parseValue(node.params.slice(1)); + node.value = parseValue(node.params.slice(1), options); } // Less variable @@ -466,7 +479,7 @@ function parseNestedCSS(node, options) { if (name === "at-root") { if (/^\(\s*(without|with)\s*:[\S\s]+\)$/.test(params)) { - node.params = parseValue(params); + node.params = parseValue(params, options); } else { node.selector = parseSelector(params); delete node.params; @@ -478,7 +491,7 @@ function parseNestedCSS(node, options) { if (lowercasedName === "import") { node.import = true; delete node.filename; - node.params = parseValue(params); + node.params = parseValue(params, options); return node; } @@ -505,7 +518,7 @@ function parseNestedCSS(node, options) { // Remove unnecessary spaces before SCSS control, mixin and function directives params = params.replace(/^(?!if)(\S+)\s+\(/, "$1("); - node.value = parseValue(params); + node.value = parseValue(params, options); delete node.params; return node; diff --git a/tests/scss/scss/__snapshots__/jsfmt.spec.js.snap b/tests/scss/scss/__snapshots__/jsfmt.spec.js.snap index e2388dddcfd3..d62d6378574f 100644 --- a/tests/scss/scss/__snapshots__/jsfmt.spec.js.snap +++ b/tests/scss/scss/__snapshots__/jsfmt.spec.js.snap @@ -39,6 +39,16 @@ $parameters: ( ); $value: dummy($parameters...); +body { + background-color: rgba(50, 50, 50, 50); + background-color: rgba(50 50 50 50...); + background-color: rgba(50 50 .50 50...); + background-color: rgba(50 50 50. .50...); + // Input is not technically valid ( output is ), but still nice to know that the \`.\` gets dropped as it would for \`50.\` + background-color: rgba(50 50 50 50....); + width: min(50px 20px 30px...); +} + =====================================output===================================== body { test: foo(return-list($list)...); @@ -72,6 +82,16 @@ $parameters: ( ); $value: dummy($parameters...); +body { + background-color: rgba(50, 50, 50, 50); + background-color: rgba(50 50 50 50...); + background-color: rgba(50 50 0.5 50...); + background-color: rgba(50 50 50 0.5...); + // Input is not technically valid ( output is ), but still nice to know that the \`.\` gets dropped as it would for \`50.\` + background-color: rgba(50 50 50 50...); + width: min(50px 20px 30px...); +} + ================================================================================ `; @@ -113,6 +133,16 @@ $parameters: ( ); $value: dummy($parameters...); +body { + background-color: rgba(50, 50, 50, 50); + background-color: rgba(50 50 50 50...); + background-color: rgba(50 50 .50 50...); + background-color: rgba(50 50 50. .50...); + // Input is not technically valid ( output is ), but still nice to know that the \`.\` gets dropped as it would for \`50.\` + background-color: rgba(50 50 50 50....); + width: min(50px 20px 30px...); +} + =====================================output===================================== body { test: foo(return-list($list)...); @@ -146,6 +176,16 @@ $parameters: ( ); $value: dummy($parameters...); +body { + background-color: rgba(50, 50, 50, 50); + background-color: rgba(50 50 50 50...); + background-color: rgba(50 50 0.5 50...); + background-color: rgba(50 50 50 0.5...); + // Input is not technically valid ( output is ), but still nice to know that the \`.\` gets dropped as it would for \`50.\` + background-color: rgba(50 50 50 50...); + width: min(50px 20px 30px...); +} + ================================================================================ `; diff --git a/tests/scss/scss/arbitrary-arguments.scss b/tests/scss/scss/arbitrary-arguments.scss index b290d5a6ce1d..531baa1af2c5 100644 --- a/tests/scss/scss/arbitrary-arguments.scss +++ b/tests/scss/scss/arbitrary-arguments.scss @@ -29,3 +29,13 @@ $parameters: ( 'b': 42 ); $value: dummy($parameters...); + +body { + background-color: rgba(50, 50, 50, 50); + background-color: rgba(50 50 50 50...); + background-color: rgba(50 50 .50 50...); + background-color: rgba(50 50 50. .50...); + // Input is not technically valid ( output is ), but still nice to know that the `.` gets dropped as it would for `50.` + background-color: rgba(50 50 50 50....); + width: min(50px 20px 30px...); +}