Skip to content

Commit 29c9400

Browse files
committed
Add more detection in transformer
- clean up - parent linking fixup
1 parent 9051a6c commit 29c9400

File tree

1 file changed

+60
-14
lines changed

1 file changed

+60
-14
lines changed

src/transformer.ts

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,80 @@
11
import * as ts from 'typescript';
22

3-
/*
4-
Transforms:
5-
(const | let | var) <name> = <styled>`` ->
6-
*/
7-
83
/** Detects that a node represents a styled function
94
* Recognizes the following patterns:
5+
*
106
* styled.tag
117
* Component.extend
128
* styled(Component)
139
* styledFunction.attrs(attributes)
1410
*/
1511
function isStyledFunction(node: ts.Node): boolean {
16-
if (node.kind === ts.SyntaxKind.PropertyAccessExpression
17-
&& (node as ts.PropertyAccessExpression).expression.kind === ts.SyntaxKind.Identifier) {
18-
const propertyName = (node as ts.PropertyAccessExpression).name.text;
19-
const objectName = ((node as ts.PropertyAccessExpression).expression as ts.Identifier).text;
20-
21-
return propertyName === 'extend'
22-
? objectName[0] === objectName[0].toUpperCase()
23-
: objectName === 'styled';
12+
if (node.kind === ts.SyntaxKind.PropertyAccessExpression) {
13+
if (isStyledObject((node as ts.PropertyAccessExpression).expression)) {
14+
return true;
15+
}
16+
17+
if ((node as ts.PropertyAccessExpression).name.text === 'extend'
18+
&& isValidComponent((node as ts.PropertyAccessExpression).expression)) {
19+
20+
return true;
21+
}
22+
23+
return false;
24+
}
25+
26+
if (node.kind === ts.SyntaxKind.CallExpression
27+
&& (node as ts.CallExpression).arguments.length === 1) {
28+
29+
if (isStyledObject((node as ts.CallExpression).expression)) {
30+
return true;
31+
}
32+
33+
if (isStyledAttrs((node as ts.CallExpression).expression)) {
34+
return true;
35+
}
2436
}
2537

2638
return false;
2739
}
2840

41+
function isStyledObject(node: ts.Node) {
42+
return node && node.kind === ts.SyntaxKind.Identifier && (node as ts.Identifier).text === 'styled';
43+
}
44+
45+
function isValidComponent(node: ts.Node) {
46+
return node && node.kind === ts.SyntaxKind.Identifier && isValidComponentName((node as ts.Identifier).text);
47+
}
48+
49+
function isValidTagName(name: string) {
50+
return name[0] === name[0].toLowerCase();
51+
}
52+
53+
function isValidComponentName(name: string) {
54+
return name[0] === name[0].toUpperCase();
55+
}
56+
57+
function isStyledAttrs(node: ts.Node) {
58+
return node && node.kind === ts.SyntaxKind.PropertyAccessExpression
59+
&& (node as ts.PropertyAccessExpression).name.text === 'attrs'
60+
&& isStyledFunction((node as ts.PropertyAccessExpression).expression);
61+
}
62+
63+
/**
64+
* Infers display name of a styled component.
65+
* Recognizes the following patterns:
66+
*
67+
* (const|var|let) ComponentName = styled...
68+
* export default styled...
69+
*/
2970
function getDisplayName(node: ts.Node): string | undefined {
3071
if (node.kind === ts.SyntaxKind.VariableDeclaration
3172
&& (node as ts.VariableDeclaration).name.kind === ts.SyntaxKind.Identifier) {
3273
return ((node as ts.VariableDeclaration).name as ts.Identifier).text;
3374
}
3475

3576
if (node.kind === ts.SyntaxKind.ExportAssignment) {
36-
77+
// todo: infer display name from file name
3778
}
3879

3980
return undefined;
@@ -58,6 +99,11 @@ const transformer: ts.TransformerFactory<ts.SourceFile> = (context) => {
5899
}
59100
}
60101

102+
ts.forEachChild(node, n => {
103+
if (!n.parent)
104+
n.parent = node;
105+
});
106+
61107
return ts.visitEachChild(node, visitor, context);
62108
}
63109

0 commit comments

Comments
 (0)