Repository: tkh44/emotion (js)

Issue:
More than 10 computed values in one class breaks the babel replacement.
<!--
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).

Please fill out this template with all the relevant information so we can
understand what's going on and fix the issue.

I'll probably ask you to submit the fix (after giving some direction). If you've
never done that before, that's great! Check this free short video tutorial to
learn how: http://kcd.im/pull-request
-->

Any number of more than 10 computed values using `css` or `styled` don't get their replacements replaced.

(Sorry for yet another issue, just been stress testing Emotion recently 😆 )

- `emotion` version: `^5.1.3`
- `react` version: `^15.6.1`

#### Relevant code.
See the demo repo here: https://github.com/hamlim/emotion-breaks-after-ten-computed/blob/master/src/App.js
```javascript
const app = css`
  background: ${'white'};
  color: ${'black'};
  text-decoration: ${'underline'};
  display: ${'block'};
  border-radius: ${'3px'};
  padding: ${'25px'};
  width: ${'500px'};
  z-index: ${100};
  font-size: ${'18px'};
  text-align: ${'center'};
  border: ${'solid 1px red'};
`;
```

#### What happened:

The 11th computed value only shows as `xxx10xxx`:
![screen shot 2017-07-05 at 3 27 47 pm](https://user-images.githubusercontent.com/5579638/27881422-91d285d0-6196-11e7-88d8-ef6735151c3d.png)

<!-- Please provide the full error message/screenshots/anything -->

#### Reproduction:
Use `css` or `styled` and have 11 computed values of any kind (just template expressions will work like in the sample above)

#### Problem description:
Seems like Emotion only catches single digits when matching `xxx[number]xxx`.

#### Suggested solution:
The plugin should catch more than just single digit replacements.

Pull request:
support more than 10 dynamic properties
<!--
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**:
Support more than 10 dyanamic values

<!-- Why are these changes necessary? -->
**Why**:
Its broken
<!-- How were these changes implemented? -->
**How**:

added `+` to regex

<!-- 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 N/A
- [x] Tests
- [x] Code complete

<!-- feel free to add additional comments -->

closes #97 

Patch:
diff --git a/src/babel.js b/src/babel.js
index 2274d529..57a42548 100644
--- a/src/babel.js
+++ b/src/babel.js
@@ -19,7 +19,7 @@ function joinExpressionsWithSpaces (expressions, t) {
 function parseDynamicValues (rules, t, options) {
   if (options.composes === undefined) options.composes = 0
   return rules.map(rule => {
-    const re = /xxx(\S)xxx|attr\(([^,\s)]+)(?:\s*([^,)]*)?)(?:,\s*(\S+))?\)/gm
+    const re = /xxx(\S+)xxx|attr\(([^,\s)]+)(?:\s*([^,)]*)?)(?:,\s*(\S+))?\)/gm
     const VAR = 'VAR'
     const ATTR = 'ATTR'
     let match
diff --git a/src/parser.js b/src/parser.js
index 146f2d94..10337594 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -39,7 +39,7 @@ export function parseCSS (
         if (decl.parent.selector !== `.${options.name}-${options.hash}`) {
           throw new Error('composes cannot be on nested selectors')
         }
-        if (!/xxx(\S)xxx/gm.exec(decl.value)) {
+        if (!/xxx(\S+)xxx/gm.exec(decl.value)) {
           throw new Error('composes must be a interpolation')
         }
         if (decl.parent.nodes[0] !== decl) {
@@ -52,7 +52,7 @@ export function parseCSS (
       }
     }
     if (!options.inlineMode) {
-      const match = /xxx(\S)xxx/gm.exec(decl.value)
+      const match = /xxx(\S+)xxx/gm.exec(decl.value)
       if (match) {
         vars++
       }
@@ -60,7 +60,7 @@ export function parseCSS (
   })
   if (!options.inlineMode && vars === options.matches && !hasCssFunction) {
     root.walkDecls((decl) => {
-      decl.value = decl.value.replace(/xxx(\S)xxx/gm, (match, p1) => {
+      decl.value = decl.value.replace(/xxx(\S+)xxx/gm, (match, p1) => {
         return `var(--${options.name}-${options.hash}-${p1})`
       })
     })


Test patch:
diff --git a/test/__snapshots__/css.test.js.snap b/test/__snapshots__/css.test.js.snap
index e01c2fb1..e644e422 100644
--- a/test/__snapshots__/css.test.js.snap
+++ b/test/__snapshots__/css.test.js.snap
@@ -5,7 +5,17 @@ exports[`css composes 1`] = `"css-cls1-vyoujf-va5xsk css-cls1-vyoujf"`;
 exports[`css composes 2`] = `"css-cls2-1qb2ovg-1em6aur css-cls2-1qb2ovg css-cls1-vyoujf-va5xsk css-cls1-vyoujf"`;
 
 exports[`css composes 3`] = `
-".css-cls1-vyoujf-va5xsk { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; }.css-cls2-1qb2ovg-1em6aur {
+".css-cls1-1gi569l-b877w5 { background: white;
+      color: black;
+      text-decoration: underline;
+      display: block;
+      border-radius: 3px;
+      padding: 25px;
+      width: 500px;
+      z-index: 100;
+      font-size: 18px;
+      text-align: center;
+      border: solid 1px red; }.css-cls1-vyoujf-va5xsk { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; }.css-cls2-1qb2ovg-1em6aur {
       -webkit-justify-content: center;
       -ms-flex-pack: center;
       -webkit-box-pack: center;
@@ -17,11 +27,37 @@ exports[`css composes with objects 1`] = `"css-q8izmm"`;
 exports[`css composes with objects 2`] = `"css-cls2-1qb2ovg-1em6aur css-cls2-1qb2ovg css-q8izmm"`;
 
 exports[`css composes with objects 3`] = `
-".css-cls1-vyoujf-va5xsk { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; }.css-cls2-1qb2ovg-1em6aur {
+".css-cls1-1gi569l-b877w5 { background: white;
+      color: black;
+      text-decoration: underline;
+      display: block;
+      border-radius: 3px;
+      padding: 25px;
+      width: 500px;
+      z-index: 100;
+      font-size: 18px;
+      text-align: center;
+      border: solid 1px red; }.css-cls1-vyoujf-va5xsk { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; }.css-cls2-1qb2ovg-1em6aur {
       -webkit-justify-content: center;
       -ms-flex-pack: center;
       -webkit-box-pack: center;
       justify-content: center; }.css-1fe3owl{display:flex}.css-q8izmm{display:flex;display:block;width:30px;height:calc(40vw - 50px)}.css-q8izmm:hover{color:blue}.css-q8izmm:after{content:\\" \\";color:red}@media(min-width: 420px){.css-q8izmm{color:green}}"
 `;
 
+exports[`css handles more than 10 dynamic properties 1`] = `"css-cls1-1gi569l-b877w5 css-cls1-1gi569l"`;
+
+exports[`css handles more than 10 dynamic properties 2`] = `
+".css-cls1-1gi569l-b877w5 { background: white;
+      color: black;
+      text-decoration: underline;
+      display: block;
+      border-radius: 3px;
+      padding: 25px;
+      width: 500px;
+      z-index: 100;
+      font-size: 18px;
+      text-align: center;
+      border: solid 1px red; }"
+`;
+
 exports[`css handles objects 1`] = `"css-1fe3owl"`;
diff --git a/test/css.test.js b/test/css.test.js
index dc6e9c92..92c2dd93 100644
--- a/test/css.test.js
+++ b/test/css.test.js
@@ -2,6 +2,27 @@
 import { sheet, css } from '../src/index'
 
 describe('css', () => {
+  test('handles more than 10 dynamic properties', () => {
+    const cls1 = css`
+      background: ${'white'};
+      color: ${'black'};
+      text-decoration: ${'underline'};
+      display: ${'block'};
+      border-radius: ${'3px'};
+      padding: ${'25px'};
+      width: ${'500px'};
+      z-index: ${100};
+      font-size: ${'18px'};
+      text-align: ${'center'};
+      border: ${'solid 1px red'};
+    `
+
+    expect(cls1).toMatchSnapshot()
+    expect(
+      sheet.tags.map(tag => tag.textContent || '').join('')
+    ).toMatchSnapshot()
+  })
+
   test('composes', () => {
     const cls1 = css`
       display: flex;