Repository: styled-components/babel-plugin-styled-components (js)

Issue:
(...).createGlobalStyle.withConfig is not a function
Similar to this [comment workaround](https://github.com/styled-components/babel-plugin-styled-components/issues/216#issuecomment-516941240), when i use createGlobalStyle like this:

`import * as styled from 'styled-components';`
`export const GlobalStyle = styled.createGlobalStyle``;`, i get the error `(...).createGlobalStyle.withConfig is not a function` on a Next.js / Typescript project

The bug is resolved when I use the solution presented in the comment above, using CommonJS require:
`const createGlobalStyle = require('styled-components').createGlobalStyle`
`export const GlobalStyle = createGlobalStyle``;`

Is it a bug or a setup issue?



Pull request:
handle namespace import helpers
Fixes #315 

Handle the following syntax:

```js
import * as styled from 'styled-components'

const css = styled.css`
  background: black;
`

const GlobalStyle = styled.createGlobalStyle`
  html {
    background: black;
  }
`

const Test = styled.default.div`
  color: red;
`

const before = styled.default.div`
  color: blue;
`

styled.default.div``

export default styled.default.button``

```

Previously `styled.default.*` was not being assigned identifiers, and helpers were being assigned identifiers when they should not be.

Patch:
diff --git a/src/utils/detectors.js b/src/utils/detectors.js
index fddb59e..94d4101 100644
--- a/src/utils/detectors.js
+++ b/src/utils/detectors.js
@@ -15,9 +15,9 @@ export const isValidTopLevelImport = (x, state) =>
 const localNameCache = {}
 
 export const importLocalName = (name, state, options = {}) => {
-  const { cacheIdentifier, bypassCache = false } = options;
-  const cacheKeyAffix = cacheIdentifier ? `|${cacheIdentifier}` : '';
-  const cacheKey = name + state.file.opts.filename + cacheKeyAffix;
+  const { cacheIdentifier, bypassCache = false } = options
+  const cacheKeyAffix = cacheIdentifier ? `|${cacheIdentifier}` : ''
+  const cacheKey = name + state.file.opts.filename + cacheKeyAffix
 
   if (!bypassCache && cacheKey in localNameCache) {
     return localNameCache[cacheKey]
@@ -36,10 +36,13 @@ export const importLocalName = (name, state, options = {}) => {
 
         if (isValidTopLevelImport(node.source.value, state)) {
           for (const specifier of path.get('specifiers')) {
-            if (specifier.isImportSpecifier() && specifier.node.imported.name === 'styled') {
+            if (
+              specifier.isImportSpecifier() &&
+              specifier.node.imported.name === 'styled'
+            ) {
               localName = 'styled'
             }
-            
+
             if (specifier.isImportDefaultSpecifier()) {
               localName = specifier.node.local.name
             }
@@ -52,7 +55,7 @@ export const importLocalName = (name, state, options = {}) => {
             }
 
             if (specifier.isImportNamespaceSpecifier()) {
-              localName = specifier.node.local.name
+              localName = name === 'default' ? specifier.node.local.name : name
             }
           }
         }
@@ -76,9 +79,16 @@ export const isStyled = t => (tag, state) => {
   } else {
     return (
       (t.isMemberExpression(tag) &&
-        tag.object.name === importLocalName('default', state, { cacheIdentifier: tag.object.name })) ||
+        tag.object.name ===
+          importLocalName('default', state, {
+            cacheIdentifier: tag.object.name,
+          }) &&
+        !isHelper(t)(tag.property, state)) ||
       (t.isCallExpression(tag) &&
-        tag.callee.name === importLocalName('default', state, { cacheIdentifier: tag.callee.name })) ||
+        tag.callee.name ===
+          importLocalName('default', state, {
+            cacheIdentifier: tag.callee.name,
+          })) ||
       /**
        * #93 Support require()
        * styled-components might be imported using a require()
@@ -95,7 +105,17 @@ export const isStyled = t => (tag, state) => {
         t.isCallExpression(tag) &&
         t.isMemberExpression(tag.callee) &&
         tag.callee.property.name === 'default' &&
-        tag.callee.object.name === state.styledRequired)
+        tag.callee.object.name === state.styledRequired) ||
+      (importLocalName('default', state) &&
+        t.isMemberExpression(tag) &&
+        t.isMemberExpression(tag.object) &&
+        tag.object.property.name === 'default' &&
+        tag.object.object.name === importLocalName('default', state)) ||
+      (importLocalName('default', state) &&
+        t.isCallExpression(tag) &&
+        t.isMemberExpression(tag.callee) &&
+        tag.object.property.name === 'default' &&
+        tag.object.object.name === importLocalName('default', state))
     )
   }
 }
@@ -116,13 +136,20 @@ export const isKeyframesHelper = t => (tag, state) =>
 export const isWithThemeHelper = t => (tag, state) =>
   t.isIdentifier(tag) && tag.name === importLocalName('withTheme', state)
 
+export const isUseTheme = t => (tag, state) =>
+  t.isIdentifier(tag) && tag.name === importLocalName('useTheme', state)
+
 export const isHelper = t => (tag, state) =>
+  isCreateGlobalStyleHelper(t)(tag, state) ||
   isCSSHelper(t)(tag, state) ||
+  isInjectGlobalHelper(t)(tag, state) ||
+  isUseTheme(t)(tag, state) ||
   isKeyframesHelper(t)(tag, state) ||
   isWithThemeHelper(t)(tag, state)
 
 export const isPureHelper = t => (tag, state) =>
+  isCreateGlobalStyleHelper(t)(tag, state) ||
   isCSSHelper(t)(tag, state) ||
   isKeyframesHelper(t)(tag, state) ||
-  isCreateGlobalStyleHelper(t)(tag, state) ||
+  isUseTheme(t)(tag, state) ||
   isWithThemeHelper(t)(tag, state)
diff --git a/src/visitors/displayNameAndId.js b/src/visitors/displayNameAndId.js
index b2fb6a2..02cc2b4 100644
--- a/src/visitors/displayNameAndId.js
+++ b/src/visitors/displayNameAndId.js
@@ -9,7 +9,11 @@ import {
 import getName from '../utils/getName'
 import prefixLeadingDigit from '../utils/prefixDigit'
 import hash from '../utils/hash'
-import { isStyled } from '../utils/detectors'
+import {
+  isCreateGlobalStyleHelper,
+  isCSSHelper,
+  isStyled,
+} from '../utils/detectors'
 
 const addConfig = t => (path, displayName, componentId) => {
   if (!displayName && !componentId) {
@@ -211,8 +215,8 @@ export default t => (path, state) => {
           t.isMemberExpression(path.node.callee.callee) &&
           path.node.callee.callee.property &&
           path.node.callee.callee.property.name &&
-          path.node.callee.callee.property.name == 'withConfig' &&
-          !path.node.callee.arguments[0].properties.some((prop) =>
+          path.node.callee.callee.property.name === 'withConfig' &&
+          !path.node.callee.arguments[0].properties.some(prop =>
             ['displayName', 'componentId'].includes(prop.key.name)
           ))
   ) {


Test patch:
diff --git a/test/fixtures/annotate-create-global-style-with-pure-comments/output.js b/test/fixtures/annotate-create-global-style-with-pure-comments/output.js
index 3081f9e..a067223 100644
--- a/test/fixtures/annotate-create-global-style-with-pure-comments/output.js
+++ b/test/fixtures/annotate-create-global-style-with-pure-comments/output.js
@@ -1,6 +1,2 @@
 import { createGlobalStyle } from 'styled-components';
-const GlobalStyle = /*#__PURE__*/createGlobalStyle`
-  body {
-    color: red;
-  }
-`;
+const GlobalStyle = /*#__PURE__*/createGlobalStyle(["body{color:red;}"]);
diff --git a/test/fixtures/minify-css-in-helpers/code.js b/test/fixtures/minify-css-in-helpers/code.js
index 0007afb..4e65089 100644
--- a/test/fixtures/minify-css-in-helpers/code.js
+++ b/test/fixtures/minify-css-in-helpers/code.js
@@ -1,11 +1,17 @@
-import { css, keyframes } from 'styled-components';
+import { createGlobalStyle, css, keyframes } from 'styled-components'
 
 const key = keyframes`
   to {
     transform: rotate(360deg);
   }
-`;
+`
 
 const color = css`
   color: ${theColor};
-`;
+`
+
+const GlobalStyles = createGlobalStyle`
+  html {
+    color: red;
+  }
+`
diff --git a/test/fixtures/minify-css-in-helpers/output.js b/test/fixtures/minify-css-in-helpers/output.js
index 06b9c52..82dbc10 100644
--- a/test/fixtures/minify-css-in-helpers/output.js
+++ b/test/fixtures/minify-css-in-helpers/output.js
@@ -1,3 +1,4 @@
-import { css, keyframes } from 'styled-components';
+import { createGlobalStyle, css, keyframes } from 'styled-components';
 const key = keyframes`to{transform:rotate(360deg);}`;
 const color = css`color:${theColor};`;
+const GlobalStyles = createGlobalStyle`html{color:red;}`;
diff --git a/test/fixtures/transpile-template-literals-with-config/.babelrc b/test/fixtures/transpile-template-literals-with-config/.babelrc
index 37c85a0..4e78d26 100644
--- a/test/fixtures/transpile-template-literals-with-config/.babelrc
+++ b/test/fixtures/transpile-template-literals-with-config/.babelrc
@@ -1,7 +1,5 @@
 {
-  "presets": [
-    "@babel/preset-env"
-  ],
+  "presets": ["@babel/preset-env"],
   "plugins": [
     [
       "../../../src",
@@ -13,4 +11,4 @@
       }
     ]
   ]
-}
\ No newline at end of file
+}
diff --git a/test/fixtures/transpile-template-literals-with-config/code.js b/test/fixtures/transpile-template-literals-with-config/code.js
index 86a6f11..c89451d 100644
--- a/test/fixtures/transpile-template-literals-with-config/code.js
+++ b/test/fixtures/transpile-template-literals-with-config/code.js
@@ -1,4 +1,4 @@
-import styled from 'styled-components'
+import styled, { css, createGlobalStyle } from 'styled-components'
 
 const Named = styled.div`
   width: 100%;
@@ -15,3 +15,13 @@ const Wrapped = styled(Inner)`
 const Foo = styled.div({
   color: 'green',
 })
+
+const style = css`
+  background: green;
+`
+
+const GlobalStyle = createGlobalStyle`
+  html {
+    background: silver;
+  }
+`
diff --git a/test/fixtures/transpile-template-literals-with-config/output.js b/test/fixtures/transpile-template-literals-with-config/output.js
index 991dead..2c5c07a 100644
--- a/test/fixtures/transpile-template-literals-with-config/output.js
+++ b/test/fixtures/transpile-template-literals-with-config/output.js
@@ -1,8 +1,12 @@
 "use strict";
 
-var _styledComponents = _interopRequireDefault(require("styled-components"));
+function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
+var _styledComponents = _interopRequireWildcard(require("styled-components"));
+
+function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
+
+function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
 
 var Named = _styledComponents["default"].div.withConfig({
   displayName: "code__Named"
@@ -23,3 +27,6 @@ var Foo = _styledComponents["default"].div.withConfig({
 })({
   color: 'green'
 });
+
+var style = (0, _styledComponents.css)(["\n  background: green;\n"]);
+var GlobalStyle = (0, _styledComponents.createGlobalStyle)(["\n  html {\n    background: silver;\n  }\n"]);
diff --git a/test/fixtures/use-namespace/.babelrc b/test/fixtures/use-namespace/.babelrc
index ab8caef..5c49c54 100644
--- a/test/fixtures/use-namespace/.babelrc
+++ b/test/fixtures/use-namespace/.babelrc
@@ -7,4 +7,4 @@
       }
     ]
   ]
-}
\ No newline at end of file
+}
diff --git a/test/fixtures/use-namespace/code.js b/test/fixtures/use-namespace/code.js
index 9715b42..85b62c7 100644
--- a/test/fixtures/use-namespace/code.js
+++ b/test/fixtures/use-namespace/code.js
@@ -1,13 +1,23 @@
-import styled from 'styled-components'
+import * as styled from 'styled-components'
 
-const Test = styled.div`
+const css = styled.css`
+  background: black;
+`
+
+const GlobalStyle = styled.createGlobalStyle`
+  html {
+    background: black;
+  }
+`
+
+const Test = styled.default.div`
   color: red;
 `
 
-const before = styled.div`
+const before = styled.default.div`
   color: blue;
 `
 
-styled.div``
+styled.default.div``
 
-export default styled.button``
+export default styled.default.button``
diff --git a/test/fixtures/use-namespace/output.js b/test/fixtures/use-namespace/output.js
index 7e6b892..883a28a 100644
--- a/test/fixtures/use-namespace/output.js
+++ b/test/fixtures/use-namespace/output.js
@@ -1,17 +1,25 @@
-import styled from 'styled-components';
-const Test = styled.div.withConfig({
+import * as styled from 'styled-components';
+const css = styled.css`
+  background: black;
+`;
+const GlobalStyle = styled.createGlobalStyle`
+  html {
+    background: black;
+  }
+`;
+const Test = styled.default.div.withConfig({
   displayName: "code__Test",
   componentId: "test-namespace__sc-3rfj0a-0"
 })(["color:red;"]);
-const before = styled.div.withConfig({
+const before = styled.default.div.withConfig({
   displayName: "code__before",
   componentId: "test-namespace__sc-3rfj0a-1"
 })(["color:blue;"]);
-styled.div.withConfig({
+styled.default.div.withConfig({
   displayName: "code",
   componentId: "test-namespace__sc-3rfj0a-2"
 })([""]);
-export default styled.button.withConfig({
+export default styled.default.button.withConfig({
   displayName: "code",
   componentId: "test-namespace__sc-3rfj0a-3"
 })([""]);