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

View File

@ -6,12 +6,12 @@ import {
isArray, isArray,
stringify, stringify,
isString, isString,
isStringMap,
RegExpWrapper, RegExpWrapper,
StringWrapper StringWrapper
} from 'angular2/src/facade/lang'; } from 'angular2/src/facade/lang';
import {StringMapWrapper} from 'angular2/src/facade/collection'; import {StringMapWrapper} from 'angular2/src/facade/collection';
import {BaseException} from 'angular2/src/facade/exceptions'; import {BaseException} from 'angular2/src/facade/exceptions';
import {NoAnnotationError} from 'angular2/src/core/di/reflective_exceptions';
import * as cpl from './compile_metadata'; import * as cpl from './compile_metadata';
import * as md from 'angular2/src/core/metadata/directives'; import * as md from 'angular2/src/core/metadata/directives';
import * as dimd from 'angular2/src/core/metadata/di'; import * as dimd from 'angular2/src/core/metadata/di';
@ -28,20 +28,18 @@ import {MODULE_SUFFIX, sanitizeIdentifier} from './util';
import {assertArrayOfStrings} from './assertions'; import {assertArrayOfStrings} from './assertions';
import {getUrlScheme} from 'angular2/src/compiler/url_resolver'; import {getUrlScheme} from 'angular2/src/compiler/url_resolver';
import {Provider} from 'angular2/src/core/di/provider'; import {Provider} from 'angular2/src/core/di/provider';
import {
constructDependencies,
ReflectiveDependency
} from 'angular2/src/core/di/reflective_provider';
import { import {
OptionalMetadata, OptionalMetadata,
SelfMetadata, SelfMetadata,
HostMetadata, HostMetadata,
SkipSelfMetadata SkipSelfMetadata,
InjectMetadata
} from 'angular2/src/core/di/metadata'; } from 'angular2/src/core/di/metadata';
import {AttributeMetadata, QueryMetadata} from 'angular2/src/core/metadata/di';
import {ReflectorReader} from 'angular2/src/core/reflection/reflector_reader'; import {ReflectorReader} from 'angular2/src/core/reflection/reflector_reader';
@Injectable() @Injectable()
export class RuntimeMetadataResolver { export class CompileMetadataResolver {
private _directiveCache = new Map<Type, cpl.CompileDirectiveMetadata>(); private _directiveCache = new Map<Type, cpl.CompileDirectiveMetadata>();
private _pipeCache = new Map<Type, cpl.CompilePipeMetadata>(); private _pipeCache = new Map<Type, cpl.CompilePipeMetadata>();
private _anonymousTypes = new Map<Object, number>(); private _anonymousTypes = new Map<Object, number>();
@ -78,7 +76,7 @@ export class RuntimeMetadataResolver {
var meta = this._directiveCache.get(directiveType); var meta = this._directiveCache.get(directiveType);
if (isBlank(meta)) { if (isBlank(meta)) {
var dirMeta = this._directiveResolver.resolve(directiveType); var dirMeta = this._directiveResolver.resolve(directiveType);
var moduleUrl = null; var moduleUrl = staticTypeModuleUrl(directiveType);
var templateMeta = null; var templateMeta = null;
var changeDetectionStrategy = null; var changeDetectionStrategy = null;
var viewProviders = []; var viewProviders = [];
@ -134,6 +132,21 @@ export class RuntimeMetadataResolver {
return meta; 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 { getTypeMetadata(type: Type, moduleUrl: string): cpl.CompileTypeMetadata {
return new cpl.CompileTypeMetadata({ return new cpl.CompileTypeMetadata({
name: this.sanitizeTokenName(type), name: this.sanitizeTokenName(type),
@ -156,9 +169,8 @@ export class RuntimeMetadataResolver {
var meta = this._pipeCache.get(pipeType); var meta = this._pipeCache.get(pipeType);
if (isBlank(meta)) { if (isBlank(meta)) {
var pipeMeta = this._pipeResolver.resolve(pipeType); var pipeMeta = this._pipeResolver.resolve(pipeType);
var moduleUrl = this._reflector.importUri(pipeType);
meta = new cpl.CompilePipeMetadata({ meta = new cpl.CompilePipeMetadata({
type: this.getTypeMetadata(pipeType, moduleUrl), type: this.getTypeMetadata(pipeType, staticTypeModuleUrl(pipeType)),
name: pipeMeta.name, name: pipeMeta.name,
pure: pipeMeta.pure, pure: pipeMeta.pure,
lifecycleHooks: LIFECYCLE_HOOKS_VALUES.filter(hook => hasLifecycleHook(hook, pipeType)), 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)}'`); `Unexpected directive value '${stringify(directives[i])}' on the View of component '${stringify(component)}'`);
} }
} }
return directives.map(type => this.getDirectiveMetadata(type)); return directives.map(type => this.getDirectiveMetadata(type));
} }
@ -195,41 +206,65 @@ export class RuntimeMetadataResolver {
getDependenciesMetadata(typeOrFunc: Type | Function, getDependenciesMetadata(typeOrFunc: Type | Function,
dependencies: any[]): cpl.CompileDiDependencyMetadata[] { dependencies: any[]): cpl.CompileDiDependencyMetadata[] {
var deps: ReflectiveDependency[]; let params = isPresent(dependencies) ? dependencies : this._reflector.parameters(typeOrFunc);
try { if (isBlank(params)) {
deps = constructDependencies(typeOrFunc, dependencies); params = [];
} catch (e) {
if (e instanceof NoAnnotationError) {
deps = [];
} else {
throw e;
}
} }
return deps.map((dep) => { return params.map((param) => {
var compileToken; if (isBlank(param)) {
var p = <dimd.AttributeMetadata>dep.properties.find(p => p instanceof dimd.AttributeMetadata); return null;
var isAttribute = false;
if (isPresent(p)) {
compileToken = this.getTokenMetadata(p.attributeName);
isAttribute = true;
} else {
compileToken = this.getTokenMetadata(dep.key.token);
} }
var compileQuery = null; let isAttribute = false;
var q = <dimd.QueryMetadata>dep.properties.find(p => p instanceof dimd.QueryMetadata); let isHost = false;
if (isPresent(q)) { let isSelf = false;
compileQuery = this.getQueryMetadata(q, null); 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({ return new cpl.CompileDiDependencyMetadata({
isAttribute: isAttribute, isAttribute: isAttribute,
isHost: dep.upperBoundVisibility instanceof HostMetadata, isHost: isHost,
isSelf: dep.upperBoundVisibility instanceof SelfMetadata, isSelf: isSelf,
isSkipSelf: dep.lowerBoundVisibility instanceof SkipSelfMetadata, isSkipSelf: isSkipSelf,
isOptional: dep.optional, isOptional: isOptional,
query: isPresent(q) && !q.isViewQuery ? compileQuery : null, query: isPresent(query) ? this.getQueryMetadata(query, null) : null,
viewQuery: isPresent(q) && q.isViewQuery ? compileQuery : null, viewQuery: isPresent(viewQuery) ? this.getQueryMetadata(viewQuery, null) : null,
token: compileToken token: this.getTokenMetadata(token)
}); });
}); });
} }
@ -240,8 +275,11 @@ export class RuntimeMetadataResolver {
compileToken = new cpl.CompileTokenMetadata({value: token}); compileToken = new cpl.CompileTokenMetadata({value: token});
} else { } else {
compileToken = new cpl.CompileTokenMetadata({ compileToken = new cpl.CompileTokenMetadata({
identifier: new cpl.CompileIdentifierMetadata( identifier: new cpl.CompileIdentifierMetadata({
{runtime: token, name: this.sanitizeTokenName(token)}) runtime: token,
name: this.sanitizeTokenName(token),
moduleUrl: staticTypeModuleUrl(token)
})
}); });
} }
return compileToken; return compileToken;
@ -256,7 +294,7 @@ export class RuntimeMetadataResolver {
} else if (provider instanceof Provider) { } else if (provider instanceof Provider) {
return this.getProviderMetadata(provider); return this.getProviderMetadata(provider);
} else { } else {
return this.getTypeMetadata(provider, null); return this.getTypeMetadata(provider, staticTypeModuleUrl(provider));
} }
}); });
} }
@ -270,12 +308,16 @@ export class RuntimeMetadataResolver {
} }
return new cpl.CompileProviderMetadata({ return new cpl.CompileProviderMetadata({
token: this.getTokenMetadata(provider.token), 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) ? useValue: isPresent(provider.useValue) ?
new cpl.CompileIdentifierMetadata({runtime: provider.useValue}) : new cpl.CompileIdentifierMetadata({runtime: provider.useValue}) :
null, null,
useFactory: isPresent(provider.useFactory) ? useFactory: isPresent(provider.useFactory) ?
this.getFactoryMetadata(provider.useFactory, null) : this.getFactoryMetadata(provider.useFactory,
staticTypeModuleUrl(provider.useFactory)) :
null, null,
useExisting: isPresent(provider.useExisting) ? this.getTokenMetadata(provider.useExisting) : useExisting: isPresent(provider.useExisting) ? this.getTokenMetadata(provider.useExisting) :
null, null,
@ -345,8 +387,16 @@ function flattenArray(tree: any[], out: Array<Type | any[]>): void {
} }
} }
function isValidType(value: Type): boolean { function isStaticType(value: any): boolean {
return isPresent(value) && (value instanceof Type); 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, 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 {ViewCompiler} from './view_compiler/view_compiler';
import {TemplateParser} from './template_parser'; import {TemplateParser} from './template_parser';
import {DirectiveNormalizer} from './directive_normalizer'; 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 {ComponentFactory} from 'angular2/src/core/linker/component_factory';
import { import {
ComponentResolver, ComponentResolver,
@ -71,7 +71,7 @@ export class RuntimeCompiler implements ComponentResolver {
private _compiledTemplateCache = new Map<any, CompiledTemplate>(); private _compiledTemplateCache = new Map<any, CompiledTemplate>();
private _compiledTemplateDone = new Map<any, Promise<CompiledTemplate>>(); private _compiledTemplateDone = new Map<any, Promise<CompiledTemplate>>();
constructor(private _runtimeMetadataResolver: RuntimeMetadataResolver, constructor(private _metadataResolver: CompileMetadataResolver,
private _templateNormalizer: DirectiveNormalizer, private _templateNormalizer: DirectiveNormalizer,
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler, private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
private _viewCompiler: ViewCompiler, private _xhr: XHR, private _viewCompiler: ViewCompiler, private _xhr: XHR,
@ -79,7 +79,7 @@ export class RuntimeCompiler implements ComponentResolver {
resolveComponent(componentType: Type): Promise<ComponentFactory> { resolveComponent(componentType: Type): Promise<ComponentFactory> {
var compMeta: CompileDirectiveMetadata = var compMeta: CompileDirectiveMetadata =
this._runtimeMetadataResolver.getDirectiveMetadata(componentType); this._metadataResolver.getDirectiveMetadata(componentType);
var hostCacheKey = this._hostCacheKeys.get(componentType); var hostCacheKey = this._hostCacheKeys.get(componentType);
if (isBlank(hostCacheKey)) { if (isBlank(hostCacheKey)) {
hostCacheKey = new Object(); hostCacheKey = new Object();
@ -146,9 +146,9 @@ export class RuntimeCompiler implements ComponentResolver {
var childCacheKey = dep.comp.type.runtime; var childCacheKey = dep.comp.type.runtime;
var childViewDirectives: CompileDirectiveMetadata[] = var childViewDirectives: CompileDirectiveMetadata[] =
this._runtimeMetadataResolver.getViewDirectivesMetadata(dep.comp.type.runtime); this._metadataResolver.getViewDirectivesMetadata(dep.comp.type.runtime);
var childViewPipes: CompilePipeMetadata[] = var childViewPipes: CompilePipeMetadata[] =
this._runtimeMetadataResolver.getViewPipesMetadata(dep.comp.type.runtime); this._metadataResolver.getViewPipesMetadata(dep.comp.type.runtime);
var childIsRecursive = ListWrapper.contains(childCompilingComponentsPath, childCacheKey); var childIsRecursive = ListWrapper.contains(childCompilingComponentsPath, childCacheKey);
childCompilingComponentsPath.push(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 { import {
isArray, isArray,
isPresent, isPresent,
isBlank,
isPrimitive, isPrimitive,
isStringMap,
CONST_EXPR,
FunctionWrapper
} from 'angular2/src/facade/lang'; } from 'angular2/src/facade/lang';
import { import {
AttributeMetadata, AttributeMetadata,
@ -22,6 +26,16 @@ import {
QueryMetadata, QueryMetadata,
} from 'angular2/src/core/metadata'; } from 'angular2/src/core/metadata';
import {ReflectorReader} from 'angular2/src/core/reflection/reflector_reader'; 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 * 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. * @param moduleId is a string identifier for a module as an absolute path.
* @returns the metadata for the given module. * @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. * 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 * @param containingFile for relative imports, the path of the file containing the import
*/ */
resolveModule(moduleName: string, containingFile?: string): string; 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 propertyCache = new Map<StaticType, {[key: string]: any}>();
private parameterCache = new Map<StaticType, any[]>(); private parameterCache = new Map<StaticType, any[]>();
private metadataCache = new Map<string, {[key: string]: 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(); } constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); }
importUri(typeOrFunc: any): string { return (<StaticType>typeOrFunc).moduleId; } importUri(typeOrFunc: any): string { return (<StaticType>typeOrFunc).moduleId; }
@ -91,13 +110,11 @@ export class StaticReflector implements ReflectorReader {
if (!isPresent(annotations)) { if (!isPresent(annotations)) {
let classMetadata = this.getTypeMetadata(type); let classMetadata = this.getTypeMetadata(type);
if (isPresent(classMetadata['decorators'])) { if (isPresent(classMetadata['decorators'])) {
annotations = (<any[]>classMetadata['decorators']) annotations = this.simplify(type.moduleId, classMetadata['decorators'], false);
.map(decorator => this.convertKnownDecorator(type.moduleId, decorator))
.filter(decorator => isPresent(decorator));
} else { } else {
annotations = []; annotations = [];
} }
this.annotationCache.set(type, annotations); this.annotationCache.set(type, annotations.filter(ann => isPresent(ann)));
} }
return annotations; return annotations;
} }
@ -106,10 +123,15 @@ export class StaticReflector implements ReflectorReader {
let propMetadata = this.propertyCache.get(type); let propMetadata = this.propertyCache.get(type);
if (!isPresent(propMetadata)) { if (!isPresent(propMetadata)) {
let classMetadata = this.getTypeMetadata(type); let classMetadata = this.getTypeMetadata(type);
propMetadata = this.getPropertyMetadata(type.moduleId, classMetadata['members']); let members = isPresent(classMetadata) ? classMetadata['members'] : {};
if (!isPresent(propMetadata)) { propMetadata = mapStringMap(members, (propData, propName) => {
propMetadata = {}; 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); this.propertyCache.set(type, propMetadata);
} }
return propMetadata; return propMetadata;
@ -119,15 +141,26 @@ export class StaticReflector implements ReflectorReader {
let parameters = this.parameterCache.get(type); let parameters = this.parameterCache.get(type);
if (!isPresent(parameters)) { if (!isPresent(parameters)) {
let classMetadata = this.getTypeMetadata(type); let classMetadata = this.getTypeMetadata(type);
if (isPresent(classMetadata)) { let members = isPresent(classMetadata) ? classMetadata['members'] : null;
let members = classMetadata['members']; let ctorData = isPresent(members) ? members['__ctor__'] : null;
if (isPresent(members)) { if (isPresent(ctorData)) {
let ctorData = members['__ctor__']; let ctor = (<any[]>ctorData).find(a => a['__symbolic'] == 'constructor');
if (isPresent(ctorData)) { let parameterTypes = <any[]>this.simplify(type.moduleId, ctor['parameters'], false);
let ctor = (<any[]>ctorData).find(a => a['__symbolic'] === 'constructor'); let parameterDecorators =
parameters = this.simplify(type.moduleId, ctor['parameters']); <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)) { if (!isPresent(parameters)) {
parameters = []; parameters = [];
@ -137,201 +170,82 @@ export class StaticReflector implements ReflectorReader {
return parameters; return parameters;
} }
private conversionMap = new Map<StaticType, (moduleContext: string, expression: any) => any>(); private registerDecoratorOrConstructor(type: StaticType, ctor: any,
private initializeConversionMap(): any { crossModuleProps: any[] = CONST_EXPR([])): void {
let core_metadata = this.host.resolveModule('angular2/src/core/metadata'); this.conversionMap.set(type, (moduleContext: string, args: any[]) => {
let conversionMap = this.conversionMap; let argValues = [];
conversionMap.set(this.getStaticType(core_metadata, 'Directive'), ListWrapper.forEachWithIndex(args, (arg, index) => {
(moduleContext, expression) => { let argValue;
let p0 = this.getDecoratorParameter(moduleContext, expression, 0); if (isStringMap(arg) && isBlank(arg['__symbolic'])) {
if (!isPresent(p0)) { argValue =
p0 = {}; mapStringMap(arg, (value, key) => this.simplify(
} moduleContext, value, crossModuleProps.indexOf(key) !== -1));
return new DirectiveMetadata({ } else {
selector: p0['selector'], argValue = this.simplify(moduleContext, arg, crossModuleProps.indexOf(index) !== -1);
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);
}
} }
argValues.push(argValue);
}); });
return result; return FunctionWrapper.apply(reflector.factory(ctor), argValues);
} });
return {};
} }
// clang-format off private initializeConversionMap(): void {
private getMemberData(moduleContext: string, member: { [key: string]: any }[]): { [key: string]: any }[] { let coreDecorators = this.host.resolveModule('angular2/src/core/metadata');
// clang-format on let diDecorators = this.host.resolveModule('angular2/src/core/di/decorators');
let result = []; let diMetadata = this.host.resolveModule('angular2/src/core/di/metadata');
if (isPresent(member)) {
for (let item of member) { let provider = this.host.resolveModule('angular2/src/core/di/provider');
result.push({ this.registerDecoratorOrConstructor(this.getStaticType(provider, 'Provider'), Provider);
kind: item['__symbolic'],
directives: this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Host'), HostMetadata);
isPresent(item['decorators']) ? this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Injectable'),
(<any[]>item['decorators']) InjectableMetadata);
.map(decorator => this.convertKnownDecorator(moduleContext, decorator)) this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Self'), SelfMetadata);
.filter(d => isPresent(d)) : this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'SkipSelf'),
null SkipSelfMetadata);
}); this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Inject'), InjectMetadata);
} this.registerDecoratorOrConstructor(this.getStaticType(diDecorators, 'Optional'),
} OptionalMetadata);
return result; 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 */ /** @internal */
public simplify(moduleContext: string, value: any): any { public simplify(moduleContext: string, value: any, crossModules: boolean): any {
let _this = this; let _this = this;
function simplify(expression: any): any { function simplify(expression: any): any {
@ -418,23 +332,44 @@ export class StaticReflector implements ReflectorReader {
if (isPresent(selectTarget) && isPrimitive(member)) return selectTarget[member]; if (isPresent(selectTarget) && isPrimitive(member)) return selectTarget[member];
return null; return null;
case "reference": case "reference":
let referenceModuleName = let referenceModuleName;
_this.host.resolveModule(expression['module'], moduleContext); let declarationPath = moduleContext;
let referenceModule = _this.getModuleMetadata(referenceModuleName); let declaredName = expression['name'];
let referenceValue = referenceModule['metadata'][expression['name']]; if (isPresent(expression['module'])) {
if (isClassMetadata(referenceValue)) { referenceModuleName = _this.host.resolveModule(expression['module'], moduleContext);
// Convert to a pseudo type let decl = _this.host.findDeclaration(referenceModuleName, expression['name']);
return _this.getStaticType(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": 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; return null;
} }
let result = {}; return mapStringMap(expression, (value, name) => simplify(value));
StringMapWrapper.forEach(expression, (value, name) => { result[name] = simplify(value); });
return result;
} }
return null; 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 { function isClassMetadata(expression: any): boolean {
return !isPrimitive(expression) && !isArray(expression) && expression['__symbolic'] == 'class'; 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;
}

View File

@ -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; import "package:angular2/core.dart" show Component;

View File

@ -14,7 +14,7 @@ import {
} from 'angular2/testing_internal'; } from 'angular2/testing_internal';
import {IS_DART, stringify} from 'angular2/src/facade/lang'; 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 {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/metadata/lifecycle_hooks';
import { import {
Component, Component,
@ -36,15 +36,15 @@ import {
import {TEST_PROVIDERS} from './test_bindings'; import {TEST_PROVIDERS} from './test_bindings';
import {MODULE_SUFFIX} from 'angular2/src/compiler/util'; import {MODULE_SUFFIX} from 'angular2/src/compiler/util';
import {PLATFORM_DIRECTIVES} from 'angular2/src/core/platform_directives_and_pipes'; 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() { export function main() {
describe('RuntimeMetadataResolver', () => { describe('CompileMetadataResolver', () => {
beforeEachProviders(() => TEST_PROVIDERS); beforeEachProviders(() => TEST_PROVIDERS);
describe('getMetadata', () => { describe('getMetadata', () => {
it('should read metadata', it('should read metadata',
inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => { inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
var meta = resolver.getDirectiveMetadata(ComponentWithEverything); var meta = resolver.getDirectiveMetadata(ComponentWithEverything);
expect(meta.selector).toEqual('someSelector'); expect(meta.selector).toEqual('someSelector');
expect(meta.exportAs).toEqual('someExportAs'); expect(meta.exportAs).toEqual('someExportAs');
@ -67,16 +67,16 @@ export function main() {
})); }));
it('should use the moduleUrl from the reflector if none is given', it('should use the moduleUrl from the reflector if none is given',
inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => { inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
var value: string = var value: string =
resolver.getDirectiveMetadata(ComponentWithoutModuleId).type.moduleUrl; resolver.getDirectiveMetadata(ComponentWithoutModuleId).type.moduleUrl;
var expectedEndValue = 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); expect(value.endsWith(expectedEndValue)).toBe(true);
})); }));
it('should throw when metadata is incorrectly typed', it('should throw when metadata is incorrectly typed',
inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => { inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
if (!IS_DART) { if (!IS_DART) {
expect(() => resolver.getDirectiveMetadata(MalformedStylesComponent)) expect(() => resolver.getDirectiveMetadata(MalformedStylesComponent))
.toThrowError(`Expected 'styles' to be an array of strings.`); .toThrowError(`Expected 'styles' to be an array of strings.`);
@ -87,7 +87,7 @@ export function main() {
describe('getViewDirectivesMetadata', () => { describe('getViewDirectivesMetadata', () => {
it('should return the directive metadatas', it('should return the directive metadatas',
inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => { inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
expect(resolver.getViewDirectivesMetadata(ComponentWithEverything)) expect(resolver.getViewDirectivesMetadata(ComponentWithEverything))
.toContain(resolver.getDirectiveMetadata(SomeDirective)); .toContain(resolver.getDirectiveMetadata(SomeDirective));
})); }));
@ -97,7 +97,7 @@ export function main() {
() => [provide(PLATFORM_DIRECTIVES, {useValue: [ADirective], multi: true})]); () => [provide(PLATFORM_DIRECTIVES, {useValue: [ADirective], multi: true})]);
it('should include platform directives when available', it('should include platform directives when available',
inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => { inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
expect(resolver.getViewDirectivesMetadata(ComponentWithEverything)) expect(resolver.getViewDirectivesMetadata(ComponentWithEverything))
.toContain(resolver.getDirectiveMetadata(ADirective)); .toContain(resolver.getDirectiveMetadata(ADirective));
expect(resolver.getViewDirectivesMetadata(ComponentWithEverything)) expect(resolver.getViewDirectivesMetadata(ComponentWithEverything))

View File

@ -1,18 +1,32 @@
import { import {describe, it, iit, expect, ddescribe, beforeEach} from 'angular2/testing_internal';
describe, import {IS_DART} from 'angular2/src/facade/lang';
it,
expect,
} from 'angular2/testing_internal';
import {ListWrapper} from 'angular2/src/facade/collection'; import {ListWrapper} from 'angular2/src/facade/collection';
import {StaticReflector, StaticReflectorHost} from 'angular2/src/compiler/static_reflector'; import {StaticReflector, StaticReflectorHost} from 'angular2/src/compiler/static_reflector';
export function main() { export function main() {
describe('StaticReflector', () => { // Static reflector is not supported in Dart
it('should get annotations for NgFor', () => { // as we use reflection to create objects.
let host = new MockReflectorHost(); if (IS_DART) return;
let reflector = new StaticReflector(host);
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( let NgFor = reflector.getStaticType(
host.resolveModule('angular2/src/common/directives/ng_for'), 'NgFor'); host.resolveModule('angular2/src/common/directives/ng_for'), 'NgFor');
let annotations = reflector.annotations(NgFor); let annotations = reflector.annotations(NgFor);
@ -20,12 +34,10 @@ export function main() {
let annotation = annotations[0]; let annotation = annotations[0];
expect(annotation.selector).toEqual('[ngFor][ngForOf]'); expect(annotation.selector).toEqual('[ngFor][ngForOf]');
expect(annotation.inputs).toEqual(['ngForTrackBy', 'ngForOf', 'ngForTemplate']); expect(annotation.inputs).toEqual(['ngForTrackBy', 'ngForOf', 'ngForTemplate']);
}); });
it('should get constructor for NgFor', () => { it('should get constructor for NgFor', () => {
let host = new MockReflectorHost();
let reflector = new StaticReflector(host);
let NgFor = reflector.getStaticType( let NgFor = reflector.getStaticType(
host.resolveModule('angular2/src/common/directives/ng_for'), 'NgFor'); host.resolveModule('angular2/src/common/directives/ng_for'), 'NgFor');
let ViewContainerRef = reflector.getStaticType( let ViewContainerRef = reflector.getStaticType(
@ -41,34 +53,32 @@ export function main() {
let parameters = reflector.parameters(NgFor); let parameters = reflector.parameters(NgFor);
expect(parameters) expect(parameters)
.toEqual([ViewContainerRef, TemplateRef, IterableDiffers, ChangeDetectorRef]); .toEqual([[ViewContainerRef], [TemplateRef], [IterableDiffers], [ChangeDetectorRef]]);
}); });
it('should get annotations for HeroDetailComponent', () => { it('should get annotations for HeroDetailComponent', () => {
let host = new MockReflectorHost();
let reflector = new StaticReflector(host);
let HeroDetailComponent = let HeroDetailComponent =
reflector.getStaticType('/src/app/hero-detail.component.ts', 'HeroDetailComponent'); reflector.getStaticType('/src/app/hero-detail.component.ts', 'HeroDetailComponent');
let annotations = reflector.annotations(HeroDetailComponent); let annotations = reflector.annotations(HeroDetailComponent);
expect(annotations.length).toEqual(1); expect(annotations.length).toEqual(1);
let annotation = annotations[0]; let annotation = annotations[0];
expect(annotation.selector).toEqual('my-hero-detail'); 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', () => { 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 UnknownClass = reflector.getStaticType('/src/app/app.component.ts', 'UnknownClass');
let annotations = reflector.annotations(UnknownClass); let annotations = reflector.annotations(UnknownClass);
expect(annotations).toEqual([]); expect(annotations).toEqual([]);
}); });
it('should get propMetadata for HeroDetailComponent', () => { it('should get propMetadata for HeroDetailComponent', () => {
let host = new MockReflectorHost();
let reflector = new StaticReflector(host);
let HeroDetailComponent = let HeroDetailComponent =
reflector.getStaticType('/src/app/hero-detail.component.ts', 'HeroDetailComponent'); reflector.getStaticType('/src/app/hero-detail.component.ts', 'HeroDetailComponent');
let props = reflector.propMetadata(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', () => { 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 UnknownClass = reflector.getStaticType('/src/app/app.component.ts', 'UnknownClass');
let properties = reflector.propMetadata(UnknownClass); let properties = reflector.propMetadata(UnknownClass);
expect(properties).toEqual({}); expect(properties).toEqual({});
}); });
it('should get empty parameters list for an unknown class ', () => { 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 UnknownClass = reflector.getStaticType('/src/app/app.component.ts', 'UnknownClass');
let parameters = reflector.parameters(UnknownClass); let parameters = reflector.parameters(UnknownClass);
expect(parameters).toEqual([]); expect(parameters).toEqual([]);
}); });
it('should simplify primitive into itself', () => { it('should simplify primitive into itself', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', 1)).toBe(1);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', true)).toBe(true);
expect(singleModuleSimplify('', "some value")).toBe("some value");
expect(reflector.simplify('', 1)).toBe(1);
expect(reflector.simplify('', true)).toBe(true);
expect(reflector.simplify('', "some value")).toBe("some value");
}); });
it('should simplify an array into a copy of the array', () => { it('should simplify an array into a copy of the array',
let host = new MockReflectorHost(); () => { expect(singleModuleSimplify('', [1, 2, 3])).toEqual([1, 2, 3]); });
let reflector = new StaticReflector(host);
expect(reflector.simplify('', [1, 2, 3])).toEqual([1, 2, 3]);
});
it('should simplify an object to a copy of the object', () => { 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}; let expr = {a: 1, b: 2, c: 3};
expect(reflector.simplify('', expr)).toEqual(expr); expect(singleModuleSimplify('', expr)).toEqual(expr);
}); });
it('should simplify &&', () => { it('should simplify &&', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '&&', left: true, right: true}))).toBe(true);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '&&', left: true, right: false}))).toBe(false);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '&&', left: true, right: true}))).toBe(true); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '&&', left: false, right: true}))).toBe(false);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '&&', left: true, right: false}))).toBe(false); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '&&', left: false, 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);
}); });
it('should simplify ||', () => { it('should simplify ||', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '||', left: true, right: true}))).toBe(true);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '||', left: true, right: false}))).toBe(true);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '||', left: true, right: true}))).toBe(true); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '||', left: false, right: true}))).toBe(true);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '||', left: true, right: false}))).toBe(true); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '||', left: false, right: false}))).toBe(false);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '||', left: false, right: true}))).toBe(true);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '||', left: false, right: false}))).toBe(false);
}); });
it('should simplify &', () => { it('should simplify &', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '&', left: 0x22, right: 0x0F}))).toBe(0x22 & 0x0F);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '&', left: 0x22, right: 0xF0}))).toBe(0x22 & 0xF0);
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);
}); });
it('should simplify |', () => { it('should simplify |', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0x0F}))).toBe(0x22 | 0x0F);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0xF0}))).toBe(0x22 | 0xF0);
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);
}); });
it('should simplify ^', () => { it('should simplify ^', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0x0F}))).toBe(0x22 | 0x0F);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0xF0}))).toBe(0x22 | 0xF0);
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);
}); });
it('should simplify ==', () => { it('should simplify ==', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '==', left: 0x22, right: 0x22}))).toBe(0x22 == 0x22);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '==', left: 0x22, right: 0xF0}))).toBe(0x22 == 0xF0);
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);
}); });
it('should simplify !=', () => { it('should simplify !=', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '!=', left: 0x22, right: 0x22}))).toBe(0x22 != 0x22);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '!=', left: 0x22, right: 0xF0}))).toBe(0x22 != 0xF0);
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);
}); });
it('should simplify ===', () => { it('should simplify ===', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '===', left: 0x22, right: 0x22}))).toBe(0x22 === 0x22);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '===', left: 0x22, right: 0xF0}))).toBe(0x22 === 0xF0);
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);
}); });
it('should simplify !==', () => { it('should simplify !==', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '!==', left: 0x22, right: 0x22}))).toBe(0x22 !== 0x22);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '!==', left: 0x22, right: 0xF0}))).toBe(0x22 !== 0xF0);
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);
}); });
it('should simplify >', () => { it('should simplify >', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>', left: 1, right: 1}))).toBe(1 > 1);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>', left: 1, right: 0}))).toBe(1 > 0);
expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>', left: 0, right: 1}))).toBe(0 > 1);
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);
}); });
it('should simplify >=', () => { it('should simplify >=', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>=', left: 1, right: 1}))).toBe(1 >= 1);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>=', left: 1, right: 0}))).toBe(1 >= 0);
expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>=', left: 0, right: 1}))).toBe(0 >= 1);
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);
}); });
it('should simplify <=', () => { it('should simplify <=', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<=', left: 1, right: 1}))).toBe(1 <= 1);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<=', left: 1, right: 0}))).toBe(1 <= 0);
expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<=', left: 0, right: 1}))).toBe(0 <= 1);
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);
}); });
it('should simplify <', () => { it('should simplify <', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<', left: 1, right: 1}))).toBe(1 < 1);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<', left: 1, right: 0}))).toBe(1 < 0);
expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<', left: 0, right: 1}))).toBe(0 < 1);
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);
}); });
it('should simplify <<', () => { it('should simplify <<', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '<<', left: 0x55, right: 2}))).toBe(0x55 << 2);
let reflector = new StaticReflector(host);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '<<', left: 0x55, right: 2}))).toBe(0x55 << 2);
}); });
it('should simplify >>', () => { it('should simplify >>', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '>>', left: 0x55, right: 2}))).toBe(0x55 >> 2);
let reflector = new StaticReflector(host);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '>>', left: 0x55, right: 2}))).toBe(0x55 >> 2);
}); });
it('should simplify +', () => { it('should simplify +', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '+', left: 0x55, right: 2}))).toBe(0x55 + 2);
let reflector = new StaticReflector(host);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '+', left: 0x55, right: 2}))).toBe(0x55 + 2);
}); });
it('should simplify -', () => { it('should simplify -', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '-', left: 0x55, right: 2}))).toBe(0x55 - 2);
let reflector = new StaticReflector(host);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '-', left: 0x55, right: 2}))).toBe(0x55 - 2);
}); });
it('should simplify *', () => { it('should simplify *', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '*', left: 0x55, right: 2}))).toBe(0x55 * 2);
let reflector = new StaticReflector(host);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '*', left: 0x55, right: 2}))).toBe(0x55 * 2);
}); });
it('should simplify /', () => { it('should simplify /', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '/', left: 0x55, right: 2}))).toBe(0x55 / 2);
let reflector = new StaticReflector(host);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '/', left: 0x55, right: 2}))).toBe(0x55 / 2);
}); });
it('should simplify %', () => { it('should simplify %', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'binop', operator: '%', left: 0x55, right: 2}))).toBe(0x55 % 2);
let reflector = new StaticReflector(host);
expect(reflector.simplify('', ({ __symbolic: 'binop', operator: '%', left: 0x55, right: 2}))).toBe(0x55 % 2);
}); });
it('should simplify prefix -', () => { it('should simplify prefix -', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'pre', operator: '-', operand: 2}))).toBe(-2);
let reflector = new StaticReflector(host);
expect(reflector.simplify('', ({ __symbolic: 'pre', operator: '-', operand: 2}))).toBe(-2);
}); });
it('should simplify prefix ~', () => { it('should simplify prefix ~', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'pre', operator: '~', operand: 2}))).toBe(~2);
let reflector = new StaticReflector(host);
expect(reflector.simplify('', ({ __symbolic: 'pre', operator: '~', operand: 2}))).toBe(~2);
}); });
it('should simplify prefix !', () => { it('should simplify prefix !', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({ __symbolic: 'pre', operator: '!', operand: true}))).toBe(!true);
let reflector = new StaticReflector(host); expect(singleModuleSimplify('', ({ __symbolic: 'pre', operator: '!', operand: false}))).toBe(!false);
expect(reflector.simplify('', ({ __symbolic: 'pre', operator: '!', operand: true}))).toBe(!true);
expect(reflector.simplify('', ({ __symbolic: 'pre', operator: '!', operand: false}))).toBe(!false);
}); });
it('should simplify an array index', () => { it('should simplify an array index', () => {
let host = new MockReflectorHost(); expect(singleModuleSimplify('', ({__symbolic: "index", expression: [1, 2, 3], index: 2})))
let reflector = new StaticReflector(host);
expect(reflector.simplify('', ({__symbolic: "index", expression: [1, 2, 3], index: 2})))
.toBe(3); .toBe(3);
}); });
it('should simplify an object index', () => { 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"}; 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', () => { it('should simplify a module reference across modules', () => {
let host = new MockReflectorHost(); expect(crossModuleSimplify('/src/cases',
let reflector = new StaticReflector(host); ({__symbolic: "reference", module: "./extern", name: "s"})))
expect(reflector.simplify('/src/cases',
({__symbolic: "reference", module: "./extern", name: "s"})))
.toEqual("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 { 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 { resolveModule(moduleName: string, containingFile?: string): string {
function splitPath(path: string): string[] { return path.split(/\/|\\/g); } function splitPath(path: string): string[] { return path.split(/\/|\\/g); }
@ -363,68 +294,80 @@ class MockReflectorHost implements StaticReflectorHost {
getMetadataFor(moduleId: string): any { getMetadataFor(moduleId: string): any {
return { return {
'/tmp/angular2/src/common/directives/ng_for.d.ts': '/tmp/angular2/src/common/forms/directives.d.ts':
{ {
"__symbolic": "module", "__symbolic": "module",
"metadata": "metadata": {
"FORM_DIRECTIVES": [
{ {
"NgFor": "__symbolic": "reference",
{ "name": "NgFor",
"__symbolic": "class", "module": "angular2/src/common/directives/ng_for"
"decorators": }
[ ]
{ }
"__symbolic": "call", },
"expression": { '/tmp/angular2/src/common/directives/ng_for.d.ts':
"__symbolic": "reference", {
"name": "Directive", "__symbolic": "module",
"module": "../../core/metadata" "metadata":
}, {
"arguments": "NgFor":
[ {
"__symbolic": "class",
"decorators":
[
{
"__symbolic": "call",
"expression": {
"__symbolic": "reference",
"name": "Directive",
"module": "../../core/metadata"
},
"arguments": [
{ {
"selector": "[ngFor][ngForOf]", "selector": "[ngFor][ngForOf]",
"inputs": ["ngForTrackBy", "ngForOf", "ngForTemplate"] "inputs": ["ngForTrackBy", "ngForOf", "ngForTemplate"]
} }
] ]
} }
], ],
"members": "members":
{
"__ctor__": [
{ {
"__symbolic": "constructor", "__ctor__": [
"parameters": {
[ "__symbolic": "constructor",
{ "parameters":
"__symbolic": "reference", [
"module": "../../core/linker/view_container_ref", {
"name": "ViewContainerRef" "__symbolic": "reference",
}, "module": "../../core/linker/view_container_ref",
{ "name": "ViewContainerRef"
"__symbolic": "reference", },
"module": "../../core/linker/template_ref", {
"name": "TemplateRef" "__symbolic": "reference",
}, "module": "../../core/linker/template_ref",
{ "name": "TemplateRef"
"__symbolic": "reference", },
"module": {
"../../core/change_detection/differs/iterable_differs", "__symbolic": "reference",
"name": "IterableDiffers" "module":
}, "../../core/change_detection/differs/iterable_differs",
{ "name": "IterableDiffers"
"__symbolic": "reference", },
"module": {
"../../core/change_detection/change_detector_ref", "__symbolic": "reference",
"name": "ChangeDetectorRef" "module":
} "../../core/change_detection/change_detector_ref",
] "name": "ChangeDetectorRef"
}
]
}
]
} }
] }
} }
} },
}
},
'/tmp/angular2/src/core/linker/view_container_ref.d.ts': '/tmp/angular2/src/core/linker/view_container_ref.d.ts':
{"metadata": {"ViewContainerRef": {"__symbolic": "class"}}}, {"metadata": {"ViewContainerRef": {"__symbolic": "class"}}},
'/tmp/angular2/src/core/linker/template_ref.d.ts': '/tmp/angular2/src/core/linker/template_ref.d.ts':
@ -453,7 +396,15 @@ class MockReflectorHost implements StaticReflectorHost {
"arguments": [ "arguments": [
{ {
"selector": "my-hero-detail", "selector": "my-hero-detail",
"template": "\n <div *ngIf=\"hero\">\n <h2>{{hero.name}} details!</h2>\n <div><label>id: </label>{{hero.id}}</div>\n <div>\n <label>name: </label>\n <input [(ngModel)]=\"hero.name\" placeholder=\"name\"/>\n </div>\n </div>\n" "template": "\n <div *ngIf=\"hero\">\n <h2>{{hero.name}} details!</h2>\n <div><label>id: </label>{{hero.id}}</div>\n <div>\n <label>name: </label>\n <input [(ngModel)]=\"hero.name\" placeholder=\"name\"/>\n </div>\n </div>\n",
"directives":
[
{
"__symbolic": "reference",
"name": "FORM_DIRECTIVES",
"module": "angular2/src/common/forms/directives"
}
]
} }
] ]
} }