Repository: tkh44/emotion
Pull request #221 (2017-08-02 11:24:28)

Random object interpolations
<!--
Thanks for your interest in the project. I appreciate bugs filed and PRs submitted!

Please make sure that you are familiar with and follow the Code of Conduct for
this project (found in the CODE_OF_CONDUCT.md file).

Also, please make sure you're familiar with and follow the instructions in the
contributing guidelines (found in the CONTRIBUTING.md file).

If you're new to contributing to open source projects, you might find this free
video course helpful: http://kcd.im/pull-request

Please fill out the information below to expedite the review and (hopefully)
merge of your pull request!
-->

<!-- What changes are being made? (What feature/bug is being fixed here?) -->
**What**:

Allow random object interpolations.
```jsx
const styles = { backgroundColor: 'hotpink' }

const Div = styled.div`
  background-color: yellow;
  ${styles};
`
```

<!-- Why are these changes necessary? -->
**Why**:

Using polished, etc...

<!-- How were these changes implemented? -->
**How**:

Change the way random interpolations work. Random interpolations have a key like this
```jsx
`$${indexOfInterpolation}`
```
and the value is whatever was interpolated.

I changed `replacePlaceholdersWithExpressions` so things where the whole thing is a single interpolation the value is replaced with the expression so that objects aren't cast to strings.

<!-- Have you done all of these things?  -->
**Checklist**:
<!-- add "N/A" to the end of each line that's irrelevant to your changes -->
<!-- to check an item, place an "x" in the box like so: "- [x] Documentation" -->
- [ ] Documentation
- [x] Tests
- [x] Code complete

<!-- feel free to add additional comments -->

This also changes from `postcss-safe-parser/lib/safe-parser` to `postcss/lib/parser`. This basically means semicolons are required and errors with code frames are thrown if they're not there. (The code frames look pretty weird since there is one from postcss and another from babel)

We _could_ support interpolating regular classes anywhere but IMO regular classes should be interpolated in composes because otherwise specificity won't make sense. e.g. the color of this class with be green.
```jsx
const cls = css`
  color: green;
  ${'class-that-has-color-hotpink'};
`
```

I added back the error for composes on nested selectors since we can't do anything if a regular class is interpolated on a nested selector and people can use random interpolations where they would want composes on a nested selector.

codecov-io: # [Codecov](https://codecov.io/gh/tkh44/emotion/pull/221?src=pr&el=h1) Report
> Merging [#221](https://codecov.io/gh/tkh44/emotion/pull/221?src=pr&el=desc) into [master](https://codecov.io/gh/tkh44/emotion/commit/ebff44bcaf845f1d8d5e0e03d7a46aceb82a2727?src=pr&el=desc) will **increase** coverage by `0.02%`.
> The diff coverage is `95.65%`.

[![Impacted file tree graph](https://codecov.io/gh/tkh44/emotion/pull/221/graphs/tree.svg?token=B1bWuYNE2t&src=pr&height=150&width=650)](https://codecov.io/gh/tkh44/emotion/pull/221?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##           master    #221      +/-   ##
=========================================
+ Coverage   90.38%   90.4%   +0.02%     
=========================================
  Files          22      22              
  Lines         967     980      +13     
  Branches      260     266       +6     
=========================================
+ Hits          874     886      +12     
- Misses         75      76       +1     
  Partials       18      18
```


| [Impacted Files](https://codecov.io/gh/tkh44/emotion/pull/221?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [test/extract/extract.test.emotion.css](https://codecov.io/gh/tkh44/emotion/pull/221?src=pr&el=tree#diff-dGVzdC9leHRyYWN0L2V4dHJhY3QudGVzdC5lbW90aW9uLmNzcw==) | `100% <ø> (ø)` | :arrow_up: |
| [src/parser.js](https://codecov.io/gh/tkh44/emotion/pull/221?src=pr&el=tree#diff-c3JjL3BhcnNlci5qcw==) | `95% <100%> (+0.4%)` | :arrow_up: |
| [src/babel.js](https://codecov.io/gh/tkh44/emotion/pull/221?src=pr&el=tree#diff-c3JjL2JhYmVsLmpz) | `97.74% <100%> (-0.02%)` | :arrow_down: |
| [src/ast-object.js](https://codecov.io/gh/tkh44/emotion/pull/221?src=pr&el=tree#diff-c3JjL2FzdC1vYmplY3QuanM=) | `89.13% <100%> (+0.4%)` | :arrow_up: |
| [src/index.js](https://codecov.io/gh/tkh44/emotion/pull/221?src=pr&el=tree#diff-c3JjL2luZGV4Lmpz) | `94.11% <90.9%> (-0.31%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/tkh44/emotion/pull/221?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/tkh44/emotion/pull/221?src=pr&el=footer). Last update [ebff44b...00e75df](https://codecov.io/gh/tkh44/emotion/pull/221?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/src/ast-object.js b/src/ast-object.js
index 4a90a5ba..89e1ed11 100644
--- a/src/ast-object.js
+++ b/src/ast-object.js
@@ -189,7 +189,7 @@ export default class ASTObject {
     const templateExpressions = []
     let cursor = 0
     // not sure how to detect when to add 'px'
-    // let hasSingleInterpolation = false
+    let hasSingleInterpolation = false
     forEach(matches, ({ value, p1, index }, i) => {
       const preMatch = str.substring(cursor, index)
       cursor = cursor + preMatch.length + value.length
@@ -200,9 +200,9 @@ export default class ASTObject {
       } else if (i === 0) {
         templateElements.push(t.templateElement({ raw: '', cooked: '' }))
       }
-      // if (value === str) {
-      // hasSingleInterpolation = true
-      // }
+      if (value === str) {
+        hasSingleInterpolation = true
+      }
 
       templateExpressions.push(
         expressions.length
@@ -221,9 +221,9 @@ export default class ASTObject {
         )
       }
     })
-    // if (hasSingleInterpolation) {
-    //   return templateExpressions[0]
-    // }
+    if (hasSingleInterpolation) {
+      return templateExpressions[0]
+    }
     return t.templateLiteral(templateElements, templateExpressions)
   }
 
diff --git a/src/babel.js b/src/babel.js
index e8114736..5ef99965 100644
--- a/src/babel.js
+++ b/src/babel.js
@@ -44,10 +44,7 @@ export function replaceCssWithCallExpression (
       if (!removePath) {
         return path.replaceWith(t.stringLiteral(`${name}-${hash}`))
       }
-
-      path.replaceWith(t.identifier('undefined'))
-
-      return
+      return path.replaceWith(t.identifier('undefined'))
     }
 
     const { styles, composesCount } = parseCSS(src, false, getFilename(path))
diff --git a/src/index.js b/src/index.js
index 17c9c803..5a20e766 100644
--- a/src/index.js
+++ b/src/index.js
@@ -245,11 +245,23 @@ function deconstruct (style) {
     } else if (key.indexOf('@supports') === 0) {
       supports = supports || {}
       supports[key] = deconstruct(style[key])
-    } else if (key.indexOf('css-') === 0) {
-      // replace fragments
+    } else if (key.indexOf('$') === 0) {
+      const fragment = style[key]
       plain = plain || {}
-      const registeredStyles = registered[key.split('css-')[1]].style
-      assign(plain, registeredStyles)
+
+      if (typeof fragment === 'object') {
+        assign(plain, fragment)
+      } else if (typeof fragment === 'string') {
+        const match = emotionClassRegex.exec(fragment)
+        if (match !== null && registered[match[1]]) {
+          // replace fragments
+          const reg = registered[match[1]]
+          if (reg.type !== 'css') {
+            throw new Error('cannot merge this rule')
+          }
+          assign(plain, reg.style)
+        }
+      }
     } else {
       plain = plain || {}
 
@@ -400,10 +412,6 @@ function build (
     }
 
     forEach(keys(_src || {}), key => {
-      if (key === 'undefined') {
-        // drop undefined fragment results
-        return
-      }
       if (isSelector(key)) {
         build(dest, {
           selector: joinSelectors(selector, key),
diff --git a/src/parser.js b/src/parser.js
index d0adb25c..bbf4586a 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -1,7 +1,7 @@
 // @flow
 import Input from 'postcss/lib/input'
 import Declaration from 'postcss/lib/declaration'
-import SafeParser from 'postcss-safe-parser/lib/safe-parser'
+import Parser from 'postcss/lib/parser'
 import postcssNested from 'postcss-nested'
 import postcssJs from 'postcss-js'
 import objParse from 'postcss-js/parser'
@@ -31,7 +31,7 @@ export function parseCSS (
   if (typeof css === 'object') {
     root = objParse(css, { from: filename })
   } else {
-    root = safeParse(css, { from: filename })
+    root = parse(css, { from: filename })
   }
   let vars = 0
   let composes: number = 0
@@ -44,6 +44,9 @@ export function parseCSS (
       if (decl.parent.nodes[0] !== decl) {
         throw new Error('composes must be the first rule')
       }
+      if (decl.parent.type !== 'root') {
+        throw new Error('composes cannot be on nested selectors')
+      }
       const composeMatches = decl.value.match(/xxx(\d+)xxx/gm)
       const numOfComposes: number = !composeMatches ? 0 : composeMatches.length
       composes += numOfComposes
@@ -87,22 +90,23 @@ export function expandCSSFallbacks (style: { [string]: any }) {
 }
 
 // Parser
-export function safeParse (css, opts) {
+export function parse (css, opts) {
   let input = new Input(css, opts)
 
-  let parser = new EmotionSafeParser(input)
+  let parser = new EmotionParser(input)
   parser.parse()
 
   return parser.root
 }
 
-export class EmotionSafeParser extends SafeParser {
+export class EmotionParser extends Parser {
   unknownWord (tokens: Array<Array<any>>) {
     if (tokens[0][0] === 'word') {
-      if (/xxx(\d+)xxx/gm.exec(tokens[0][1])) {
+      const match = /xxx(\d+)xxx/gm.exec(tokens[0][1])
+      if (match) {
         this.init(
           new Declaration(
-            { prop: tokens[0][1], value: 'fragment' },
+            { prop: `$${match[1]}`, value: tokens[0][1] },
             tokens[0][2],
             tokens[0][3]
           )


Test patch:
diff --git a/test/__snapshots__/react.test.js.snap b/test/__snapshots__/react.test.js.snap
index bdc92a37..2fd3ddcf 100644
--- a/test/__snapshots__/react.test.js.snap
+++ b/test/__snapshots__/react.test.js.snap
@@ -297,7 +297,6 @@ exports[`styled handles more than 10 dynamic properties 1`] = `
   z-index: 100;
   font-size: 18px;
   text-align: center;
-  border-left: undefined;
 }
 
 <h1
@@ -310,7 +309,6 @@ exports[`styled handles more than 10 dynamic properties 1`] = `
 exports[`styled higher order component 1`] = `
 .glamor-1 {
   font-size: 20px;
-  name: onyx;
   background-color: '#343a40';
   -webkit-box-orient: vertical;
   -webkit-box-direction: normal;
@@ -379,19 +377,6 @@ exports[`styled input placeholder object 1`] = `
 </input>
 `;
 
-exports[`styled name 1`] = `
-.glamor-1 {
-  name: FancyH1;
-  font-size: 20px;
-}
-
-<h1
-  className="glamor-0 glamor-1"
->
-  hello world
-</h1>
-`;
-
 exports[`styled nested 1`] = `
 .glamor-1 {
   font-size: 20px;
@@ -488,9 +473,9 @@ exports[`styled objects with spread properties 1`] = `
 exports[`styled random expressions 1`] = `
 .glamor-1 {
   font-size: 1rem;
-  margin-top: 0px;
+  margin-top: 0;
   margin-right: auto;
-  margin-bottom: 0px;
+  margin-bottom: 0;
   margin-left: auto;
   color: green;
 }
@@ -515,6 +500,25 @@ exports[`styled random expressions undefined return 1`] = `
 </h1>
 `;
 
+exports[`styled random object expression 1`] = `
+.glamor-1 {
+  background-color: hotpink;
+  font-size: 1rem;
+  margin-top: 0;
+  margin-right: auto;
+  margin-bottom: 0;
+  margin-left: auto;
+  color: green;
+}
+
+<h1
+  className="glamor-0 legacy__class glamor-1"
+  prop={true}
+>
+  hello world
+</h1>
+`;
+
 exports[`styled themes 1`] = `
 .glamor-1 {
   background-color: #ffd43b;
diff --git a/test/__snapshots__/server.test.js.snap b/test/__snapshots__/server.test.js.snap
index aa81c4a9..041e42f8 100644
--- a/test/__snapshots__/server.test.js.snap
+++ b/test/__snapshots__/server.test.js.snap
@@ -3,7 +3,7 @@
 exports[`extractCritical returns static css 1`] = `
 Object {
   "css": "@font-face{font-family:'Patrick Hand SC';font-style:normal;font-weight:400;src:local('Patrick Hand SC'), local('PatrickHandSC-Regular'), url(https://fonts.gstatic.com/s/patrickhandsc/v4/OYFWCgfCR-7uHIovjUZXsZ71Uis0Qeb9Gqo8IZV7ckE.woff2) format('woff2');unicode-range:U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;}@-webkit-keyframes animation_7jdctn{from, 20%, 53%, 80%, to {-webkit-animation-timing-function:cubic-bezier(0.215, 0.610, 0.355, 1.000);animation-timing-function:cubic-bezier(0.215, 0.610, 0.355, 1.000);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);}40%, 43% {-webkit-animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);-webkit-transform:translate3d(0, -30px, 0);transform:translate3d(0, -30px, 0);}70% {-webkit-animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);-webkit-transform:translate3d(0, -15px, 0);transform:translate3d(0, -15px, 0);}90% {-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0);}}@keyframes animation_7jdctn{from, 20%, 53%, 80%, to {-webkit-animation-timing-function:cubic-bezier(0.215, 0.610, 0.355, 1.000);animation-timing-function:cubic-bezier(0.215, 0.610, 0.355, 1.000);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);}40%, 43% {-webkit-animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);-webkit-transform:translate3d(0, -30px, 0);transform:translate3d(0, -30px, 0);}70% {-webkit-animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);-webkit-transform:translate3d(0, -15px, 0);transform:translate3d(0, -15px, 0);}90% {-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0);}}.no-prefix {display:-webkit-box; display: -ms-flexbox; display: flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;}.css-1kjabrg{color:hotpink;display:-webkit-box; display: -ms-flexbox; display: flex;}.css-1kjabrg:hover{color:white;background-color:lightgray;border-color:aqua;-webkit-box-shadow:-15px -15px 0 0 aqua, -30px -30px 0 0 cornflowerblue;box-shadow:-15px -15px 0 0 aqua, -30px -30px 0 0 cornflowerblue;}.css-1j6ha19{-webkit-animation:animation_7jdctn;animation:animation_7jdctn;border-radius:50%;height:50px;width:50px;background-color:red;}",
-  "html": "<main class=\\"css-fcaqzd0 css-1kjabrg\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"-997632446\\"><img size=\\"30\\" class=\\"css-fcaqzd1 css-1j6ha19\\" data-reactid=\\"2\\"/><img size=\\"100\\" class=\\"css-fcaqzd1 css-1j6ha19\\" data-reactid=\\"3\\"/><img class=\\"css-fcaqzd1 css-1j6ha19\\" data-reactid=\\"4\\"/></main>",
+  "html": "<main class=\\"css-pcr4x20 css-1kjabrg\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"230905066\\"><img size=\\"30\\" class=\\"css-pcr4x21 css-1j6ha19\\" data-reactid=\\"2\\"/><img size=\\"100\\" class=\\"css-pcr4x21 css-1j6ha19\\" data-reactid=\\"3\\"/><img class=\\"css-pcr4x21 css-1j6ha19\\" data-reactid=\\"4\\"/></main>",
   "ids": Array [
     "1vx6krt",
     "7jdctn",
@@ -40,7 +40,7 @@ Object {
 exports[`extractCritical returns static css 2`] = `
 Object {
   "css": "@font-face{font-family:'Patrick Hand SC';font-style:normal;font-weight:400;src:local('Patrick Hand SC'), local('PatrickHandSC-Regular'), url(https://fonts.gstatic.com/s/patrickhandsc/v4/OYFWCgfCR-7uHIovjUZXsZ71Uis0Qeb9Gqo8IZV7ckE.woff2) format('woff2');unicode-range:U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;}@-webkit-keyframes animation_7jdctn{from, 20%, 53%, 80%, to {-webkit-animation-timing-function:cubic-bezier(0.215, 0.610, 0.355, 1.000);animation-timing-function:cubic-bezier(0.215, 0.610, 0.355, 1.000);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);}40%, 43% {-webkit-animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);-webkit-transform:translate3d(0, -30px, 0);transform:translate3d(0, -30px, 0);}70% {-webkit-animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);-webkit-transform:translate3d(0, -15px, 0);transform:translate3d(0, -15px, 0);}90% {-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0);}}@keyframes animation_7jdctn{from, 20%, 53%, 80%, to {-webkit-animation-timing-function:cubic-bezier(0.215, 0.610, 0.355, 1.000);animation-timing-function:cubic-bezier(0.215, 0.610, 0.355, 1.000);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);}40%, 43% {-webkit-animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);-webkit-transform:translate3d(0, -30px, 0);transform:translate3d(0, -30px, 0);}70% {-webkit-animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);-webkit-transform:translate3d(0, -15px, 0);transform:translate3d(0, -15px, 0);}90% {-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0);}}.no-prefix {display:-webkit-box; display: -ms-flexbox; display: flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;}.css-1kjabrg{color:hotpink;display:-webkit-box; display: -ms-flexbox; display: flex;}.css-1kjabrg:hover{color:white;background-color:lightgray;border-color:aqua;-webkit-box-shadow:-15px -15px 0 0 aqua, -30px -30px 0 0 cornflowerblue;box-shadow:-15px -15px 0 0 aqua, -30px -30px 0 0 cornflowerblue;}",
-  "html": "<main class=\\"css-fcaqzd0 css-1kjabrg\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"-1456331201\\"><div data-reactid=\\"2\\">Hello</div></main>",
+  "html": "<main class=\\"css-pcr4x20 css-1kjabrg\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"-1970723351\\"><div data-reactid=\\"2\\">Hello</div></main>",
   "ids": Array [
     "1vx6krt",
     "7jdctn",
@@ -73,7 +73,7 @@ Object {
 exports[`hydration only rules that are not in the critical css are inserted 1`] = `
 Object {
   "css": "@font-face{font-family:'Patrick Hand SC';font-style:normal;font-weight:400;src:local('Patrick Hand SC'), local('PatrickHandSC-Regular'), url(https://fonts.gstatic.com/s/patrickhandsc/v4/OYFWCgfCR-7uHIovjUZXsZ71Uis0Qeb9Gqo8IZV7ckE.woff2) format('woff2');unicode-range:U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;}@-webkit-keyframes animation_7jdctn{from, 20%, 53%, 80%, to {-webkit-animation-timing-function:cubic-bezier(0.215, 0.610, 0.355, 1.000);animation-timing-function:cubic-bezier(0.215, 0.610, 0.355, 1.000);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);}40%, 43% {-webkit-animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);-webkit-transform:translate3d(0, -30px, 0);transform:translate3d(0, -30px, 0);}70% {-webkit-animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);-webkit-transform:translate3d(0, -15px, 0);transform:translate3d(0, -15px, 0);}90% {-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0);}}@keyframes animation_7jdctn{from, 20%, 53%, 80%, to {-webkit-animation-timing-function:cubic-bezier(0.215, 0.610, 0.355, 1.000);animation-timing-function:cubic-bezier(0.215, 0.610, 0.355, 1.000);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);}40%, 43% {-webkit-animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);-webkit-transform:translate3d(0, -30px, 0);transform:translate3d(0, -30px, 0);}70% {-webkit-animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);animation-timing-function:cubic-bezier(0.755, 0.050, 0.855, 0.060);-webkit-transform:translate3d(0, -15px, 0);transform:translate3d(0, -15px, 0);}90% {-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0);}}.no-prefix {display:-webkit-box; display: -ms-flexbox; display: flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;}.css-1kjabrg{color:hotpink;display:-webkit-box; display: -ms-flexbox; display: flex;}.css-1kjabrg:hover{color:white;background-color:lightgray;border-color:aqua;-webkit-box-shadow:-15px -15px 0 0 aqua, -30px -30px 0 0 cornflowerblue;box-shadow:-15px -15px 0 0 aqua, -30px -30px 0 0 cornflowerblue;}.css-1j6ha19{-webkit-animation:animation_7jdctn;animation:animation_7jdctn;border-radius:50%;height:50px;width:50px;background-color:red;}",
-  "html": "<main class=\\"css-fcaqzd0 css-1kjabrg\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"-997632446\\"><img size=\\"30\\" class=\\"css-fcaqzd1 css-1j6ha19\\" data-reactid=\\"2\\"/><img size=\\"100\\" class=\\"css-fcaqzd1 css-1j6ha19\\" data-reactid=\\"3\\"/><img class=\\"css-fcaqzd1 css-1j6ha19\\" data-reactid=\\"4\\"/></main>",
+  "html": "<main class=\\"css-pcr4x20 css-1kjabrg\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"230905066\\"><img size=\\"30\\" class=\\"css-pcr4x21 css-1j6ha19\\" data-reactid=\\"2\\"/><img size=\\"100\\" class=\\"css-pcr4x21 css-1j6ha19\\" data-reactid=\\"3\\"/><img class=\\"css-pcr4x21 css-1j6ha19\\" data-reactid=\\"4\\"/></main>",
   "ids": Array [
     "1vx6krt",
     "7jdctn",
diff --git a/test/babel/__snapshots__/css-prop.test.js.snap b/test/babel/__snapshots__/css-prop.test.js.snap
index 3d92f1dc..dac5f7b3 100644
--- a/test/babel/__snapshots__/css-prop.test.js.snap
+++ b/test/babel/__snapshots__/css-prop.test.js.snap
@@ -64,7 +64,7 @@ exports[`babel css prop dynamic inline 1`] = `
 "import { css as _css } from \\"emotion\\";
 <div className={\\"a\\" + \\" \\" + /*#__PURE__*/_css([], [color], function createEmotionStyledRules(x0) {
   return [{
-    \\"color\\": \`\${x0}\`
+    \\"color\\": x0
   }];
 })}></div>;"
 `;
diff --git a/test/babel/__snapshots__/css.test.js.snap b/test/babel/__snapshots__/css.test.js.snap
index de3c0e55..6b5a8824 100644
--- a/test/babel/__snapshots__/css.test.js.snap
+++ b/test/babel/__snapshots__/css.test.js.snap
@@ -10,14 +10,14 @@ exports[`babel css extract composes 1`] = `
 "import './css.test.emotion.css';
 
 const cls1 = 'css-cls1-1q8jsgx';
-const cls2 = /*#__PURE__*/css([['one-class', 'another-class', cls1]], ['center'], function createEmotionStyledRules(x0) {
+const cls2 = /*#__PURE__*/css(['one-class', 'another-class', cls1], ['center'], function createEmotionStyledRules(x0) {
   return [{
     'WebkitBoxPack': 'center',
     'msFlexPack': 'center',
     'justifyContent': 'center',
-    'WebkitBoxAlign': \`\${x0}\`,
-    'msFlexAlign': \`\${x0}\`,
-    'alignItems': \`\${x0}\`
+    'WebkitBoxAlign': x0,
+    'msFlexAlign': x0,
+    'alignItems': x0
   }];
 });"
 `;
@@ -102,7 +102,7 @@ css([{
   'borderRadius': '50%',
   'WebkitBoxSizing': 'border-box',
   'boxSizing': 'border-box',
-  [\`\${display}\`]: 'flex',
+  [display]: 'flex',
   ':hover': {
     'WebkitTransform': 'scale(1.2)',
     'transform': 'scale(1.2)'
@@ -216,7 +216,7 @@ const cls2 = css([{
   'WebkitBoxFlex': '1',
   'msFlex': '1',
   'flex': '1',
-  'alignItems': \`\${'center'}\`
+  'alignItems': 'center'
 }, {
   'WebkitBoxPack': 'start',
   'msFlexPack': 'start',
@@ -236,9 +236,9 @@ const cls2 = /*#__PURE__*/css(['one-class', 'another-class', cls1], ['center'],
     'WebkitBoxPack': 'center',
     'msFlexPack': 'center',
     'justifyContent': 'center',
-    'WebkitBoxAlign': \`\${x0}\`,
-    'msFlexAlign': \`\${x0}\`,
-    'alignItems': \`\${x0}\`
+    'WebkitBoxAlign': x0,
+    'msFlexAlign': x0,
+    'alignItems': x0
   }];
 });"
 `;
@@ -256,7 +256,7 @@ exports[`babel css inline css basic 1`] = `
     \\"@media (min-width: 420px)\\": {
       \\"lineHeight\\": \\"40px\\"
     },
-    \\"width\\": \`\${x0}\`
+    \\"width\\": x0
   }];
 });"
 `;
@@ -267,15 +267,16 @@ exports[`babel css inline css random expression 1`] = `
     \\"width\\": \\"96px\\",
     \\"height\\": \\"96px\\"
   }];
-})], function createEmotionStyledRules(x0) {
+}), { backgroundColor: \\"hotpink\\" }], function createEmotionStyledRules(x0, x1) {
   return [{
     \\"fontSize\\": \\"20px\\",
     \\"@media (min-width: 420px)\\": {
       \\"color\\": \\"blue\\",
-      [\`\${x0}\`]: \\"fragment\\",
+      \\"$0\\": x0,
       \\"lineHeight\\": \\"26px\\"
     },
-    \\"background\\": \\"green\\"
+    \\"background\\": \\"green\\",
+    \\"$1\\": x1
   }];
 });"
 `;
@@ -286,7 +287,7 @@ const cls2 = /*#__PURE__*/css([], [className], function createEmotionStyledRules
   return [{
     \\"margin\\": \\"12px 48px\\",
     \\"color\\": \\"#ffffff\\",
-    [\`\${x0}\`]: {
+    [x0]: {
       \\"display\\": \\"none\\"
     }
   }];
@@ -300,9 +301,9 @@ const cls2 = /*#__PURE__*/css(['one-class', 'another-class', 'another-class', 'a
     'WebkitBoxPack': 'center',
     'msFlexPack': 'center',
     'justifyContent': 'center',
-    'WebkitBoxAlign': \`\${x0}\`,
-    'msFlexAlign': \`\${x0}\`,
-    'alignItems': \`\${x0}\`
+    'WebkitBoxAlign': x0,
+    'msFlexAlign': x0,
+    'alignItems': x0
   }];
 });"
 `;
@@ -326,7 +327,7 @@ const cls2 = css({
   'WebkitBoxFlex': '1',
   'msFlex': '1',
   'flex': '1',
-  'alignItems': \`\${'center'}\`
+  'alignItems': 'center'
 });"
 `;
 
diff --git a/test/babel/__snapshots__/font-face.test.js.snap b/test/babel/__snapshots__/font-face.test.js.snap
index 400a8d6e..08ffd149 100644
--- a/test/babel/__snapshots__/font-face.test.js.snap
+++ b/test/babel/__snapshots__/font-face.test.js.snap
@@ -36,7 +36,7 @@ exports[`fontFace babel extract interpolation 1`] = `
 "
 fontFace([], [fontFamilyName], function createEmotionStyledRules(x0) {
      return [{
-          \\"fontFamily\\": \`\${x0}\`,
+          \\"fontFamily\\": x0,
           \\"src\\": \\"local(\\\\\\"Helvetica Neue Bold\\\\\\"),\\\\n               local(\\\\\\"HelveticaNeue-Bold\\\\\\"),\\\\n               url(MgOpenModernaBold.ttf)\\",
           \\"fontWeight\\": \\"bold\\"
      }];
@@ -58,7 +58,7 @@ exports[`fontFace babel inline interpolation 1`] = `
 "
 fontFace([], [fontFamilyName], function createEmotionStyledRules(x0) {
      return [{
-          \\"fontFamily\\": \`\${x0}\`,
+          \\"fontFamily\\": x0,
           \\"src\\": \\"local(\\\\\\"Helvetica Neue Bold\\\\\\"),\\\\n               local(\\\\\\"HelveticaNeue-Bold\\\\\\"),\\\\n               url(MgOpenModernaBold.ttf)\\",
           \\"fontWeight\\": \\"bold\\"
      }];
diff --git a/test/babel/__snapshots__/inject-global.test.js.snap b/test/babel/__snapshots__/inject-global.test.js.snap
index 2c982bcc..9d29245d 100644
--- a/test/babel/__snapshots__/inject-global.test.js.snap
+++ b/test/babel/__snapshots__/inject-global.test.js.snap
@@ -45,7 +45,7 @@ injectGlobal([], [display], function createEmotionStyledRules(x0) {
     \\"body\\": {
       \\"margin\\": \\"0\\",
       \\"padding\\": \\"0\\",
-      \\"display\\": \`\${x0}\`
+      \\"display\\": x0
     },
     \\"body > div\\": {
       \\"display\\": \\"none\\"
@@ -82,7 +82,7 @@ injectGlobal([], [display], function createEmotionStyledRules(x0) {
     \\"body\\": {
       \\"margin\\": \\"0\\",
       \\"padding\\": \\"0\\",
-      \\"display\\": \`\${x0}\`
+      \\"display\\": x0
     },
     \\"body > div\\": {
       \\"display\\": \\"none\\"
diff --git a/test/babel/__snapshots__/macro.test.js.snap b/test/babel/__snapshots__/macro.test.js.snap
index 9fa894ce..9e4d1b8f 100644
--- a/test/babel/__snapshots__/macro.test.js.snap
+++ b/test/babel/__snapshots__/macro.test.js.snap
@@ -11,7 +11,7 @@ exports[`babel macro css 1`] = `
         'WebkitBoxFlex': '1',
         'msFlex': '1 0 auto',
         'flex': '1 0 auto',
-        'width': \`\${x0}\`
+        'width': x0
     }];
 });"
 `;
@@ -122,7 +122,7 @@ const thing = /*#__PURE__*/_css([], [widthVar], function createEmotionStyledRule
     'WebkitBoxFlex': '1',
     'msFlex': '1 0 auto',
     'flex': '1 0 auto',
-    'width': \`\${x0}\`
+    'width': x0
   }];
 });"
 `;
diff --git a/test/babel/__snapshots__/styled.test.js.snap b/test/babel/__snapshots__/styled.test.js.snap
index c1951c36..dfb14348 100644
--- a/test/babel/__snapshots__/styled.test.js.snap
+++ b/test/babel/__snapshots__/styled.test.js.snap
@@ -45,7 +45,7 @@ exports[`babel styled component extract no use 2`] = `".styled-0 {}"`;
 exports[`babel styled component inline basic 1`] = `
 "const H1 = /*#__PURE__*/styled('h1', 'css-uutogn0', [], [fontSize + 'px'], function createEmotionStyledRules(x0) {
   return [{
-    'fontSize': \`\${x0}\`
+    'fontSize': x0
   }];
 });"
 `;
@@ -60,7 +60,7 @@ const H1 = /*#__PURE__*/styled('h1', 'css-gzpfex0', [props => {
   return props.a ? cssA : cssB;
 }], [fontSize + 'px', props => props.translateX], function createEmotionStyledRules(x0, x1) {
   return [{
-    'fontSize': \`\${x0}\`,
+    'fontSize': x0,
     'height': '20px',
     'WebkitTransform': \`translateX(\${x1})\`,
     'transform': \`translateX(\${x1})\`
@@ -73,7 +73,7 @@ exports[`babel styled component inline dynamic fns 1`] = `
   return [{
     'width': '96px',
     'height': '96px',
-    'borderRadius': \`\${x0}\`,
+    'borderRadius': x0,
     'border': \`1px solid \${x1}\`
   }];
 });"
@@ -82,23 +82,23 @@ exports[`babel styled component inline dynamic fns 1`] = `
 exports[`babel styled component inline function call 1`] = `
 "/*#__PURE__*/styled(MyComponent, 'css-1gd4urc0', [], [fontSize + 'px'], function createEmotionStyledRules(x0) {
   return [{
-    'fontSize': \`\${x0}\`
+    'fontSize': x0
   }];
 });"
 `;
 
 exports[`babel styled component inline interpolation in different places 1`] = `
 "
-const H1 = /*#__PURE__*/styled('h1', 'css-1kajwdu0', [], [fontSize + 'px', props => props.translateX, something, something, props => props.translateX, props => props.translateX, props => props.translateX, props => props.translateX, props => props.translateX, props => props.translateX], function createEmotionStyledRules(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) {
+const H1 = /*#__PURE__*/styled('h1', 'css-16hd4av0', [], [fontSize + 'px', props => props.translateX, something, something, props => props.translateX, props => props.translateX, props => props.translateX, props => props.translateX, props => props.translateX, props => props.translateX], function createEmotionStyledRules(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) {
   return [{
-    'fontSize': \`\${x0}\`,
+    'fontSize': x0,
     'height': '20px',
     'WebkitTransform': \`translateX(\${x1}); -webkit-transform: translateX(\${x4}) translateY(\${x5})\`,
     'transform': \`translateX(\${x1}); transform: translateX(\${x4}) translateY(\${x5})\`,
     'height1': \`\${x2}wow\`,
     'width': \`w\${x3}ow\`,
     'transform1': \`translateX(\${x6}) translateY(\${x7})\`,
-    'transform2': \`translateX(\${x8}) translateY(\${x9}\`
+    'transform2': \`translateX(\${x8}) \${x9}\`
   }];
 });"
 `;
@@ -131,19 +131,19 @@ exports[`babel styled component inline media query 1`] = `
 exports[`babel styled component inline more than 10 dynamic values 1`] = `
 "const H1 = /*#__PURE__*/styled('h1', 'css-kzo7z60', [], ['underline', 54, 'white', 'black', 'block', '3px', '25px', '500px', 100, '18px', 'center', p => p.theme.blue], function createEmotionStyledRules(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) {
       return [{
-            'WebkitTextDecoration': \`\${x0}\`,
-            'textDecoration': \`\${x0}\`,
+            'WebkitTextDecoration': x0,
+            'textDecoration': x0,
             'borderRight': \`solid blue \${x1}px\`,
-            'background': \`\${x2}\`,
-            'color': \`\${x3}\`,
-            'display': \`\${x4}\`,
-            'borderRadius': \`\${x5}\`,
-            'padding': \`\${x6}\`,
-            'width': \`\${x7}\`,
-            'zIndex': \`\${x8}\`,
-            'fontSize': \`\${x9}\`,
-            'textAlign': \`\${x10}\`,
-            'borderLeft': \`\${x11}\`
+            'background': x2,
+            'color': x3,
+            'display': x4,
+            'borderRadius': x5,
+            'padding': x6,
+            'width': x7,
+            'zIndex': x8,
+            'fontSize': x9,
+            'textAlign': x10,
+            'borderLeft': x11
       }];
 });"
 `;
@@ -151,7 +151,7 @@ exports[`babel styled component inline more than 10 dynamic values 1`] = `
 exports[`babel styled component inline nested 1`] = `
 "const H1 = /*#__PURE__*/styled('h1', 'css-17vfrab0', [], [fontSize + 'px'], function createEmotionStyledRules(x0) {
   return [{
-    'fontSize': \`\${x0}\`,
+    'fontSize': x0,
     '& div': {
       'color': 'blue'
     },
@@ -224,25 +224,26 @@ const a = () => /*#__PURE__*/css([], [], function createEmotionStyledRules() {
     \\"fontSize\\": \\"1rem\\"
   }];
 });
-/*#__PURE__*/styled(\\"h1\\", \\"css-1ep7oc10\\", [], [/*#__PURE__*/css([], [], function createEmotionStyledRules() {
+/*#__PURE__*/styled(\\"h1\\", \\"css-1evx9zo0\\", [], [/*#__PURE__*/css([], [], function createEmotionStyledRules() {
   return [{
     \\"fontSize\\": \\"32px\\"
   }];
-}), props => props.prop && a()], function createEmotionStyledRules(x0, x1) {
+}), props => props.prop && a(), { backgroundColor: \\"hotpink\\" }], function createEmotionStyledRules(x0, x1, x2) {
   return [{
     \\"margin\\": \\"12px 48px\\",
-    [\`\${x0}\`]: \\"fragment\\",
+    \\"$0\\": x0,
     \\"color\\": \\"#ffffff\\",
     \\"& .profile\\": {
-      [\`\${x1}\`]: \\"fragment\\"
-    }
+      \\"$1\\": x1
+    },
+    \\"$2\\": x2
   }];
 });"
 `;
 
 exports[`babel styled component inline shorthand property 1`] = `
 "const H1 = styled(\\"h1\\", \\"css-1o8pmqr0\\", [{
-  \\"fontSize\\": \`\${fontSize}\`
+  \\"fontSize\\": fontSize
 }]);"
 `;
 
@@ -254,7 +255,7 @@ const SomeComponent = /*#__PURE__*/styled(\\"div\\", \\"css-1jq2uck0\\", [], [],
 /*#__PURE__*/styled(\\"h1\\", \\"css-1jq2uck1\\", [], [SomeComponent], function createEmotionStyledRules(x0) {
   return [{
     \\"color\\": \\"blue\\",
-    [\`\${x0}\`]: {
+    [x0]: {
       \\"color\\": \\"green\\"
     }
   }];
diff --git a/test/babel/css-prop.test.js b/test/babel/css-prop.test.js
index 5904df61..cadb7011 100644
--- a/test/babel/css-prop.test.js
+++ b/test/babel/css-prop.test.js
@@ -30,7 +30,7 @@ describe('babel css prop', () => {
 
   test('basic object', () => {
     const basic = '(<div className="a" css={{ color: \'brown\' }}></div>)'
-    const {code} = babel.transform(basic, {
+    const { code } = babel.transform(basic, {
       plugins: [plugin]
     })
     expect(code).toMatchSnapshot()
@@ -111,7 +111,7 @@ describe('babel css prop', () => {
 
   test('no import css prop', () => {
     const basic =
-    '(<div className={`test__class`} css={`color: brown;`}></div>)'
+      '(<div className={`test__class`} css={`color: brown;`}></div>)'
     const { code } = babel.transform(basic, {
       plugins: [[plugin, { autoImportCssProp: false }]]
     })
diff --git a/test/babel/css.test.js b/test/babel/css.test.js
index daffa7b1..22223542 100644
--- a/test/babel/css.test.js
+++ b/test/babel/css.test.js
@@ -36,6 +36,7 @@ describe('babel css', () => {
           line-height: 26px;
         }
         background: green;
+        \${{ backgroundColor: "hotpink" }};        
       \`
       `
       const { code } = babel.transform(basic, {
@@ -80,7 +81,7 @@ describe('babel css', () => {
           display: flex;
         \`
         const cls2 = css\`
-          composes: \${'one-class'} \${'another-class'}\${cls1}
+          composes: \${'one-class'} \${'another-class'}\${cls1};
           justify-content: center;
           align-items: \${'center'}
         \`
@@ -184,7 +185,7 @@ describe('babel css', () => {
         \`
         const cls2 = css\`
           justify-content: center;
-          composes: \${['one-class', 'another-class', cls1]}
+          composes: \${'one-class'} \${'another-class'}\${cls1};
           align-items: \${'center'}
         \`
       `
@@ -211,10 +212,8 @@ describe('babel css', () => {
         })
       ).toThrowErrorMatchingSnapshot()
     })
-    test.skip(
-      'throws correct error when composes is on a nested selector',
-      () => {
-        const basic = `
+    test('throws correct error when composes is on a nested selector', () => {
+      const basic = `
         const cls1 = css\`
           display: flex;
         \`
@@ -226,13 +225,12 @@ describe('babel css', () => {
           }
         \`
       `
-        expect(() =>
-          babel.transform(basic, {
-            plugins: [[plugin]]
-          })
-        ).toThrowErrorMatchingSnapshot()
-      }
-    )
+      expect(() =>
+        babel.transform(basic, {
+          plugins: [[plugin]]
+        })
+      ).toThrowErrorMatchingSnapshot()
+    })
     test('object with a bunch of stuff', () => {
       const basic = `
       const cls2 = css({
@@ -288,7 +286,7 @@ describe('babel css', () => {
           display: flex;
         \`
         const cls2 = css\`
-          composes: \${['one-class', 'another-class', cls1]}
+          composes: \${'one-class'}\${'another-class'}\${cls1};
           justify-content: center;
           align-items: \${'center'}
         \`
@@ -308,7 +306,7 @@ describe('babel css', () => {
           display: flex;
         \`
         const cls2 = css\`
-          composes: \${'one-class'} \${'another-class'}\${cls1}
+          composes: \${'one-class'} \${'another-class'}\${cls1};
           justify-content: center;
           align-items: center
         \`
diff --git a/test/babel/styled.test.js b/test/babel/styled.test.js
index b126eb74..0880bb3f 100644
--- a/test/babel/styled.test.js
+++ b/test/babel/styled.test.js
@@ -99,6 +99,7 @@ describe('babel styled component', () => {
           & .profile {
             \${props => props.prop && a()}
           }
+          \${{ backgroundColor: "hotpink" }};
         \`
       `
       const { code } = babel.transform(basic, {
@@ -140,7 +141,7 @@ describe('babel styled component', () => {
         width: w\${something}ow;
         transform: translateX(\${(props) => props.translateX}) translateY(\${(props) => props.translateX});
         transform1: translateX(\${(props) => props.translateX}) translateY(\${(props) => props.translateX});
-        transform2: translateX(\${(props) => props.translateX}) translateY(\${(props) => props.translateX};
+        transform2: translateX(\${(props) => props.translateX}) \${(props) => props.translateX};
         \``
       const { code } = babel.transform(basic, {
         plugins: [plugin]
diff --git a/test/browserslist/css.test.js b/test/browserslist/css.test.js
index 5f2c2673..786076fc 100644
--- a/test/browserslist/css.test.js
+++ b/test/browserslist/css.test.js
@@ -9,9 +9,7 @@ expect.addSnapshotSerializer(serializer(sheet))
 
 describe('prefixing', () => {
   test('styled', () => {
-    const Div = styled.div`
-      display: flex;
-    `
+    const Div = styled.div`display: flex;`
     const tree = renderer.create(<Div>hello world</Div>).toJSON()
 
     expect(tree).toMatchSnapshot()
@@ -20,7 +18,9 @@ describe('prefixing', () => {
     const cls1 = css`
       display: flex;
     `
-    const tree = renderer.create(<div className={cls1}>hello world</div>).toJSON()
+    const tree = renderer
+      .create(<div className={cls1}>hello world</div>)
+      .toJSON()
 
     expect(tree).toMatchSnapshot()
   })
diff --git a/test/extract/__snapshots__/extract.test.js.snap b/test/extract/__snapshots__/extract.test.js.snap
index 0025a95b..d2d3fee9 100644
--- a/test/extract/__snapshots__/extract.test.js.snap
+++ b/test/extract/__snapshots__/extract.test.js.snap
@@ -2,7 +2,7 @@
 
 exports[`styled basic render nested 1`] = `
 <h1
-  className="styled-H1-1l4sfy8 css-d5wsk51"
+  className="styled-H1-1f87tx4 css-dabj7x1"
 >
   hello world
 </h1>
@@ -10,7 +10,7 @@ exports[`styled basic render nested 1`] = `
 
 exports[`styled name 1`] = `
 <h1
-  className="styled-FancyH1-131pfth css-d5wsk52"
+  className="styled-FancyH1-131pfth css-dabj7x2"
 >
   hello world
 </h1>
@@ -18,7 +18,7 @@ exports[`styled name 1`] = `
 
 exports[`styled no dynamic 1`] = `
 <h1
-  className="styled-H1-ijh7uz css-d5wsk50"
+  className="styled-H1-ijh7uz css-dabj7x0"
 >
   hello world
 </h1>
@@ -28,16 +28,16 @@ exports[`styled writes the correct css 1`] = `
 ".styled-H1-ijh7uz {
     font-size: 12px
 }
-.styled-H1-1l4sfy8 {
+.styled-H1-1f87tx4 {
     font-size: 20px
 }
-.styled-H1-1l4sfy8 span {
+.styled-H1-1f87tx4 span {
     color: blue
 }
-.styled-H1-1l4sfy8 span:hover {
+.styled-H1-1f87tx4 span:hover {
     color: green
 }
-.styled-H1-1l4sfy8 span:hover:after {
+.styled-H1-1f87tx4 span:hover:after {
     content: \\"after\\"
 }
 .styled-FancyH1-131pfth {
diff --git a/test/extract/extract.test.emotion.css b/test/extract/extract.test.emotion.css
index 00d1ee44..923a54b7 100644
--- a/test/extract/extract.test.emotion.css
+++ b/test/extract/extract.test.emotion.css
@@ -1,16 +1,16 @@
 .styled-H1-ijh7uz {
     font-size: 12px
 }
-.styled-H1-1l4sfy8 {
+.styled-H1-1f87tx4 {
     font-size: 20px
 }
-.styled-H1-1l4sfy8 span {
+.styled-H1-1f87tx4 span {
     color: blue
 }
-.styled-H1-1l4sfy8 span:hover {
+.styled-H1-1f87tx4 span:hover {
     color: green
 }
-.styled-H1-1l4sfy8 span:hover:after {
+.styled-H1-1f87tx4 span:hover:after {
     content: "after"
 }
 .styled-FancyH1-131pfth {
diff --git a/test/extract/extract.test.js b/test/extract/extract.test.js
index 315c8342..e0f6592f 100644
--- a/test/extract/extract.test.js
+++ b/test/extract/extract.test.js
@@ -23,10 +23,10 @@ describe('styled', () => {
       font-size: 20px;
       & span {
         color: blue;
-        
+
         &:hover {
           color: green;
-          
+
           &:after {
             content: "after";
           }
diff --git a/test/inject-global.test.js b/test/inject-global.test.js
index b7c721c4..d45490fd 100644
--- a/test/inject-global.test.js
+++ b/test/inject-global.test.js
@@ -14,7 +14,7 @@ test('injectGlobal', () => {
   const color = 'yellow'
   injectGlobal`
     body {
-      color: ${color}
+      color: ${color};
       margin: 0;
       padding: 0;
     }
diff --git a/test/keyframes.test.js b/test/keyframes.test.js
index 1e7a4114..c17f2b69 100644
--- a/test/keyframes.test.js
+++ b/test/keyframes.test.js
@@ -31,9 +31,7 @@ describe('keyframes', () => {
       }
     `
 
-    const H1 = styled.h1`
-      animation: ${bounce} 2s linear infinite;
-    `
+    const H1 = styled.h1`animation: ${bounce} 2s linear infinite;`
 
     const tree = renderer.create(<H1>hello world</H1>).toJSON()
 
diff --git a/test/macro/inject-global.test.js b/test/macro/inject-global.test.js
index b8b9e1db..b1cec907 100644
--- a/test/macro/inject-global.test.js
+++ b/test/macro/inject-global.test.js
@@ -15,7 +15,7 @@ test('injectGlobal', () => {
   const color = 'yellow'
   injectGlobal`
     body {
-      color: ${color}
+      color: ${color};
       margin: 0;
       padding: 0;
     }
diff --git a/test/macro/keyframes.test.js b/test/macro/keyframes.test.js
index 4f2c637e..6c67b757 100644
--- a/test/macro/keyframes.test.js
+++ b/test/macro/keyframes.test.js
@@ -31,9 +31,7 @@ describe('keyframes - macro', () => {
       }
     `
 
-    const H1 = styled.h1`
-      animation: ${bounce} 2s linear infinite;
-    `
+    const H1 = styled.h1`animation: ${bounce} 2s linear infinite;`
 
     const tree = renderer.create(<H1>hello world</H1>).toJSON()
 
diff --git a/test/macro/react.test.js b/test/macro/react.test.js
index b2f1358f..b8e4f84f 100644
--- a/test/macro/react.test.js
+++ b/test/macro/react.test.js
@@ -75,9 +75,7 @@ describe('styled', () => {
 
   test('component as selector', () => {
     const fontSize = '20px'
-    const H1 = styled.h1`
-      font-size: ${fontSize};
-    `
+    const H1 = styled.h1`font-size: ${fontSize};`
 
     const Thing = styled.div`
       display: flex;
@@ -87,7 +85,11 @@ describe('styled', () => {
     `
 
     const tree = renderer
-      .create(<Thing>hello <H1>This will be green</H1> world</Thing>)
+      .create(
+        <Thing>
+          hello <H1>This will be green</H1> world
+        </Thing>
+      )
       .toJSON()
 
     expect(tree).toMatchSnapshot()
@@ -101,13 +103,7 @@ describe('styled', () => {
 
     const H2 = styled(H1)`font-size: ${({ scale }) => fontSize * scale};`
 
-    const tree = renderer
-      .create(
-        <H2 scale={2}>
-          hello world
-        </H2>
-      )
-      .toJSON()
+    const tree = renderer.create(<H2 scale={2}>hello world</H2>).toJSON()
 
     expect(tree).toMatchSnapshot()
   })
@@ -120,24 +116,18 @@ describe('styled', () => {
     `
 
     const cssB = css`
-      composes: ${cssA}
+      composes: ${cssA};
       height: 64px;
     `
 
     const H1 = styled('h1')`
-      composes: ${cssB}
+      composes: ${cssB};
       font-size: ${fontSize};
     `
 
     const H2 = styled(H1)`font-size:32px;`
 
-    const tree = renderer
-      .create(
-        <H2 scale={2}>
-          hello world
-        </H2>
-      )
-      .toJSON()
+    const tree = renderer.create(<H2 scale={2}>hello world</H2>).toJSON()
 
     expect(tree).toMatchSnapshot()
   })
@@ -152,24 +142,18 @@ describe('styled', () => {
     }
 
     const cssB = css`
-      composes: ${cssA}
+      composes: ${cssA};
       height: 64px;
     `
 
     const H1 = styled('h1')`
-      composes: ${cssB}
+      composes: ${cssB};
       font-size: ${modularScale(4)};
     `
 
     const H2 = styled(H1)`font-size:32px;`
 
-    const tree = renderer
-      .create(
-        <H2 scale={2}>
-          hello world
-        </H2>
-      )
-      .toJSON()
+    const tree = renderer.create(<H2 scale={2}>hello world</H2>).toJSON()
 
     expect(tree).toMatchSnapshot()
   })
@@ -201,7 +185,7 @@ describe('styled', () => {
     `
 
     const cssB = css`
-      composes: ${cssA}
+      composes: ${cssA};
       height: 64px;
     `
 
@@ -210,9 +194,9 @@ describe('styled', () => {
     `
 
     const H1 = styled(Heading)`
-      composes: ${cssB}
+      composes: ${cssB};
       font-size: ${fontSize};
-      color: ${p => p.theme.purple}
+      color: ${p => p.theme.purple};
     `
 
     const H2 = styled(H1)`font-size:32px;`
@@ -274,22 +258,10 @@ describe('styled', () => {
       }};
     `
 
-    const tree = renderer
-      .create(
-        <H1 a>
-          hello world
-        </H1>
-      )
-      .toJSON()
+    const tree = renderer.create(<H1 a>hello world</H1>).toJSON()
 
     expect(tree).toMatchSnapshot()
-    const tree2 = renderer
-      .create(
-        <H1>
-          hello world
-        </H1>
-      )
-      .toJSON()
+    const tree2 = renderer.create(<H1>hello world</H1>).toJSON()
 
     expect(tree2).toMatchSnapshot()
   })
@@ -298,13 +270,7 @@ describe('styled', () => {
     const H1 = styled('h1')('some-class', { padding: 10 }, props => ({
       display: props.display
     }))
-    const tree = renderer
-      .create(
-        <H1 display='flex'>
-          hello world
-        </H1>
-      )
-      .toJSON()
+    const tree = renderer.create(<H1 display='flex'>hello world</H1>).toJSON()
 
     expect(tree).toMatchSnapshot()
   })
diff --git a/test/parser.test.js b/test/parser.test.js
index 53387ed5..7534e4ed 100644
--- a/test/parser.test.js
+++ b/test/parser.test.js
@@ -26,13 +26,13 @@ const fancyCSS = `.some-selector {
     color: blue;
     width: 20px;
     height: 20px;
-    content: 'pseudo'
+    content: 'pseudo';
   }
 }`
 
 const staticCSS = `.thing {
   display: block;
-  height: 50px
+  height: 50px;
   width: 30px;
 }`
 
diff --git a/test/react.test.js b/test/react.test.js
index 92aa4b03..c92048a5 100644
--- a/test/react.test.js
+++ b/test/react.test.js
@@ -42,18 +42,6 @@ describe('styled', () => {
     expect(tree).toMatchSnapshot()
   })
 
-  test('name', () => {
-    const fontSize = 20
-    const H1 = styled.h1`
-      name: FancyH1;
-      font-size: ${fontSize}px;
-    `
-
-    const tree = renderer.create(<H1>hello world</H1>).toJSON()
-
-    expect(tree).toMatchSnapshot()
-  })
-
   test('call expression', () => {
     const fontSize = 20
     const H1 = styled('h1')`
@@ -95,11 +83,11 @@ describe('styled', () => {
 
   test('random expressions', () => {
     const margin = (t, r, b, l) => {
-      return (props) => css`
-        margin-top: ${t}
-        margin-right: ${r}
-        margin-bottom: ${b}
-        margin-left: ${l}
+      return props => css`
+        margin-top: ${t};
+        margin-right: ${r};
+        margin-bottom: ${b};
+        margin-left: ${l};
       `
     }
     const H1 = styled('h1')`
@@ -132,6 +120,33 @@ describe('styled', () => {
     expect(tree).toMatchSnapshot()
   })
 
+  test('random object expression', () => {
+    const margin = (t, r, b, l) => {
+      return props => ({
+        marginTop: t,
+        marginRight: r,
+        marginBottom: b,
+        marginLeft: l
+      })
+    }
+    const H1 = styled.h1`
+      background-color: hotpink;
+      ${props => props.prop && { fontSize: '1rem' }};
+      ${margin(0, 'auto', 0, 'auto')};
+      color: green;
+    `
+
+    const tree = renderer
+      .create(
+        <H1 className={'legacy__class'} prop>
+          hello world
+        </H1>
+      )
+      .toJSON()
+
+    expect(tree).toMatchSnapshot()
+  })
+
   test('composition', () => {
     const fontSize = 20
     const H1 = styled('h1')`
@@ -207,7 +222,7 @@ describe('styled', () => {
     ])
 
     const Avatar = styled('img')`
-      composes: ${prettyStyles} ${imageStyles} ${blue}
+      composes: ${prettyStyles} ${imageStyles} ${blue};
     `
 
     const tree = renderer.create(<Avatar />).toJSON()
@@ -312,7 +327,7 @@ describe('styled', () => {
     `
 
     const cssB = css`
-      composes: ${cssA}
+      composes: ${cssA};
       color: red;
     `
 
@@ -345,12 +360,12 @@ describe('styled', () => {
     }
 
     const cssB = css`
-      composes: ${cssA}
+      composes: ${cssA};
       height: 64px;
     `
 
     const H1 = styled('h1')`
-      composes: ${cssB}
+      composes: ${cssB};
       font-size: ${modularScale(4)};
     `
 
@@ -394,7 +409,7 @@ describe('styled', () => {
     `
 
     const cssB = css`
-      composes: ${cssA}
+      composes: ${cssA};
       height: 64px;
     `
 
@@ -403,9 +418,9 @@ describe('styled', () => {
     `
 
     const H1 = styled(Heading)`
-      composes: ${cssB}
+      composes: ${cssB};
       font-size: ${fontSize};
-      color: ${p => p.theme.purple}
+      color: ${p => p.theme.purple};
     `
 
     const H2 = styled(H1)`font-size:32px;`
@@ -430,14 +445,12 @@ describe('styled', () => {
     `
 
     const squirtleBlueBackground = css`
-      name: squirtle-blue-bg;
       background-color: #7FC8D6;
     `
 
     const flexColumn = Component => {
       const NewComponent = styled(Component)`
-        composes: ${squirtleBlueBackground}
-        name: onyx;
+        composes: ${squirtleBlueBackground};
         background-color: '#343a40';
         flex-direction: column;
       `
@@ -464,7 +477,7 @@ describe('styled', () => {
     `
 
     const H1 = styled('h1')`
-      composes: ${props => (props.a ? cssA : cssB)}
+      composes: ${props => (props.a ? cssA : cssB)};
     `
 
     const tree = renderer.create(<H1 a>hello world</H1>).toJSON()
diff --git a/test/server.test.js b/test/server.test.js
index ca043fcb..24ba8ae8 100644
--- a/test/server.test.js
+++ b/test/server.test.js
@@ -5,7 +5,15 @@
 import React from 'react'
 import { renderToString } from 'react-dom/server'
 import styled from '../src/react'
-import { css, injectGlobal, keyframes, flush, hydrate, fontFace, sheet } from '../src/index'
+import {
+  css,
+  injectGlobal,
+  keyframes,
+  flush,
+  hydrate,
+  fontFace,
+  sheet
+} from '../src/index'
 import { extractCritical } from '../src/server'
 
 const getComponents = () => {