Repository: tkh44/emotion
Pull request #200 (2017-07-29 00:08:41)

Auto import css for css prop
<!--
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**:

<!-- Why are these changes necessary? -->
**Why**:

<!-- How were these changes implemented? -->
**How**:

<!-- 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" -->
- [x] Documentation
- [x] Tests
- [x] Code complete

<!-- feel free to add additional comments -->


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

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

```diff
@@            Coverage Diff             @@
##           master     #200      +/-   ##
==========================================
+ Coverage   90.82%   90.91%   +0.09%     
==========================================
  Files          22       22              
  Lines         850      859       +9     
  Branches      220      224       +4     
==========================================
+ Hits          772      781       +9     
  Misses         63       63              
  Partials       15       15
```


| [Impacted Files](https://codecov.io/gh/tkh44/emotion/pull/200?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/babel.js](https://codecov.io/gh/tkh44/emotion/pull/200?src=pr&el=tree#diff-c3JjL2JhYmVsLmpz) | `98.07% <100%> (+0.07%)` | :arrow_up: |
| [src/css-prop.js](https://codecov.io/gh/tkh44/emotion/pull/200?src=pr&el=tree#diff-c3JjL2Nzcy1wcm9wLmpz) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/tkh44/emotion/pull/200?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/200?src=pr&el=footer). Last update [e4e3438...96149d8](https://codecov.io/gh/tkh44/emotion/pull/200?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/docs/css-prop.md b/docs/css-prop.md
index 8c174371..3db8210e 100644
--- a/docs/css-prop.md
+++ b/docs/css-prop.md
@@ -1,9 +1,6 @@
 ## CSS prop
 
 ```jsx
-// To use the css prop you have to import css just like importing React for jsx
-import { css } from 'emotion'
-
 
 function SomeComponent (props) {
   // Create styles as if you're calling css and the class will be applied to the component
diff --git a/example/src/preview/index.js b/example/src/preview/index.js
index 51b290c2..2f689918 100644
--- a/example/src/preview/index.js
+++ b/example/src/preview/index.js
@@ -91,7 +91,7 @@ class Preview extends Component {
       `,
         {
           presets: ['es2015', 'react', 'stage-1'],
-          plugins: [['emotion/babel', { inline: true }]]
+          plugins: [['emotion/babel', { inline: true, autoImportCssProp: false }]]
         }
       ).code
     } else {
@@ -103,7 +103,7 @@ class Preview extends Component {
       `,
         {
           presets: ['es2015', 'react', 'stage-1'],
-          plugins: [['emotion/babel', { inline: true }]]
+          plugins: [['emotion/babel', { inline: true, autoImportCssProp: false }]]
         }
       ).code
     }
diff --git a/package.json b/package.json
index bf2a7df7..337d6b12 100644
--- a/package.json
+++ b/package.json
@@ -116,6 +116,10 @@
     "transform": {
       "\\.css$": "<rootDir>/test/styleTransform.js",
       "^.+\\.js?$": "babel-jest"
+    },
+    "moduleNameMapper": {
+      "^emotion$": "<rootDir>/src",
+      "^emotion\/react$": "<rootDir>/src/react"
     }
   },
   "bugs": {
diff --git a/src/babel.js b/src/babel.js
index ce3d2019..150bff9b 100644
--- a/src/babel.js
+++ b/src/babel.js
@@ -204,10 +204,18 @@ export default function (babel) {
               fs.writeFileSync(cssFilename, toWrite)
             }
           }
+          if (state.cssPropIdentifier) {
+            path.node.body.unshift(
+              t.importDeclaration(
+                [t.importSpecifier(state.cssPropIdentifier, t.identifier('css'))],
+                t.stringLiteral('emotion')
+              )
+            )
+          }
         }
       },
       JSXOpeningElement (path, state) {
-        cssProps(path, t)
+        cssProps(path, state, t)
       },
       CallExpression (path) {
         if (path[visited]) {
@@ -299,6 +307,8 @@ export default function (babel) {
               (name, hash, src) => src,
               true
             )
+          } else if (state.cssPropIdentifier && path.node.tag === state.cssPropIdentifier) {
+            replaceCssWithCallExpression(path, state.cssPropIdentifier, state, t)
           }
         }
       }
diff --git a/src/css-prop.js b/src/css-prop.js
index fc57c52c..35aa34ab 100644
--- a/src/css-prop.js
+++ b/src/css-prop.js
@@ -1,4 +1,4 @@
-export default function (path, t) {
+export default function (path, state, t) {
   let cssPath
   let classNamesPath
 
@@ -91,6 +91,13 @@ export default function (path, t) {
   }
 
   function createCssTemplateExpression (templateLiteral) {
-    return t.taggedTemplateExpression(t.identifier('css'), templateLiteral)
+    let identifier = t.identifier('css')
+    if (state.opts.autoImportCssProp !== false) {
+      if (!state.cssPropIdentifier) {
+        state.cssPropIdentifier = path.scope.generateUidIdentifier('css')
+      }
+      identifier = state.cssPropIdentifier
+    }
+    return t.taggedTemplateExpression(identifier, templateLiteral)
   }
 }


Test patch:
diff --git a/test/babel/__snapshots__/css-prop.test.js.snap b/test/babel/__snapshots__/css-prop.test.js.snap
index 796edddc..53f4a69e 100644
--- a/test/babel/__snapshots__/css-prop.test.js.snap
+++ b/test/babel/__snapshots__/css-prop.test.js.snap
@@ -1,7 +1,8 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`babel css prop StringLiteral css prop value 1`] = `
-"<div className={/*#__PURE__*/css([], [], function createEmotionStyledRules() {
+"import { css as _css } from \\"emotion\\";
+<div className={/*#__PURE__*/_css([], [], function createEmotionStyledRules() {
   return [{
     \\"color\\": \\"brown\\"
   }];
@@ -9,7 +10,8 @@ exports[`babel css prop StringLiteral css prop value 1`] = `
 `;
 
 exports[`babel css prop basic 1`] = `
-"import \\"./css-prop.test.emotion.css\\";
+"import { css as _css } from \\"emotion\\";
+import \\"./css-prop.test.emotion.css\\";
 <div className={\\"a\\" + \\" \\" + \\"css-jf1v9l\\"}></div>;"
 `;
 
@@ -20,7 +22,8 @@ exports[`babel css prop basic 2`] = `
 `;
 
 exports[`babel css prop basic inline 1`] = `
-"<div className={\\"a\\" + \\" \\" + /*#__PURE__*/css([], [], function createEmotionStyledRules() {
+"import { css as _css } from \\"emotion\\";
+<div className={\\"a\\" + \\" \\" + /*#__PURE__*/_css([], [], function createEmotionStyledRules() {
   return [{
     \\"color\\": \\"brown\\"
   }];
@@ -28,7 +31,8 @@ exports[`babel css prop basic inline 1`] = `
 `;
 
 exports[`babel css prop className as expression 1`] = `
-"<div className={variable + \\" \\" + /*#__PURE__*/css([], [], function createEmotionStyledRules() {
+"import { css as _css } from \\"emotion\\";
+<div className={variable + \\" \\" + /*#__PURE__*/_css([], [], function createEmotionStyledRules() {
   return [{
     \\"color\\": \\"brown\\"
   }];
@@ -36,7 +40,8 @@ exports[`babel css prop className as expression 1`] = `
 `;
 
 exports[`babel css prop className as expression string 1`] = `
-"<div className={\`test__class\` + \\" \\" + /*#__PURE__*/css([], [], function createEmotionStyledRules() {
+"import { css as _css } from \\"emotion\\";
+<div className={\`test__class\` + \\" \\" + /*#__PURE__*/_css([], [], function createEmotionStyledRules() {
   return [{
     \\"color\\": \\"brown\\"
   }];
@@ -44,13 +49,15 @@ exports[`babel css prop className as expression string 1`] = `
 `;
 
 exports[`babel css prop css empty 1`] = `
-"<div className={/*#__PURE__*/css([], [], function createEmotionStyledRules() {
+"import { css as _css } from \\"emotion\\";
+<div className={/*#__PURE__*/_css([], [], function createEmotionStyledRules() {
   return [{}];
 })}></div>;"
 `;
 
 exports[`babel css prop dynamic inline 1`] = `
-"<div className={\\"a\\" + \\" \\" + /*#__PURE__*/css([], [color], function createEmotionStyledRules(x0) {
+"import { css as _css } from \\"emotion\\";
+<div className={\\"a\\" + \\" \\" + /*#__PURE__*/_css([], [color], function createEmotionStyledRules(x0) {
   return [{
     \\"color\\": \`\${x0}\`
   }];
@@ -58,7 +65,8 @@ exports[`babel css prop dynamic inline 1`] = `
 `;
 
 exports[`babel css prop emptyClassName 1`] = `
-"<div className={\\"\\" + \\" \\" + /*#__PURE__*/css([], [], function createEmotionStyledRules() {
+"import { css as _css } from \\"emotion\\";
+<div className={\\"\\" + \\" \\" + /*#__PURE__*/_css([], [], function createEmotionStyledRules() {
   return [{
     \\"color\\": \\"brown\\"
   }];
@@ -67,8 +75,17 @@ exports[`babel css prop emptyClassName 1`] = `
 
 exports[`babel css prop no css attr 1`] = `"<div></div>;"`;
 
+exports[`babel css prop no import css prop 1`] = `
+"<div className={\`test__class\` + \\" \\" + /*#__PURE__*/css([], [], function createEmotionStyledRules() {
+  return [{
+    \\"color\\": \\"brown\\"
+  }];
+})}></div>;"
+`;
+
 exports[`babel css prop noClassName 1`] = `
-"<div className={/*#__PURE__*/css([], [], function createEmotionStyledRules() {
+"import { css as _css } from \\"emotion\\";
+<div className={/*#__PURE__*/_css([], [], function createEmotionStyledRules() {
   return [{
     \\"color\\": \\"brown\\"
   }];
@@ -76,7 +93,8 @@ exports[`babel css prop noClassName 1`] = `
 `;
 
 exports[`babel css prop with spread arg in jsx opening tag 1`] = `
-"<div className={\\"a\\" + \\" \\" + /*#__PURE__*/css([], [], function createEmotionStyledRules() {
+"import { css as _css } from \\"emotion\\";
+<div className={\\"a\\" + \\" \\" + /*#__PURE__*/_css([], [], function createEmotionStyledRules() {
   return [{
     \\"color\\": \\"brown\\"
   }];
diff --git a/test/babel/css-prop.test.js b/test/babel/css-prop.test.js
index 802e47a9..4aee1ac4 100644
--- a/test/babel/css-prop.test.js
+++ b/test/babel/css-prop.test.js
@@ -109,4 +109,13 @@ describe('babel css prop', () => {
     })
     expect(code).toMatchSnapshot()
   })
+
+  test('no import css prop', () => {
+    const basic =
+    '(<div className={`test__class`} css={`color: brown;`}></div>)'
+    const { code } = babel.transform(basic, {
+      plugins: [[plugin, { autoImportCssProp: false }]]
+    })
+    expect(code).toMatchSnapshot()
+  })
 })