1+ import { DirectiveMetadata , SourceModule , ViewEncapsulation } from './api' ;
2+ import { XHR } from 'angular2/src/core/render/xhr' ;
3+ import { StringWrapper , isJsObject , isBlank } from 'angular2/src/core/facade/lang' ;
4+ import { PromiseWrapper , Promise } from 'angular2/src/core/facade/async' ;
5+ import { ShadowCss } from 'angular2/src/core/render/dom/compiler/shadow_css' ;
6+ import { UrlResolver } from 'angular2/src/core/services/url_resolver' ;
7+ import { resolveStyleUrls } from './style_url_resolver' ;
8+
9+ const COMPONENT_VARIABLE = '%COMP%' ;
10+ var COMPONENT_REGEX = / % C O M P % / g;
11+ const HOST_ATTR = `_nghost-${ COMPONENT_VARIABLE } ` ;
12+ const CONTENT_ATTR = `_ngcontent-${ COMPONENT_VARIABLE } ` ;
13+ var ESCAPE_STRING_RE = / ' | \\ | \n / g;
14+ var IS_DART = ! isJsObject ( { } ) ;
15+
16+ export class StyleCompiler {
17+ private _styleCache : Map < string , Promise < string [ ] > > = new Map < string , Promise < string [ ] > > ( ) ;
18+ private _shadowCss : ShadowCss = new ShadowCss ( ) ;
19+
20+ constructor ( private _xhr : XHR , private _urlResolver : UrlResolver ) { }
21+
22+ compileComponentRuntime ( component : DirectiveMetadata ) : Promise < string [ ] > {
23+ var styles = component . template . styles ;
24+ var styleAbsUrls = component . template . styleAbsUrls ;
25+ return this . _loadStyles ( styles , styleAbsUrls ,
26+ component . template . encapsulation === ViewEncapsulation . Emulated )
27+ . then ( styles => styles . map ( style => StringWrapper . replaceAll ( style , COMPONENT_REGEX ,
28+ `${ component . type . id } ` ) ) ) ;
29+ }
30+
31+ compileComponentCodeGen ( component : DirectiveMetadata ) : SourceModule {
32+ var shim = component . template . encapsulation === ViewEncapsulation . Emulated ;
33+ var suffix ;
34+ if ( shim ) {
35+ var componentId = `${ component . type . id } ` ;
36+ suffix =
37+ codeGenMapArray ( [ 'style' ] , `style${ codeGenReplaceAll ( COMPONENT_VARIABLE , componentId ) } ` ) ;
38+ } else {
39+ suffix = '' ;
40+ }
41+ return this . _styleCodeGen ( `$component.type.typeUrl}.styles` , component . template . styles ,
42+ component . template . styleAbsUrls , shim , suffix ) ;
43+ }
44+
45+ compileStylesheetCodeGen ( moduleName : string , cssText : string ) : SourceModule [ ] {
46+ var styleWithImports = resolveStyleUrls ( this . _urlResolver , moduleName , cssText ) ;
47+ return [
48+ this . _styleCodeGen ( moduleName , [ styleWithImports . style ] , styleWithImports . styleUrls , false ,
49+ '' ) ,
50+ this . _styleCodeGen ( moduleName , [ styleWithImports . style ] , styleWithImports . styleUrls , true , '' )
51+ ] ;
52+ }
53+
54+ private _loadStyles ( plainStyles : string [ ] , absUrls : string [ ] ,
55+ encapsulate : boolean ) : Promise < string [ ] > {
56+ var promises = absUrls . map ( ( absUrl ) => {
57+ var cacheKey = `${ absUrl } ${ encapsulate ? '.shim' : '' } ` ;
58+ var result = this . _styleCache . get ( cacheKey ) ;
59+ if ( isBlank ( result ) ) {
60+ result = this . _xhr . get ( absUrl ) . then ( ( style ) => {
61+ var styleWithImports = resolveStyleUrls ( this . _urlResolver , absUrl , style ) ;
62+ return this . _loadStyles ( [ styleWithImports . style ] , styleWithImports . styleUrls ,
63+ encapsulate ) ;
64+ } ) ;
65+ this . _styleCache . set ( cacheKey , result ) ;
66+ }
67+ return result ;
68+ } ) ;
69+ return PromiseWrapper . all ( promises ) . then ( ( nestedStyles : string [ ] [ ] ) => {
70+ var result = plainStyles . map ( plainStyle => this . _shimIfNeeded ( plainStyle , encapsulate ) ) ;
71+ nestedStyles . forEach ( styles => styles . forEach ( style => result . push ( style ) ) ) ;
72+ return result ;
73+ } ) ;
74+ }
75+
76+ private _styleCodeGen ( moduleName : string , plainStyles : string [ ] , absUrls : string [ ] , shim : boolean ,
77+ suffix : string ) : SourceModule {
78+ var imports : string [ ] [ ] = [ ] ;
79+ var moduleSource = `${ codeGenExportVar ( 'STYLES' ) } (` ;
80+ moduleSource +=
81+ `[${ plainStyles . map ( plainStyle => escapeString ( this . _shimIfNeeded ( plainStyle , shim ) ) ) . join ( ',' ) } ]` ;
82+ for ( var i = 0 ; i < absUrls . length ; i ++ ) {
83+ var url = absUrls [ i ] ;
84+ var moduleAlias = `import${ i } ` ;
85+ imports . push ( [ this . _shimModuleName ( url , shim ) , moduleAlias ] ) ;
86+ moduleSource += `${ codeGenConcatArray ( moduleAlias + '.STYLES' ) } ` ;
87+ }
88+ moduleSource += `)${ suffix } ;` ;
89+ return new SourceModule ( this . _shimModuleName ( moduleName , shim ) , moduleSource , imports ) ;
90+ }
91+
92+ private _shimIfNeeded ( style : string , shim : boolean ) : string {
93+ return shim ? this . _shadowCss . shimCssText ( style , CONTENT_ATTR , HOST_ATTR ) : style ;
94+ }
95+
96+ private _shimModuleName ( originalUrl : string , shim : boolean ) : string {
97+ return shim ? `${ originalUrl } .shim` : originalUrl ;
98+ }
99+ }
100+
101+ function escapeString ( input : string ) : string {
102+ var escapedInput = StringWrapper . replaceAllMapped ( input , ESCAPE_STRING_RE , ( match ) => {
103+ if ( match [ 0 ] == "'" || match [ 0 ] == '\\' ) {
104+ return `\\${ match [ 0 ] } ` ;
105+ } else {
106+ return '\\n' ;
107+ }
108+ } ) ;
109+ return `'${ escapedInput } '` ;
110+ }
111+
112+ function codeGenExportVar ( name : string ) : string {
113+ if ( IS_DART ) {
114+ return `var ${ name } =` ;
115+ } else {
116+ return `var ${ name } = exports.${ name } =` ;
117+ }
118+ }
119+
120+ function codeGenConcatArray ( expression : string ) : string {
121+ return `${ IS_DART ? '..addAll' : '.concat' } (${ expression } )` ;
122+ }
123+
124+ function codeGenMapArray ( argNames : string [ ] , callback : string ) : string {
125+ if ( IS_DART ) {
126+ return `.map( (${ argNames . join ( ',' ) } ) => ${ callback } ).toList()` ;
127+ } else {
128+ return `.map(function(${ argNames . join ( ',' ) } ) { return ${ callback } ; })` ;
129+ }
130+ }
131+
132+ function codeGenReplaceAll ( pattern : string , value : string ) : string {
133+ if ( IS_DART ) {
134+ return `.replaceAll('${ pattern } ', '${ value } ')` ;
135+ } else {
136+ return `.replace(/${ pattern } /g, '${ value } ')` ;
137+ }
138+ }
0 commit comments