feat(core): introduce @AppModule

Main part for #9726
Closes #9730
This commit is contained in:
Tobias Bosch
2016-06-28 09:54:42 -07:00
parent 1608d91728
commit 17e4cfc748
52 changed files with 2085 additions and 851 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, AttributeMetadata, ComponentMetadata, HostMetadata, Inject, InjectMetadata, Injectable, Optional, OptionalMetadata, Provider, QueryMetadata, SelfMetadata, SkipSelfMetadata, ViewMetadata, ViewQueryMetadata, resolveForwardRef} from '@angular/core';
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, AppModuleMetadata, AttributeMetadata, ComponentMetadata, HostMetadata, Inject, InjectMetadata, Injectable, Optional, OptionalMetadata, Provider, QueryMetadata, SelfMetadata, SkipSelfMetadata, ViewMetadata, ViewQueryMetadata, resolveForwardRef} from '@angular/core';
import {LIFECYCLE_HOOKS_VALUES, ReflectorReader, createProvider, isProviderLiteral, reflector} from '../core_private';
import {StringMapWrapper} from '../src/facade/collection';
@ -27,6 +27,7 @@ import {ViewResolver} from './view_resolver';
export class CompileMetadataResolver {
private _directiveCache = new Map<Type, cpl.CompileDirectiveMetadata>();
private _pipeCache = new Map<Type, cpl.CompilePipeMetadata>();
private _appModuleCache = new Map<Type, cpl.CompileAppModuleMetadata>();
private _anonymousTypes = new Map<Object, number>();
private _anonymousTypeIndex = 0;
@ -49,14 +50,16 @@ export class CompileMetadataResolver {
return sanitizeIdentifier(identifier);
}
clearCacheFor(compType: Type) {
this._directiveCache.delete(compType);
this._pipeCache.delete(compType);
clearCacheFor(type: Type) {
this._directiveCache.delete(type);
this._pipeCache.delete(type);
this._appModuleCache.delete(type);
}
clearCache() {
this._directiveCache.clear();
this._pipeCache.clear();
this._appModuleCache.clear();
}
getAnimationEntryMetadata(entry: AnimationEntryMetadata): cpl.CompileAnimationEntryMetadata {
@ -102,6 +105,7 @@ export class CompileMetadataResolver {
}
getDirectiveMetadata(directiveType: Type): cpl.CompileDirectiveMetadata {
directiveType = resolveForwardRef(directiveType);
var meta = this._directiveCache.get(directiveType);
if (isBlank(meta)) {
var dirMeta = this._directiveResolver.resolve(directiveType);
@ -176,6 +180,72 @@ export class CompileMetadataResolver {
return meta;
}
getAppModuleMetadata(moduleType: any, meta: AppModuleMetadata = null):
cpl.CompileAppModuleMetadata {
// Only cache if we read the metadata via the reflector,
// as we use the moduleType as cache key.
let useCache = !meta;
moduleType = resolveForwardRef(moduleType);
var compileMeta = this._appModuleCache.get(moduleType);
if (isBlank(compileMeta) || !useCache) {
if (!meta) {
meta = this._reflector.annotations(moduleType)
.find((meta) => meta instanceof AppModuleMetadata);
}
if (!meta) {
throw new BaseException(
`Could not compile '${stringify(moduleType)}' because it is not an AppModule.`);
}
let providers: any[] = [];
if (meta.providers) {
providers.push(...this.getProvidersMetadata(meta.providers));
}
let directives: cpl.CompileTypeMetadata[] = [];
if (meta.directives) {
directives.push(...flattenArray(meta.directives)
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
}
let pipes: cpl.CompileTypeMetadata[] = [];
if (meta.pipes) {
pipes.push(...flattenArray(meta.pipes)
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
}
let precompile: cpl.CompileTypeMetadata[] = [];
if (meta.precompile) {
precompile.push(...flattenArray(meta.precompile)
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
}
let modules: cpl.CompileTypeMetadata[] = [];
if (meta.modules) {
flattenArray(meta.modules).forEach((moduleType) => {
var meta = this.getAppModuleMetadata(moduleType);
providers.push(...meta.providers);
directives.push(...meta.directives);
pipes.push(...meta.pipes);
precompile.push(...meta.precompile);
modules.push(meta.type);
modules.push(...meta.modules);
});
}
compileMeta = new cpl.CompileAppModuleMetadata({
type: this.getTypeMetadata(moduleType, staticTypeModuleUrl(moduleType)),
providers: providers,
directives: directives,
pipes: pipes,
precompile: precompile,
modules: modules
});
if (useCache) {
this._appModuleCache.set(moduleType, compileMeta);
}
}
return compileMeta;
}
/**
* @param someType a symbol which may or may not be a directive type
* @returns {cpl.CompileDirectiveMetadata} if possible, otherwise null.
@ -193,6 +263,7 @@ export class CompileMetadataResolver {
getTypeMetadata(type: Type, moduleUrl: string, dependencies: any[] = null):
cpl.CompileTypeMetadata {
type = resolveForwardRef(type);
return new cpl.CompileTypeMetadata({
name: this.sanitizeTokenName(type),
moduleUrl: moduleUrl,
@ -203,6 +274,7 @@ export class CompileMetadataResolver {
getFactoryMetadata(factory: Function, moduleUrl: string, dependencies: any[] = null):
cpl.CompileFactoryMetadata {
factory = resolveForwardRef(factory);
return new cpl.CompileFactoryMetadata({
name: this.sanitizeTokenName(factory),
moduleUrl: moduleUrl,
@ -212,6 +284,7 @@ export class CompileMetadataResolver {
}
getPipeMetadata(pipeType: Type): cpl.CompilePipeMetadata {
pipeType = resolveForwardRef(pipeType);
var meta = this._pipeCache.get(pipeType);
if (isBlank(meta)) {
var pipeMeta = this._pipeResolver.resolve(pipeType);
@ -349,8 +422,11 @@ export class CompileMetadataResolver {
return this.getProviderMetadata(provider);
} else if (isProviderLiteral(provider)) {
return this.getProviderMetadata(createProvider(provider));
} else {
} else if (isValidType(provider)) {
return this.getTypeMetadata(provider, staticTypeModuleUrl(provider));
} else {
throw new BaseException(
`Invalid provider - only instances of Provider and Type are allowed, got: ${stringify(provider)}`);
}
});
}
@ -468,21 +544,17 @@ function verifyNonBlankProviders(
return providersTree;
}
function isStaticType(value: any): boolean {
return isStringMap(value) && isPresent(value['name']) && isPresent(value['filePath']);
}
function isValidType(value: any): boolean {
return isStaticType(value) || (value instanceof Type);
return cpl.isStaticSymbol(value) || (value instanceof Type);
}
function staticTypeModuleUrl(value: any): string {
return isStaticType(value) ? value['filePath'] : null;
return cpl.isStaticSymbol(value) ? value.filePath : null;
}
function componentModuleUrl(
reflector: ReflectorReader, type: any, cmpMetadata: ComponentMetadata): string {
if (isStaticType(type)) {
if (cpl.isStaticSymbol(type)) {
return staticTypeModuleUrl(type);
}
@ -503,9 +575,8 @@ function convertToCompileValue(value: any): any {
class _CompileValueConverter extends ValueTransformer {
visitOther(value: any, context: any): any {
if (isStaticType(value)) {
return new cpl.CompileIdentifierMetadata(
{name: value['name'], moduleUrl: staticTypeModuleUrl(value)});
if (cpl.isStaticSymbol(value)) {
return new cpl.CompileIdentifierMetadata({name: value.name, moduleUrl: value.filePath});
} else {
return new cpl.CompileIdentifierMetadata({runtime: value});
}