chore(compiler): refactoring for offline compiler cli

- pass a baseUrl for asset resolution from static symbols
- fixes in StaticReflector to work with a path-aware host

see #7483
This commit is contained in:
Alex Eagle
2016-04-28 21:54:02 -07:00
parent 8bf6ef6544
commit c493d88405
11 changed files with 357 additions and 280 deletions

View File

@ -468,13 +468,16 @@ export class CompileTemplateMetadata {
styles: string[];
styleUrls: string[];
ngContentSelectors: string[];
constructor({encapsulation, template, templateUrl, styles, styleUrls, ngContentSelectors}: {
baseUrl: string;
constructor({encapsulation, template, templateUrl, styles, styleUrls, ngContentSelectors,
baseUrl}: {
encapsulation?: ViewEncapsulation,
template?: string,
templateUrl?: string,
styles?: string[],
styleUrls?: string[],
ngContentSelectors?: string[]
ngContentSelectors?: string[],
baseUrl?: string
} = {}) {
this.encapsulation = isPresent(encapsulation) ? encapsulation : ViewEncapsulation.Emulated;
this.template = template;
@ -482,6 +485,7 @@ export class CompileTemplateMetadata {
this.styles = isPresent(styles) ? styles : [];
this.styleUrls = isPresent(styleUrls) ? styleUrls : [];
this.ngContentSelectors = isPresent(ngContentSelectors) ? ngContentSelectors : [];
this.baseUrl = baseUrl;
}
static fromJson(data: {[key: string]: any}): CompileTemplateMetadata {
@ -493,7 +497,8 @@ export class CompileTemplateMetadata {
templateUrl: data['templateUrl'],
styles: data['styles'],
styleUrls: data['styleUrls'],
ngContentSelectors: data['ngContentSelectors']
ngContentSelectors: data['ngContentSelectors'],
baseUrl: data['baseUrl']
});
}
@ -505,7 +510,8 @@ export class CompileTemplateMetadata {
'templateUrl': this.templateUrl,
'styles': this.styles,
'styleUrls': this.styleUrls,
'ngContentSelectors': this.ngContentSelectors
'ngContentSelectors': this.ngContentSelectors,
'baseUrl': this.baseUrl
};
}
}

View File

@ -66,9 +66,9 @@ export class DirectiveNormalizer {
template: CompileTemplateMetadata): Promise<CompileTemplateMetadata> {
if (isPresent(template.template)) {
return PromiseWrapper.resolve(this.normalizeLoadedTemplate(
directiveType, template, template.template, directiveType.moduleUrl));
directiveType, template, template.template, template.baseUrl));
} else if (isPresent(template.templateUrl)) {
var sourceAbsUrl = this._urlResolver.resolve(directiveType.moduleUrl, template.templateUrl);
var sourceAbsUrl = this._urlResolver.resolve(template.baseUrl, template.templateUrl);
return this._xhr.get(sourceAbsUrl)
.then(templateContent => this.normalizeLoadedTemplate(directiveType, template,
templateContent, sourceAbsUrl));
@ -93,7 +93,7 @@ export class DirectiveNormalizer {
visitor.styleUrls.filter(isStyleUrlResolvable)
.map(url => this._urlResolver.resolve(templateAbsUrl, url))
.concat(templateMeta.styleUrls.filter(isStyleUrlResolvable)
.map(url => this._urlResolver.resolve(directiveType.moduleUrl, url)));
.map(url => this._urlResolver.resolve(templateMeta.baseUrl, url)));
var allResolvedStyles = allStyles.map(style => {
var styleWithImports = extractStyleUrls(this._urlResolver, templateAbsUrl, style);

View File

@ -76,7 +76,6 @@ export class CompileMetadataResolver {
var meta = this._directiveCache.get(directiveType);
if (isBlank(meta)) {
var dirMeta = this._directiveResolver.resolve(directiveType);
var moduleUrl = staticTypeModuleUrl(directiveType);
var templateMeta = null;
var changeDetectionStrategy = null;
var viewProviders = [];
@ -84,7 +83,6 @@ export class CompileMetadataResolver {
if (dirMeta instanceof md.ComponentMetadata) {
assertArrayOfStrings('styles', dirMeta.styles);
var cmpMeta = <md.ComponentMetadata>dirMeta;
moduleUrl = calcModuleUrl(this._reflector, directiveType, cmpMeta);
var viewMeta = this._viewResolver.resolve(directiveType);
assertArrayOfStrings('styles', viewMeta.styles);
templateMeta = new cpl.CompileTemplateMetadata({
@ -92,7 +90,8 @@ export class CompileMetadataResolver {
template: viewMeta.template,
templateUrl: viewMeta.templateUrl,
styles: viewMeta.styles,
styleUrls: viewMeta.styleUrls
styleUrls: viewMeta.styleUrls,
baseUrl: calcTemplateBaseUrl(this._reflector, directiveType, cmpMeta)
});
changeDetectionStrategy = cmpMeta.changeDetection;
if (isPresent(dirMeta.viewProviders)) {
@ -114,7 +113,7 @@ export class CompileMetadataResolver {
selector: dirMeta.selector,
exportAs: dirMeta.exportAs,
isComponent: isPresent(templateMeta),
type: this.getTypeMetadata(directiveType, moduleUrl),
type: this.getTypeMetadata(directiveType, staticTypeModuleUrl(directiveType)),
template: templateMeta,
changeDetection: changeDetectionStrategy,
inputs: dirMeta.inputs,
@ -399,14 +398,19 @@ function staticTypeModuleUrl(value: any): string {
return isStaticType(value) ? value['moduleId'] : null;
}
function calcModuleUrl(reflector: ReflectorReader, type: Type,
cmpMetadata: md.ComponentMetadata): string {
var moduleId = cmpMetadata.moduleId;
if (isPresent(moduleId)) {
function calcTemplateBaseUrl(reflector: ReflectorReader, type: any,
cmpMetadata: md.ComponentMetadata): string {
if (isStaticType(type)) {
return type['filePath'];
}
if (isPresent(cmpMetadata.moduleId)) {
var moduleId = cmpMetadata.moduleId;
var scheme = getUrlScheme(moduleId);
return isPresent(scheme) && scheme.length > 0 ? moduleId :
`package:${moduleId}${MODULE_SUFFIX}`;
} else {
return reflector.importUri(type);
}
return reflector.importUri(type);
}

View File

@ -19,7 +19,6 @@ import {
HostListenerMetadata,
OutputMetadata,
PipeMetadata,
ViewMetadata,
ViewChildMetadata,
ViewChildrenMetadata,
ViewQueryMetadata,
@ -37,6 +36,10 @@ import {
InjectMetadata
} from "angular2/src/core/di/metadata";
export class ModuleContext {
constructor(public moduleId: string, public filePath: string) {}
}
/**
* The host of the static resolver is expected to be able to provide module metadata in the form of
* ModuleMetadata. Angular 2 CLI will produce this metadata for a module whenever a .d.ts files is
@ -53,14 +56,13 @@ export interface StaticReflectorHost {
getMetadataFor(modulePath: string): {[key: string]: any};
/**
* Resolve a module from an import statement form to an absolute path.
* @param moduleName the location imported from
* Resolve a symbol from an import statement form, to the file where it is declared.
* @param module the location imported from
* @param containingFile for relative imports, the path of the file containing the import
*/
resolveModule(moduleName: string, containingFile?: string): string;
findDeclaration(modulePath: string, symbolName: string, containingFile?: string): StaticSymbol;
findDeclaration(modulePath: string,
symbolName: string): {declarationPath: string, declaredName: string};
getStaticSymbol(moduleId: string, declarationFile: string, name: string): StaticSymbol;
}
/**
@ -68,8 +70,8 @@ export interface StaticReflectorHost {
*
* This token is unique for a moduleId and name and can be used as a hash table key.
*/
export class StaticType {
constructor(public moduleId: string, public name: string) {}
export class StaticSymbol {
constructor(public moduleId: string, public filePath: string, public name: string) {}
}
/**
@ -77,40 +79,23 @@ export class StaticType {
* templates statically.
*/
export class StaticReflector implements ReflectorReader {
private typeCache = new Map<string, StaticType>();
private annotationCache = new Map<StaticType, any[]>();
private propertyCache = new Map<StaticType, {[key: string]: any}>();
private parameterCache = new Map<StaticType, any[]>();
private annotationCache = new Map<StaticSymbol, any[]>();
private propertyCache = new Map<StaticSymbol, {[key: string]: any}>();
private parameterCache = new Map<StaticSymbol, any[]>();
private metadataCache = new Map<string, {[key: string]: any}>();
private conversionMap = new Map<StaticType, (moduleContext: string, args: any[]) => any>();
private conversionMap =
new Map<StaticSymbol, (moduleContext: ModuleContext, args: any[]) => any>();
constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); }
importUri(typeOrFunc: any): string { return (<StaticType>typeOrFunc).moduleId; }
importUri(typeOrFunc: any): string { return (<StaticSymbol>typeOrFunc).filePath; }
/**
* getStaticType produces a Type whose metadata is known but whose implementation is not loaded.
* All types passed to the StaticResolver should be pseudo-types returned by this method.
*
* @param moduleId the module identifier as an absolute path.
* @param name the name of the type.
*/
public getStaticType(moduleId: string, name: string): StaticType {
let key = `"${moduleId}".${name}`;
let result = this.typeCache.get(key);
if (!isPresent(result)) {
result = new StaticType(moduleId, name);
this.typeCache.set(key, result);
}
return result;
}
public annotations(type: StaticType): any[] {
public annotations(type: StaticSymbol): any[] {
let annotations = this.annotationCache.get(type);
if (!isPresent(annotations)) {
let classMetadata = this.getTypeMetadata(type);
if (isPresent(classMetadata['decorators'])) {
annotations = this.simplify(type.moduleId, classMetadata['decorators'], false);
annotations = this.simplify(type, classMetadata['decorators'], false);
} else {
annotations = [];
}
@ -119,7 +104,7 @@ export class StaticReflector implements ReflectorReader {
return annotations;
}
public propMetadata(type: StaticType): {[key: string]: any} {
public propMetadata(type: StaticSymbol): {[key: string]: any} {
let propMetadata = this.propertyCache.get(type);
if (!isPresent(propMetadata)) {
let classMetadata = this.getTypeMetadata(type);
@ -127,7 +112,7 @@ export class StaticReflector implements ReflectorReader {
propMetadata = mapStringMap(members, (propData, propName) => {
let prop = (<any[]>propData).find(a => a['__symbolic'] == 'property');
if (isPresent(prop) && isPresent(prop['decorators'])) {
return this.simplify(type.moduleId, prop['decorators'], false);
return this.simplify(type, prop['decorators'], false);
} else {
return [];
}
@ -137,7 +122,7 @@ export class StaticReflector implements ReflectorReader {
return propMetadata;
}
public parameters(type: StaticType): any[] {
public parameters(type: StaticSymbol): any[] {
let parameters = this.parameterCache.get(type);
if (!isPresent(parameters)) {
let classMetadata = this.getTypeMetadata(type);
@ -145,9 +130,8 @@ export class StaticReflector implements ReflectorReader {
let ctorData = isPresent(members) ? members['__ctor__'] : null;
if (isPresent(ctorData)) {
let ctor = (<any[]>ctorData).find(a => a['__symbolic'] == 'constructor');
let parameterTypes = <any[]>this.simplify(type.moduleId, ctor['parameters'], false);
let parameterDecorators =
<any[]>this.simplify(type.moduleId, ctor['parameterDecorators'], false);
let parameterTypes = <any[]>this.simplify(type, ctor['parameters'], false);
let parameterDecorators = <any[]>this.simplify(type, ctor['parameterDecorators'], false);
parameters = [];
ListWrapper.forEachWithIndex(parameterTypes, (paramType, index) => {
@ -170,9 +154,9 @@ export class StaticReflector implements ReflectorReader {
return parameters;
}
private registerDecoratorOrConstructor(type: StaticType, ctor: any,
private registerDecoratorOrConstructor(type: StaticSymbol, ctor: any,
crossModuleProps: any[] = CONST_EXPR([])): void {
this.conversionMap.set(type, (moduleContext: string, args: any[]) => {
this.conversionMap.set(type, (moduleContext: ModuleContext, args: any[]) => {
let argValues = [];
ListWrapper.forEachWithIndex(args, (arg, index) => {
let argValue;
@ -190,62 +174,67 @@ export class StaticReflector implements ReflectorReader {
}
private initializeConversionMap(): void {
let coreDecorators = this.host.resolveModule('angular2/src/core/metadata');
let diDecorators = this.host.resolveModule('angular2/src/core/di/decorators');
let diMetadata = this.host.resolveModule('angular2/src/core/di/metadata');
let coreDecorators = 'angular2/src/core/metadata';
let diDecorators = 'angular2/src/core/di/decorators';
let diMetadata = 'angular2/src/core/di/metadata';
let provider = 'angular2/src/core/di/provider';
this.registerDecoratorOrConstructor(this.host.findDeclaration(provider, 'Provider'), Provider);
let provider = this.host.resolveModule('angular2/src/core/di/provider');
this.registerDecoratorOrConstructor(this.getStaticType(provider, 'Provider'), Provider);
this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Host'), HostMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Injectable'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Host'),
HostMetadata);
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Injectable'),
InjectableMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Self'), SelfMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'SkipSelf'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Self'),
SelfMetadata);
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'SkipSelf'),
SkipSelfMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Inject'), InjectMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Optional'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Inject'),
InjectMetadata);
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Optional'),
OptionalMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Attribute'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Attribute'),
AttributeMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Query'), QueryMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'ViewQuery'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Query'),
QueryMetadata);
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ViewQuery'),
ViewQueryMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'ContentChild'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ContentChild'),
ContentChildMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'ContentChildren'),
ContentChildrenMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'ViewChild'),
this.registerDecoratorOrConstructor(
this.host.findDeclaration(coreDecorators, 'ContentChildren'), ContentChildrenMetadata);
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ViewChild'),
ViewChildMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'ViewChildren'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ViewChildren'),
ViewChildrenMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Input'), InputMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Output'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Input'),
InputMetadata);
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Output'),
OutputMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Pipe'), PipeMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'HostBinding'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Pipe'),
PipeMetadata);
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'HostBinding'),
HostBindingMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'HostListener'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'HostListener'),
HostListenerMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Directive'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Directive'),
DirectiveMetadata, ['bindings', 'providers']);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Component'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Component'),
ComponentMetadata,
['bindings', 'providers', 'directives', 'pipes']);
// Note: Some metadata classes can be used directly with Provider.deps.
this.registerDecoratorOrConstructor(this.getStaticType(diMetadata, 'HostMetadata'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'HostMetadata'),
HostMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diMetadata, 'SelfMetadata'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'SelfMetadata'),
SelfMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diMetadata, 'SkipSelfMetadata'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'SkipSelfMetadata'),
SkipSelfMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diMetadata, 'OptionalMetadata'),
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'OptionalMetadata'),
OptionalMetadata);
}
/** @internal */
public simplify(moduleContext: string, value: any, crossModules: boolean): any {
public simplify(moduleContext: ModuleContext, value: any, crossModules: boolean): any {
let _this = this;
function simplify(expression: any): any {
@ -261,6 +250,7 @@ export class StaticReflector implements ReflectorReader {
}
if (isPresent(expression)) {
if (isPresent(expression['__symbolic'])) {
let staticSymbol;
switch (expression['__symbolic']) {
case "binop":
let left = simplify(expression['left']);
@ -332,35 +322,34 @@ export class StaticReflector implements ReflectorReader {
if (isPresent(selectTarget) && isPrimitive(member)) return selectTarget[member];
return null;
case "reference":
let referenceModuleName;
let declarationPath = moduleContext;
let declaredName = expression['name'];
if (isPresent(expression['module'])) {
referenceModuleName = _this.host.resolveModule(expression['module'], moduleContext);
let decl = _this.host.findDeclaration(referenceModuleName, expression['name']);
declarationPath = decl['declarationPath'];
declaredName = decl['declaredName'];
staticSymbol = _this.host.findDeclaration(expression['module'], expression['name'],
moduleContext.filePath);
} else {
staticSymbol = _this.host.getStaticSymbol(
moduleContext.moduleId, moduleContext.filePath, expression['name']);
}
let result;
if (crossModules || isBlank(expression['module'])) {
let moduleMetadata = _this.getModuleMetadata(declarationPath);
let declarationValue = moduleMetadata['metadata'][declaredName];
let moduleMetadata = _this.getModuleMetadata(staticSymbol.filePath);
let declarationValue = moduleMetadata['metadata'][staticSymbol.name];
if (isClassMetadata(declarationValue)) {
result = _this.getStaticType(declarationPath, declaredName);
result = staticSymbol;
} else {
result = _this.simplify(declarationPath, declarationValue, crossModules);
const newModuleContext =
new ModuleContext(staticSymbol.moduleId, staticSymbol.filePath);
result = _this.simplify(newModuleContext, declarationValue, crossModules);
}
} else {
result = _this.getStaticType(declarationPath, declaredName);
result = staticSymbol;
}
return result;
case "new":
case "call":
let target = expression['expression'];
let moduleId = _this.host.resolveModule(target['module'], moduleContext);
let decl = _this.host.findDeclaration(moduleId, target['name']);
let staticType = _this.getStaticType(decl['declarationPath'], decl['declaredName']);
let converter = _this.conversionMap.get(staticType);
staticSymbol = _this.host.findDeclaration(target['module'], target['name'],
moduleContext.filePath);
let converter = _this.conversionMap.get(staticSymbol);
let args = expression['arguments'];
if (isBlank(args)) {
args = [];
@ -392,8 +381,11 @@ export class StaticReflector implements ReflectorReader {
return moduleMetadata;
}
private getTypeMetadata(type: StaticType): {[key: string]: any} {
let moduleMetadata = this.getModuleMetadata(type.moduleId);
private getTypeMetadata(type: StaticSymbol): {[key: string]: any} {
if (!(type instanceof StaticSymbol)) {
throw new Error('not static type');
}
let moduleMetadata = this.getModuleMetadata(type.filePath);
let result = moduleMetadata['metadata'][type.name];
if (!isPresent(result)) {
result = {__symbolic: "class"};

View File

@ -87,7 +87,8 @@ export class CompileEventListener {
[
new o.ReturnStatement(
o.THIS_EXPR.callMethod(this._methodName, [EventHandlerVars.event]))
], o.BOOL_TYPE)
],
o.BOOL_TYPE)
]);
if (isPresent(this.eventTarget)) {
listenExpr = ViewProperties.renderer.callMethod(