From 70b23ae2cad07600e787103a431e76871d69feb4 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Thu, 18 Feb 2016 10:53:21 -0800 Subject: [PATCH] refactor(compiler): make static reflector work Also adjust `RuntimeMetadataResolver` to be able to use it. Also rename `RuntimeMetadataResolver` into `CompileMetadataResolver`. Closes #8313 --- modules/angular2/src/compiler/compiler.ts | 4 +- ...ntime_metadata.ts => metadata_resolver.ts} | 144 ++++--- .../angular2/src/compiler/runtime_compiler.ts | 10 +- .../angular2/src/compiler/static_reflector.ts | 388 +++++++---------- ...re.dart => metadata_resolver_fixture.dart} | 2 +- ...ixture.ts => metadata_resolver_fixture.ts} | 0 ...data_spec.ts => metadata_resolver_spec.ts} | 18 +- .../test/compiler/static_reflector_spec.ts | 393 ++++++++---------- 8 files changed, 447 insertions(+), 512 deletions(-) rename modules/angular2/src/compiler/{runtime_metadata.ts => metadata_resolver.ts} (76%) rename modules/angular2/test/compiler/{runtime_metadata_fixture.dart => metadata_resolver_fixture.dart} (83%) rename modules/angular2/test/compiler/{runtime_metadata_fixture.ts => metadata_resolver_fixture.ts} (100%) rename modules/angular2/test/compiler/{runtime_metadata_spec.ts => metadata_resolver_spec.ts} (89%) diff --git a/modules/angular2/src/compiler/compiler.ts b/modules/angular2/src/compiler/compiler.ts index f063868a61..70ae659726 100644 --- a/modules/angular2/src/compiler/compiler.ts +++ b/modules/angular2/src/compiler/compiler.ts @@ -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 = CONST_EXPR([ HtmlParser, TemplateParser, DirectiveNormalizer, - RuntimeMetadataResolver, + CompileMetadataResolver, DEFAULT_PACKAGE_URL_PROVIDER, StyleCompiler, ViewCompiler, diff --git a/modules/angular2/src/compiler/runtime_metadata.ts b/modules/angular2/src/compiler/metadata_resolver.ts similarity index 76% rename from modules/angular2/src/compiler/runtime_metadata.ts rename to modules/angular2/src/compiler/metadata_resolver.ts index ea05bc88f0..c4ffca214f 100644 --- a/modules/angular2/src/compiler/runtime_metadata.ts +++ b/modules/angular2/src/compiler/metadata_resolver.ts @@ -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(); private _pipeCache = new Map(); private _anonymousTypes = new Map(); @@ -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 = 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 = 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)) { + (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): 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, diff --git a/modules/angular2/src/compiler/runtime_compiler.ts b/modules/angular2/src/compiler/runtime_compiler.ts index 706d961ab8..5d802fa2a7 100644 --- a/modules/angular2/src/compiler/runtime_compiler.ts +++ b/modules/angular2/src/compiler/runtime_compiler.ts @@ -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(); private _compiledTemplateDone = new Map>(); - 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 { 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); diff --git a/modules/angular2/src/compiler/static_reflector.ts b/modules/angular2/src/compiler/static_reflector.ts index 7092ef120f..23b8001574 100644 --- a/modules/angular2/src/compiler/static_reflector.ts +++ b/modules/angular2/src/compiler/static_reflector.ts @@ -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(); private parameterCache = new Map(); private metadataCache = new Map(); + private conversionMap = new Map any>(); + constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); } importUri(typeOrFunc: any): string { return (typeOrFunc).moduleId; } @@ -91,13 +110,11 @@ export class StaticReflector implements ReflectorReader { if (!isPresent(annotations)) { let classMetadata = this.getTypeMetadata(type); if (isPresent(classMetadata['decorators'])) { - annotations = (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 = (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 = (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 = (ctorData).find(a => a['__symbolic'] == 'constructor'); + let parameterTypes = this.simplify(type.moduleId, ctor['parameters'], false); + let parameterDecorators = + 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 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']) && - (expression['arguments']).length <= index + 1) { - return this.simplify(moduleContext, (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) => (p).concat(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']) ? - (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; +} diff --git a/modules/angular2/test/compiler/runtime_metadata_fixture.dart b/modules/angular2/test/compiler/metadata_resolver_fixture.dart similarity index 83% rename from modules/angular2/test/compiler/runtime_metadata_fixture.dart rename to modules/angular2/test/compiler/metadata_resolver_fixture.dart index b26f0f259a..bfc85acaee 100644 --- a/modules/angular2/test/compiler/runtime_metadata_fixture.dart +++ b/modules/angular2/test/compiler/metadata_resolver_fixture.dart @@ -1,4 +1,4 @@ -library angular2.test.compiler.runtime_metadata_fixture; +library angular2.test.compiler.metadata_resolver_fixture; import "package:angular2/core.dart" show Component; diff --git a/modules/angular2/test/compiler/runtime_metadata_fixture.ts b/modules/angular2/test/compiler/metadata_resolver_fixture.ts similarity index 100% rename from modules/angular2/test/compiler/runtime_metadata_fixture.ts rename to modules/angular2/test/compiler/metadata_resolver_fixture.ts diff --git a/modules/angular2/test/compiler/runtime_metadata_spec.ts b/modules/angular2/test/compiler/metadata_resolver_spec.ts similarity index 89% rename from modules/angular2/test/compiler/runtime_metadata_spec.ts rename to modules/angular2/test/compiler/metadata_resolver_spec.ts index ec2163ec73..a9efa58137 100644 --- a/modules/angular2/test/compiler/runtime_metadata_spec.ts +++ b/modules/angular2/test/compiler/metadata_resolver_spec.ts @@ -14,7 +14,7 @@ import { } from 'angular2/testing_internal'; import {IS_DART, stringify} from 'angular2/src/facade/lang'; -import {RuntimeMetadataResolver} from 'angular2/src/compiler/runtime_metadata'; +import {CompileMetadataResolver} from 'angular2/src/compiler/metadata_resolver'; import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/metadata/lifecycle_hooks'; import { Component, @@ -36,15 +36,15 @@ import { import {TEST_PROVIDERS} from './test_bindings'; import {MODULE_SUFFIX} from 'angular2/src/compiler/util'; import {PLATFORM_DIRECTIVES} from 'angular2/src/core/platform_directives_and_pipes'; -import {MalformedStylesComponent} from './runtime_metadata_fixture'; +import {MalformedStylesComponent} from './metadata_resolver_fixture'; export function main() { - describe('RuntimeMetadataResolver', () => { + describe('CompileMetadataResolver', () => { beforeEachProviders(() => TEST_PROVIDERS); describe('getMetadata', () => { it('should read metadata', - inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => { + inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { var meta = resolver.getDirectiveMetadata(ComponentWithEverything); expect(meta.selector).toEqual('someSelector'); expect(meta.exportAs).toEqual('someExportAs'); @@ -67,16 +67,16 @@ export function main() { })); it('should use the moduleUrl from the reflector if none is given', - inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => { + inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { var value: string = resolver.getDirectiveMetadata(ComponentWithoutModuleId).type.moduleUrl; var expectedEndValue = - IS_DART ? 'test/compiler/runtime_metadata_spec.dart' : './ComponentWithoutModuleId'; + IS_DART ? 'test/compiler/metadata_resolver_spec.dart' : './ComponentWithoutModuleId'; expect(value.endsWith(expectedEndValue)).toBe(true); })); it('should throw when metadata is incorrectly typed', - inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => { + inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { if (!IS_DART) { expect(() => resolver.getDirectiveMetadata(MalformedStylesComponent)) .toThrowError(`Expected 'styles' to be an array of strings.`); @@ -87,7 +87,7 @@ export function main() { describe('getViewDirectivesMetadata', () => { it('should return the directive metadatas', - inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => { + inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { expect(resolver.getViewDirectivesMetadata(ComponentWithEverything)) .toContain(resolver.getDirectiveMetadata(SomeDirective)); })); @@ -97,7 +97,7 @@ export function main() { () => [provide(PLATFORM_DIRECTIVES, {useValue: [ADirective], multi: true})]); it('should include platform directives when available', - inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => { + inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { expect(resolver.getViewDirectivesMetadata(ComponentWithEverything)) .toContain(resolver.getDirectiveMetadata(ADirective)); expect(resolver.getViewDirectivesMetadata(ComponentWithEverything)) diff --git a/modules/angular2/test/compiler/static_reflector_spec.ts b/modules/angular2/test/compiler/static_reflector_spec.ts index db4ebf939d..d6e3869aa4 100644 --- a/modules/angular2/test/compiler/static_reflector_spec.ts +++ b/modules/angular2/test/compiler/static_reflector_spec.ts @@ -1,18 +1,32 @@ -import { - describe, - it, - expect, -} from 'angular2/testing_internal'; +import {describe, it, iit, expect, ddescribe, beforeEach} from 'angular2/testing_internal'; +import {IS_DART} from 'angular2/src/facade/lang'; import {ListWrapper} from 'angular2/src/facade/collection'; import {StaticReflector, StaticReflectorHost} from 'angular2/src/compiler/static_reflector'; export function main() { - describe('StaticReflector', () => { - it('should get annotations for NgFor', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); + // Static reflector is not supported in Dart + // as we use reflection to create objects. + if (IS_DART) return; + describe('StaticReflector', () => { + let host: StaticReflectorHost; + let reflector: StaticReflector; + + beforeEach(() => { + host = new MockReflectorHost(); + reflector = new StaticReflector(host); + }); + + function singleModuleSimplify(moduleContext: string, value: any) { + return reflector.simplify(moduleContext, value, false); + } + + function crossModuleSimplify(moduleContext: string, value: any) { + return reflector.simplify(moduleContext, value, true); + } + + it('should get annotations for NgFor', () => { let NgFor = reflector.getStaticType( host.resolveModule('angular2/src/common/directives/ng_for'), 'NgFor'); let annotations = reflector.annotations(NgFor); @@ -20,12 +34,10 @@ export function main() { let annotation = annotations[0]; expect(annotation.selector).toEqual('[ngFor][ngForOf]'); expect(annotation.inputs).toEqual(['ngForTrackBy', 'ngForOf', 'ngForTemplate']); + }); it('should get constructor for NgFor', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - let NgFor = reflector.getStaticType( host.resolveModule('angular2/src/common/directives/ng_for'), 'NgFor'); let ViewContainerRef = reflector.getStaticType( @@ -41,34 +53,32 @@ export function main() { let parameters = reflector.parameters(NgFor); expect(parameters) - .toEqual([ViewContainerRef, TemplateRef, IterableDiffers, ChangeDetectorRef]); + .toEqual([[ViewContainerRef], [TemplateRef], [IterableDiffers], [ChangeDetectorRef]]); }); it('should get annotations for HeroDetailComponent', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - let HeroDetailComponent = reflector.getStaticType('/src/app/hero-detail.component.ts', 'HeroDetailComponent'); let annotations = reflector.annotations(HeroDetailComponent); expect(annotations.length).toEqual(1); let annotation = annotations[0]; expect(annotation.selector).toEqual('my-hero-detail'); + expect(annotation.directives) + .toEqual([ + [ + reflector.getStaticType(host.resolveModule('angular2/src/common/directives/ng_for'), + 'NgFor') + ] + ]); }); it('should get and empty annotation list for an unknown class', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - let UnknownClass = reflector.getStaticType('/src/app/app.component.ts', 'UnknownClass'); let annotations = reflector.annotations(UnknownClass); expect(annotations).toEqual([]); }); it('should get propMetadata for HeroDetailComponent', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - let HeroDetailComponent = reflector.getStaticType('/src/app/hero-detail.component.ts', 'HeroDetailComponent'); let props = reflector.propMetadata(HeroDetailComponent); @@ -76,254 +86,175 @@ export function main() { }); it('should get an empty object from propMetadata for an unknown class', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - let UnknownClass = reflector.getStaticType('/src/app/app.component.ts', 'UnknownClass'); let properties = reflector.propMetadata(UnknownClass); expect(properties).toEqual({}); }); it('should get empty parameters list for an unknown class ', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - let UnknownClass = reflector.getStaticType('/src/app/app.component.ts', 'UnknownClass'); let parameters = reflector.parameters(UnknownClass); expect(parameters).toEqual([]); }); it('should simplify primitive into itself', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', 1)).toBe(1); - expect(reflector.simplify('', true)).toBe(true); - expect(reflector.simplify('', "some value")).toBe("some value"); + expect(singleModuleSimplify('', 1)).toBe(1); + expect(singleModuleSimplify('', true)).toBe(true); + expect(singleModuleSimplify('', "some value")).toBe("some value"); }); - it('should simplify an array into a copy of the array', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', [1, 2, 3])).toEqual([1, 2, 3]); - }); + it('should simplify an array into a copy of the array', + () => { expect(singleModuleSimplify('', [1, 2, 3])).toEqual([1, 2, 3]); }); it('should simplify an object to a copy of the object', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); let expr = {a: 1, b: 2, c: 3}; - expect(reflector.simplify('', expr)).toEqual(expr); + expect(singleModuleSimplify('', expr)).toEqual(expr); }); it('should simplify &&', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '&&', left: true, right: true}))).toBe(true); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '&&', left: true, right: false}))).toBe(false); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '&&', left: false, right: true}))).toBe(false); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '&&', left: false, right: false}))).toBe(false); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '&&', left: true, right: true}))).toBe(true); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '&&', left: true, right: false}))).toBe(false); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '&&', left: false, right: true}))).toBe(false); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '&&', left: false, right: false}))).toBe(false); }); it('should simplify ||', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '||', left: true, right: true}))).toBe(true); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '||', left: true, right: false}))).toBe(true); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '||', left: false, right: true}))).toBe(true); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '||', left: false, right: false}))).toBe(false); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '||', left: true, right: true}))).toBe(true); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '||', left: true, right: false}))).toBe(true); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '||', left: false, right: true}))).toBe(true); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '||', left: false, right: false}))).toBe(false); }); it('should simplify &', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '&', left: 0x22, right: 0x0F}))).toBe(0x22 & 0x0F); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '&', left: 0x22, right: 0xF0}))).toBe(0x22 & 0xF0); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '&', left: 0x22, right: 0x0F}))).toBe(0x22 & 0x0F); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '&', left: 0x22, right: 0xF0}))).toBe(0x22 & 0xF0); }); it('should simplify |', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0x0F}))).toBe(0x22 | 0x0F); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0xF0}))).toBe(0x22 | 0xF0); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0x0F}))).toBe(0x22 | 0x0F); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0xF0}))).toBe(0x22 | 0xF0); }); it('should simplify ^', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0x0F}))).toBe(0x22 | 0x0F); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0xF0}))).toBe(0x22 | 0xF0); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0x0F}))).toBe(0x22 | 0x0F); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0xF0}))).toBe(0x22 | 0xF0); }); it('should simplify ==', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '==', left: 0x22, right: 0x22}))).toBe(0x22 == 0x22); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '==', left: 0x22, right: 0xF0}))).toBe(0x22 == 0xF0); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '==', left: 0x22, right: 0x22}))).toBe(0x22 == 0x22); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '==', left: 0x22, right: 0xF0}))).toBe(0x22 == 0xF0); }); it('should simplify !=', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '!=', left: 0x22, right: 0x22}))).toBe(0x22 != 0x22); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '!=', left: 0x22, right: 0xF0}))).toBe(0x22 != 0xF0); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '!=', left: 0x22, right: 0x22}))).toBe(0x22 != 0x22); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '!=', left: 0x22, right: 0xF0}))).toBe(0x22 != 0xF0); }); it('should simplify ===', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '===', left: 0x22, right: 0x22}))).toBe(0x22 === 0x22); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '===', left: 0x22, right: 0xF0}))).toBe(0x22 === 0xF0); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '===', left: 0x22, right: 0x22}))).toBe(0x22 === 0x22); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '===', left: 0x22, right: 0xF0}))).toBe(0x22 === 0xF0); }); it('should simplify !==', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '!==', left: 0x22, right: 0x22}))).toBe(0x22 !== 0x22); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '!==', left: 0x22, right: 0xF0}))).toBe(0x22 !== 0xF0); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '!==', left: 0x22, right: 0x22}))).toBe(0x22 !== 0x22); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '!==', left: 0x22, right: 0xF0}))).toBe(0x22 !== 0xF0); }); it('should simplify >', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '>', left: 1, right: 1}))).toBe(1 > 1); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '>', left: 1, right: 0}))).toBe(1 > 0); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '>', left: 0, right: 1}))).toBe(0 > 1); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>', left: 1, right: 1}))).toBe(1 > 1); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>', left: 1, right: 0}))).toBe(1 > 0); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>', left: 0, right: 1}))).toBe(0 > 1); }); it('should simplify >=', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '>=', left: 1, right: 1}))).toBe(1 >= 1); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '>=', left: 1, right: 0}))).toBe(1 >= 0); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '>=', left: 0, right: 1}))).toBe(0 >= 1); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>=', left: 1, right: 1}))).toBe(1 >= 1); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>=', left: 1, right: 0}))).toBe(1 >= 0); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>=', left: 0, right: 1}))).toBe(0 >= 1); }); it('should simplify <=', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '<=', left: 1, right: 1}))).toBe(1 <= 1); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '<=', left: 1, right: 0}))).toBe(1 <= 0); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '<=', left: 0, right: 1}))).toBe(0 <= 1); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<=', left: 1, right: 1}))).toBe(1 <= 1); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<=', left: 1, right: 0}))).toBe(1 <= 0); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<=', left: 0, right: 1}))).toBe(0 <= 1); }); it('should simplify <', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '<', left: 1, right: 1}))).toBe(1 < 1); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '<', left: 1, right: 0}))).toBe(1 < 0); - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '<', left: 0, right: 1}))).toBe(0 < 1); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<', left: 1, right: 1}))).toBe(1 < 1); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<', left: 1, right: 0}))).toBe(1 < 0); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<', left: 0, right: 1}))).toBe(0 < 1); }); it('should simplify <<', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '<<', left: 0x55, right: 2}))).toBe(0x55 << 2); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<<', left: 0x55, right: 2}))).toBe(0x55 << 2); }); it('should simplify >>', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '>>', left: 0x55, right: 2}))).toBe(0x55 >> 2); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>>', left: 0x55, right: 2}))).toBe(0x55 >> 2); }); it('should simplify +', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '+', left: 0x55, right: 2}))).toBe(0x55 + 2); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '+', left: 0x55, right: 2}))).toBe(0x55 + 2); }); it('should simplify -', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '-', left: 0x55, right: 2}))).toBe(0x55 - 2); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '-', left: 0x55, right: 2}))).toBe(0x55 - 2); }); it('should simplify *', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '*', left: 0x55, right: 2}))).toBe(0x55 * 2); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '*', left: 0x55, right: 2}))).toBe(0x55 * 2); }); it('should simplify /', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '/', left: 0x55, right: 2}))).toBe(0x55 / 2); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '/', left: 0x55, right: 2}))).toBe(0x55 / 2); }); it('should simplify %', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '%', left: 0x55, right: 2}))).toBe(0x55 % 2); + expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '%', left: 0x55, right: 2}))).toBe(0x55 % 2); }); it('should simplify prefix -', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'pre', operator: '-', operand: 2}))).toBe(-2); + expect(singleModuleSimplify('', ({ __symbolic: 'pre', operator: '-', operand: 2}))).toBe(-2); }); it('should simplify prefix ~', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'pre', operator: '~', operand: 2}))).toBe(~2); + expect(singleModuleSimplify('', ({ __symbolic: 'pre', operator: '~', operand: 2}))).toBe(~2); }); it('should simplify prefix !', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({ __symbolic: 'pre', operator: '!', operand: true}))).toBe(!true); - expect(reflector.simplify('', ({ __symbolic: 'pre', operator: '!', operand: false}))).toBe(!false); + expect(singleModuleSimplify('', ({ __symbolic: 'pre', operator: '!', operand: true}))).toBe(!true); + expect(singleModuleSimplify('', ({ __symbolic: 'pre', operator: '!', operand: false}))).toBe(!false); }); it('should simplify an array index', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('', ({__symbolic: "index", expression: [1, 2, 3], index: 2}))) + expect(singleModuleSimplify('', ({__symbolic: "index", expression: [1, 2, 3], index: 2}))) .toBe(3); }); it('should simplify an object index', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); let expr = {__symbolic: "select", expression: {a: 1, b: 2, c: 3}, member: "b"}; - expect(reflector.simplify('', expr)).toBe(2); + expect(singleModuleSimplify('', expr)).toBe(2); }); - it('should simplify a module reference', () => { - let host = new MockReflectorHost(); - let reflector = new StaticReflector(host); - - expect(reflector.simplify('/src/cases', - ({__symbolic: "reference", module: "./extern", name: "s"}))) + it('should simplify a module reference across modules', () => { + expect(crossModuleSimplify('/src/cases', + ({__symbolic: "reference", module: "./extern", name: "s"}))) .toEqual("s"); }); + + it('should simplify a module reference without crossing modules', () => { + expect(singleModuleSimplify('/src/cases', + ({__symbolic: "reference", module: "./extern", name: "s"}))) + .toEqual(reflector.getStaticType('/src/extern.d.ts', 's')); + }); }); } class MockReflectorHost implements StaticReflectorHost { + // In tests, assume that symbols are not re-exported + findDeclaration(modulePath: string, + symbolName: string): {declarationPath: string, declaredName: string} { + return {declarationPath: modulePath, declaredName: symbolName}; + } resolveModule(moduleName: string, containingFile?: string): string { function splitPath(path: string): string[] { return path.split(/\/|\\/g); } @@ -363,68 +294,80 @@ class MockReflectorHost implements StaticReflectorHost { getMetadataFor(moduleId: string): any { return { - '/tmp/angular2/src/common/directives/ng_for.d.ts': + '/tmp/angular2/src/common/forms/directives.d.ts': { "__symbolic": "module", - "metadata": + "metadata": { + "FORM_DIRECTIVES": [ { - "NgFor": - { - "__symbolic": "class", - "decorators": - [ - { - "__symbolic": "call", - "expression": { - "__symbolic": "reference", - "name": "Directive", - "module": "../../core/metadata" - }, - "arguments": - [ + "__symbolic": "reference", + "name": "NgFor", + "module": "angular2/src/common/directives/ng_for" + } + ] + } + }, + '/tmp/angular2/src/common/directives/ng_for.d.ts': + { + "__symbolic": "module", + "metadata": + { + "NgFor": + { + "__symbolic": "class", + "decorators": + [ + { + "__symbolic": "call", + "expression": { + "__symbolic": "reference", + "name": "Directive", + "module": "../../core/metadata" + }, + "arguments": [ { "selector": "[ngFor][ngForOf]", "inputs": ["ngForTrackBy", "ngForOf", "ngForTemplate"] } ] - } - ], - "members": - { - "__ctor__": [ + } + ], + "members": { - "__symbolic": "constructor", - "parameters": - [ - { - "__symbolic": "reference", - "module": "../../core/linker/view_container_ref", - "name": "ViewContainerRef" - }, - { - "__symbolic": "reference", - "module": "../../core/linker/template_ref", - "name": "TemplateRef" - }, - { - "__symbolic": "reference", - "module": - "../../core/change_detection/differs/iterable_differs", - "name": "IterableDiffers" - }, - { - "__symbolic": "reference", - "module": - "../../core/change_detection/change_detector_ref", - "name": "ChangeDetectorRef" - } - ] + "__ctor__": [ + { + "__symbolic": "constructor", + "parameters": + [ + { + "__symbolic": "reference", + "module": "../../core/linker/view_container_ref", + "name": "ViewContainerRef" + }, + { + "__symbolic": "reference", + "module": "../../core/linker/template_ref", + "name": "TemplateRef" + }, + { + "__symbolic": "reference", + "module": + "../../core/change_detection/differs/iterable_differs", + "name": "IterableDiffers" + }, + { + "__symbolic": "reference", + "module": + "../../core/change_detection/change_detector_ref", + "name": "ChangeDetectorRef" + } + ] + } + ] } - ] - } - } - } - }, + } + } + }, '/tmp/angular2/src/core/linker/view_container_ref.d.ts': {"metadata": {"ViewContainerRef": {"__symbolic": "class"}}}, '/tmp/angular2/src/core/linker/template_ref.d.ts': @@ -453,7 +396,15 @@ class MockReflectorHost implements StaticReflectorHost { "arguments": [ { "selector": "my-hero-detail", - "template": "\n
\n

{{hero.name}} details!

\n
{{hero.id}}
\n
\n \n \n
\n
\n" + "template": "\n
\n

{{hero.name}} details!

\n
{{hero.id}}
\n
\n \n \n
\n
\n", + "directives": + [ + { + "__symbolic": "reference", + "name": "FORM_DIRECTIVES", + "module": "angular2/src/common/forms/directives" + } + ] } ] }