|
|
|
@ -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"};
|
|
|
|
|