Skip to content

Commit 1dd7883

Browse files
committed
[feat] support styled-components
Intentionally only supports simple overt cases: - variable initialized with styled-component - variable initialized with non-block arrow function expression return styled-component - default export of styled component (uses filename or folder name if index)
1 parent 0a531d1 commit 1dd7883

File tree

7 files changed

+202
-41
lines changed

7 files changed

+202
-41
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"babel-preset-es2015": "^6.24.1",
3131
"babel-preset-react": "^6.24.1",
3232
"babel-preset-stage-0": "^6.24.1",
33+
"babel-types": "^6.26.0",
3334
"husky": "^1.1.2",
3435
"mocha": "^3.1.2",
3536
"semantic-release": "^15.10.3",

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import checkValidOptions from './options'
2+
import TaggedTemplateExpression from './styled-components'
23

34
function isReactFragment (openingElement) {
45
return (
@@ -44,6 +45,7 @@ function functionBodyPushAttributes (t, path, options, componentName) {
4445
export default function ({types: t}) {
4546
return {
4647
visitor: {
48+
TaggedTemplateExpression,
4749
FunctionDeclaration (path, state) {
4850
if (!path.node.id || !path.node.id.name) return;
4951

src/styled-components.js

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
1-
import checkValidOptions from './options'
1+
import * as _path from 'path'
22
import * as t from 'babel-types'
33

4+
import checkValidOptions from './options'
5+
46
export default function TaggedTemplateExpression(path, state) {
57
const options = checkValidOptions(state)
68
const scope = path.scope
79

810
try {
11+
// simple case
912
if (isStyledPrefix(path.node.tag)) {
1013
const id = getIdFrom(path.parentPath)
1114
if (!id) return
1215
path.node.tag = insertBefore(path.node.tag, id)
1316
return
1417
}
18+
19+
// chained case. traverse until prefix found.
20+
// NB: styled-component chain api is always CallExpression+MemberExpression pairs.
1521
let node = path.node.tag
1622
while (true) {
17-
if (!node.callee) debugger
1823
if (!node || !node.callee) break
1924
if (isStyledPrefix(node.callee.object)) {
2025
const id = getIdFrom(path.parentPath)
@@ -24,11 +29,11 @@ export default function TaggedTemplateExpression(path, state) {
2429
}
2530
node = node.callee.object
2631
}
27-
} catch (e) {
28-
console.log(e)
29-
return
30-
}
32+
} catch (e) {}
3133

34+
return
35+
36+
// hoisted helpers in closure
3237
function insertBefore(node, id) {
3338
return t.callExpression(t.memberExpression(node, t.identifier('attrs')), [
3439
t.arrowFunctionExpression(
@@ -53,14 +58,22 @@ export default function TaggedTemplateExpression(path, state) {
5358
}
5459
}
5560
function getIdFrom(parentPath) {
56-
while (parentPath && !parentPath.node.id && !parentPath.node.left) {
57-
parentPath = parentPath.parentPath
61+
if (t.isVariableDeclarator(parentPath.node)) {
62+
return parentPath.node.id.name
63+
}
64+
if (t.isArrowFunctionExpression(parentPath.node)) {
65+
if (t.isVariableDeclarator(parentPath.parentPath.node)) {
66+
return parentPath.parentPath.node.id.name
67+
}
68+
}
69+
if (t.isExportDefaultDeclaration(parentPath.node)) {
70+
const path = state.file.opts.filename
71+
const filename = _path.parse(path).name
72+
if (filename === 'index') {
73+
const parent = _path.basename(_path.dirname(filename))
74+
return parent
75+
}
76+
return filename
5877
}
59-
const id =
60-
parentPath &&
61-
parentPath.node &&
62-
((parentPath.node.id && parentPath.node.id.name) ||
63-
(parentPath.node.left && parentPath.node.left.name))
64-
return id
6578
}
6679
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import React, { Component } from 'react'
2+
import styled from 'styled-components'
3+
4+
/* should be transformed */
5+
6+
const basic = styled.div`
7+
color: black;
8+
`
9+
10+
const withChain = styled.div.withConfig()`
11+
color: black;
12+
`
13+
14+
const el = styled(El)`
15+
color: black;
16+
`
17+
18+
const arrowExpr = () => styled.div`
19+
color: black;
20+
`
21+
22+
// covered by VariableDeclaraion cases
23+
export const exported = styled.div`
24+
color: black;
25+
`
26+
27+
export default styled.div`
28+
color: black;
29+
`
30+
31+
/* should not be transformed */
32+
33+
let assigned
34+
assigned = styled.div`
35+
color: black;
36+
`
37+
38+
const arrowReturn = () => {
39+
return styled.div`
40+
color: black;
41+
`
42+
}
43+
44+
function fnReturn(){
45+
return styled.div`
46+
color: black;
47+
`
48+
}
49+
50+
const fnExprReturn = function(){
51+
return styled.div`
52+
color: black;
53+
`
54+
}
55+
56+
const namedFnExprReturn = function namedFnExpr(){
57+
return styled.div`
58+
color: black;
59+
`
60+
}
61+
62+
const ternary = cond ? styled.div`color: black;` : null
63+
64+
const conditional = cond && styled.div`color: black;`
65+
66+
const map = {
67+
comp: styled.div`color: black;`
68+
}
69+
70+
const comps = [styled.div`color: black;`]
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import React, { Component } from 'react';
2+
import styled from 'styled-components';
3+
4+
/* should be transformed */
5+
6+
const basic = styled.div.attrs(() => ({
7+
'data-qa': 'basic'
8+
}))`
9+
color: black;
10+
`;
11+
12+
const withChain = styled.div.attrs(() => ({
13+
'data-qa': 'withChain'
14+
})).withConfig()`
15+
color: black;
16+
`;
17+
18+
const el = styled(El).attrs(() => ({
19+
'data-qa': 'el'
20+
}))`
21+
color: black;
22+
`;
23+
24+
const arrowExpr = () => styled.div.attrs(() => ({
25+
'data-qa': 'arrowExpr'
26+
}))`
27+
color: black;
28+
`;
29+
30+
// covered by VariableDeclaraion cases
31+
export const exported = styled.div.attrs(() => ({
32+
'data-qa': 'exported'
33+
}))`
34+
color: black;
35+
`;
36+
37+
export default styled.div.attrs(() => ({
38+
'data-qa': 'actual'
39+
}))`
40+
color: black;
41+
`;
42+
43+
/* should not be transformed */
44+
45+
let assigned;
46+
assigned = styled.div`
47+
color: black;
48+
`;
49+
50+
const arrowReturn = () => {
51+
return styled.div`
52+
color: black;
53+
`;
54+
};
55+
56+
function fnReturn() {
57+
return styled.div`
58+
color: black;
59+
`;
60+
}
61+
62+
const fnExprReturn = function () {
63+
return styled.div`
64+
color: black;
65+
`;
66+
};
67+
68+
const namedFnExprReturn = function namedFnExpr() {
69+
return styled.div`
70+
color: black;
71+
`;
72+
};
73+
74+
const ternary = cond ? styled.div`color: black;` : null;
75+
76+
const conditional = cond && styled.div`color: black;`;
77+
78+
const map = {
79+
comp: styled.div`color: black;`
80+
};
81+
82+
const comps = [styled.div`color: black;`];
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"plugins": [
3+
"syntax-jsx",
4+
["../../../../src"]
5+
]
6+
}

yarn.lock

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,7 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0:
15641564
invariant "^2.2.2"
15651565
lodash "^4.17.4"
15661566

1567-
babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
1567+
babel-types@^6.19.0, babel-types@^6.24.1:
15681568
version "6.26.0"
15691569
resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
15701570
dependencies:
@@ -1573,6 +1573,15 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
15731573
lodash "^4.17.4"
15741574
to-fast-properties "^1.0.3"
15751575

1576+
babel-types@^6.26.0:
1577+
version "6.26.0"
1578+
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
1579+
dependencies:
1580+
babel-runtime "^6.26.0"
1581+
esutils "^2.0.2"
1582+
lodash "^4.17.4"
1583+
to-fast-properties "^1.0.3"
1584+
15761585
babylon@^6.18.0:
15771586
version "6.18.0"
15781587
resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
@@ -2200,7 +2209,7 @@ debug@^4.0.0:
22002209
dependencies:
22012210
ms "^2.1.1"
22022211

2203-
debuglog@*, debuglog@^1.0.1:
2212+
debuglog@^1.0.1:
22042213
version "1.0.1"
22052214
resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
22062215

@@ -3095,7 +3104,7 @@ import-lazy@^2.1.0:
30953104
version "2.1.0"
30963105
resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
30973106

3098-
imurmurhash@*, imurmurhash@^0.1.4:
3107+
imurmurhash@^0.1.4:
30993108
version "0.1.4"
31003109
resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
31013110

@@ -3649,36 +3658,18 @@ lodash._basecreate@^3.0.0:
36493658
version "3.0.3"
36503659
resolved "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821"
36513660

3652-
lodash._baseindexof@*:
3653-
version "3.1.0"
3654-
resolved "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
3655-
36563661
lodash._baseuniq@~4.6.0:
36573662
version "4.6.0"
36583663
resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
36593664
dependencies:
36603665
lodash._createset "~4.0.0"
36613666
lodash._root "~3.0.0"
36623667

3663-
lodash._bindcallback@*:
3664-
version "3.0.1"
3665-
resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
3666-
3667-
lodash._cacheindexof@*:
3668-
version "3.0.2"
3669-
resolved "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
3670-
3671-
lodash._createcache@*:
3672-
version "3.1.2"
3673-
resolved "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
3674-
dependencies:
3675-
lodash._getnative "^3.0.0"
3676-
36773668
lodash._createset@~4.0.0:
36783669
version "4.0.3"
36793670
resolved "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
36803671

3681-
lodash._getnative@*, lodash._getnative@^3.0.0:
3672+
lodash._getnative@^3.0.0:
36823673
version "3.9.1"
36833674
resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
36843675

@@ -3746,10 +3737,6 @@ lodash.keys@^3.0.0:
37463737
lodash.isarguments "^3.0.0"
37473738
lodash.isarray "^3.0.0"
37483739

3749-
lodash.restparam@*:
3750-
version "3.6.1"
3751-
resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
3752-
37533740
lodash.snakecase@^4.1.1:
37543741
version "4.1.1"
37553742
resolved "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d"
@@ -5029,7 +5016,7 @@ readable-stream@~1.1.10:
50295016
isarray "0.0.1"
50305017
string_decoder "~0.10.x"
50315018

5032-
readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0:
5019+
readdir-scoped-modules@^1.0.0:
50335020
version "1.0.2"
50345021
resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747"
50355022
dependencies:

0 commit comments

Comments
 (0)