Skip to content

Commit

Permalink
Use scss parser for css-in-js (#7883)
Browse files Browse the repository at this point in the history
  • Loading branch information
thorn0 committed Mar 31, 2020
1 parent 0f56b4a commit 2d1142f
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 43 deletions.
28 changes: 28 additions & 0 deletions changelog_unreleased/javascript/pr-7883.md
@@ -0,0 +1,28 @@
#### Fix regressions in styled-components template literals ([#7883](https://github.com/prettier/prettier/pull/7883) by [@thorn0](https://github.com/thorn0))

<!-- prettier-ignore -->
```js
// Input
const Icon = styled.div`
background: var(--${background});
${Link}:not(:first-child) {
fill: rebeccapurple;
}
`;

// Prettier stable
const Icon = styled.div`
background: var(-- ${background});
${Link}:not (:first-child) {
fill: rebeccapurple;
}
`;

// Prettier master
const Icon = styled.div`
background: var(--${background});
${Link}:not(:first-child) {
fill: rebeccapurple;
}
`;
```
22 changes: 18 additions & 4 deletions src/language-css/printer-postcss.js
Expand Up @@ -246,11 +246,16 @@ function genericPrint(path, options, print) {
? concat([
isDetachedRulesetCallNode(node)
? ""
: isTemplatePlaceholderNode(node) &&
/^\s*\n/.test(node.raws.afterName)
? /^\s*\n\s*\n/.test(node.raws.afterName)
: isTemplatePlaceholderNode(node)
? node.raws.afterName === ""
? ""
: node.name.endsWith(":")
? " "
: /^\s*\n\s*\n/.test(node.raws.afterName)
? concat([hardline, hardline])
: hardline
: /^\s*\n/.test(node.raws.afterName)
? hardline
: " "
: " ",
path.call(print, "params"),
])
Expand Down Expand Up @@ -530,6 +535,15 @@ function genericPrint(path, options, print) {
continue;
}

// styled.div` background: var(--${one}); `
if (
!iPrevNode &&
iNode.value === "--" &&
iNextNode.type === "value-atword"
) {
continue;
}

// Ignore spaces before/after string interpolation (i.e. `"#{my-fn("_")}"`)
const isStartSCSSInterpolationInString =
iNode.type === "value-string" && iNode.value.startsWith("#{");
Expand Down
50 changes: 11 additions & 39 deletions src/language-js/embed.js
Expand Up @@ -36,36 +36,15 @@ function embed(path, print, textToDoc, options) {
const rawQuasis = node.quasis.map((q) => q.value.raw);
let placeholderID = 0;
const text = rawQuasis.reduce((prevVal, currVal, idx) => {
if (idx === 0) {
return currVal;
}

let specialSuffix = ""; // colons and whitespaces

const trailingColons = currVal.match(/^(\s*)(:+)(\s*)/);
if (trailingColons) {
const whitespaceBeforeColons = !!trailingColons[1];
const numberOfColons = trailingColons[2].length;
const whitespaceAfterColons = !!trailingColons[3];

if (whitespaceAfterColons) {
// do nothing, it's not a pseudo-element or pseudo-class
} else {
if (whitespaceBeforeColons) {
specialSuffix += "-whitespace";
}
specialSuffix += "-colon".repeat(numberOfColons);

currVal = "\uffff" + currVal.slice(trailingColons[0].length);
}
}

const placeholder = `@prettier-placeholder${specialSuffix}-${placeholderID++}-id`;

return prevVal + placeholder + currVal;
return idx === 0
? currVal
: prevVal +
"@prettier-placeholder-" +
placeholderID++ +
"-id" +
currVal;
}, "");

const doc = textToDoc(text, { parser: "css" });
const doc = textToDoc(text, { parser: "scss" });
return transformCssDoc(doc, path, print);
}

Expand Down Expand Up @@ -313,21 +292,14 @@ function replacePlaceholders(quasisDoc, expressionDocs) {
const placeholder = parts[atPlaceholderIndex];
const rest = parts.slice(atPlaceholderIndex + 1);
const placeholderMatch = placeholder.match(
/@prettier-placeholder((?:-whitespace|-colon)*)-(.+)-id([\s\S]*)/
/@prettier-placeholder-(.+)-id([\s\S]*)/
);
const specialSuffix = placeholderMatch[1]; // colons and whitespaces
const placeholderID = placeholderMatch[2];
const placeholderID = placeholderMatch[1];
// When the expression has a suffix appended, like:
// animation: linear ${time}s ease-out;
let suffix = placeholderMatch[3];
const suffix = placeholderMatch[2];
const expression = expressions[placeholderID];

if (specialSuffix) {
suffix =
specialSuffix.replace(/-whitespace/g, " ").replace(/-colon/g, ":") +
suffix.replace(/^\uffff/g, "");
}

replaceCounter++;
parts = parts
.slice(0, atPlaceholderIndex)
Expand Down
78 changes: 78 additions & 0 deletions tests/multiparser_js_css/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -45,6 +45,64 @@ const Icon = styled.div\`
================================================================================
`;

exports[`colons-after-substitutions2.js 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
const Icon = styled.div\`
height: 48px;
\${Link}:nth-child(2) {
fill: rebeccapurple;
}
\`;
const Icon2 = styled.div\`
height: 48px;
\${Link}:empty:before{
fill: rebeccapurple;
}
\`;
const Icon3 = styled.div\`
height: 48px;
\${Link}:not(:first-child) {
fill: rebeccapurple;
}
\`;
=====================================output=====================================
const Icon = styled.div\`
height: 48px;
\${Link}:nth-child(2) {
fill: rebeccapurple;
}
\`;
const Icon2 = styled.div\`
height: 48px;
\${Link}:empty:before {
fill: rebeccapurple;
}
\`;
const Icon3 = styled.div\`
height: 48px;
\${Link}:not(:first-child) {
fill: rebeccapurple;
}
\`;
================================================================================
`;

exports[`styled-components.js 1`] = `
====================================options=====================================
parsers: ["babel"]
Expand Down Expand Up @@ -555,3 +613,23 @@ const Foo = styled.p\`
================================================================================
`;
exports[`var.js 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
const Something = styled.div\`
background: var(--\${one}); /* ... */
border: 1px solid var(--\${two}); /* ... */
\`;
=====================================output=====================================
const Something = styled.div\`
background: var(--\${one}); /* ... */
border: 1px solid var(--\${two}); /* ... */
\`;
================================================================================
`;
23 changes: 23 additions & 0 deletions tests/multiparser_js_css/colons-after-substitutions2.js
@@ -0,0 +1,23 @@
const Icon = styled.div`
height: 48px;
${Link}:nth-child(2) {
fill: rebeccapurple;
}
`;

const Icon2 = styled.div`
height: 48px;
${Link}:empty:before{
fill: rebeccapurple;
}
`;

const Icon3 = styled.div`
height: 48px;
${Link}:not(:first-child) {
fill: rebeccapurple;
}
`;
4 changes: 4 additions & 0 deletions tests/multiparser_js_css/var.js
@@ -0,0 +1,4 @@
const Something = styled.div`
background: var(--${one}); /* ... */
border: 1px solid var(--${two}); /* ... */
`;

0 comments on commit 2d1142f

Please sign in to comment.