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