refactor(compiler): make static reflector work

Also adjust `RuntimeMetadataResolver` to
be able to use it. 

Also rename `RuntimeMetadataResolver` into `CompileMetadataResolver`.
Closes #8313
This commit is contained in:
Alex Eagle
2016-02-18 10:53:21 -08:00
committed by Tobias Bosch
parent 769835e53e
commit 70b23ae2ca
8 changed files with 447 additions and 512 deletions

View File

@ -17,7 +17,7 @@ import {provide, Provider} from 'angular2/src/core/di';
import {TemplateParser} from 'angular2/src/compiler/template_parser';
import {HtmlParser} from 'angular2/src/compiler/html_parser';
import {DirectiveNormalizer} from 'angular2/src/compiler/directive_normalizer';
import {RuntimeMetadataResolver} from 'angular2/src/compiler/runtime_metadata';
import {CompileMetadataResolver} from 'angular2/src/compiler/metadata_resolver';
import {StyleCompiler} from 'angular2/src/compiler/style_compiler';
import {ViewCompiler} from 'angular2/src/compiler/view_compiler/view_compiler';
import {CompilerConfig} from './config';
@ -46,7 +46,7 @@ export const COMPILER_PROVIDERS: Array<Type | Provider | any[]> = CONST_EXPR([
HtmlParser,
TemplateParser,
DirectiveNormalizer,
RuntimeMetadataResolver,
CompileMetadataResolver,
DEFAULT_PACKAGE_URL_PROVIDER,
StyleCompiler,
ViewCompiler,

View File

@ -6,12 +6,12 @@ import {
isArray,
stringify,
isString,
isStringMap,
RegExpWrapper,
StringWrapper
} from 'angular2/src/facade/lang';
import {StringMapWrapper} from 'angular2/src/facade/collection';
import {BaseException} from 'angular2/src/facade/exceptions';
import {NoAnnotationError} from 'angular2/src/core/di/reflective_exceptions';
import * as cpl from './compile_metadata';
import * as md from 'angular2/src/core/metadata/directives';
import * as dimd from 'angular2/src/core/metadata/di';
@ -28,20 +28,18 @@ import {MODULE_SUFFIX, sanitizeIdentifier} from './util';
import {assertArrayOfStrings} from './assertions';
import {getUrlScheme} from 'angular2/src/compiler/url_resolver';
import {Provider} from 'angular2/src/core/di/provider';
import {
constructDependencies,
ReflectiveDependency
} from 'angular2/src/core/di/reflective_provider';
import {
OptionalMetadata,
SelfMetadata,
HostMetadata,
SkipSelfMetadata
SkipSelfMetadata,
InjectMetadata
} from 'angular2/src/core/di/metadata';
import {AttributeMetadata, QueryMetadata} from 'angular2/src/core/metadata/di';
import {ReflectorReader} from 'angular2/src/core/reflection/reflector_reader';
@Injectable()
export class RuntimeMetadataResolver {
export class CompileMetadataResolver {
private _directiveCache = new Map<Type, cpl.CompileDirectiveMetadata>();
private _pipeCache = new Map<Type, cpl.CompilePipeMetadata>();
private _anonymousTypes = new Map<Object, number>();
@ -78,7 +76,7 @@ export class RuntimeMetadataResolver {
var meta = this._directiveCache.get(directiveType);
if (isBlank(meta)) {
var dirMeta = this._directiveResolver.resolve(directiveType);
var moduleUrl = null;
var moduleUrl = staticTypeModuleUrl(directiveType);
var templateMeta = null;
var changeDetectionStrategy = null;
var viewProviders = [];
@ -134,6 +132,21 @@ export class RuntimeMetadataResolver {
return meta;
}
/**
* @param someType a symbol which may or may not be a directive type
* @returns {cpl.CompileDirectiveMetadata} if possible, otherwise null.
*/
maybeGetDirectiveMetadata(someType: Type): cpl.CompileDirectiveMetadata {
try {
return this.getDirectiveMetadata(someType);
} catch (e) {
if (e.message.indexOf('No Directive annotation') !== -1) {
return null;
}
throw e;
}
}
getTypeMetadata(type: Type, moduleUrl: string): cpl.CompileTypeMetadata {
return new cpl.CompileTypeMetadata({
name: this.sanitizeTokenName(type),
@ -156,9 +169,8 @@ export class RuntimeMetadataResolver {
var meta = this._pipeCache.get(pipeType);
if (isBlank(meta)) {
var pipeMeta = this._pipeResolver.resolve(pipeType);
var moduleUrl = this._reflector.importUri(pipeType);
meta = new cpl.CompilePipeMetadata({
type: this.getTypeMetadata(pipeType, moduleUrl),
type: this.getTypeMetadata(pipeType, staticTypeModuleUrl(pipeType)),
name: pipeMeta.name,
pure: pipeMeta.pure,
lifecycleHooks: LIFECYCLE_HOOKS_VALUES.filter(hook => hasLifecycleHook(hook, pipeType)),
@ -177,7 +189,6 @@ export class RuntimeMetadataResolver {
`Unexpected directive value '${stringify(directives[i])}' on the View of component '${stringify(component)}'`);
}
}
return directives.map(type => this.getDirectiveMetadata(type));
}
@ -195,41 +206,65 @@ export class RuntimeMetadataResolver {
getDependenciesMetadata(typeOrFunc: Type | Function,
dependencies: any[]): cpl.CompileDiDependencyMetadata[] {
var deps: ReflectiveDependency[];
try {
deps = constructDependencies(typeOrFunc, dependencies);
} catch (e) {
if (e instanceof NoAnnotationError) {
deps = [];
} else {
throw e;
}
let params = isPresent(dependencies) ? dependencies : this._reflector.parameters(typeOrFunc);
if (isBlank(params)) {
params = [];
}
return deps.map((dep) => {
var compileToken;
var p = <dimd.AttributeMetadata>dep.properties.find(p => p instanceof dimd.AttributeMetadata);
var isAttribute = false;
if (isPresent(p)) {
compileToken = this.getTokenMetadata(p.attributeName);
isAttribute = true;
} else {
compileToken = this.getTokenMetadata(dep.key.token);
return params.map((param) => {
if (isBlank(param)) {
return null;
}
var compileQuery = null;
var q = <dimd.QueryMetadata>dep.properties.find(p => p instanceof dimd.QueryMetadata);
if (isPresent(q)) {
compileQuery = this.getQueryMetadata(q, null);
let isAttribute = false;
let isHost = false;
let isSelf = false;
let isSkipSelf = false;
let isOptional = false;
let query: dimd.QueryMetadata = null;
let viewQuery: dimd.ViewQueryMetadata = null;
var token = null;
if (isArray(param)) {
(<any[]>param)
.forEach((paramEntry) => {
if (paramEntry instanceof HostMetadata) {
isHost = true;
} else if (paramEntry instanceof SelfMetadata) {
isSelf = true;
} else if (paramEntry instanceof SkipSelfMetadata) {
isSkipSelf = true;
} else if (paramEntry instanceof OptionalMetadata) {
isOptional = true;
} else if (paramEntry instanceof AttributeMetadata) {
isAttribute = true;
token = paramEntry.attributeName;
} else if (paramEntry instanceof QueryMetadata) {
if (paramEntry.isViewQuery) {
viewQuery = paramEntry;
} else {
query = paramEntry;
}
} else if (paramEntry instanceof InjectMetadata) {
token = paramEntry.token;
} else if (isValidType(paramEntry) && isBlank(token)) {
token = paramEntry;
}
});
} else {
token = param;
}
if (isBlank(token)) {
return null;
}
return new cpl.CompileDiDependencyMetadata({
isAttribute: isAttribute,
isHost: dep.upperBoundVisibility instanceof HostMetadata,
isSelf: dep.upperBoundVisibility instanceof SelfMetadata,
isSkipSelf: dep.lowerBoundVisibility instanceof SkipSelfMetadata,
isOptional: dep.optional,
query: isPresent(q) && !q.isViewQuery ? compileQuery : null,
viewQuery: isPresent(q) && q.isViewQuery ? compileQuery : null,
token: compileToken
isHost: isHost,
isSelf: isSelf,
isSkipSelf: isSkipSelf,
isOptional: isOptional,
query: isPresent(query) ? this.getQueryMetadata(query, null) : null,
viewQuery: isPresent(viewQuery) ? this.getQueryMetadata(viewQuery, null) : null,
token: this.getTokenMetadata(token)
});
});
}
@ -240,8 +275,11 @@ export class RuntimeMetadataResolver {
compileToken = new cpl.CompileTokenMetadata({value: token});
} else {
compileToken = new cpl.CompileTokenMetadata({
identifier: new cpl.CompileIdentifierMetadata(
{runtime: token, name: this.sanitizeTokenName(token)})
identifier: new cpl.CompileIdentifierMetadata({
runtime: token,
name: this.sanitizeTokenName(token),
moduleUrl: staticTypeModuleUrl(token)
})
});
}
return compileToken;
@ -256,7 +294,7 @@ export class RuntimeMetadataResolver {
} else if (provider instanceof Provider) {
return this.getProviderMetadata(provider);
} else {
return this.getTypeMetadata(provider, null);
return this.getTypeMetadata(provider, staticTypeModuleUrl(provider));
}
});
}
@ -270,12 +308,16 @@ export class RuntimeMetadataResolver {
}
return new cpl.CompileProviderMetadata({
token: this.getTokenMetadata(provider.token),
useClass: isPresent(provider.useClass) ? this.getTypeMetadata(provider.useClass, null) : null,
useClass:
isPresent(provider.useClass) ?
this.getTypeMetadata(provider.useClass, staticTypeModuleUrl(provider.useClass)) :
null,
useValue: isPresent(provider.useValue) ?
new cpl.CompileIdentifierMetadata({runtime: provider.useValue}) :
null,
useFactory: isPresent(provider.useFactory) ?
this.getFactoryMetadata(provider.useFactory, null) :
this.getFactoryMetadata(provider.useFactory,
staticTypeModuleUrl(provider.useFactory)) :
null,
useExisting: isPresent(provider.useExisting) ? this.getTokenMetadata(provider.useExisting) :
null,
@ -345,8 +387,16 @@ function flattenArray(tree: any[], out: Array<Type | any[]>): void {
}
}
function isValidType(value: Type): boolean {
return isPresent(value) && (value instanceof Type);
function isStaticType(value: any): boolean {
return isStringMap(value) && isPresent(value['name']) && isPresent(value['moduleId']);
}
function isValidType(value: any): boolean {
return isStaticType(value) || (value instanceof Type);
}
function staticTypeModuleUrl(value: any): string {
return isStaticType(value) ? value['moduleId'] : null;
}
function calcModuleUrl(reflector: ReflectorReader, type: Type,

View File

@ -44,7 +44,7 @@ import {StyleCompiler, StylesCompileDependency, StylesCompileResult} from './sty
import {ViewCompiler} from './view_compiler/view_compiler';
import {TemplateParser} from './template_parser';
import {DirectiveNormalizer} from './directive_normalizer';
import {RuntimeMetadataResolver} from './runtime_metadata';
import {CompileMetadataResolver} from './metadata_resolver';
import {ComponentFactory} from 'angular2/src/core/linker/component_factory';
import {
ComponentResolver,
@ -71,7 +71,7 @@ export class RuntimeCompiler implements ComponentResolver {
private _compiledTemplateCache = new Map<any, CompiledTemplate>();
private _compiledTemplateDone = new Map<any, Promise<CompiledTemplate>>();
constructor(private _runtimeMetadataResolver: RuntimeMetadataResolver,
constructor(private _metadataResolver: CompileMetadataResolver,
private _templateNormalizer: DirectiveNormalizer,
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
private _viewCompiler: ViewCompiler, private _xhr: XHR,
@ -79,7 +79,7 @@ export class RuntimeCompiler implements ComponentResolver {
resolveComponent(componentType: Type): Promise<ComponentFactory> {
var compMeta: CompileDirectiveMetadata =
this._runtimeMetadataResolver.getDirectiveMetadata(componentType);
this._metadataResolver.getDirectiveMetadata(componentType);
var hostCacheKey = this._hostCacheKeys.get(componentType);
if (isBlank(hostCacheKey)) {
hostCacheKey = new Object();
@ -146,9 +146,9 @@ export class RuntimeCompiler implements ComponentResolver {
var childCacheKey = dep.comp.type.runtime;
var childViewDirectives: CompileDirectiveMetadata[] =
this._runtimeMetadataResolver.getViewDirectivesMetadata(dep.comp.type.runtime);
this._metadataResolver.getViewDirectivesMetadata(dep.comp.type.runtime);
var childViewPipes: CompilePipeMetadata[] =
this._runtimeMetadataResolver.getViewPipesMetadata(dep.comp.type.runtime);
this._metadataResolver.getViewPipesMetadata(dep.comp.type.runtime);
var childIsRecursive = ListWrapper.contains(childCompilingComponentsPath, childCacheKey);
childCompilingComponentsPath.push(childCacheKey);

View File

@ -1,8 +1,12 @@
import {StringMapWrapper} from 'angular2/src/facade/collection';
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {
isArray,
isPresent,
isBlank,
isPrimitive,
isStringMap,
CONST_EXPR,
FunctionWrapper
} from 'angular2/src/facade/lang';
import {
AttributeMetadata,
@ -22,6 +26,16 @@ import {
QueryMetadata,
} from 'angular2/src/core/metadata';
import {ReflectorReader} from 'angular2/src/core/reflection/reflector_reader';
import {reflector} from 'angular2/src/core/reflection/reflection';
import {Provider} from 'angular2/src/core/di/provider';
import {
HostMetadata,
OptionalMetadata,
InjectableMetadata,
SelfMetadata,
SkipSelfMetadata,
InjectMetadata
} from "angular2/src/core/di/metadata";
/**
* The host of the static resolver is expected to be able to provide module metadata in the form of
@ -36,7 +50,7 @@ export interface StaticReflectorHost {
* @param moduleId is a string identifier for a module as an absolute path.
* @returns the metadata for the given module.
*/
getMetadataFor(moduleId: string): {[key: string]: any};
getMetadataFor(modulePath: string): {[key: string]: any};
/**
* Resolve a module from an import statement form to an absolute path.
@ -44,6 +58,9 @@ export interface StaticReflectorHost {
* @param containingFile for relative imports, the path of the file containing the import
*/
resolveModule(moduleName: string, containingFile?: string): string;
findDeclaration(modulePath: string,
symbolName: string): {declarationPath: string, declaredName: string};
}
/**
@ -65,6 +82,8 @@ export class StaticReflector implements ReflectorReader {
private propertyCache = new Map<StaticType, {[key: string]: any}>();
private parameterCache = new Map<StaticType, any[]>();
private metadataCache = new Map<string, {[key: string]: any}>();
private conversionMap = new Map<StaticType, (moduleContext: string, args: any[]) => any>();
constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); }
importUri(typeOrFunc: any): string { return (<StaticType>typeOrFunc).moduleId; }
@ -91,13 +110,11 @@ export class StaticReflector implements ReflectorReader {
if (!isPresent(annotations)) {
let classMetadata = this.getTypeMetadata(type);
if (isPresent(classMetadata['decorators'])) {
annotations = (<any[]>classMetadata['decorators'])
.map(decorator => this.convertKnownDecorator(type.moduleId, decorator))
.filter(decorator => isPresent(decorator));
annotations = this.simplify(type.moduleId, classMetadata['decorators'], false);
} else {
annotations = [];
}
this.annotationCache.set(type, annotations);
this.annotationCache.set(type, annotations.filter(ann => isPresent(ann)));
}
return annotations;
}
@ -106,10 +123,15 @@ export class StaticReflector implements ReflectorReader {
let propMetadata = this.propertyCache.get(type);
if (!isPresent(propMetadata)) {
let classMetadata = this.getTypeMetadata(type);
propMetadata = this.getPropertyMetadata(type.moduleId, classMetadata['members']);
if (!isPresent(propMetadata)) {
propMetadata = {};
}
let members = isPresent(classMetadata) ? classMetadata['members'] : {};
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);
} else {
return [];
}
});
this.propertyCache.set(type, propMetadata);
}
return propMetadata;
@ -119,15 +141,26 @@ export class StaticReflector implements ReflectorReader {
let parameters = this.parameterCache.get(type);
if (!isPresent(parameters)) {
let classMetadata = this.getTypeMetadata(type);
if (isPresent(classMetadata)) {
let members = classMetadata['members'];
if (isPresent(members)) {
let ctorData = members['__ctor__'];
if (isPresent(ctorData)) {
let ctor = (<any[]>ctorData).find(a => a['__symbolic'] === 'constructor');
parameters = this.simplify(type.moduleId, ctor['parameters']);
let members = isPresent(classMetadata) ? classMetadata['members'] : null;
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);
parameters = [];
ListWrapper.forEachWithIndex(parameterTypes, (paramType, index) => {
let nestedResult = [];
if (isPresent(paramType)) {
nestedResult.push(paramType);
}
}
let decorators = isPresent(parameterDecorators) ? parameterDecorators[index] : null;
if (isPresent(decorators)) {
ListWrapper.addAll(nestedResult, decorators);
}
parameters.push(nestedResult);
});
}
if (!isPresent(parameters)) {
parameters = [];
@ -137,201 +170,82 @@ export class StaticReflector implements ReflectorReader {
return parameters;
}
private conversionMap = new Map<StaticType, (moduleContext: string, expression: any) => any>();
private initializeConversionMap(): any {
let core_metadata = this.host.resolveModule('angular2/src/core/metadata');
let conversionMap = this.conversionMap;
conversionMap.set(this.getStaticType(core_metadata, 'Directive'),
(moduleContext, expression) => {
let p0 = this.getDecoratorParameter(moduleContext, expression, 0);
if (!isPresent(p0)) {
p0 = {};
}
return new DirectiveMetadata({
selector: p0['selector'],
inputs: p0['inputs'],
outputs: p0['outputs'],
events: p0['events'],
host: p0['host'],
bindings: p0['bindings'],
providers: p0['providers'],
exportAs: p0['exportAs'],
queries: p0['queries'],
});
});
conversionMap.set(this.getStaticType(core_metadata, 'Component'),
(moduleContext, expression) => {
let p0 = this.getDecoratorParameter(moduleContext, expression, 0);
if (!isPresent(p0)) {
p0 = {};
}
return new ComponentMetadata({
selector: p0['selector'],
inputs: p0['inputs'],
outputs: p0['outputs'],
properties: p0['properties'],
events: p0['events'],
host: p0['host'],
exportAs: p0['exportAs'],
moduleId: p0['moduleId'],
bindings: p0['bindings'],
providers: p0['providers'],
viewBindings: p0['viewBindings'],
viewProviders: p0['viewProviders'],
changeDetection: p0['changeDetection'],
queries: p0['queries'],
templateUrl: p0['templateUrl'],
template: p0['template'],
styleUrls: p0['styleUrls'],
styles: p0['styles'],
directives: p0['directives'],
pipes: p0['pipes'],
encapsulation: p0['encapsulation']
});
});
conversionMap.set(this.getStaticType(core_metadata, 'Input'),
(moduleContext, expression) => new InputMetadata(
this.getDecoratorParameter(moduleContext, expression, 0)));
conversionMap.set(this.getStaticType(core_metadata, 'Output'),
(moduleContext, expression) => new OutputMetadata(
this.getDecoratorParameter(moduleContext, expression, 0)));
conversionMap.set(this.getStaticType(core_metadata, 'View'), (moduleContext, expression) => {
let p0 = this.getDecoratorParameter(moduleContext, expression, 0);
if (!isPresent(p0)) {
p0 = {};
}
return new ViewMetadata({
templateUrl: p0['templateUrl'],
template: p0['template'],
directives: p0['directives'],
pipes: p0['pipes'],
encapsulation: p0['encapsulation'],
styles: p0['styles'],
});
});
conversionMap.set(this.getStaticType(core_metadata, 'Attribute'),
(moduleContext, expression) => new AttributeMetadata(
this.getDecoratorParameter(moduleContext, expression, 0)));
conversionMap.set(this.getStaticType(core_metadata, 'Query'), (moduleContext, expression) => {
let p0 = this.getDecoratorParameter(moduleContext, expression, 0);
let p1 = this.getDecoratorParameter(moduleContext, expression, 1);
if (!isPresent(p1)) {
p1 = {};
}
return new QueryMetadata(p0, {descendants: p1.descendants, first: p1.first});
});
conversionMap.set(this.getStaticType(core_metadata, 'ContentChildren'),
(moduleContext, expression) => new ContentChildrenMetadata(
this.getDecoratorParameter(moduleContext, expression, 0)));
conversionMap.set(this.getStaticType(core_metadata, 'ContentChild'),
(moduleContext, expression) => new ContentChildMetadata(
this.getDecoratorParameter(moduleContext, expression, 0)));
conversionMap.set(this.getStaticType(core_metadata, 'ViewChildren'),
(moduleContext, expression) => new ViewChildrenMetadata(
this.getDecoratorParameter(moduleContext, expression, 0)));
conversionMap.set(this.getStaticType(core_metadata, 'ViewChild'),
(moduleContext, expression) => new ViewChildMetadata(
this.getDecoratorParameter(moduleContext, expression, 0)));
conversionMap.set(this.getStaticType(core_metadata, 'ViewQuery'),
(moduleContext, expression) => {
let p0 = this.getDecoratorParameter(moduleContext, expression, 0);
let p1 = this.getDecoratorParameter(moduleContext, expression, 1);
if (!isPresent(p1)) {
p1 = {};
}
return new ViewQueryMetadata(p0, {
descendants: p1['descendants'],
first: p1['first'],
});
});
conversionMap.set(this.getStaticType(core_metadata, 'Pipe'), (moduleContext, expression) => {
let p0 = this.getDecoratorParameter(moduleContext, expression, 0);
if (!isPresent(p0)) {
p0 = {};
}
return new PipeMetadata({
name: p0['name'],
pure: p0['pure'],
});
});
conversionMap.set(this.getStaticType(core_metadata, 'HostBinding'),
(moduleContext, expression) => new HostBindingMetadata(
this.getDecoratorParameter(moduleContext, expression, 0)));
conversionMap.set(this.getStaticType(core_metadata, 'HostListener'),
(moduleContext, expression) => new HostListenerMetadata(
this.getDecoratorParameter(moduleContext, expression, 0),
this.getDecoratorParameter(moduleContext, expression, 1)));
return null;
}
private convertKnownDecorator(moduleContext: string, expression: {[key: string]: any}): any {
let converter = this.conversionMap.get(this.getDecoratorType(moduleContext, expression));
if (isPresent(converter)) return converter(moduleContext, expression);
return null;
}
private getDecoratorType(moduleContext: string, expression: {[key: string]: any}): StaticType {
if (isMetadataSymbolicCallExpression(expression)) {
let target = expression['expression'];
if (isMetadataSymbolicReferenceExpression(target)) {
let moduleId = this.host.resolveModule(target['module'], moduleContext);
return this.getStaticType(moduleId, target['name']);
}
}
return null;
}
private getDecoratorParameter(moduleContext: string, expression: {[key: string]: any},
index: number): any {
if (isMetadataSymbolicCallExpression(expression) && isPresent(expression['arguments']) &&
(<any[]>expression['arguments']).length <= index + 1) {
return this.simplify(moduleContext, (<any[]>expression['arguments'])[index]);
}
return null;
}
private getPropertyMetadata(moduleContext: string,
value: {[key: string]: any}): {[key: string]: any} {
if (isPresent(value)) {
let result = {};
StringMapWrapper.forEach(value, (value, name) => {
let data = this.getMemberData(moduleContext, value);
if (isPresent(data)) {
let propertyData = data.filter(d => d['kind'] == "property")
.map(d => d['directives'])
.reduce((p, c) => (<any[]>p).concat(<any[]>c), []);
if (propertyData.length != 0) {
StringMapWrapper.set(result, name, propertyData);
}
private registerDecoratorOrConstructor(type: StaticType, ctor: any,
crossModuleProps: any[] = CONST_EXPR([])): void {
this.conversionMap.set(type, (moduleContext: string, args: any[]) => {
let argValues = [];
ListWrapper.forEachWithIndex(args, (arg, index) => {
let argValue;
if (isStringMap(arg) && isBlank(arg['__symbolic'])) {
argValue =
mapStringMap(arg, (value, key) => this.simplify(
moduleContext, value, crossModuleProps.indexOf(key) !== -1));
} else {
argValue = this.simplify(moduleContext, arg, crossModuleProps.indexOf(index) !== -1);
}
argValues.push(argValue);
});
return result;
}
return {};
return FunctionWrapper.apply(reflector.factory(ctor), argValues);
});
}
// clang-format off
private getMemberData(moduleContext: string, member: { [key: string]: any }[]): { [key: string]: any }[] {
// clang-format on
let result = [];
if (isPresent(member)) {
for (let item of member) {
result.push({
kind: item['__symbolic'],
directives:
isPresent(item['decorators']) ?
(<any[]>item['decorators'])
.map(decorator => this.convertKnownDecorator(moduleContext, decorator))
.filter(d => isPresent(d)) :
null
});
}
}
return result;
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 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'),
InjectableMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Self'), SelfMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'SkipSelf'),
SkipSelfMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Inject'), InjectMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Optional'),
OptionalMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Attribute'),
AttributeMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Query'), QueryMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'ViewQuery'),
ViewQueryMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'ContentChild'),
ContentChildMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'ContentChildren'),
ContentChildrenMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'ViewChild'),
ViewChildMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'ViewChildren'),
ViewChildrenMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Input'), InputMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Output'),
OutputMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Pipe'), PipeMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'HostBinding'),
HostBindingMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'HostListener'),
HostListenerMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Directive'),
DirectiveMetadata, ['bindings', 'providers']);
this.registerDecoratorOrConstructor(this.getStaticType(coreDecorators, 'Component'),
ComponentMetadata,
['bindings', 'providers', 'directives', 'pipes']);
// Note: Some metadata classes can be used directly with Provider.deps.
this.registerDecoratorOrConstructor(this.getStaticType(diMetadata, 'HostMetadata'),
HostMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diMetadata, 'SelfMetadata'),
SelfMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diMetadata, 'SkipSelfMetadata'),
SkipSelfMetadata);
this.registerDecoratorOrConstructor(this.getStaticType(diMetadata, 'OptionalMetadata'),
OptionalMetadata);
}
/** @internal */
public simplify(moduleContext: string, value: any): any {
public simplify(moduleContext: string, value: any, crossModules: boolean): any {
let _this = this;
function simplify(expression: any): any {
@ -418,23 +332,44 @@ export class StaticReflector implements ReflectorReader {
if (isPresent(selectTarget) && isPrimitive(member)) return selectTarget[member];
return null;
case "reference":
let referenceModuleName =
_this.host.resolveModule(expression['module'], moduleContext);
let referenceModule = _this.getModuleMetadata(referenceModuleName);
let referenceValue = referenceModule['metadata'][expression['name']];
if (isClassMetadata(referenceValue)) {
// Convert to a pseudo type
return _this.getStaticType(referenceModuleName, expression['name']);
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'];
}
return _this.simplify(referenceModuleName, referenceValue);
let result;
if (crossModules || isBlank(expression['module'])) {
let moduleMetadata = _this.getModuleMetadata(declarationPath);
let declarationValue = moduleMetadata['metadata'][declaredName];
if (isClassMetadata(declarationValue)) {
result = _this.getStaticType(declarationPath, declaredName);
} else {
result = _this.simplify(declarationPath, declarationValue, crossModules);
}
} else {
result = _this.getStaticType(declarationPath, declaredName);
}
return result;
case "new":
case "call":
return null;
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);
let args = expression['arguments'];
if (isBlank(args)) {
args = [];
}
return isPresent(converter) ? converter(moduleContext, args) : null;
}
return null;
}
let result = {};
StringMapWrapper.forEach(expression, (value, name) => { result[name] = simplify(value); });
return result;
return mapStringMap(expression, (value, name) => simplify(value));
}
return null;
}
@ -467,15 +402,14 @@ export class StaticReflector implements ReflectorReader {
}
}
function isMetadataSymbolicCallExpression(expression: any): boolean {
return !isPrimitive(expression) && !isArray(expression) && expression['__symbolic'] == 'call';
}
function isMetadataSymbolicReferenceExpression(expression: any): boolean {
return !isPrimitive(expression) && !isArray(expression) &&
expression['__symbolic'] == 'reference';
}
function isClassMetadata(expression: any): boolean {
return !isPrimitive(expression) && !isArray(expression) && expression['__symbolic'] == 'class';
}
function mapStringMap(input: {[key: string]: any},
transform: (value: any, key: string) => any): {[key: string]: any} {
if (isBlank(input)) return {};
var result = {};
StringMapWrapper.keys(input).forEach((key) => { result[key] = transform(input[key], key); });
return result;
}