diff --git a/modules/@angular/compiler-cli/README.md b/modules/@angular/compiler-cli/README.md
index 1d78cb044c..b4f8fc673c 100644
--- a/modules/@angular/compiler-cli/README.md
+++ b/modules/@angular/compiler-cli/README.md
@@ -107,6 +107,9 @@ $ cp tools/@angular/tsc-wrapped/package.json dist/tools/@angular/tsc-wrapped
$ ./scripts/ci-lite/offline_compiler_test.sh
# Keep a package fresh in watch mode
./node_modules/.bin/tsc -p modules/@angular/compiler/tsconfig-es5.json -w
+# Recompile @angular/core module (needs to use tsc-ext to keep the metadata)
+export NODE_PATH=${NODE_PATH}:$(pwd)/dist/all:$(pwd)/dist/tools
+node dist/tools/@angular/tsc-wrapped/src/main -p modules/@angular/core/tsconfig-es5.json
# Iterate on the test
cd /tmp/wherever/e2e_test.1464388257/
./node_modules/.bin/ngc
diff --git a/modules/@angular/compiler-cli/integrationtest/src/app_module.ts b/modules/@angular/compiler-cli/integrationtest/src/app_module.ts
new file mode 100644
index 0000000000..4c2c794e5a
--- /dev/null
+++ b/modules/@angular/compiler-cli/integrationtest/src/app_module.ts
@@ -0,0 +1,53 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {LowerCasePipe, NgIf} from '@angular/common';
+import {AppModule, Component, ComponentFactoryResolver, Injectable} from '@angular/core';
+
+@Injectable()
+export class SomeService {
+ public prop = 'someValue';
+}
+
+@Injectable()
+export class NestedService {
+}
+
+@Component({
+ selector: 'cmp',
+ template: `
`
+})
+export class SomeComp {
+ constructor() {}
+}
+
+@Component({selector: 'parent', template: ``, directives: [SomeComp]})
+export class ParentComp {
+}
+
+@AppModule({providers: [NestedService]})
+export class NestedModule {
+}
+
+@AppModule({
+ directives: [NgIf],
+ pipes: [LowerCasePipe],
+ providers: [SomeService],
+ precompile: [SomeComp],
+ modules: [NestedModule]
+})
+export class SomeModule {
+}
+
+@AppModule({
+ directives: [NgIf],
+ pipes: [LowerCasePipe],
+ precompile: [ParentComp],
+})
+export class SomeModuleUsingParentComp {
+}
diff --git a/modules/@angular/compiler-cli/integrationtest/test/app_module_spec.ts b/modules/@angular/compiler-cli/integrationtest/test/app_module_spec.ts
new file mode 100644
index 0000000000..49c4637713
--- /dev/null
+++ b/modules/@angular/compiler-cli/integrationtest/test/app_module_spec.ts
@@ -0,0 +1,75 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {ComponentFactoryResolver, DebugElement, ReflectiveInjector, getDebugNode, lockRunMode} from '@angular/core';
+import {BROWSER_APP_PROVIDERS, By} from '@angular/platform-browser';
+import {serverPlatform} from '@angular/platform-server';
+
+import {NestedModule, NestedService, ParentComp, SomeComp, SomeModule, SomeService} from '../src/app_module';
+import {SomeModuleNgFactory, SomeModuleUsingParentCompNgFactory} from '../src/app_module.ngfactory';
+
+
+// Need to lock the mode explicitely as this test is not using Angular's testing framework.
+lockRunMode();
+
+describe('AppModule', () => {
+ it('should support providers', () => {
+ var moduleRef = SomeModuleNgFactory.create();
+ expect(moduleRef.instance instanceof SomeModule).toBe(true);
+ expect(moduleRef.injector.get(SomeModule) instanceof SomeModule).toBe(true);
+ expect(moduleRef.injector.get(SomeService) instanceof SomeService).toBe(true);
+ });
+
+ it('should support precompile components', () => {
+ const appInjector =
+ ReflectiveInjector.resolveAndCreate(BROWSER_APP_PROVIDERS, serverPlatform().injector);
+ var moduleRef = SomeModuleNgFactory.create(appInjector);
+ var cf = moduleRef.injector.get(ComponentFactoryResolver).resolveComponentFactory(SomeComp);
+ expect(cf.componentType).toBe(SomeComp);
+ var comp = cf.create(moduleRef.injector);
+ });
+
+ it('should support module directives and pipes', () => {
+ const appInjector =
+ ReflectiveInjector.resolveAndCreate(BROWSER_APP_PROVIDERS, serverPlatform().injector);
+ var moduleRef = SomeModuleNgFactory.create(appInjector);
+ var cf = moduleRef.injector.get(ComponentFactoryResolver).resolveComponentFactory(SomeComp);
+ var comp = cf.create(moduleRef.injector);
+ var debugElement = getDebugNode(comp.location.nativeElement);
+
+ // NgIf should work, is being used as module directive
+ expect(debugElement.children.length).toBe(1);
+ comp.changeDetectorRef.detectChanges();
+ expect(debugElement.children.length).toBe(2);
+ expect(debugElement.children[0].properties['title']).toBe('hello');
+ });
+
+ it('should support module directives and pipes on nested components', () => {
+ const appInjector =
+ ReflectiveInjector.resolveAndCreate(BROWSER_APP_PROVIDERS, serverPlatform().injector);
+ var moduleRef = SomeModuleUsingParentCompNgFactory.create(appInjector);
+ var cf = moduleRef.injector.get(ComponentFactoryResolver).resolveComponentFactory(ParentComp);
+ var comp = cf.create(moduleRef.injector);
+ var debugElement = getDebugNode(comp.location.nativeElement);
+
+ debugElement = debugElement.children[0];
+ // NgIf should work, is being used as module directive
+ expect(debugElement.children.length).toBe(1);
+ comp.changeDetectorRef.detectChanges();
+ expect(debugElement.children.length).toBe(2);
+ expect(debugElement.children[0].properties['title']).toBe('hello');
+ });
+
+ it('should support child moduless', () => {
+ var moduleRef = SomeModuleNgFactory.create();
+ expect(moduleRef.instance instanceof SomeModule).toBe(true);
+ expect(moduleRef.injector.get(NestedModule) instanceof NestedModule).toBe(true);
+ expect(moduleRef.injector.get(NestedService) instanceof NestedService).toBe(true);
+ });
+
+});
diff --git a/modules/@angular/compiler-cli/src/codegen.ts b/modules/@angular/compiler-cli/src/codegen.ts
index 950086bfa7..7354087736 100644
--- a/modules/@angular/compiler-cli/src/codegen.ts
+++ b/modules/@angular/compiler-cli/src/codegen.ts
@@ -11,15 +11,15 @@
* Intended to be used in a build step.
*/
import * as compiler from '@angular/compiler';
-import {ViewEncapsulation, lockRunMode} from '@angular/core';
+import {AppModuleMetadata, ComponentMetadata, ViewEncapsulation, lockRunMode} from '@angular/core';
import {AngularCompilerOptions} from '@angular/tsc-wrapped';
import * as path from 'path';
import * as ts from 'typescript';
-import {CompileMetadataResolver, DirectiveNormalizer, DomElementSchemaRegistry, HtmlParser, Lexer, Parser, StyleCompiler, TemplateParser, TypeScriptEmitter, ViewCompiler} from './compiler_private';
+import {AppModuleCompiler, CompileMetadataResolver, DirectiveNormalizer, DomElementSchemaRegistry, HtmlParser, Lexer, Parser, StyleCompiler, TemplateParser, TypeScriptEmitter, ViewCompiler} from './compiler_private';
import {ReflectorHost, ReflectorHostContext} from './reflector_host';
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
-import {StaticReflector} from './static_reflector';
+import {StaticReflector, StaticSymbol} from './static_reflector';
const GENERATED_FILES = /\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
@@ -40,26 +40,9 @@ export class CodeGenerator {
lockRunMode();
}
- private generateSource(metadatas: compiler.CompileDirectiveMetadata[]) {
- const normalize = (metadata: compiler.CompileDirectiveMetadata) => {
- const directiveType = metadata.type.runtime;
- const directives = this.resolver.getViewDirectivesMetadata(directiveType);
- return Promise.all(directives.map(d => this.compiler.normalizeDirectiveMetadata(d)))
- .then(normalizedDirectives => {
- const pipes = this.resolver.getViewPipesMetadata(directiveType);
- return new compiler.NormalizedComponentWithViewDirectives(
- metadata, normalizedDirectives, pipes);
- });
- };
- return Promise.all(metadatas.map(normalize))
- .then(
- normalizedCompWithDirectives =>
- this.compiler.compileTemplates(normalizedCompWithDirectives));
- }
-
- private readComponents(absSourcePath: string) {
- const result: Promise[] = [];
+ private readFileMetadata(absSourcePath: string): FileMetadata {
const moduleMetadata = this.staticReflector.getModuleMetadata(absSourcePath);
+ const result: FileMetadata = {components: [], appModules: [], fileUrl: absSourcePath};
if (!moduleMetadata) {
console.log(`WARNING: no metadata found for ${absSourcePath}`);
return result;
@@ -75,13 +58,14 @@ export class CodeGenerator {
continue;
}
const staticType = this.reflectorHost.findDeclaration(absSourcePath, symbol, absSourcePath);
- let directive: compiler.CompileDirectiveMetadata;
- directive = this.resolver.maybeGetDirectiveMetadata(staticType);
-
- if (!directive || !directive.isComponent) {
- continue;
- }
- result.push(this.compiler.normalizeDirectiveMetadata(directive));
+ const annotations = this.staticReflector.annotations(staticType);
+ annotations.forEach((annotation) => {
+ if (annotation instanceof AppModuleMetadata) {
+ result.appModules.push(staticType);
+ } else if (annotation instanceof ComponentMetadata) {
+ result.components.push(staticType);
+ }
+ });
}
return result;
}
@@ -102,30 +86,31 @@ export class CodeGenerator {
}
codegen(): Promise {
- const generateOneFile = (absSourcePath: string) =>
- Promise.all(this.readComponents(absSourcePath))
- .then((metadatas: compiler.CompileDirectiveMetadata[]) => {
- if (!metadatas || !metadatas.length) {
- return;
- }
- return this.generateSource(metadatas);
- })
- .then(generatedModules => {
- if (generatedModules) {
- generatedModules.forEach((generatedModule) => {
- const sourceFile = this.program.getSourceFile(absSourcePath);
- const emitPath = this.calculateEmitPath(generatedModule.moduleUrl);
- this.host.writeFile(
- emitPath, PREAMBLE + generatedModule.source, false, () => {}, [sourceFile]);
- });
- }
- })
- .catch((e) => { console.error(e.stack); });
- var compPromises = this.program.getSourceFiles()
- .map(sf => sf.fileName)
- .filter(f => !GENERATED_FILES.test(f))
- .map(generateOneFile);
- return Promise.all(compPromises);
+ let filePaths =
+ this.program.getSourceFiles().map(sf => sf.fileName).filter(f => !GENERATED_FILES.test(f));
+ let fileMetas = filePaths.map((filePath) => this.readFileMetadata(filePath));
+ let appModules = fileMetas.reduce((appModules, fileMeta) => {
+ appModules.push(...fileMeta.appModules);
+ return appModules;
+ }, []);
+ let analyzedAppModules = this.compiler.analyzeModules(appModules);
+ return Promise
+ .all(fileMetas.map(
+ (fileMeta) => this.compiler
+ .compile(
+ fileMeta.fileUrl, analyzedAppModules, fileMeta.components,
+ fileMeta.appModules)
+ .then((generatedModules) => {
+ generatedModules.forEach((generatedModule) => {
+ const sourceFile = this.program.getSourceFile(fileMeta.fileUrl);
+ const emitPath =
+ this.calculateEmitPath(generatedModule.moduleUrl);
+ this.host.writeFile(
+ emitPath, PREAMBLE + generatedModule.source, false, () => {},
+ [sourceFile]);
+ });
+ })))
+ .catch((e) => { console.error(e.stack); });
}
static create(
@@ -158,14 +143,20 @@ export class CodeGenerator {
const tmplParser = new TemplateParser(
parser, new DomElementSchemaRegistry(), htmlParser,
/*console*/ null, []);
- const offlineCompiler = new compiler.OfflineCompiler(
- normalizer, tmplParser, new StyleCompiler(urlResolver), new ViewCompiler(config),
- new TypeScriptEmitter(reflectorHost));
const resolver = new CompileMetadataResolver(
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
new compiler.ViewResolver(staticReflector), config, staticReflector);
+ const offlineCompiler = new compiler.OfflineCompiler(
+ resolver, normalizer, tmplParser, new StyleCompiler(urlResolver), new ViewCompiler(config),
+ new AppModuleCompiler(), new TypeScriptEmitter(reflectorHost));
return new CodeGenerator(
options, program, compilerHost, staticReflector, resolver, offlineCompiler, reflectorHost);
}
}
+
+interface FileMetadata {
+ fileUrl: string;
+ components: StaticSymbol[];
+ appModules: StaticSymbol[];
+}
\ No newline at end of file
diff --git a/modules/@angular/compiler-cli/src/compiler_private.ts b/modules/@angular/compiler-cli/src/compiler_private.ts
index 16e745d1b9..06617f3c16 100644
--- a/modules/@angular/compiler-cli/src/compiler_private.ts
+++ b/modules/@angular/compiler-cli/src/compiler_private.ts
@@ -61,5 +61,8 @@ export var StyleCompiler: typeof _c.StyleCompiler = _c.StyleCompiler;
export type ViewCompiler = _c.ViewCompiler;
export var ViewCompiler: typeof _c.ViewCompiler = _c.ViewCompiler;
+export type AppModuleCompiler = _c.AppModuleCompiler;
+export var AppModuleCompiler: typeof _c.AppModuleCompiler = _c.AppModuleCompiler;
+
export type TypeScriptEmitter = _c.TypeScriptEmitter;
export var TypeScriptEmitter: typeof _c.TypeScriptEmitter = _c.TypeScriptEmitter;
diff --git a/modules/@angular/compiler-cli/src/extract_i18n.ts b/modules/@angular/compiler-cli/src/extract_i18n.ts
index 8106f8ccb0..ca42ddc000 100644
--- a/modules/@angular/compiler-cli/src/extract_i18n.ts
+++ b/modules/@angular/compiler-cli/src/extract_i18n.ts
@@ -22,7 +22,7 @@ import * as compiler from '@angular/compiler';
import {ViewEncapsulation, lockRunMode} from '@angular/core';
import {StaticReflector} from './static_reflector';
-import {CompileMetadataResolver, HtmlParser, DirectiveNormalizer, Lexer, Parser, TemplateParser, DomElementSchemaRegistry, StyleCompiler, ViewCompiler, TypeScriptEmitter, MessageExtractor, removeDuplicates, ExtractionResult, Message, ParseError, serializeXmb,} from './compiler_private';
+import {CompileMetadataResolver, HtmlParser, DirectiveNormalizer, Lexer, Parser, DomElementSchemaRegistry, TypeScriptEmitter, MessageExtractor, removeDuplicates, ExtractionResult, Message, ParseError, serializeXmb,} from './compiler_private';
import {ReflectorHost} from './reflector_host';
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
@@ -40,42 +40,27 @@ class Extractor {
constructor(
private _options: tsc.AngularCompilerOptions, private _program: ts.Program,
public host: ts.CompilerHost, private staticReflector: StaticReflector,
- private _resolver: CompileMetadataResolver, private _compiler: compiler.OfflineCompiler,
+ private _resolver: CompileMetadataResolver, private _normalizer: DirectiveNormalizer,
private _reflectorHost: ReflectorHost, private _extractor: MessageExtractor) {
lockRunMode();
}
- private _extractCmpMessages(metadatas: compiler.CompileDirectiveMetadata[]):
- Promise {
- if (!metadatas || !metadatas.length) {
+ private _extractCmpMessages(components: compiler.CompileDirectiveMetadata[]): ExtractionResult {
+ if (!components || !components.length) {
return null;
}
- const normalize = (metadata: compiler.CompileDirectiveMetadata) => {
- const directiveType = metadata.type.runtime;
- const directives = this._resolver.getViewDirectivesMetadata(directiveType);
- return Promise.all(directives.map(d => this._compiler.normalizeDirectiveMetadata(d)))
- .then(normalizedDirectives => {
- const pipes = this._resolver.getViewPipesMetadata(directiveType);
- return new compiler.NormalizedComponentWithViewDirectives(
- metadata, normalizedDirectives, pipes);
- });
- };
+ let messages: Message[] = [];
+ let errors: ParseError[] = [];
+ components.forEach(metadata => {
+ let url = _dirPaths.get(metadata);
+ let result = this._extractor.extract(metadata.template.template, url);
+ errors = errors.concat(result.errors);
+ messages = messages.concat(result.messages);
+ });
- return Promise.all(metadatas.map(normalize))
- .then((cmps: compiler.NormalizedComponentWithViewDirectives[]) => {
- let messages: Message[] = [];
- let errors: ParseError[] = [];
- cmps.forEach(cmp => {
- let url = _dirPaths.get(cmp.component);
- let result = this._extractor.extract(cmp.component.template.template, url);
- errors = errors.concat(result.errors);
- messages = messages.concat(result.messages);
- });
-
- // Extraction Result might contain duplicate messages at this point
- return new ExtractionResult(messages, errors);
- });
+ // Extraction Result might contain duplicate messages at this point
+ return new ExtractionResult(messages, errors);
}
private _readComponents(absSourcePath: string): Promise[] {
@@ -96,7 +81,7 @@ class Extractor {
directive = this._resolver.maybeGetDirectiveMetadata(staticType);
if (directive && directive.isComponent) {
- let promise = this._compiler.normalizeDirectiveMetadata(directive);
+ let promise = this._normalizer.normalizeDirective(directive).asyncResult;
promise.then(md => _dirPaths.set(md, absSourcePath));
result.push(promise);
}
@@ -165,12 +150,6 @@ class Extractor {
});
const normalizer = new DirectiveNormalizer(xhr, urlResolver, htmlParser, config);
const parser = new Parser(new Lexer());
- const tmplParser = new TemplateParser(
- parser, new DomElementSchemaRegistry(), htmlParser,
- /*console*/ null, []);
- const offlineCompiler = new compiler.OfflineCompiler(
- normalizer, tmplParser, new StyleCompiler(urlResolver), new ViewCompiler(config),
- new TypeScriptEmitter(reflectorHost));
const resolver = new CompileMetadataResolver(
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
new compiler.ViewResolver(staticReflector), config, staticReflector);
@@ -179,7 +158,7 @@ class Extractor {
const extractor = new MessageExtractor(htmlParser, parser, [], {});
return new Extractor(
- options, program, compilerHost, staticReflector, resolver, offlineCompiler, reflectorHost,
+ options, program, compilerHost, staticReflector, resolver, normalizer, reflectorHost,
extractor);
}
}
diff --git a/modules/@angular/compiler-cli/src/static_reflector.ts b/modules/@angular/compiler-cli/src/static_reflector.ts
index 171f7538b6..6109b64c5b 100644
--- a/modules/@angular/compiler-cli/src/static_reflector.ts
+++ b/modules/@angular/compiler-cli/src/static_reflector.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {AttributeMetadata, ComponentMetadata, ContentChildMetadata, ContentChildrenMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, HostMetadata, InjectMetadata, InjectableMetadata, InputMetadata, OptionalMetadata, OutputMetadata, PipeMetadata, Provider, QueryMetadata, SelfMetadata, SkipSelfMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
+import {AppModuleMetadata, AttributeMetadata, ComponentMetadata, ContentChildMetadata, ContentChildrenMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, HostMetadata, InjectMetadata, InjectableMetadata, InputMetadata, OptionalMetadata, OutputMetadata, PipeMetadata, Provider, QueryMetadata, SelfMetadata, SkipSelfMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
import {ReflectorReader} from './core_private';
@@ -216,6 +216,8 @@ export class StaticReflector implements ReflectorReader {
this.host.findDeclaration(coreDecorators, 'Directive'), DirectiveMetadata);
this.registerDecoratorOrConstructor(
this.host.findDeclaration(coreDecorators, 'Component'), ComponentMetadata);
+ this.registerDecoratorOrConstructor(
+ this.host.findDeclaration(coreDecorators, 'AppModule'), AppModuleMetadata);
// Note: Some metadata classes can be used directly with Provider.deps.
this.registerDecoratorOrConstructor(
diff --git a/modules/@angular/compiler/compiler.ts b/modules/@angular/compiler/compiler.ts
index 2d20021a92..4812b0f876 100644
--- a/modules/@angular/compiler/compiler.ts
+++ b/modules/@angular/compiler/compiler.ts
@@ -11,7 +11,7 @@
* @description
* Starting point to import all compiler APIs.
*/
-export {COMPILER_PROVIDERS, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileFactoryMetadata, CompileIdentifierMetadata, CompileMetadataWithIdentifier, CompileMetadataWithType, CompilePipeMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata, CompilerConfig, DEFAULT_PACKAGE_URL_PROVIDER, DirectiveResolver, NormalizedComponentWithViewDirectives, OfflineCompiler, PipeResolver, RenderTypes, RuntimeCompiler, SourceModule, TEMPLATE_TRANSFORMS, UrlResolver, ViewResolver, XHR, createOfflineCompileUrlResolver} from './src/compiler';
+export {COMPILER_PROVIDERS, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileFactoryMetadata, CompileIdentifierMetadata, CompileMetadataWithIdentifier, CompileMetadataWithType, CompilePipeMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata, CompilerConfig, DEFAULT_PACKAGE_URL_PROVIDER, DirectiveResolver, OfflineCompiler, PipeResolver, RenderTypes, RuntimeCompiler, SourceModule, TEMPLATE_TRANSFORMS, UrlResolver, ViewResolver, XHR, createOfflineCompileUrlResolver} from './src/compiler';
export {ElementSchemaRegistry} from './src/schema/element_schema_registry';
export * from './src/template_ast';
diff --git a/modules/@angular/compiler/core_private.ts b/modules/@angular/compiler/core_private.ts
index 9e4d0e46ac..a47beb008c 100644
--- a/modules/@angular/compiler/core_private.ts
+++ b/modules/@angular/compiler/core_private.ts
@@ -29,6 +29,7 @@ export var CodegenComponentFactoryResolver: typeof t.CodegenComponentFactoryReso
export var AppView: typeof t.AppView = r.AppView;
export type DebugAppView = t.DebugAppView;
export var DebugAppView: typeof t.DebugAppView = r.DebugAppView;
+export var AppModuleInjector: typeof t.AppModuleInjector = r.AppModuleInjector;
export type ViewType = t.ViewType;
export var ViewType: typeof t.ViewType = r.ViewType;
export var MAX_INTERPOLATION_VALUES: typeof t.MAX_INTERPOLATION_VALUES = r.MAX_INTERPOLATION_VALUES;
diff --git a/modules/@angular/compiler/private_export.ts b/modules/@angular/compiler/private_export.ts
index a53a2fe72d..be6557d3ab 100644
--- a/modules/@angular/compiler/private_export.ts
+++ b/modules/@angular/compiler/private_export.ts
@@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
+import * as app_module_compiler from './src/app_module_compiler';
import * as directive_normalizer from './src/directive_normalizer';
import * as lexer from './src/expression_parser/lexer';
import * as parser from './src/expression_parser/parser';
@@ -98,6 +99,9 @@ export var StyleCompiler = style_compiler.StyleCompiler;
export type ViewCompiler = view_compiler.ViewCompiler;
export var ViewCompiler = view_compiler.ViewCompiler;
+export type AppModuleCompiler = app_module_compiler.AppModuleCompiler;
+export var AppModuleCompiler = app_module_compiler.AppModuleCompiler;
+
export type TypeScriptEmitter = ts_emitter.TypeScriptEmitter;
export var TypeScriptEmitter = ts_emitter.TypeScriptEmitter;
}
diff --git a/modules/@angular/compiler/src/app_module_compiler.ts b/modules/@angular/compiler/src/app_module_compiler.ts
new file mode 100644
index 0000000000..907c7fecdd
--- /dev/null
+++ b/modules/@angular/compiler/src/app_module_compiler.ts
@@ -0,0 +1,215 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {Injectable} from '@angular/core';
+
+import {CompileAppModuleMetadata, CompileDiDependencyMetadata, CompileIdentifierMetadata, CompileProviderMetadata, CompileTokenMap, CompileTokenMetadata, CompileTypeMetadata} from './compile_metadata';
+import {isBlank, isPresent} from './facade/lang';
+import {Identifiers, identifierToken} from './identifiers';
+import * as o from './output/output_ast';
+import {ParseLocation, ParseSourceFile, ParseSourceSpan} from './parse_util';
+import {AppModuleProviderParser} from './provider_parser';
+import {ProviderAst, ProviderAstType} from './template_ast';
+import {createDiTokenExpression} from './util';
+
+export class ComponentFactoryDependency {
+ constructor(
+ public comp: CompileIdentifierMetadata, public placeholder: CompileIdentifierMetadata) {}
+}
+
+export class AppModuleCompileResult {
+ constructor(
+ public statements: o.Statement[], public appModuleFactoryVar: string,
+ public dependencies: ComponentFactoryDependency[]) {}
+}
+
+@Injectable()
+export class AppModuleCompiler {
+ compile(appModuleMeta: CompileAppModuleMetadata): AppModuleCompileResult {
+ var sourceFileName = isPresent(appModuleMeta.type.moduleUrl) ?
+ `in AppModule ${appModuleMeta.type.name} in ${appModuleMeta.type.moduleUrl}` :
+ `in AppModule ${appModuleMeta.type.name}`;
+ var sourceFile = new ParseSourceFile('', sourceFileName);
+ var sourceSpan = new ParseSourceSpan(
+ new ParseLocation(sourceFile, null, null, null),
+ new ParseLocation(sourceFile, null, null, null));
+ var deps: ComponentFactoryDependency[] = [];
+ var precompileComponents = appModuleMeta.precompile.map((precompileComp) => {
+ var id = new CompileIdentifierMetadata({name: precompileComp.name});
+ deps.push(new ComponentFactoryDependency(precompileComp, id));
+ return id;
+ });
+ var builder = new _InjectorBuilder(appModuleMeta, precompileComponents, sourceSpan);
+
+ var providerParser = new AppModuleProviderParser(appModuleMeta, sourceSpan);
+ providerParser.parse().forEach((provider) => builder.addProvider(provider));
+ var injectorClass = builder.build();
+ var appModuleFactoryVar = `${appModuleMeta.type.name}NgFactory`;
+ var appModuleFactoryStmt =
+ o.variable(appModuleFactoryVar)
+ .set(o.importExpr(Identifiers.AppModuleFactory)
+ .instantiate(
+ [o.variable(injectorClass.name), o.importExpr(appModuleMeta.type)],
+ o.importType(
+ Identifiers.AppModuleFactory, [o.importType(appModuleMeta.type)],
+ [o.TypeModifier.Const])))
+ .toDeclStmt(null, [o.StmtModifier.Final]);
+
+ return new AppModuleCompileResult(
+ [injectorClass, appModuleFactoryStmt], appModuleFactoryVar, deps);
+ }
+}
+
+class _InjectorBuilder {
+ private _instances = new CompileTokenMap();
+ private _fields: o.ClassField[] = [];
+ private _createStmts: o.Statement[] = [];
+ private _getters: o.ClassGetter[] = [];
+
+ constructor(
+ private _appModuleMeta: CompileAppModuleMetadata,
+ private _precompileComponents: CompileIdentifierMetadata[],
+ private _sourceSpan: ParseSourceSpan) {}
+
+ addProvider(resolvedProvider: ProviderAst) {
+ var providerValueExpressions =
+ resolvedProvider.providers.map((provider) => this._getProviderValue(provider));
+ var propName = `_${resolvedProvider.token.name}_${this._instances.size}`;
+ var instance = this._createProviderProperty(
+ propName, resolvedProvider, providerValueExpressions, resolvedProvider.multiProvider,
+ resolvedProvider.eager);
+ this._instances.add(resolvedProvider.token, instance);
+ }
+
+ build(): o.ClassStmt {
+ let getMethodStmts: o.Statement[] = this._instances.keys().map((token) => {
+ var providerExpr = this._instances.get(token);
+ return new o.IfStmt(
+ InjectMethodVars.token.identical(createDiTokenExpression(token)),
+ [new o.ReturnStatement(providerExpr)]);
+ });
+ var methods = [
+ new o.ClassMethod(
+ 'createInternal', [], this._createStmts.concat(
+ new o.ReturnStatement(this._instances.get(identifierToken(this._appModuleMeta.type)))
+ ), o.importType(this._appModuleMeta.type)
+ ),
+ new o.ClassMethod(
+ 'getInternal',
+ [
+ new o.FnParam(InjectMethodVars.token.name, o.DYNAMIC_TYPE),
+ new o.FnParam(InjectMethodVars.notFoundResult.name, o.DYNAMIC_TYPE)
+ ],
+ getMethodStmts.concat([new o.ReturnStatement(InjectMethodVars.notFoundResult)]),
+ o.DYNAMIC_TYPE)
+ ];
+
+ var ctor = new o.ClassMethod(
+ null, [new o.FnParam(InjectorProps.parent.name, o.importType(Identifiers.Injector))],
+ [o.SUPER_EXPR
+ .callFn([
+ o.variable(InjectorProps.parent.name),
+ o.literalArr(this._precompileComponents.map(
+ (precompiledComponent) => o.importExpr(precompiledComponent)))
+ ])
+ .toStmt()]);
+
+ var injClassName = `${this._appModuleMeta.type.name}Injector`;
+ return new o.ClassStmt(
+ injClassName,
+ o.importExpr(Identifiers.AppModuleInjector, [o.importType(this._appModuleMeta.type)]),
+ this._fields, this._getters, ctor, methods);
+ }
+
+ private _getProviderValue(provider: CompileProviderMetadata): o.Expression {
+ var result: o.Expression;
+ if (isPresent(provider.useExisting)) {
+ result = this._getDependency(new CompileDiDependencyMetadata({token: provider.useExisting}));
+ } else if (isPresent(provider.useFactory)) {
+ var deps = isPresent(provider.deps) ? provider.deps : provider.useFactory.diDeps;
+ var depsExpr = deps.map((dep) => this._getDependency(dep));
+ result = o.importExpr(provider.useFactory).callFn(depsExpr);
+ } else if (isPresent(provider.useClass)) {
+ var deps = isPresent(provider.deps) ? provider.deps : provider.useClass.diDeps;
+ var depsExpr = deps.map((dep) => this._getDependency(dep));
+ result =
+ o.importExpr(provider.useClass).instantiate(depsExpr, o.importType(provider.useClass));
+ } else {
+ result = o.literal(provider.useValue);
+ }
+ return result;
+ }
+
+
+ private _createProviderProperty(
+ propName: string, provider: ProviderAst, providerValueExpressions: o.Expression[],
+ isMulti: boolean, isEager: boolean): o.Expression {
+ var resolvedProviderValueExpr: o.Expression;
+ var type: o.Type;
+ if (isMulti) {
+ resolvedProviderValueExpr = o.literalArr(providerValueExpressions);
+ type = new o.ArrayType(o.DYNAMIC_TYPE);
+ } else {
+ resolvedProviderValueExpr = providerValueExpressions[0];
+ type = providerValueExpressions[0].type;
+ }
+ if (isBlank(type)) {
+ type = o.DYNAMIC_TYPE;
+ }
+ if (isEager) {
+ this._fields.push(new o.ClassField(propName, type));
+ this._createStmts.push(o.THIS_EXPR.prop(propName).set(resolvedProviderValueExpr).toStmt());
+ } else {
+ var internalField = `_${propName}`;
+ this._fields.push(new o.ClassField(internalField, type));
+ // Note: Equals is important for JS so that it also checks the undefined case!
+ var getterStmts = [
+ new o.IfStmt(
+ o.THIS_EXPR.prop(internalField).isBlank(),
+ [o.THIS_EXPR.prop(internalField).set(resolvedProviderValueExpr).toStmt()]),
+ new o.ReturnStatement(o.THIS_EXPR.prop(internalField))
+ ];
+ this._getters.push(new o.ClassGetter(propName, getterStmts, type));
+ }
+ return o.THIS_EXPR.prop(propName);
+ }
+
+ private _getDependency(dep: CompileDiDependencyMetadata): o.Expression {
+ var result: o.Expression = null;
+ if (dep.isValue) {
+ result = o.literal(dep.value);
+ }
+ if (!dep.isSkipSelf) {
+ if (dep.token &&
+ (dep.token.equalsTo(identifierToken(Identifiers.Injector)) ||
+ dep.token.equalsTo(identifierToken(Identifiers.ComponentFactoryResolver)))) {
+ result = o.THIS_EXPR;
+ }
+ if (isBlank(result)) {
+ result = this._instances.get(dep.token);
+ }
+ }
+ if (isBlank(result)) {
+ var args = [createDiTokenExpression(dep.token)];
+ if (dep.isOptional) {
+ args.push(o.NULL_EXPR);
+ }
+ result = InjectorProps.parent.callMethod('get', args);
+ }
+ return result;
+ }
+}
+
+class InjectorProps {
+ static parent = o.THIS_EXPR.prop('parent');
+}
+
+class InjectMethodVars {
+ static token = o.variable('token');
+ static notFoundResult = o.variable('notFoundResult');
+}
diff --git a/modules/@angular/compiler/src/compile_metadata.ts b/modules/@angular/compiler/src/compile_metadata.ts
index 9e0023e968..2c12439084 100644
--- a/modules/@angular/compiler/src/compile_metadata.ts
+++ b/modules/@angular/compiler/src/compile_metadata.ts
@@ -11,13 +11,14 @@ import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
import {CHANGE_DETECTION_STRATEGY_VALUES, LIFECYCLE_HOOKS_VALUES, LifecycleHooks, VIEW_ENCAPSULATION_VALUES, reflector} from '../core_private';
import {ListWrapper, StringMapWrapper} from '../src/facade/collection';
import {BaseException, unimplemented} from '../src/facade/exceptions';
-import {NumberWrapper, RegExpWrapper, Type, isArray, isBlank, isBoolean, isNumber, isPresent, isString, normalizeBlank, normalizeBool, serializeEnum} from '../src/facade/lang';
+import {NumberWrapper, RegExpWrapper, Type, isArray, isBlank, isBoolean, isNumber, isPresent, isString, isStringMap, normalizeBlank, normalizeBool, serializeEnum} from '../src/facade/lang';
import {CssSelector} from './selector';
import {getUrlScheme} from './url_resolver';
import {sanitizeIdentifier, splitAtColon} from './util';
+
// group 2: "event" from "(event)"
var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g;
@@ -468,12 +469,14 @@ export class CompileTokenMetadata implements CompileMetadataWithIdentifier {
export class CompileTokenMap {
private _valueMap = new Map();
private _values: VALUE[] = [];
+ private _tokens: CompileTokenMetadata[] = [];
add(token: CompileTokenMetadata, value: VALUE) {
var existing = this.get(token);
if (isPresent(existing)) {
throw new BaseException(`Can only add to a TokenMap! Token: ${token.name}`);
}
+ this._tokens.push(token);
this._values.push(value);
var rk = token.runtimeCacheKey;
if (isPresent(rk)) {
@@ -496,6 +499,7 @@ export class CompileTokenMap {
}
return result;
}
+ keys(): CompileTokenMetadata[] { return this._tokens; }
values(): VALUE[] { return this._values; }
get size(): number { return this._values.length; }
}
@@ -966,7 +970,61 @@ export class CompilePipeMetadata implements CompileMetadataWithType {
}
}
+/**
+ * Metadata regarding compilation of a directive.
+ */
+export class CompileAppModuleMetadata implements CompileMetadataWithType {
+ type: CompileTypeMetadata;
+ providers: CompileProviderMetadata[];
+ directives: CompileTypeMetadata[];
+ pipes: CompileTypeMetadata[];
+ precompile: CompileTypeMetadata[];
+ modules: CompileTypeMetadata[];
+
+ constructor({type, providers, directives, pipes, precompile, modules}: {
+ type?: CompileTypeMetadata,
+ providers?: Array,
+ directives?: CompileTypeMetadata[],
+ pipes?: CompileTypeMetadata[],
+ precompile?: CompileTypeMetadata[],
+ modules?: CompileTypeMetadata[]
+ } = {}) {
+ this.type = type;
+ this.directives = _normalizeArray(directives);
+ this.pipes = _normalizeArray(pipes);
+ this.providers = _normalizeArray(providers);
+ this.precompile = _normalizeArray(precompile);
+ this.modules = _normalizeArray(modules);
+ }
+
+ get identifier(): CompileIdentifierMetadata { return this.type; }
+
+ static fromJson(data: {[key: string]: any}): CompileAppModuleMetadata {
+ return new CompileAppModuleMetadata({
+ type: isPresent(data['type']) ? CompileTypeMetadata.fromJson(data['type']) : data['type'],
+ providers: _arrayFromJson(data['providers'], metadataFromJson),
+ directives: _arrayFromJson(data['directives'], metadataFromJson),
+ pipes: _arrayFromJson(data['pipes'], metadataFromJson),
+ precompile: _arrayFromJson(data['precompile'], CompileTypeMetadata.fromJson),
+ modules: _arrayFromJson(data['modules'], CompileTypeMetadata.fromJson)
+ });
+ }
+
+ toJson(): {[key: string]: any} {
+ return {
+ 'class': 'AppModule',
+ 'type': isPresent(this.type) ? this.type.toJson() : this.type,
+ 'providers': _arrayToJson(this.providers),
+ 'directives': _arrayToJson(this.directives),
+ 'pipes': _arrayToJson(this.pipes),
+ 'precompile': _arrayToJson(this.precompile),
+ 'modules': _arrayToJson(this.modules)
+ };
+ }
+}
+
var _COMPILE_METADATA_FROM_JSON = {
+ 'AppModule': CompileAppModuleMetadata.fromJson,
'Directive': CompileDirectiveMetadata.fromJson,
'Pipe': CompilePipeMetadata.fromJson,
'Type': CompileTypeMetadata.fromJson,
@@ -1006,3 +1064,12 @@ function _objToJson(obj: any): string|{[key: string]: any} {
function _normalizeArray(obj: any[]): any[] {
return isPresent(obj) ? obj : [];
}
+
+export function isStaticSymbol(value: any): value is StaticSymbol {
+ return isStringMap(value) && isPresent(value['name']) && isPresent(value['filePath']);
+}
+
+export interface StaticSymbol {
+ name: string;
+ filePath: string;
+}
diff --git a/modules/@angular/compiler/src/compiler.ts b/modules/@angular/compiler/src/compiler.ts
index ee0867b33f..c6e2b61dba 100644
--- a/modules/@angular/compiler/src/compiler.ts
+++ b/modules/@angular/compiler/src/compiler.ts
@@ -27,6 +27,7 @@ import {DirectiveNormalizer} from './directive_normalizer';
import {CompileMetadataResolver} from './metadata_resolver';
import {StyleCompiler} from './style_compiler';
import {ViewCompiler} from './view_compiler/view_compiler';
+import {AppModuleCompiler} from './app_module_compiler';
import {CompilerConfig} from './config';
import {RuntimeCompiler} from './runtime_compiler';
import {ElementSchemaRegistry} from './schema/element_schema_registry';
@@ -44,13 +45,24 @@ import {PipeResolver} from './pipe_resolver';
*/
export const COMPILER_PROVIDERS: Array =
/*@ts2dart_const*/[
- Lexer, Parser, HtmlParser, TemplateParser, DirectiveNormalizer, CompileMetadataResolver,
- DEFAULT_PACKAGE_URL_PROVIDER, StyleCompiler, ViewCompiler,
+ Lexer,
+ Parser,
+ HtmlParser,
+ TemplateParser,
+ DirectiveNormalizer,
+ CompileMetadataResolver,
+ DEFAULT_PACKAGE_URL_PROVIDER,
+ StyleCompiler,
+ ViewCompiler,
+ AppModuleCompiler,
/*@ts2dart_Provider*/ {provide: CompilerConfig, useValue: new CompilerConfig()},
RuntimeCompiler,
/*@ts2dart_Provider*/ {provide: ComponentResolver, useExisting: RuntimeCompiler},
/*@ts2dart_Provider*/ {provide: Compiler, useExisting: RuntimeCompiler},
DomElementSchemaRegistry,
/*@ts2dart_Provider*/ {provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry},
- UrlResolver, ViewResolver, DirectiveResolver, PipeResolver
+ UrlResolver,
+ ViewResolver,
+ DirectiveResolver,
+ PipeResolver
];
diff --git a/modules/@angular/compiler/src/directive_normalizer.ts b/modules/@angular/compiler/src/directive_normalizer.ts
index e08f09c0e3..1a1f1c7654 100644
--- a/modules/@angular/compiler/src/directive_normalizer.ts
+++ b/modules/@angular/compiler/src/directive_normalizer.ts
@@ -20,14 +20,9 @@ import {HtmlParser} from './html_parser';
import {extractStyleUrls, isStyleUrlResolvable} from './style_url_resolver';
import {PreparsedElementType, preparseElement} from './template_preparser';
import {UrlResolver} from './url_resolver';
+import {SyncAsyncResult} from './util';
import {XHR} from './xhr';
-export class NormalizeDirectiveResult {
- constructor(
- public syncResult: CompileDirectiveMetadata,
- public asyncResult: Promise) {}
-}
-
@Injectable()
export class DirectiveNormalizer {
private _xhrCache = new Map>();
@@ -56,10 +51,11 @@ export class DirectiveNormalizer {
return result;
}
- normalizeDirective(directive: CompileDirectiveMetadata): NormalizeDirectiveResult {
+ normalizeDirective(directive: CompileDirectiveMetadata):
+ SyncAsyncResult {
if (!directive.isComponent) {
// For non components there is nothing to be normalized yet.
- return new NormalizeDirectiveResult(directive, Promise.resolve(directive));
+ return new SyncAsyncResult(directive, Promise.resolve(directive));
}
let normalizedTemplateSync: CompileTemplateMetadata = null;
let normalizedTemplateAsync: Promise;
@@ -74,11 +70,10 @@ export class DirectiveNormalizer {
if (normalizedTemplateSync && normalizedTemplateSync.styleUrls.length === 0) {
// sync case
let normalizedDirective = _cloneDirectiveWithTemplate(directive, normalizedTemplateSync);
- return new NormalizeDirectiveResult(
- normalizedDirective, Promise.resolve(normalizedDirective));
+ return new SyncAsyncResult(normalizedDirective, Promise.resolve(normalizedDirective));
} else {
// async case
- return new NormalizeDirectiveResult(
+ return new SyncAsyncResult(
null,
normalizedTemplateAsync
.then((normalizedTemplate) => this.normalizeExternalStylesheets(normalizedTemplate))
diff --git a/modules/@angular/compiler/src/identifiers.ts b/modules/@angular/compiler/src/identifiers.ts
index 7138e63d62..f83a893813 100644
--- a/modules/@angular/compiler/src/identifiers.ts
+++ b/modules/@angular/compiler/src/identifiers.ts
@@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactoryResolver, ElementRef, Injector, QueryList, RenderComponentType, Renderer, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
+import {AppModuleFactory, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ElementRef, Injector, QueryList, RenderComponentType, Renderer, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
-import {AnimationGroupPlayer as AnimationGroupPlayer_, AnimationKeyframe as AnimationKeyframe_, AnimationSequencePlayer as AnimationSequencePlayer_, AnimationStyles as AnimationStyles_, AppElement, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, DebugAppView, DebugContext, EMPTY_ARRAY, EMPTY_MAP, NoOpAnimationPlayer as NoOpAnimationPlayer_, SecurityContext, StaticNodeDebugInfo, TemplateRef_, ValueUnwrapper, ViewType, ViewUtils, balanceAnimationKeyframes as impBalanceAnimationKeyframes, castByValue, checkBinding, clearStyles as impClearStyles, collectAndResolveStyles as impCollectAndResolveStyles, devModeEqual, flattenNestedViewRenderNodes, interpolate, prepareFinalAnimationStyles as impBalanceAnimationStyles, pureProxy1, pureProxy10, pureProxy2, pureProxy3, pureProxy4, pureProxy5, pureProxy6, pureProxy7, pureProxy8, pureProxy9, renderStyles as impRenderStyles, uninitialized} from '../core_private';
+import {AnimationGroupPlayer as AnimationGroupPlayer_, AnimationKeyframe as AnimationKeyframe_, AnimationSequencePlayer as AnimationSequencePlayer_, AnimationStyles as AnimationStyles_, AppElement, AppModuleInjector, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, DebugAppView, DebugContext, EMPTY_ARRAY, EMPTY_MAP, NoOpAnimationPlayer as NoOpAnimationPlayer_, SecurityContext, StaticNodeDebugInfo, TemplateRef_, ValueUnwrapper, ViewType, ViewUtils, balanceAnimationKeyframes as impBalanceAnimationKeyframes, castByValue, checkBinding, clearStyles as impClearStyles, collectAndResolveStyles as impCollectAndResolveStyles, devModeEqual, flattenNestedViewRenderNodes, interpolate, prepareFinalAnimationStyles as impBalanceAnimationStyles, pureProxy1, pureProxy10, pureProxy2, pureProxy3, pureProxy4, pureProxy5, pureProxy6, pureProxy7, pureProxy8, pureProxy9, renderStyles as impRenderStyles, uninitialized} from '../core_private';
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
import {assetUrl} from './util';
@@ -108,6 +108,21 @@ export class Identifiers {
moduleUrl: assetUrl('core', 'linker/component_factory_resolver'),
runtime: ComponentFactoryResolver
});
+ static ComponentFactory = new CompileIdentifierMetadata({
+ name: 'ComponentFactory',
+ runtime: ComponentFactory,
+ moduleUrl: assetUrl('core', 'linker/component_factory')
+ });
+ static AppModuleFactory = new CompileIdentifierMetadata({
+ name: 'AppModuleFactory',
+ runtime: AppModuleFactory,
+ moduleUrl: assetUrl('core', 'linker/app_module_factory')
+ });
+ static AppModuleInjector = new CompileIdentifierMetadata({
+ name: 'AppModuleInjector',
+ runtime: AppModuleInjector,
+ moduleUrl: assetUrl('core', 'linker/app_module_factory')
+ });
static ValueUnwrapper = new CompileIdentifierMetadata(
{name: 'ValueUnwrapper', moduleUrl: CD_MODULE_URL, runtime: impValueUnwrapper});
static Injector = new CompileIdentifierMetadata(
diff --git a/modules/@angular/compiler/src/metadata_resolver.ts b/modules/@angular/compiler/src/metadata_resolver.ts
index 08c6d4e480..4d13f9abed 100644
--- a/modules/@angular/compiler/src/metadata_resolver.ts
+++ b/modules/@angular/compiler/src/metadata_resolver.ts
@@ -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();
private _pipeCache = new Map();
+ private _appModuleCache = new Map();
private _anonymousTypes = new Map