88 isTaggedTemplateExpression ,
99} from './ts-is-kind' ;
1010
11- import { Options } from './models/Options' ;
11+ import { Options , CustomStyledIdentifiers } from './models/Options' ;
1212import { hash } from './hash' ;
13- import * as fs from 'fs' ;
1413import * as path from 'path' ;
1514
1615/** Detects that a node represents a styled function
@@ -21,9 +20,9 @@ import * as path from 'path';
2120 * styled(Component)
2221 * styledFunction.attrs(attributes)
2322*/
24- function isStyledFunction ( node : ts . Node , styledIdentifiers : string [ ] ) : boolean {
23+ function isStyledFunction ( node : ts . Node , identifiers : CustomStyledIdentifiers ) : boolean {
2524 if ( isPropertyAccessExpression ( node ) ) {
26- if ( isStyledObject ( node . expression , styledIdentifiers ) ) {
25+ if ( isStyledObject ( node . expression , identifiers ) ) {
2726 return true ;
2827 }
2928
@@ -38,20 +37,24 @@ function isStyledFunction(node: ts.Node, styledIdentifiers: string[]): boolean {
3837
3938 if ( isCallExpression ( node ) && node . arguments . length === 1 ) {
4039
41- if ( isStyledObject ( node . expression , styledIdentifiers ) ) {
40+ if ( isStyledObject ( node . expression , identifiers ) ) {
4241 return true ;
4342 }
4443
45- if ( isStyledAttrs ( node . expression , styledIdentifiers ) ) {
44+ if ( isStyledAttrs ( node . expression , identifiers ) ) {
4645 return true ;
4746 }
4847 }
4948
5049 return false ;
5150}
5251
53- function isStyledObject ( node : ts . Node , styledIdentifiers : string [ ] ) {
54- return node && isIdentifier ( node ) && ( node . text === 'styled' || styledIdentifiers . indexOf ( node . text ) !== - 1 ) ;
52+ function isStyledObjectIdentifier ( name : string , { styled : styledIdentifiers = [ 'styled' ] } : CustomStyledIdentifiers ) {
53+ return styledIdentifiers . indexOf ( name ) >= 0 ;
54+ }
55+
56+ function isStyledObject ( node : ts . Node , identifiers : CustomStyledIdentifiers ) {
57+ return node && isIdentifier ( node ) && isStyledObjectIdentifier ( node . text , identifiers ) ;
5558}
5659
5760function isValidComponent ( node : ts . Node ) {
@@ -66,18 +69,27 @@ function isValidComponentName(name: string) {
6669 return name [ 0 ] === name [ 0 ] . toUpperCase ( ) ;
6770}
6871
69- function isStyledAttrs ( node : ts . Node , styledIdentifiers : string [ ] ) {
72+ function isStyledAttrsIdentifier ( name : string , { attrs : attrsIdentifiers = [ 'attrs' ] } : CustomStyledIdentifiers ) {
73+ return attrsIdentifiers . indexOf ( name ) >= 0 ;
74+ }
75+
76+ function isStyledAttrs ( node : ts . Node , identifiers : CustomStyledIdentifiers ) {
7077 return node && isPropertyAccessExpression ( node )
71- && node . name . text === 'attrs'
72- && isStyledFunction ( ( node as ts . PropertyAccessExpression ) . expression , styledIdentifiers ) ;
78+ && isStyledAttrsIdentifier ( node . name . text , identifiers )
79+ && isStyledFunction ( ( node as ts . PropertyAccessExpression ) . expression , identifiers ) ;
7380}
7481
7582function defaultGetDisplayName ( filename : string , bindingName : string | undefined ) : string | undefined {
7683 return bindingName ;
7784}
7885
7986export function createTransformer ( options ?: Partial < Options > ) : ts . TransformerFactory < ts . SourceFile >
80- export function createTransformer ( { getDisplayName = defaultGetDisplayName , styledIdentifiers = [ ] , ssr, displayName = true , rootCheck = 'package.json' } : Partial < Options > = { } ) {
87+ export function createTransformer ( {
88+ getDisplayName = defaultGetDisplayName ,
89+ identifiers = { } ,
90+ ssr = true ,
91+ displayName = true
92+ } : Partial < Options > = { } ) {
8193
8294 /**
8395 * Infers display name of a styled component.
@@ -98,71 +110,63 @@ export function createTransformer({ getDisplayName = defaultGetDisplayName, styl
98110 return undefined ;
99111 }
100112
101- const separatorRegExp = new RegExp ( `\\${ path . sep } ` , 'g' ) ;
102- const findModuleRoot = ( filename : string ) : string | null => {
103- if ( ! filename ) {
104- return null
105- }
106- let dir = path . dirname ( filename )
107- if ( fs . existsSync ( path . join ( dir , rootCheck ) ) ) {
108- return dir
109- } else if ( dir !== filename ) {
110- return findModuleRoot ( dir )
111- } else {
112- return null
113- }
114- }
115-
116- function getIdFromNode ( node : ts . Node ) : string | undefined {
113+ function getIdFromNode ( node : ts . Node , sourceRoot : string | undefined , position : number ) : string | undefined {
117114 if ( ( isVariableDeclaration ( node ) && isIdentifier ( node . name ) ) || isExportAssignment ( node ) ) {
118115 const fileName = node . getSourceFile ( ) . fileName ;
119- const moduleRoot = findModuleRoot ( fileName ) ;
120- const filePath = moduleRoot ? path . relative ( moduleRoot , fileName ) . replace ( separatorRegExp , '/' ) : '' ;
121- return 'ssr-' + hash ( `${ getDisplayNameFromNode ( node ) } ${ filePath } ` ) ;
116+ const filePath = sourceRoot ? path . relative ( sourceRoot , fileName ) . replace ( path . sep , path . posix . sep ) : fileName ;
117+ return 'sc-' + hash ( `${ getDisplayNameFromNode ( node ) } ${ filePath } ${ position } ` ) ;
122118 }
123119 return undefined ;
124120 }
125121
126122 const transformer : ts . TransformerFactory < ts . SourceFile > = ( context ) => {
127- const visitor : ts . Visitor = ( node ) => {
128- if ( node . parent
129-
130- && isTaggedTemplateExpression ( node . parent )
131- && node . parent . tag === node
132- && node . parent . parent
133- && isVariableDeclaration ( node . parent . parent )
134- && isStyledFunction ( node , styledIdentifiers as string [ ] ) ) {
135-
136- const styledConfig = [ ] ;
137-
138- if ( displayName ) {
139- const displayNameValue = getDisplayNameFromNode ( node . parent . parent ) ;
140- if ( displayNameValue ) {
141- styledConfig . push ( ts . createPropertyAssignment ( 'displayName' , ts . createLiteral ( displayNameValue ) ) ) ;
142- }
143- }
144- if ( ssr ) {
145- const componentId = getIdFromNode ( node . parent . parent ) ;
146- if ( componentId ) {
147- styledConfig . push ( ts . createPropertyAssignment ( 'componentId' , ts . createLiteral ( componentId ) ) ) ;
148- }
123+ const { sourceRoot } = context . getCompilerOptions ( ) ;
124+
125+ return ( node ) => {
126+ let lastComponentPosition = 0 ;
127+
128+ const visitor : ts . Visitor = ( node ) => {
129+ if (
130+ node . parent
131+ && isTaggedTemplateExpression ( node . parent )
132+ && node . parent . tag === node
133+ && node . parent . parent
134+ && isVariableDeclaration ( node . parent . parent )
135+ && isStyledFunction ( node , identifiers )
136+ ) {
137+
138+ const styledConfig = [ ] ;
139+
140+ if ( displayName ) {
141+ const displayNameValue = getDisplayNameFromNode ( node . parent . parent ) ;
142+ if ( displayNameValue ) {
143+ styledConfig . push ( ts . createPropertyAssignment ( 'displayName' , ts . createLiteral ( displayNameValue ) ) ) ;
144+ }
145+ }
146+
147+ if ( ssr ) {
148+ const componentId = getIdFromNode ( node . parent . parent , sourceRoot , ++ lastComponentPosition ) ;
149+ if ( componentId ) {
150+ styledConfig . push ( ts . createPropertyAssignment ( 'componentId' , ts . createLiteral ( componentId ) ) ) ;
151+ }
152+ }
153+
154+ return ts . createCall (
155+ ts . createPropertyAccess ( node as ts . Expression , 'withConfig' ) ,
156+ undefined ,
157+ [ ts . createObjectLiteral ( styledConfig ) ] ) ;
149158 }
150- return ts . createCall (
151- ts . createPropertyAccess ( node as ts . Expression , 'withConfig' ) ,
152- undefined ,
153- [ ts . createObjectLiteral ( styledConfig ) , ] ) ;
154-
155- }
156159
157- ts . forEachChild ( node , n => {
158- if ( ! n . parent )
159- n . parent = node ;
160- } ) ;
160+ ts . forEachChild ( node , n => {
161+ if ( ! n . parent )
162+ n . parent = node ;
163+ } ) ;
161164
162- return ts . visitEachChild ( node , visitor , context ) ;
163- }
165+ return ts . visitEachChild ( node , visitor , context ) ;
166+ }
164167
165- return ( node ) => ts . visitNode ( node , visitor ) ;
168+ return ts . visitNode ( node , visitor ) ;
169+ } ;
166170 } ;
167171
168172 return transformer ;
0 commit comments