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

Issue:
Support require() calls
## Plugin will not work properly with Typescript

from https://github.com/styled-components/styled-components/issues/1168#issuecomment-335465598 (Include workaround)

`import` default in Babel and Typescript have a little different. The result of Typescript come with `.default` 

## Reproduce
1. Clone this repo https://github.com/zapkub/nextjs-typescript-styled-component
2. Modify `index.tsx` line 2 from `StyledComponents` to `styled` and remove line no. 3
3. Run project
4. Plugin will be broken

## Detail
babel-plugin-styled-components@1.2.1
styled-component@2.2.1
next@4.0.1


Pull request description:
Fix #93 support require(), detect default call expression 
from #93 
# Support require()
Add detect styled variable on typescript `require` by finding styled `require` variable


ref
https://github.com/styled-components/styled-components/issues/1168#issuecomment-335465598

Patch:
diff --git a/src/index.js b/src/index.js
index 8037af5..df812a2 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,7 @@
 import minify from './visitors/minify'
 import displayNameAndId from './visitors/displayNameAndId'
 import templateLiterals from './visitors/templateLiterals'
+import assignStyledRequired from './visitors/assignStyledRequired'
 import { noParserImportDeclaration, noParserRequireCallExpression } from './visitors/noParserImport'
 
 export default function({ types: t }) {
@@ -16,6 +17,9 @@ export default function({ types: t }) {
         minify(path, state)
         displayNameAndId(path, state)
         templateLiterals(path, state)
+      },
+      VariableDeclarator(path, state) {
+        assignStyledRequired(path, state)
       }
     }
   }
diff --git a/src/utils/detectors.js b/src/utils/detectors.js
index ba6b6e0..f4e2bae 100644
--- a/src/utils/detectors.js
+++ b/src/utils/detectors.js
@@ -14,13 +14,23 @@ const importLocalName = (name, state) => {
 }
 
 export const isStyled = (tag, state) => {
-  if (t.isCallExpression(tag) && t.isMemberExpression(tag.callee)) {
+  if (t.isCallExpression(tag) && t.isMemberExpression(tag.callee) && tag.callee.property.name !== 'default' /** ignore default for #93 below */) {
     // styled.something()
     return isStyled(tag.callee.object, state)
   } else {
     return (
       (t.isMemberExpression(tag) && tag.object.name === importLocalName('default', state)) ||
-      (t.isCallExpression(tag) && tag.callee.name === importLocalName('default', state))
+      (t.isCallExpression(tag) && tag.callee.name === importLocalName('default', state)) ||
+
+      /**
+       * #93 Support require()
+       * styled-components might be imported using a require()
+       * call and assigned to a variable of any name.
+       * - styled.default.div``
+       * - styled.default.something()
+       */
+      (state.styledRequired && t.isMemberExpression(tag) && t.isMemberExpression(tag.object) && tag.object.property.name === 'default' && tag.object.object.name === state.styledRequired) ||
+      (state.styledRequired && t.isCallExpression(tag) && t.isMemberExpression(tag.callee) && tag.callee.property.name === 'default' && tag.callee.object.name === state.styledRequired)
     )
   }
 }
@@ -44,4 +54,3 @@ export const isHelper = (tag, state) => (
   isCSSHelper(tag, state) ||
   isKeyframesHelper(tag, state)
 )
-
diff --git a/src/visitors/assignStyledRequired.js b/src/visitors/assignStyledRequired.js
new file mode 100644
index 0000000..fd8ca10
--- /dev/null
+++ b/src/visitors/assignStyledRequired.js
@@ -0,0 +1,14 @@
+import * as t from 'babel-types'
+
+export default (path, state) => {
+  if (t.isCallExpression(path.node.init) &&
+    t.isIdentifier(path.node.init.callee) &&
+    path.node.init.callee.name === 'require' &&
+    path.node.init.arguments &&
+    path.node.init.arguments[0] &&
+    t.isLiteral(path.node.init.arguments[0]) &&
+    path.node.init.arguments[0].value === 'styled-components'
+  ) {
+    state.styledRequired = path.node.id.name
+  }
+}


Test patch:
diff --git a/test/fixtures/19-transpile-require-default/.babelrc b/test/fixtures/19-transpile-require-default/.babelrc
new file mode 100644
index 0000000..cd03658
--- /dev/null
+++ b/test/fixtures/19-transpile-require-default/.babelrc
@@ -0,0 +1,8 @@
+{
+  "plugins": [
+    ["../../../src", {
+      "preprocess": true,
+      "ssr": true
+    }]
+  ]
+}
diff --git a/test/fixtures/19-transpile-require-default/after.js b/test/fixtures/19-transpile-require-default/after.js
new file mode 100644
index 0000000..586978f
--- /dev/null
+++ b/test/fixtures/19-transpile-require-default/after.js
@@ -0,0 +1,16 @@
+const styled_default = require("styled-components/no-parser");
+
+const TestNormal = styled.div.withConfig({
+  displayName: "before__TestNormal",
+  componentId: "y0c69d-0"
+})([["{width: 100%;}"]]);
+
+const Test = styled_default.default.div.withConfig({
+  displayName: "before__Test",
+  componentId: "y0c69d-1"
+})([["{width: 100%;}"]]);
+
+const TestCallExpression = styled_default.default(Test).withConfig({
+  displayName: "before__TestCallExpression",
+  componentId: "y0c69d-2"
+})([["{height: 20px;}"]]);
\ No newline at end of file
diff --git a/test/fixtures/19-transpile-require-default/before.js b/test/fixtures/19-transpile-require-default/before.js
new file mode 100644
index 0000000..87ae149
--- /dev/null
+++ b/test/fixtures/19-transpile-require-default/before.js
@@ -0,0 +1,13 @@
+const styled_default = require("styled-components");
+
+const TestNormal = styled.div`
+  width: 100%;
+`
+
+const Test = styled_default.default.div`
+  width: 100%;
+`
+
+const TestCallExpression = styled_default.default(Test)`
+  height: 20px;
+`
\ No newline at end of file