refactor(core): change module semantics

This contains major changes to the compiler, bootstrap of the platforms
and test environment initialization.

Main part of #10043
Closes #10164

BREAKING CHANGE:
- Semantics and name of `@AppModule` (now `@NgModule`) changed quite a bit.
  This is actually not breaking as `@AppModules` were not part of rc.4.
  We will have detailed docs on `@NgModule` separately.
- `coreLoadAndBootstrap` and `coreBootstrap` can't be used any more (without migration support).
  Use `bootstrapModule` / `bootstrapModuleFactory` instead.
- All Components listed in routes have to be part of the `declarations` of an NgModule.
  Either directly on the bootstrap module / lazy loaded module, or in an NgModule imported by them.
This commit is contained in:
Tobias Bosch 2016-07-18 03:50:31 -07:00
parent ca16fc29a6
commit 46b212706b
129 changed files with 3580 additions and 3366 deletions

View File

@ -6,9 +6,25 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {NgModule} from '@angular/core';
import {COMMON_DIRECTIVES} from './src/common_directives';
import {COMMON_PIPES} from './src/pipes';
export * from './src/pipes'; export * from './src/pipes';
export * from './src/directives'; export * from './src/directives';
export * from './src/forms-deprecated'; export * from './src/forms-deprecated';
export * from './src/common_directives'; export * from './src/common_directives';
export * from './src/location'; export * from './src/location';
export {NgLocalization} from './src/localization'; export {NgLocalization} from './src/localization';
// Note: This does not contain the location providers,
// as they need some platform specific implementations to work.
/**
* The module that includes all the basic Angular directives like {@link NgIf}, ${link NgFor}, ...
*
* @experimental
*/
@NgModule(
{declarations: [COMMON_DIRECTIVES, COMMON_PIPES], exports: [COMMON_DIRECTIVES, COMMON_PIPES]})
export class CommonModule {
}

View File

@ -18,7 +18,7 @@
* Forms providers are not included in default providers; you must import these providers * Forms providers are not included in default providers; you must import these providers
* explicitly. * explicitly.
*/ */
import {AppModule, Type} from '@angular/core'; import {NgModule, Type} from '@angular/core';
import {FORM_DIRECTIVES} from './forms-deprecated/directives'; import {FORM_DIRECTIVES} from './forms-deprecated/directives';
import {RadioControlRegistry} from './forms-deprecated/directives/radio_control_value_accessor'; import {RadioControlRegistry} from './forms-deprecated/directives/radio_control_value_accessor';
@ -61,15 +61,15 @@ export const FORM_PROVIDERS: Type[] = /*@ts2dart_const*/[FormBuilder, RadioContr
/** /**
* The app module for the deprecated forms API. * The ng module for the deprecated forms API.
* @deprecated * @deprecated
*/ */
@AppModule({ @NgModule({
providers: [ providers: [
FORM_PROVIDERS, FORM_PROVIDERS,
], ],
directives: FORM_DIRECTIVES, declarations: FORM_DIRECTIVES,
pipes: [] exports: FORM_DIRECTIVES
}) })
export class DeprecatedFormsModule { export class DeprecatedFormsModule {
} }

View File

@ -22,7 +22,7 @@ import {PromiseWrapper} from '../../src/facade/promise';
export function main() { export function main() {
describe('integration tests', () => { describe('integration tests', () => {
beforeEach(() => { configureModule({modules: [DeprecatedFormsModule]}); }); beforeEach(() => configureModule({imports: [DeprecatedFormsModule]}));
it('should initialize DOM elements with the given form object', it('should initialize DOM elements with the given form object',
inject( inject(

View File

@ -30,13 +30,14 @@ generated code:
main_module.ts main_module.ts
------------- -------------
import {BrowserModule} from '@angular/platform-browser'; import {BrowserModule} from '@angular/platform-browser';
import {Component, AppModule, ApplicationRef} from '@angular/core'; import {Component, NgModule, ApplicationRef} from '@angular/core';
@Component(...) @Component(...)
export class MyComponent {} export class MyComponent {}
@AppModule({ @NgModule({
modules: [BrowserModule], imports: [BrowserModule],
declarations: [MyComponent],
precompile: [MyComponent] precompile: [MyComponent]
}) })
export class MainModule { export class MainModule {

View File

@ -8,10 +8,7 @@
import {Component} from '@angular/core'; import {Component} from '@angular/core';
@Component({ @Component({selector: 'my-comp', template: '<div></div>', directives: [NextComp]})
selector: 'my-comp',
template: '<div></div>',
})
export class MultipleComponentsMyComp { export class MultipleComponentsMyComp {
} }

View File

@ -1,4 +1,4 @@
<div [attr.array]="[0]" [attr.map]="{a:1}" title="translate me" i18n-title="meaning|desc">{{ctxProp}}</div> <div [attr.array]="[0]" [attr.map]="{a:1}" title="translate me" i18n-title="meaning|desc">{{ctxProp}}</div>
<form><input type="button" [(ngModel)]="ctxProp"/></form> <form><input type="button" [(ngModel)]="ctxProp" name="first"/></form>
<my-comp *ngIf="ctxBool"></my-comp> <my-comp *ngIf="ctxBool"></my-comp>
<div *ngFor="let x of ctxArr" [attr.value]="x"></div> <div *ngFor="let x of ctxArr" [attr.value]="x"></div>

View File

@ -6,8 +6,9 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {FORM_DIRECTIVES, NgFor, NgIf} from '@angular/common'; import {NgFor, NgIf} from '@angular/common';
import {Component, Inject} from '@angular/core'; import {Component, Inject} from '@angular/core';
import {FORM_DIRECTIVES} from '@angular/forms';
import {MultipleComponentsMyComp} from './a/multiple_components'; import {MultipleComponentsMyComp} from './a/multiple_components';

View File

@ -10,4 +10,4 @@ import {browserPlatform} from '@angular/platform-browser';
import {BasicComp} from './basic'; import {BasicComp} from './basic';
import {MainModuleNgFactory} from './module.ngfactory'; import {MainModuleNgFactory} from './module.ngfactory';
MainModuleNgFactory.create().instance.appRef.bootstrap(BasicComp); MainModuleNgFactory.create(null).instance.appRef.bootstrap(BasicComp);

View File

@ -6,20 +6,29 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AppModule, ApplicationRef} from '@angular/core'; import {ApplicationRef, NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {BrowserModule} from '@angular/platform-browser'; import {BrowserModule} from '@angular/platform-browser';
import {AnimateCmp} from './animate'; import {AnimateCmp} from './animate';
import {BasicComp} from './basic'; import {BasicComp} from './basic';
import {CompWithProviders, CompWithReferences} from './features';
import {CompUsingRootModuleDirectiveAndPipe, SomeDirectiveInRootModule, SomeLibModule, SomePipeInRootModule, SomeService} from './module_fixtures';
import {CompWithAnalyzePrecompileProvider, CompWithPrecompile} from './precompile'; import {CompWithAnalyzePrecompileProvider, CompWithPrecompile} from './precompile';
import {ProjectingComp} from './projection'; import {ProjectingComp} from './projection';
import {CompWithChildQuery} from './queries'; import {CompWithChildQuery, CompWithDirectiveChild} from './queries';
@AppModule({ @NgModule({
modules: [BrowserModule], declarations: [
SomeDirectiveInRootModule, SomePipeInRootModule, AnimateCmp, BasicComp, CompWithPrecompile,
CompWithAnalyzePrecompileProvider, ProjectingComp, CompWithChildQuery, CompWithDirectiveChild,
CompUsingRootModuleDirectiveAndPipe, CompWithProviders, CompWithReferences
],
imports: [BrowserModule, FormsModule, SomeLibModule],
providers: [SomeService],
precompile: [ precompile: [
AnimateCmp, BasicComp, CompWithPrecompile, CompWithAnalyzePrecompileProvider, ProjectingComp, AnimateCmp, BasicComp, CompWithPrecompile, CompWithAnalyzePrecompileProvider, ProjectingComp,
CompWithChildQuery CompWithChildQuery, CompUsingRootModuleDirectiveAndPipe
] ]
}) })
export class MainModule { export class MainModule {

View File

@ -7,7 +7,7 @@
*/ */
import {LowerCasePipe, NgIf} from '@angular/common'; import {LowerCasePipe, NgIf} from '@angular/common';
import {ANALYZE_FOR_PRECOMPILE, AppModule, Component, ComponentFactoryResolver, Directive, Inject, Injectable, Input, OpaqueToken, Pipe} from '@angular/core'; import {ANALYZE_FOR_PRECOMPILE, Component, ComponentFactoryResolver, Directive, Inject, Injectable, Input, NgModule, OpaqueToken, Pipe} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser'; import {BrowserModule} from '@angular/platform-browser';
@Injectable() @Injectable()
@ -16,50 +16,37 @@ export class SomeService {
} }
@Injectable() @Injectable()
export class NestedService { export class ServiceUsingLibModule {
} }
@Directive({selector: '[someDir]', host: {'[title]': 'someDir'}}) @Directive({selector: '[someDir]', host: {'[title]': 'someDir'}})
export class SomeDirective { export class SomeDirectiveInRootModule {
@Input()
someDir: string;
}
@Directive({selector: '[someDir]', host: {'[title]': 'someDir'}})
export class SomeDirectiveInLibModule {
@Input() @Input()
someDir: string; someDir: string;
} }
@Pipe({name: 'somePipe'}) @Pipe({name: 'somePipe'})
export class SomePipe { export class SomePipeInRootModule {
transform(value: string): any { return `transformed ${value}`; } transform(value: string): any { return `transformed ${value}`; }
} }
@Component({selector: 'cmp', template: `<div [someDir]="'someValue' | somePipe"></div>`}) @Pipe({name: 'somePipe'})
export class SomeComp { export class SomePipeInLibModule {
constructor() {} transform(value: string): any { return `transformed ${value}`; }
} }
@Component({selector: 'parent', template: `<cmp></cmp>`, directives: [SomeComp]}) @Component({selector: 'comp', template: `<div [someDir]="'someValue' | somePipe"></div>`})
export class ParentComp { export class CompUsingRootModuleDirectiveAndPipe {
} }
@AppModule({providers: [NestedService]}) @Component({selector: 'comp', template: `<div [someDir]="'someValue' | somePipe"></div>`})
export class NestedModule { export class CompUsingLibModuleDirectiveAndPipe {
}
@AppModule({
directives: [SomeDirective],
pipes: [SomePipe],
providers: [SomeService],
precompile: [SomeComp],
modules: [NestedModule, BrowserModule]
})
export class SomeModule {
}
@AppModule({
directives: [SomeDirective],
pipes: [SomePipe],
precompile: [ParentComp],
modules: [BrowserModule]
})
export class SomeModuleUsingParentComp {
} }
export const SOME_TOKEN = new OpaqueToken('someToken'); export const SOME_TOKEN = new OpaqueToken('someToken');
@ -71,7 +58,13 @@ export function provideValueWithPrecompile(value: any) {
]; ];
} }
@AppModule({providers: [provideValueWithPrecompile([{a: 'b', component: SomeComp}])]}) @NgModule({
export class SomeModuleWithAnalyzePrecompileProvider { declarations: [SomeDirectiveInLibModule, SomePipeInLibModule, CompUsingLibModuleDirectiveAndPipe],
constructor(@Inject(SOME_TOKEN) public providedValue: any) {} precompile: [CompUsingLibModuleDirectiveAndPipe],
providers: [
ServiceUsingLibModule,
provideValueWithPrecompile([{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}])
],
})
export class SomeLibModule {
} }

View File

@ -1,62 +0,0 @@
/**
* @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 './init';
import {NestedModule, NestedService, ParentComp, SomeComp, SomeModule, SomeService} from '../src/module_fixtures';
import {SomeModuleNgFactory, SomeModuleUsingParentCompNgFactory, SomeModuleWithAnalyzePrecompileProviderNgFactory} from '../src/module_fixtures.ngfactory';
import {createComponent, createModule} from './util';
describe('AppModule', () => {
it('should support providers', () => {
var moduleRef = createModule(SomeModuleNgFactory);
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', () => {
var moduleRef = createModule(SomeModuleNgFactory);
var cf = moduleRef.componentFactoryResolver.resolveComponentFactory(SomeComp);
expect(cf.componentType).toBe(SomeComp);
var compRef = cf.create(moduleRef.injector);
expect(compRef.instance instanceof SomeComp).toBe(true);
});
it('should support precompile via the ANALYZE_FOR_PRECOMPILE provider and function providers in components',
() => {
const moduleRef = createModule(SomeModuleWithAnalyzePrecompileProviderNgFactory);
const cf = moduleRef.componentFactoryResolver.resolveComponentFactory(SomeComp);
expect(cf.componentType).toBe(SomeComp);
// check that the function call that created the provider for ANALYZE_FOR_PRECOMPILE worked.
expect(moduleRef.instance.providedValue).toEqual([{a: 'b', component: SomeComp}]);
});
it('should support module directives and pipes', () => {
var compFixture = createComponent(SomeComp, SomeModuleNgFactory);
compFixture.detectChanges();
var debugElement = compFixture.debugElement;
expect(debugElement.children[0].properties['title']).toBe('transformed someValue');
});
it('should support module directives and pipes on nested components', () => {
var compFixture = createComponent(ParentComp, SomeModuleUsingParentCompNgFactory);
compFixture.detectChanges();
var debugElement = compFixture.debugElement;
debugElement = debugElement.children[0];
expect(debugElement.children[0].properties['title']).toBe('transformed someValue');
});
it('should support child moduless', () => {
var moduleRef = createModule(SomeModuleNgFactory);
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);
});
});

View File

@ -0,0 +1,63 @@
/**
* @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 './init';
import {MainModule} from '../src/module';
import {CompUsingLibModuleDirectiveAndPipe, CompUsingRootModuleDirectiveAndPipe, SOME_TOKEN, ServiceUsingLibModule, SomeLibModule, SomeService} from '../src/module_fixtures';
import {createComponent, createModule} from './util';
describe('NgModule', () => {
it('should support providers', () => {
const moduleRef = createModule();
expect(moduleRef.instance instanceof MainModule).toBe(true);
expect(moduleRef.injector.get(MainModule) instanceof MainModule).toBe(true);
expect(moduleRef.injector.get(SomeService) instanceof SomeService).toBe(true);
});
it('should support precompile components', () => {
const moduleRef = createModule();
const cf = moduleRef.componentFactoryResolver.resolveComponentFactory(
CompUsingRootModuleDirectiveAndPipe);
expect(cf.componentType).toBe(CompUsingRootModuleDirectiveAndPipe);
const compRef = cf.create(moduleRef.injector);
expect(compRef.instance instanceof CompUsingRootModuleDirectiveAndPipe).toBe(true);
});
it('should support precompile via the ANALYZE_FOR_PRECOMPILE provider and function providers in components',
() => {
const moduleRef = createModule();
const cf = moduleRef.componentFactoryResolver.resolveComponentFactory(
CompUsingRootModuleDirectiveAndPipe);
expect(cf.componentType).toBe(CompUsingRootModuleDirectiveAndPipe);
// check that the function call that created the provider for ANALYZE_FOR_PRECOMPILE worked.
expect(moduleRef.injector.get(SOME_TOKEN)).toEqual([
{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}
]);
});
it('should support module directives and pipes', () => {
const compFixture = createComponent(CompUsingRootModuleDirectiveAndPipe);
compFixture.detectChanges();
const debugElement = compFixture.debugElement;
expect(debugElement.children[0].properties['title']).toBe('transformed someValue');
});
it('should support module directives and pipes on lib modules', () => {
const compFixture = createComponent(CompUsingLibModuleDirectiveAndPipe);
compFixture.detectChanges();
const debugElement = compFixture.debugElement;
expect(debugElement.children[0].properties['title']).toBe('transformed someValue');
expect(debugElement.injector.get(SomeLibModule) instanceof SomeLibModule).toBe(true);
expect(debugElement.injector.get(ServiceUsingLibModule) instanceof ServiceUsingLibModule)
.toBe(true);
});
});

View File

@ -6,23 +6,19 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AppModuleFactory, AppModuleRef, bootstrapModuleFactory} from '@angular/core'; import {NgModuleFactory, NgModuleRef, bootstrapModuleFactory} from '@angular/core';
import {ComponentFixture} from '@angular/core/testing'; import {ComponentFixture} from '@angular/core/testing';
import {serverPlatform} from '@angular/platform-server'; import {serverPlatform} from '@angular/platform-server';
import {MainModule} from '../src/module';
import {MainModuleNgFactory} from '../src/module.ngfactory'; import {MainModuleNgFactory} from '../src/module.ngfactory';
export function createModule<M>(factory: AppModuleFactory<M>): AppModuleRef<M> { export function createModule(): NgModuleRef<MainModule> {
return bootstrapModuleFactory(factory, serverPlatform()); return bootstrapModuleFactory(MainModuleNgFactory, serverPlatform());
} }
export function createComponent<C>( export function createComponent<C>(comp: {new (...args: any[]): C}): ComponentFixture<C> {
comp: {new (...args: any[]): C}, const moduleRef = createModule();
moduleFactory: AppModuleFactory<any> = null): ComponentFixture<C> {
if (!moduleFactory) {
moduleFactory = MainModuleNgFactory;
}
const moduleRef = createModule(moduleFactory);
const compRef = const compRef =
moduleRef.componentFactoryResolver.resolveComponentFactory(comp).create(moduleRef.injector); moduleRef.componentFactoryResolver.resolveComponentFactory(comp).create(moduleRef.injector);
return new ComponentFixture(compRef, null, null); return new ComponentFixture(compRef, null, null);

View File

@ -11,12 +11,12 @@
* Intended to be used in a build step. * Intended to be used in a build step.
*/ */
import * as compiler from '@angular/compiler'; import * as compiler from '@angular/compiler';
import {AppModuleMetadata, ComponentMetadata, ViewEncapsulation} from '@angular/core'; import {ComponentMetadata, NgModuleMetadata, ViewEncapsulation} from '@angular/core';
import {AngularCompilerOptions} from '@angular/tsc-wrapped'; import {AngularCompilerOptions} from '@angular/tsc-wrapped';
import * as path from 'path'; import * as path from 'path';
import * as ts from 'typescript'; import * as ts from 'typescript';
import {AppModuleCompiler, CompileMetadataResolver, DirectiveNormalizer, DomElementSchemaRegistry, HtmlParser, Lexer, Parser, StyleCompiler, TemplateParser, TypeScriptEmitter, ViewCompiler} from './compiler_private'; import {CompileMetadataResolver, DirectiveNormalizer, DomElementSchemaRegistry, HtmlParser, Lexer, NgModuleCompiler, Parser, StyleCompiler, TemplateParser, TypeScriptEmitter, ViewCompiler} from './compiler_private';
import {ReflectorHost, ReflectorHostContext} from './reflector_host'; import {ReflectorHost, ReflectorHostContext} from './reflector_host';
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities'; import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
import {StaticReflector, StaticSymbol} from './static_reflector'; import {StaticReflector, StaticSymbol} from './static_reflector';
@ -39,7 +39,7 @@ export class CodeGenerator {
private readFileMetadata(absSourcePath: string): FileMetadata { private readFileMetadata(absSourcePath: string): FileMetadata {
const moduleMetadata = this.staticReflector.getModuleMetadata(absSourcePath); const moduleMetadata = this.staticReflector.getModuleMetadata(absSourcePath);
const result: FileMetadata = {components: [], appModules: [], fileUrl: absSourcePath}; const result: FileMetadata = {components: [], ngModules: [], fileUrl: absSourcePath};
if (!moduleMetadata) { if (!moduleMetadata) {
console.log(`WARNING: no metadata found for ${absSourcePath}`); console.log(`WARNING: no metadata found for ${absSourcePath}`);
return result; return result;
@ -57,8 +57,8 @@ export class CodeGenerator {
const staticType = this.reflectorHost.findDeclaration(absSourcePath, symbol, absSourcePath); const staticType = this.reflectorHost.findDeclaration(absSourcePath, symbol, absSourcePath);
const annotations = this.staticReflector.annotations(staticType); const annotations = this.staticReflector.annotations(staticType);
annotations.forEach((annotation) => { annotations.forEach((annotation) => {
if (annotation instanceof AppModuleMetadata) { if (annotation instanceof NgModuleMetadata) {
result.appModules.push(staticType); result.ngModules.push(staticType);
} else if (annotation instanceof ComponentMetadata) { } else if (annotation instanceof ComponentMetadata) {
result.components.push(staticType); result.components.push(staticType);
} }
@ -86,17 +86,17 @@ export class CodeGenerator {
let filePaths = let filePaths =
this.program.getSourceFiles().map(sf => sf.fileName).filter(f => !GENERATED_FILES.test(f)); this.program.getSourceFiles().map(sf => sf.fileName).filter(f => !GENERATED_FILES.test(f));
let fileMetas = filePaths.map((filePath) => this.readFileMetadata(filePath)); let fileMetas = filePaths.map((filePath) => this.readFileMetadata(filePath));
let appModules = fileMetas.reduce((appModules, fileMeta) => { let ngModules = fileMetas.reduce((ngModules, fileMeta) => {
appModules.push(...fileMeta.appModules); ngModules.push(...fileMeta.ngModules);
return appModules; return ngModules;
}, <StaticSymbol[]>[]); }, <StaticSymbol[]>[]);
let analyzedAppModules = this.compiler.analyzeModules(appModules); let analyzedNgModules = this.compiler.analyzeModules(ngModules);
return Promise return Promise
.all(fileMetas.map( .all(fileMetas.map(
(fileMeta) => this.compiler (fileMeta) => this.compiler
.compile( .compile(
fileMeta.fileUrl, analyzedAppModules, fileMeta.components, fileMeta.fileUrl, analyzedNgModules, fileMeta.components,
fileMeta.appModules) fileMeta.ngModules)
.then((generatedModules) => { .then((generatedModules) => {
generatedModules.forEach((generatedModule) => { generatedModules.forEach((generatedModule) => {
const sourceFile = this.program.getSourceFile(fileMeta.fileUrl); const sourceFile = this.program.getSourceFile(fileMeta.fileUrl);
@ -139,11 +139,12 @@ export class CodeGenerator {
expressionParser, new DomElementSchemaRegistry(), htmlParser, expressionParser, new DomElementSchemaRegistry(), htmlParser,
/*console*/ null, []); /*console*/ null, []);
const resolver = new CompileMetadataResolver( const resolver = new CompileMetadataResolver(
new compiler.NgModuleResolver(staticReflector),
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector), new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
new compiler.ViewResolver(staticReflector), config, staticReflector); new compiler.ViewResolver(staticReflector), config, /*console*/ null, staticReflector);
const offlineCompiler = new compiler.OfflineCompiler( const offlineCompiler = new compiler.OfflineCompiler(
resolver, normalizer, tmplParser, new StyleCompiler(urlResolver), new ViewCompiler(config), resolver, normalizer, tmplParser, new StyleCompiler(urlResolver), new ViewCompiler(config),
new AppModuleCompiler(), new TypeScriptEmitter(reflectorHost)); new NgModuleCompiler(), new TypeScriptEmitter(reflectorHost));
return new CodeGenerator( return new CodeGenerator(
options, program, compilerHost, staticReflector, offlineCompiler, reflectorHost); options, program, compilerHost, staticReflector, offlineCompiler, reflectorHost);
@ -153,5 +154,5 @@ export class CodeGenerator {
interface FileMetadata { interface FileMetadata {
fileUrl: string; fileUrl: string;
components: StaticSymbol[]; components: StaticSymbol[];
appModules: StaticSymbol[]; ngModules: StaticSymbol[];
} }

View File

@ -61,8 +61,8 @@ export var StyleCompiler: typeof _c.StyleCompiler = _c.StyleCompiler;
export type ViewCompiler = _c.ViewCompiler; export type ViewCompiler = _c.ViewCompiler;
export var ViewCompiler: typeof _c.ViewCompiler = _c.ViewCompiler; export var ViewCompiler: typeof _c.ViewCompiler = _c.ViewCompiler;
export type AppModuleCompiler = _c.AppModuleCompiler; export type NgModuleCompiler = _c.NgModuleCompiler;
export var AppModuleCompiler: typeof _c.AppModuleCompiler = _c.AppModuleCompiler; export var NgModuleCompiler: typeof _c.NgModuleCompiler = _c.NgModuleCompiler;
export type TypeScriptEmitter = _c.TypeScriptEmitter; export type TypeScriptEmitter = _c.TypeScriptEmitter;
export var TypeScriptEmitter: typeof _c.TypeScriptEmitter = _c.TypeScriptEmitter; export var TypeScriptEmitter: typeof _c.TypeScriptEmitter = _c.TypeScriptEmitter;

View File

@ -76,7 +76,7 @@ class Extractor {
for (const symbol of symbols) { for (const symbol of symbols) {
const staticType = this._reflectorHost.findDeclaration(absSourcePath, symbol, absSourcePath); const staticType = this._reflectorHost.findDeclaration(absSourcePath, symbol, absSourcePath);
let directive: compiler.CompileDirectiveMetadata; let directive: compiler.CompileDirectiveMetadata;
directive = this._resolver.maybeGetDirectiveMetadata(<any>staticType); directive = this._resolver.getDirectiveMetadata(<any>staticType, false);
if (directive && directive.isComponent) { if (directive && directive.isComponent) {
let promise = this._normalizer.normalizeDirective(directive).asyncResult; let promise = this._normalizer.normalizeDirective(directive).asyncResult;
@ -147,8 +147,9 @@ class Extractor {
const normalizer = new DirectiveNormalizer(xhr, urlResolver, htmlParser, config); const normalizer = new DirectiveNormalizer(xhr, urlResolver, htmlParser, config);
const expressionParser = new Parser(new Lexer()); const expressionParser = new Parser(new Lexer());
const resolver = new CompileMetadataResolver( const resolver = new CompileMetadataResolver(
new compiler.NgModuleResolver(staticReflector),
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector), new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
new compiler.ViewResolver(staticReflector), config, staticReflector); new compiler.ViewResolver(staticReflector), config, /*console*/ null, staticReflector);
// TODO(vicb): handle implicit // TODO(vicb): handle implicit
const extractor = new MessageExtractor(htmlParser, expressionParser, [], {}); const extractor = new MessageExtractor(htmlParser, expressionParser, [], {});

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
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 {AttributeMetadata, ComponentMetadata, ContentChildMetadata, ContentChildrenMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, HostMetadata, InjectMetadata, InjectableMetadata, InputMetadata, NgModuleMetadata, 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'; import {ReflectorReader} from './core_private';
@ -217,7 +217,7 @@ export class StaticReflector implements ReflectorReader {
this.registerDecoratorOrConstructor( this.registerDecoratorOrConstructor(
this.host.findDeclaration(coreDecorators, 'Component'), ComponentMetadata); this.host.findDeclaration(coreDecorators, 'Component'), ComponentMetadata);
this.registerDecoratorOrConstructor( this.registerDecoratorOrConstructor(
this.host.findDeclaration(coreDecorators, 'AppModule'), AppModuleMetadata); this.host.findDeclaration(coreDecorators, 'NgModule'), NgModuleMetadata);
// Note: Some metadata classes can be used directly with Provider.deps. // Note: Some metadata classes can be used directly with Provider.deps.
this.registerDecoratorOrConstructor( this.registerDecoratorOrConstructor(
@ -619,4 +619,4 @@ function sameSymbol(a: StaticSymbol, b: StaticSymbol): boolean {
function shouldIgnore(value: any): boolean { function shouldIgnore(value: any): boolean {
return value && value.__symbolic == 'ignore'; return value && value.__symbolic == 'ignore';
} }

View File

@ -11,7 +11,7 @@
* @description * @description
* Starting point to import all compiler APIs. * 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, OfflineCompiler, PipeResolver, RUNTIME_COMPILER_FACTORY, RenderTypes, RuntimeCompiler, SourceModule, TEMPLATE_TRANSFORMS, UrlResolver, ViewResolver, XHR, createOfflineCompileUrlResolver} from './src/compiler'; export {COMPILER_PROVIDERS, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileFactoryMetadata, CompileIdentifierMetadata, CompileMetadataWithIdentifier, CompilePipeMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata, CompilerConfig, DEFAULT_PACKAGE_URL_PROVIDER, DirectiveResolver, NgModuleResolver, OfflineCompiler, PipeResolver, RenderTypes, RuntimeCompiler, SourceModule, TEMPLATE_TRANSFORMS, UrlResolver, ViewResolver, XHR, analyzeAppProvidersForDeprecatedConfiguration, coreDynamicPlatform, createOfflineCompileUrlResolver} from './src/compiler';
export {ElementSchemaRegistry} from './src/schema/element_schema_registry'; export {ElementSchemaRegistry} from './src/schema/element_schema_registry';
export * from './src/template_ast'; export * from './src/template_ast';

View File

@ -20,8 +20,6 @@ export var LifecycleHooks: typeof t.LifecycleHooks = r.LifecycleHooks;
export var LIFECYCLE_HOOKS_VALUES: typeof t.LIFECYCLE_HOOKS_VALUES = r.LIFECYCLE_HOOKS_VALUES; export var LIFECYCLE_HOOKS_VALUES: typeof t.LIFECYCLE_HOOKS_VALUES = r.LIFECYCLE_HOOKS_VALUES;
export type ReflectorReader = t.ReflectorReader; export type ReflectorReader = t.ReflectorReader;
export var ReflectorReader: typeof t.ReflectorReader = r.ReflectorReader; export var ReflectorReader: typeof t.ReflectorReader = r.ReflectorReader;
export var ReflectorComponentResolver: typeof t.ReflectorComponentResolver =
r.ReflectorComponentResolver;
export type AppElement = t.AppElement; export type AppElement = t.AppElement;
export var AppElement: typeof t.AppElement = r.AppElement; export var AppElement: typeof t.AppElement = r.AppElement;
export var CodegenComponentFactoryResolver: typeof t.CodegenComponentFactoryResolver = export var CodegenComponentFactoryResolver: typeof t.CodegenComponentFactoryResolver =
@ -29,7 +27,7 @@ export var CodegenComponentFactoryResolver: typeof t.CodegenComponentFactoryReso
export var AppView: typeof t.AppView = r.AppView; export var AppView: typeof t.AppView = r.AppView;
export type DebugAppView<T> = t.DebugAppView<T>; export type DebugAppView<T> = t.DebugAppView<T>;
export var DebugAppView: typeof t.DebugAppView = r.DebugAppView; export var DebugAppView: typeof t.DebugAppView = r.DebugAppView;
export var AppModuleInjector: typeof t.AppModuleInjector = r.AppModuleInjector; export var NgModuleInjector: typeof t.NgModuleInjector = r.NgModuleInjector;
export type ViewType = t.ViewType; export type ViewType = t.ViewType;
export var ViewType: typeof t.ViewType = r.ViewType; export var ViewType: typeof t.ViewType = r.ViewType;
export var MAX_INTERPOLATION_VALUES: typeof t.MAX_INTERPOLATION_VALUES = r.MAX_INTERPOLATION_VALUES; export var MAX_INTERPOLATION_VALUES: typeof t.MAX_INTERPOLATION_VALUES = r.MAX_INTERPOLATION_VALUES;
@ -68,6 +66,8 @@ export var Console: typeof t.Console = r.Console;
export var reflector: t.Reflector = r.reflector; export var reflector: t.Reflector = r.reflector;
export var Reflector: typeof t.Reflector = r.Reflector; export var Reflector: typeof t.Reflector = r.Reflector;
export type Reflector = t.Reflector; export type Reflector = t.Reflector;
export var ReflectionCapabilities: typeof t.ReflectionCapabilities = r.ReflectionCapabilities;
export type ReflectionCapabilities = t.ReflectionCapabilities;
export type NoOpAnimationPlayer = t.NoOpAnimationPlayer; export type NoOpAnimationPlayer = t.NoOpAnimationPlayer;
export var NoOpAnimationPlayer: typeof t.NoOpAnimationPlayer = r.NoOpAnimationPlayer; export var NoOpAnimationPlayer: typeof t.NoOpAnimationPlayer = r.NoOpAnimationPlayer;
export type AnimationPlayer = t.AnimationPlayer; export type AnimationPlayer = t.AnimationPlayer;

View File

@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license * 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 directive_normalizer from './src/directive_normalizer';
import * as lexer from './src/expression_parser/lexer'; import * as lexer from './src/expression_parser/lexer';
import * as parser from './src/expression_parser/parser'; import * as parser from './src/expression_parser/parser';
@ -16,6 +15,7 @@ import * as i18n_message from './src/i18n/message';
import * as i18n_extractor from './src/i18n/message_extractor'; import * as i18n_extractor from './src/i18n/message_extractor';
import * as xmb_serializer from './src/i18n/xmb_serializer'; import * as xmb_serializer from './src/i18n/xmb_serializer';
import * as metadata_resolver from './src/metadata_resolver'; import * as metadata_resolver from './src/metadata_resolver';
import * as ng_module_compiler from './src/ng_module_compiler';
import * as path_util from './src/output/path_util'; import * as path_util from './src/output/path_util';
import * as ts_emitter from './src/output/ts_emitter'; import * as ts_emitter from './src/output/ts_emitter';
import * as parse_util from './src/parse_util'; import * as parse_util from './src/parse_util';
@ -99,8 +99,8 @@ export var StyleCompiler = style_compiler.StyleCompiler;
export type ViewCompiler = view_compiler.ViewCompiler; export type ViewCompiler = view_compiler.ViewCompiler;
export var ViewCompiler = view_compiler.ViewCompiler; export var ViewCompiler = view_compiler.ViewCompiler;
export type AppModuleCompiler = app_module_compiler.AppModuleCompiler; export type NgModuleCompiler = ng_module_compiler.NgModuleCompiler;
export var AppModuleCompiler = app_module_compiler.AppModuleCompiler; export var NgModuleCompiler = ng_module_compiler.NgModuleCompiler;
export type TypeScriptEmitter = ts_emitter.TypeScriptEmitter; export type TypeScriptEmitter = ts_emitter.TypeScriptEmitter;
export var TypeScriptEmitter = ts_emitter.TypeScriptEmitter; export var TypeScriptEmitter = ts_emitter.TypeScriptEmitter;

View File

@ -22,139 +22,55 @@ import {sanitizeIdentifier, splitAtColon} from './util';
// group 1: "prop" from "[prop]" // group 1: "prop" from "[prop]"
// group 2: "event" from "(event)" // group 2: "event" from "(event)"
// group 3: "@trigger" from "@trigger" // group 3: "@trigger" from "@trigger"
var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))|(\@[-\w]+)$/g; const HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))|(\@[-\w]+)$/g;
const UNDEFINED = new Object();
export abstract class CompileMetadataWithIdentifier { export abstract class CompileMetadataWithIdentifier {
abstract toJson(): {[key: string]: any};
get identifier(): CompileIdentifierMetadata { return <CompileIdentifierMetadata>unimplemented(); } get identifier(): CompileIdentifierMetadata { return <CompileIdentifierMetadata>unimplemented(); }
}
export abstract class CompileMetadataWithType extends CompileMetadataWithIdentifier { get runtimeCacheKey(): any { return unimplemented(); }
abstract toJson(): {[key: string]: any};
get type(): CompileTypeMetadata { return <CompileTypeMetadata>unimplemented(); } get assetCacheKey(): any { return unimplemented(); }
get identifier(): CompileIdentifierMetadata { return <CompileIdentifierMetadata>unimplemented(); } equalsTo(id2: CompileMetadataWithIdentifier): boolean { return unimplemented(); }
}
export function metadataFromJson(data: {[key: string]: any}): any {
return (_COMPILE_METADATA_FROM_JSON as any)[data['class']](data);
} }
export class CompileAnimationEntryMetadata { export class CompileAnimationEntryMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationEntryMetadata {
var value = data['value'];
var defs = _arrayFromJson(value['definitions'], metadataFromJson);
return new CompileAnimationEntryMetadata(value['name'], defs);
}
constructor( constructor(
public name: string = null, public definitions: CompileAnimationStateMetadata[] = null) {} public name: string = null, public definitions: CompileAnimationStateMetadata[] = null) {}
toJson(): {[key: string]: any} {
return {
'class': 'AnimationEntryMetadata',
'value': {'name': this.name, 'definitions': _arrayToJson(this.definitions)}
};
}
} }
export abstract class CompileAnimationStateMetadata {} export abstract class CompileAnimationStateMetadata {}
export class CompileAnimationStateDeclarationMetadata extends CompileAnimationStateMetadata { export class CompileAnimationStateDeclarationMetadata extends CompileAnimationStateMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationStateDeclarationMetadata {
var value = data['value'];
var styles = _objFromJson(value['styles'], metadataFromJson);
return new CompileAnimationStateDeclarationMetadata(value['stateNameExpr'], styles);
}
constructor(public stateNameExpr: string, public styles: CompileAnimationStyleMetadata) { constructor(public stateNameExpr: string, public styles: CompileAnimationStyleMetadata) {
super(); super();
} }
toJson(): {[key: string]: any} {
return {
'class': 'AnimationStateDeclarationMetadata',
'value': {'stateNameExpr': this.stateNameExpr, 'styles': this.styles.toJson()}
};
}
} }
export class CompileAnimationStateTransitionMetadata extends CompileAnimationStateMetadata { export class CompileAnimationStateTransitionMetadata extends CompileAnimationStateMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationStateTransitionMetadata {
var value = data['value'];
var steps = _objFromJson(value['steps'], metadataFromJson);
return new CompileAnimationStateTransitionMetadata(value['stateChangeExpr'], steps);
}
constructor(public stateChangeExpr: string, public steps: CompileAnimationMetadata) { super(); } constructor(public stateChangeExpr: string, public steps: CompileAnimationMetadata) { super(); }
toJson(): {[key: string]: any} {
return {
'class': 'AnimationStateTransitionMetadata',
'value': {'stateChangeExpr': this.stateChangeExpr, 'steps': this.steps.toJson()}
};
}
} }
export abstract class CompileAnimationMetadata { abstract toJson(): {[key: string]: any}; } export abstract class CompileAnimationMetadata {}
export class CompileAnimationKeyframesSequenceMetadata extends CompileAnimationMetadata { export class CompileAnimationKeyframesSequenceMetadata extends CompileAnimationMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationKeyframesSequenceMetadata {
var steps = _arrayFromJson(data['value'], metadataFromJson);
return new CompileAnimationKeyframesSequenceMetadata(<CompileAnimationStyleMetadata[]>steps);
}
constructor(public steps: CompileAnimationStyleMetadata[] = []) { super(); } constructor(public steps: CompileAnimationStyleMetadata[] = []) { super(); }
toJson(): {[key: string]: any} {
return {'class': 'AnimationKeyframesSequenceMetadata', 'value': _arrayToJson(this.steps)};
}
} }
export class CompileAnimationStyleMetadata extends CompileAnimationMetadata { export class CompileAnimationStyleMetadata extends CompileAnimationMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationStyleMetadata {
var value = data['value'];
var offsetVal = value['offset'];
var offset = isPresent(offsetVal) ? NumberWrapper.parseFloat(offsetVal) : null;
var styles = <Array<string|{[key: string]: string | number}>>value['styles'];
return new CompileAnimationStyleMetadata(offset, styles);
}
constructor( constructor(
public offset: number, public styles: Array<string|{[key: string]: string | number}> = null) { public offset: number, public styles: Array<string|{[key: string]: string | number}> = null) {
super(); super();
} }
toJson(): {[key: string]: any} {
return {
'class': 'AnimationStyleMetadata',
'value': {'offset': this.offset, 'styles': this.styles}
};
}
} }
export class CompileAnimationAnimateMetadata extends CompileAnimationMetadata { export class CompileAnimationAnimateMetadata extends CompileAnimationMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationAnimateMetadata {
var value = data['value'];
var timings = <string|number>value['timings'];
var styles = _objFromJson(value['styles'], metadataFromJson);
return new CompileAnimationAnimateMetadata(timings, styles);
}
constructor( constructor(
public timings: string|number = 0, public styles: CompileAnimationStyleMetadata| public timings: string|number = 0, public styles: CompileAnimationStyleMetadata|
CompileAnimationKeyframesSequenceMetadata = null) { CompileAnimationKeyframesSequenceMetadata = null) {
super(); super();
} }
toJson(): {[key: string]: any} {
return {
'class': 'AnimationAnimateMetadata',
'value': {'timings': this.timings, 'styles': _objToJson(this.styles)}
};
}
} }
export abstract class CompileAnimationWithStepsMetadata extends CompileAnimationMetadata { export abstract class CompileAnimationWithStepsMetadata extends CompileAnimationMetadata {
@ -162,29 +78,11 @@ export abstract class CompileAnimationWithStepsMetadata extends CompileAnimation
} }
export class CompileAnimationSequenceMetadata extends CompileAnimationWithStepsMetadata { export class CompileAnimationSequenceMetadata extends CompileAnimationWithStepsMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationSequenceMetadata {
var steps = _arrayFromJson(data['value'], metadataFromJson);
return new CompileAnimationSequenceMetadata(steps);
}
constructor(steps: CompileAnimationMetadata[] = null) { super(steps); } constructor(steps: CompileAnimationMetadata[] = null) { super(steps); }
toJson(): {[key: string]: any} {
return {'class': 'AnimationSequenceMetadata', 'value': _arrayToJson(this.steps)};
}
} }
export class CompileAnimationGroupMetadata extends CompileAnimationWithStepsMetadata { export class CompileAnimationGroupMetadata extends CompileAnimationWithStepsMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationGroupMetadata {
var steps = _arrayFromJson(data['value'], metadataFromJson);
return new CompileAnimationGroupMetadata(steps);
}
constructor(steps: CompileAnimationMetadata[] = null) { super(steps); } constructor(steps: CompileAnimationMetadata[] = null) { super(steps); }
toJson(): {[key: string]: any} {
return {'class': 'AnimationGroupMetadata', 'value': _arrayToJson(this.steps)};
}
} }
export class CompileIdentifierMetadata implements CompileMetadataWithIdentifier { export class CompileIdentifierMetadata implements CompileMetadataWithIdentifier {
@ -193,6 +91,7 @@ export class CompileIdentifierMetadata implements CompileMetadataWithIdentifier
prefix: string; prefix: string;
moduleUrl: string; moduleUrl: string;
value: any; value: any;
private _assetCacheKey: any = UNDEFINED;
constructor( constructor(
{runtime, name, moduleUrl, prefix, value}: {runtime, name, moduleUrl, prefix, value}:
@ -204,26 +103,28 @@ export class CompileIdentifierMetadata implements CompileMetadataWithIdentifier
this.value = value; this.value = value;
} }
static fromJson(data: {[key: string]: any}): CompileIdentifierMetadata {
let value = isArray(data['value']) ? _arrayFromJson(data['value'], metadataFromJson) :
_objFromJson(data['value'], metadataFromJson);
return new CompileIdentifierMetadata(
{name: data['name'], prefix: data['prefix'], moduleUrl: data['moduleUrl'], value: value});
}
toJson(): {[key: string]: any} {
let value = isArray(this.value) ? _arrayToJson(this.value) : _objToJson(this.value);
return {
// Note: Runtime type can't be serialized...
'class': 'Identifier',
'name': this.name,
'moduleUrl': this.moduleUrl,
'prefix': this.prefix,
'value': value
};
}
get identifier(): CompileIdentifierMetadata { return this; } get identifier(): CompileIdentifierMetadata { return this; }
get runtimeCacheKey(): any { return this.identifier.runtime; }
get assetCacheKey(): any {
if (this._assetCacheKey === UNDEFINED) {
if (isPresent(this.moduleUrl) && isPresent(getUrlScheme(this.moduleUrl))) {
var uri = reflector.importUri({'filePath': this.moduleUrl, 'name': this.name});
this._assetCacheKey = `${this.name}|${uri}`;
} else {
this._assetCacheKey = null;
}
}
return this._assetCacheKey;
}
equalsTo(id2: CompileIdentifierMetadata): boolean {
var rk = this.runtimeCacheKey;
var ak = this.assetCacheKey;
return (isPresent(rk) && rk == id2.runtimeCacheKey) ||
(isPresent(ak) && ak == id2.assetCacheKey);
}
} }
export class CompileDiDependencyMetadata { export class CompileDiDependencyMetadata {
@ -263,36 +164,6 @@ export class CompileDiDependencyMetadata {
this.token = token; this.token = token;
this.value = value; this.value = value;
} }
static fromJson(data: {[key: string]: any}): CompileDiDependencyMetadata {
return new CompileDiDependencyMetadata({
token: _objFromJson(data['token'], CompileTokenMetadata.fromJson),
query: _objFromJson(data['query'], CompileQueryMetadata.fromJson),
viewQuery: _objFromJson(data['viewQuery'], CompileQueryMetadata.fromJson),
value: data['value'],
isAttribute: data['isAttribute'],
isSelf: data['isSelf'],
isHost: data['isHost'],
isSkipSelf: data['isSkipSelf'],
isOptional: data['isOptional'],
isValue: data['isValue']
});
}
toJson(): {[key: string]: any} {
return {
'token': _objToJson(this.token),
'query': _objToJson(this.query),
'viewQuery': _objToJson(this.viewQuery),
'value': this.value,
'isAttribute': this.isAttribute,
'isSelf': this.isSelf,
'isHost': this.isHost,
'isSkipSelf': this.isSkipSelf,
'isOptional': this.isOptional,
'isValue': this.isValue
};
}
} }
export class CompileProviderMetadata { export class CompileProviderMetadata {
@ -321,41 +192,9 @@ export class CompileProviderMetadata {
this.deps = normalizeBlank(deps); this.deps = normalizeBlank(deps);
this.multi = normalizeBool(multi); this.multi = normalizeBool(multi);
} }
static fromJson(data: {[key: string]: any}): CompileProviderMetadata {
return new CompileProviderMetadata({
token: _objFromJson(data['token'], CompileTokenMetadata.fromJson),
useClass: _objFromJson(data['useClass'], CompileTypeMetadata.fromJson),
useExisting: _objFromJson(data['useExisting'], CompileTokenMetadata.fromJson),
useValue: _objFromJson(data['useValue'], CompileIdentifierMetadata.fromJson),
useFactory: _objFromJson(data['useFactory'], CompileFactoryMetadata.fromJson),
multi: data['multi'],
deps: _arrayFromJson(data['deps'], CompileDiDependencyMetadata.fromJson)
});
}
toJson(): {[key: string]: any} {
return {
// Note: Runtime type can't be serialized...
'class': 'Provider',
'token': _objToJson(this.token),
'useClass': _objToJson(this.useClass),
'useExisting': _objToJson(this.useExisting),
'useValue': _objToJson(this.useValue),
'useFactory': _objToJson(this.useFactory),
'multi': this.multi,
'deps': _arrayToJson(this.deps)
};
}
} }
export class CompileFactoryMetadata implements CompileIdentifierMetadata, export class CompileFactoryMetadata extends CompileIdentifierMetadata {
CompileMetadataWithIdentifier {
runtime: Function;
name: string;
prefix: string;
moduleUrl: string;
value: any;
diDeps: CompileDiDependencyMetadata[]; diDeps: CompileDiDependencyMetadata[];
constructor({runtime, name, moduleUrl, prefix, diDeps, value}: { constructor({runtime, name, moduleUrl, prefix, diDeps, value}: {
@ -366,45 +205,15 @@ export class CompileFactoryMetadata implements CompileIdentifierMetadata,
value?: boolean, value?: boolean,
diDeps?: CompileDiDependencyMetadata[] diDeps?: CompileDiDependencyMetadata[]
}) { }) {
this.runtime = runtime; super({runtime: runtime, name: name, prefix: prefix, moduleUrl: moduleUrl, value: value});
this.name = name;
this.prefix = prefix;
this.moduleUrl = moduleUrl;
this.diDeps = _normalizeArray(diDeps); this.diDeps = _normalizeArray(diDeps);
this.value = value;
}
get identifier(): CompileIdentifierMetadata { return this; }
static fromJson(data: {[key: string]: any}): CompileFactoryMetadata {
return new CompileFactoryMetadata({
name: data['name'],
prefix: data['prefix'],
moduleUrl: data['moduleUrl'],
value: data['value'],
diDeps: _arrayFromJson(data['diDeps'], CompileDiDependencyMetadata.fromJson)
});
}
toJson(): {[key: string]: any} {
return {
'class': 'Factory',
'name': this.name,
'prefix': this.prefix,
'moduleUrl': this.moduleUrl,
'value': this.value,
'diDeps': _arrayToJson(this.diDeps)
};
} }
} }
var UNDEFINED = new Object();
export class CompileTokenMetadata implements CompileMetadataWithIdentifier { export class CompileTokenMetadata implements CompileMetadataWithIdentifier {
value: any; value: any;
identifier: CompileIdentifierMetadata; identifier: CompileIdentifierMetadata;
identifierIsInstance: boolean; identifierIsInstance: boolean;
private _assetCacheKey = UNDEFINED;
constructor( constructor(
{value, identifier, identifierIsInstance}: {value, identifier, identifierIsInstance}:
@ -414,46 +223,20 @@ export class CompileTokenMetadata implements CompileMetadataWithIdentifier {
this.identifierIsInstance = normalizeBool(identifierIsInstance); this.identifierIsInstance = normalizeBool(identifierIsInstance);
} }
static fromJson(data: {[key: string]: any}): CompileTokenMetadata {
return new CompileTokenMetadata({
value: data['value'],
identifier: _objFromJson(data['identifier'], CompileIdentifierMetadata.fromJson),
identifierIsInstance: data['identifierIsInstance']
});
}
toJson(): {[key: string]: any} {
return {
'value': this.value,
'identifier': _objToJson(this.identifier),
'identifierIsInstance': this.identifierIsInstance
};
}
get runtimeCacheKey(): any { get runtimeCacheKey(): any {
if (isPresent(this.identifier)) { if (isPresent(this.identifier)) {
return this.identifier.runtime; return this.identifier.runtimeCacheKey;
} else { } else {
return this.value; return this.value;
} }
} }
get assetCacheKey(): any { get assetCacheKey(): any {
if (this._assetCacheKey === UNDEFINED) { if (isPresent(this.identifier)) {
if (isPresent(this.identifier)) { return this.identifier.assetCacheKey;
if (isPresent(this.identifier.moduleUrl) && } else {
isPresent(getUrlScheme(this.identifier.moduleUrl))) { return this.value;
var uri = reflector.importUri(
{'filePath': this.identifier.moduleUrl, 'name': this.identifier.name});
this._assetCacheKey = `${this.identifier.name}|${uri}|${this.identifierIsInstance}`;
} else {
this._assetCacheKey = null;
}
} else {
this._assetCacheKey = this.value;
}
} }
return this._assetCacheKey;
} }
equalsTo(token2: CompileTokenMetadata): boolean { equalsTo(token2: CompileTokenMetadata): boolean {
@ -468,15 +251,24 @@ export class CompileTokenMetadata implements CompileMetadataWithIdentifier {
} }
} }
export class CompileTokenMap<VALUE> { /**
* Note: We only need this in places where we need to support identifiers that
* don't have a `runtime` value given by the `StaticReflector`. E.g. see the `identifiers`
* file where we have some identifiers hard coded by name/module path.
*
* TODO(tbosch): Eventually, all of these places should go through the static reflector
* as well, providing them with a valid `StaticSymbol` that is again a singleton.
*/
export class CompileIdentifierMap<KEY extends CompileMetadataWithIdentifier, VALUE> {
private _valueMap = new Map<any, VALUE>(); private _valueMap = new Map<any, VALUE>();
private _values: VALUE[] = []; private _values: VALUE[] = [];
private _tokens: CompileTokenMetadata[] = []; private _tokens: KEY[] = [];
add(token: CompileTokenMetadata, value: VALUE) { add(token: KEY, value: VALUE) {
var existing = this.get(token); var existing = this.get(token);
if (isPresent(existing)) { if (isPresent(existing)) {
throw new BaseException(`Can only add to a TokenMap! Token: ${token.name}`); throw new BaseException(
`Cannot overwrite in a CompileIdentifierMap! Token: ${token.identifier.name}`);
} }
this._tokens.push(token); this._tokens.push(token);
this._values.push(value); this._values.push(value);
@ -489,7 +281,7 @@ export class CompileTokenMap<VALUE> {
this._valueMap.set(ak, value); this._valueMap.set(ak, value);
} }
} }
get(token: CompileTokenMetadata): VALUE { get(token: KEY): VALUE {
var rk = token.runtimeCacheKey; var rk = token.runtimeCacheKey;
var ak = token.assetCacheKey; var ak = token.assetCacheKey;
var result: VALUE; var result: VALUE;
@ -501,7 +293,7 @@ export class CompileTokenMap<VALUE> {
} }
return result; return result;
} }
keys(): CompileTokenMetadata[] { return this._tokens; } keys(): KEY[] { return this._tokens; }
values(): VALUE[] { return this._values; } values(): VALUE[] { return this._values; }
get size(): number { return this._values.length; } get size(): number { return this._values.length; }
} }
@ -509,13 +301,8 @@ export class CompileTokenMap<VALUE> {
/** /**
* Metadata regarding compilation of a type. * Metadata regarding compilation of a type.
*/ */
export class CompileTypeMetadata implements CompileIdentifierMetadata, CompileMetadataWithType { export class CompileTypeMetadata extends CompileIdentifierMetadata {
runtime: Type;
name: string;
prefix: string;
moduleUrl: string;
isHost: boolean; isHost: boolean;
value: any;
diDeps: CompileDiDependencyMetadata[]; diDeps: CompileDiDependencyMetadata[];
constructor({runtime, name, moduleUrl, prefix, isHost, value, diDeps}: { constructor({runtime, name, moduleUrl, prefix, isHost, value, diDeps}: {
@ -527,41 +314,10 @@ export class CompileTypeMetadata implements CompileIdentifierMetadata, CompileMe
value?: any, value?: any,
diDeps?: CompileDiDependencyMetadata[] diDeps?: CompileDiDependencyMetadata[]
} = {}) { } = {}) {
this.runtime = runtime; super({runtime: runtime, name: name, moduleUrl: moduleUrl, prefix: prefix, value: value});
this.name = name;
this.moduleUrl = moduleUrl;
this.prefix = prefix;
this.isHost = normalizeBool(isHost); this.isHost = normalizeBool(isHost);
this.value = value;
this.diDeps = _normalizeArray(diDeps); this.diDeps = _normalizeArray(diDeps);
} }
static fromJson(data: {[key: string]: any}): CompileTypeMetadata {
return new CompileTypeMetadata({
name: data['name'],
moduleUrl: data['moduleUrl'],
prefix: data['prefix'],
isHost: data['isHost'],
value: data['value'],
diDeps: _arrayFromJson(data['diDeps'], CompileDiDependencyMetadata.fromJson)
});
}
get identifier(): CompileIdentifierMetadata { return this; }
get type(): CompileTypeMetadata { return this; }
toJson(): {[key: string]: any} {
return {
// Note: Runtime type can't be serialized...
'class': 'Type',
'name': this.name,
'moduleUrl': this.moduleUrl,
'prefix': this.prefix,
'isHost': this.isHost,
'value': this.value,
'diDeps': _arrayToJson(this.diDeps)
};
}
} }
export class CompileQueryMetadata { export class CompileQueryMetadata {
@ -584,26 +340,6 @@ export class CompileQueryMetadata {
this.propertyName = propertyName; this.propertyName = propertyName;
this.read = read; this.read = read;
} }
static fromJson(data: {[key: string]: any}): CompileQueryMetadata {
return new CompileQueryMetadata({
selectors: _arrayFromJson(data['selectors'], CompileTokenMetadata.fromJson),
descendants: data['descendants'],
first: data['first'],
propertyName: data['propertyName'],
read: _objFromJson(data['read'], CompileTokenMetadata.fromJson)
});
}
toJson(): {[key: string]: any} {
return {
'selectors': _arrayToJson(this.selectors),
'descendants': this.descendants,
'first': this.first,
'propertyName': this.propertyName,
'read': _objToJson(this.read)
};
}
} }
/** /**
@ -620,15 +356,6 @@ export class CompileStylesheetMetadata {
this.styles = _normalizeArray(styles); this.styles = _normalizeArray(styles);
this.styleUrls = _normalizeArray(styleUrls); this.styleUrls = _normalizeArray(styleUrls);
} }
static fromJson(data: {[key: string]: any}): CompileStylesheetMetadata {
return new CompileStylesheetMetadata(
{moduleUrl: data['moduleUrl'], styles: data['styles'], styleUrls: data['styleUrls']});
}
toJson(): {[key: string]: any} {
return {'moduleUrl': this.moduleUrl, 'styles': this.styles, 'styleUrls': this.styleUrls};
}
} }
/** /**
@ -670,46 +397,12 @@ export class CompileTemplateMetadata {
} }
this.interpolation = interpolation; this.interpolation = interpolation;
} }
static fromJson(data: {[key: string]: any}): CompileTemplateMetadata {
var animations =
<CompileAnimationEntryMetadata[]>_arrayFromJson(data['animations'], metadataFromJson);
return new CompileTemplateMetadata({
encapsulation: isPresent(data['encapsulation']) ?
VIEW_ENCAPSULATION_VALUES[data['encapsulation']] :
data['encapsulation'],
template: data['template'],
templateUrl: data['templateUrl'],
styles: data['styles'],
styleUrls: data['styleUrls'],
externalStylesheets:
_arrayFromJson(data['externalStylesheets'], CompileStylesheetMetadata.fromJson),
animations: animations,
ngContentSelectors: data['ngContentSelectors'],
interpolation: data['interpolation']
});
}
toJson(): {[key: string]: any} {
return {
'encapsulation': isPresent(this.encapsulation) ? serializeEnum(this.encapsulation) :
this.encapsulation,
'template': this.template,
'templateUrl': this.templateUrl,
'styles': this.styles,
'styleUrls': this.styleUrls,
'externalStylesheets': _objToJson(this.externalStylesheets),
'animations': _objToJson(this.animations),
'ngContentSelectors': this.ngContentSelectors,
'interpolation': this.interpolation
};
}
} }
/** /**
* Metadata regarding compilation of a directive. * Metadata regarding compilation of a directive.
*/ */
export class CompileDirectiveMetadata implements CompileMetadataWithType { export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
static create( static create(
{type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host, {type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
lifecycleHooks, providers, viewProviders, queries, viewQueries, precompile, template}: { lifecycleHooks, providers, viewProviders, queries, viewQueries, precompile, template}: {
@ -796,6 +489,7 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
viewProviders: CompileProviderMetadata[]; viewProviders: CompileProviderMetadata[];
queries: CompileQueryMetadata[]; queries: CompileQueryMetadata[];
viewQueries: CompileQueryMetadata[]; viewQueries: CompileQueryMetadata[];
// Note: Need to keep types here to prevent cycles!
precompile: CompileTypeMetadata[]; precompile: CompileTypeMetadata[];
template: CompileTemplateMetadata; template: CompileTemplateMetadata;
@ -844,68 +538,26 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
get identifier(): CompileIdentifierMetadata { return this.type; } get identifier(): CompileIdentifierMetadata { return this.type; }
static fromJson(data: {[key: string]: any}): CompileDirectiveMetadata { get runtimeCacheKey(): any { return this.type.runtimeCacheKey; }
return new CompileDirectiveMetadata({
isComponent: data['isComponent'],
selector: data['selector'],
exportAs: data['exportAs'],
type: isPresent(data['type']) ? CompileTypeMetadata.fromJson(data['type']) : data['type'],
changeDetection: isPresent(data['changeDetection']) ?
CHANGE_DETECTION_STRATEGY_VALUES[data['changeDetection']] :
data['changeDetection'],
inputs: data['inputs'],
outputs: data['outputs'],
hostListeners: data['hostListeners'],
hostProperties: data['hostProperties'],
hostAttributes: data['hostAttributes'],
lifecycleHooks:
(<any[]>data['lifecycleHooks']).map(hookValue => LIFECYCLE_HOOKS_VALUES[hookValue]),
template: isPresent(data['template']) ? CompileTemplateMetadata.fromJson(data['template']) :
data['template'],
providers: _arrayFromJson(data['providers'], metadataFromJson),
viewProviders: _arrayFromJson(data['viewProviders'], metadataFromJson),
queries: _arrayFromJson(data['queries'], CompileQueryMetadata.fromJson),
viewQueries: _arrayFromJson(data['viewQueries'], CompileQueryMetadata.fromJson),
precompile: _arrayFromJson(data['precompile'], CompileTypeMetadata.fromJson)
});
}
toJson(): {[key: string]: any} { get assetCacheKey(): any { return this.type.assetCacheKey; }
return {
'class': 'Directive', equalsTo(other: CompileMetadataWithIdentifier): boolean {
'isComponent': this.isComponent, return this.type.equalsTo(other.identifier);
'selector': this.selector,
'exportAs': this.exportAs,
'type': isPresent(this.type) ? this.type.toJson() : this.type,
'changeDetection': isPresent(this.changeDetection) ? serializeEnum(this.changeDetection) :
this.changeDetection,
'inputs': this.inputs,
'outputs': this.outputs,
'hostListeners': this.hostListeners,
'hostProperties': this.hostProperties,
'hostAttributes': this.hostAttributes,
'lifecycleHooks': this.lifecycleHooks.map(hook => serializeEnum(hook)),
'template': isPresent(this.template) ? this.template.toJson() : this.template,
'providers': _arrayToJson(this.providers),
'viewProviders': _arrayToJson(this.viewProviders),
'queries': _arrayToJson(this.queries),
'viewQueries': _arrayToJson(this.viewQueries),
'precompile': _arrayToJson(this.precompile)
};
} }
} }
/** /**
* Construct {@link CompileDirectiveMetadata} from {@link ComponentTypeMetadata} and a selector. * Construct {@link CompileDirectiveMetadata} from {@link ComponentTypeMetadata} and a selector.
*/ */
export function createHostComponentMeta( export function createHostComponentMeta(compMeta: CompileDirectiveMetadata):
componentType: CompileTypeMetadata, componentSelector: string): CompileDirectiveMetadata { CompileDirectiveMetadata {
var template = CssSelector.parse(componentSelector)[0].getMatchingElementTemplate(); var template = CssSelector.parse(compMeta.selector)[0].getMatchingElementTemplate();
return CompileDirectiveMetadata.create({ return CompileDirectiveMetadata.create({
type: new CompileTypeMetadata({ type: new CompileTypeMetadata({
runtime: Object, runtime: Object,
name: `${componentType.name}_Host`, name: `${compMeta.type.name}_Host`,
moduleUrl: componentType.moduleUrl, moduleUrl: compMeta.type.moduleUrl,
isHost: true isHost: true
}), }),
template: new CompileTemplateMetadata({ template: new CompileTemplateMetadata({
@ -931,7 +583,7 @@ export function createHostComponentMeta(
} }
export class CompilePipeMetadata implements CompileMetadataWithType { export class CompilePipeMetadata implements CompileMetadataWithIdentifier {
type: CompileTypeMetadata; type: CompileTypeMetadata;
name: string; name: string;
pure: boolean; pure: boolean;
@ -949,114 +601,91 @@ export class CompilePipeMetadata implements CompileMetadataWithType {
this.lifecycleHooks = _normalizeArray(lifecycleHooks); this.lifecycleHooks = _normalizeArray(lifecycleHooks);
} }
get identifier(): CompileIdentifierMetadata { return this.type; } get identifier(): CompileIdentifierMetadata { return this.type; }
get runtimeCacheKey(): any { return this.type.runtimeCacheKey; }
static fromJson(data: {[key: string]: any}): CompilePipeMetadata { get assetCacheKey(): any { return this.type.assetCacheKey; }
return new CompilePipeMetadata({
type: isPresent(data['type']) ? CompileTypeMetadata.fromJson(data['type']) : data['type'],
name: data['name'],
pure: data['pure']
});
}
toJson(): {[key: string]: any} { equalsTo(other: CompileMetadataWithIdentifier): boolean {
return { return this.type.equalsTo(other.identifier);
'class': 'Pipe',
'type': isPresent(this.type) ? this.type.toJson() : null,
'name': this.name,
'pure': this.pure
};
} }
} }
/** /**
* Metadata regarding compilation of a directive. * Metadata regarding compilation of a directive.
*/ */
export class CompileAppModuleMetadata implements CompileMetadataWithType { export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
type: CompileTypeMetadata; type: CompileTypeMetadata;
providers: CompileProviderMetadata[]; declaredDirectives: CompileDirectiveMetadata[];
directives: CompileTypeMetadata[]; exportedDirectives: CompileDirectiveMetadata[];
pipes: CompileTypeMetadata[]; declaredPipes: CompilePipeMetadata[];
exportedPipes: CompilePipeMetadata[];
// Note: See CompileDirectiveMetadata.precompile why this has to be a type.
precompile: CompileTypeMetadata[]; precompile: CompileTypeMetadata[];
modules: CompileTypeMetadata[]; providers: CompileProviderMetadata[];
constructor({type, providers, directives, pipes, precompile, modules}: { importedModules: CompileNgModuleMetadata[];
type?: CompileTypeMetadata, exportedModules: CompileNgModuleMetadata[];
providers?: Array<CompileProviderMetadata|CompileTypeMetadata|CompileIdentifierMetadata|any[]>,
directives?: CompileTypeMetadata[], transitiveModule: TransitiveCompileNgModuleMetadata;
pipes?: CompileTypeMetadata[],
precompile?: CompileTypeMetadata[], constructor(
modules?: CompileTypeMetadata[] {type, providers, declaredDirectives, exportedDirectives, declaredPipes, exportedPipes,
} = {}) { precompile, importedModules, exportedModules, transitiveModule}: {
type?: CompileTypeMetadata,
providers?:
Array<CompileProviderMetadata|CompileTypeMetadata|CompileIdentifierMetadata|any[]>,
declaredDirectives?: CompileDirectiveMetadata[],
exportedDirectives?: CompileDirectiveMetadata[],
declaredPipes?: CompilePipeMetadata[],
exportedPipes?: CompilePipeMetadata[],
precompile?: CompileTypeMetadata[],
importedModules?: CompileNgModuleMetadata[],
exportedModules?: CompileNgModuleMetadata[],
transitiveModule?: TransitiveCompileNgModuleMetadata
} = {}) {
this.type = type; this.type = type;
this.directives = _normalizeArray(directives); this.declaredDirectives = _normalizeArray(declaredDirectives);
this.pipes = _normalizeArray(pipes); this.exportedDirectives = _normalizeArray(exportedDirectives);
this.declaredPipes = _normalizeArray(declaredPipes);
this.exportedPipes = _normalizeArray(exportedPipes);
this.providers = _normalizeArray(providers); this.providers = _normalizeArray(providers);
this.precompile = _normalizeArray(precompile); this.precompile = _normalizeArray(precompile);
this.modules = _normalizeArray(modules); this.importedModules = _normalizeArray(importedModules);
this.exportedModules = _normalizeArray(exportedModules);
this.transitiveModule = transitiveModule;
} }
get identifier(): CompileIdentifierMetadata { return this.type; } get identifier(): CompileIdentifierMetadata { return this.type; }
get runtimeCacheKey(): any { return this.type.runtimeCacheKey; }
static fromJson(data: {[key: string]: any}): CompileAppModuleMetadata { get assetCacheKey(): any { return this.type.assetCacheKey; }
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} { equalsTo(other: CompileMetadataWithIdentifier): boolean {
return { return this.type.equalsTo(other.identifier);
'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 = { export class TransitiveCompileNgModuleMetadata {
'AppModule': CompileAppModuleMetadata.fromJson, directivesSet = new Set<Type>();
'Directive': CompileDirectiveMetadata.fromJson, pipesSet = new Set<Type>();
'Pipe': CompilePipeMetadata.fromJson, constructor(
'Type': CompileTypeMetadata.fromJson, public modules: CompileNgModuleMetadata[], public providers: CompileProviderMetadata[],
'Provider': CompileProviderMetadata.fromJson, public precompile: CompileTypeMetadata[], public directives: CompileDirectiveMetadata[],
'Identifier': CompileIdentifierMetadata.fromJson, public pipes: CompilePipeMetadata[]) {
'Factory': CompileFactoryMetadata.fromJson, directives.forEach(dir => this.directivesSet.add(dir.type.runtime));
'AnimationEntryMetadata': CompileAnimationEntryMetadata.fromJson, pipes.forEach(pipe => this.pipesSet.add(pipe.type.runtime));
'AnimationStateDeclarationMetadata': CompileAnimationStateDeclarationMetadata.fromJson, }
'AnimationStateTransitionMetadata': CompileAnimationStateTransitionMetadata.fromJson,
'AnimationSequenceMetadata': CompileAnimationSequenceMetadata.fromJson,
'AnimationGroupMetadata': CompileAnimationGroupMetadata.fromJson,
'AnimationAnimateMetadata': CompileAnimationAnimateMetadata.fromJson,
'AnimationStyleMetadata': CompileAnimationStyleMetadata.fromJson,
'AnimationKeyframesSequenceMetadata': CompileAnimationKeyframesSequenceMetadata.fromJson
};
function _arrayFromJson(obj: any[], fn: (a: {[key: string]: any}) => any): any {
return isBlank(obj) ? null : obj.map(o => _objFromJson(o, fn));
} }
function _arrayToJson(obj: any[]): string|{[key: string]: any} { export function removeIdentifierDuplicates<T extends CompileMetadataWithIdentifier>(items: T[]):
return isBlank(obj) ? null : obj.map(_objToJson); T[] {
} const map = new CompileIdentifierMap<T, T>();
items.forEach((item) => {
function _objFromJson(obj: any, fn: (a: {[key: string]: any}) => any): any { if (!map.get(item)) {
if (isArray(obj)) return _arrayFromJson(obj, fn); map.add(item, item);
if (isString(obj) || isBlank(obj) || isBoolean(obj) || isNumber(obj)) return obj; }
return fn(obj); });
} return map.keys();
function _objToJson(obj: any): string|{[key: string]: any} {
if (isArray(obj)) return _arrayToJson(obj);
if (isString(obj) || isBlank(obj) || isBoolean(obj) || isNumber(obj)) return obj;
return obj.toJson();
} }
function _normalizeArray(obj: any[]): any[] { function _normalizeArray(obj: any[]): any[] {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Compiler, CompilerFactory, CompilerOptions, ComponentResolver, Injectable, PLATFORM_DIRECTIVES, PLATFORM_PIPES, ReflectiveInjector, Type, ViewEncapsulation, isDevMode} from '@angular/core'; import {Compiler, CompilerFactory, CompilerOptions, Component, ComponentResolver, Inject, Injectable, NgModule, PLATFORM_DIRECTIVES, PLATFORM_INITIALIZER, PLATFORM_PIPES, PlatformRef, ReflectiveInjector, Type, ViewEncapsulation, corePlatform, createPlatformFactory, disposePlatform, isDevMode} from '@angular/core';
export * from './template_ast'; export * from './template_ast';
export {TEMPLATE_TRANSFORMS} from './template_parser'; export {TEMPLATE_TRANSFORMS} from './template_parser';
@ -20,14 +20,17 @@ export * from './xhr';
export {ViewResolver} from './view_resolver'; export {ViewResolver} from './view_resolver';
export {DirectiveResolver} from './directive_resolver'; export {DirectiveResolver} from './directive_resolver';
export {PipeResolver} from './pipe_resolver'; export {PipeResolver} from './pipe_resolver';
export {NgModuleResolver} from './ng_module_resolver';
import {stringify} from './facade/lang';
import {ListWrapper} from './facade/collection';
import {TemplateParser} from './template_parser'; import {TemplateParser} from './template_parser';
import {HtmlParser} from './html_parser'; import {HtmlParser} from './html_parser';
import {DirectiveNormalizer} from './directive_normalizer'; import {DirectiveNormalizer} from './directive_normalizer';
import {CompileMetadataResolver} from './metadata_resolver'; import {CompileMetadataResolver} from './metadata_resolver';
import {StyleCompiler} from './style_compiler'; import {StyleCompiler} from './style_compiler';
import {ViewCompiler} from './view_compiler/view_compiler'; import {ViewCompiler} from './view_compiler/view_compiler';
import {AppModuleCompiler} from './app_module_compiler'; import {NgModuleCompiler} from './ng_module_compiler';
import {CompilerConfig} from './config'; import {CompilerConfig} from './config';
import {RuntimeCompiler} from './runtime_compiler'; import {RuntimeCompiler} from './runtime_compiler';
import {ElementSchemaRegistry} from './schema/element_schema_registry'; import {ElementSchemaRegistry} from './schema/element_schema_registry';
@ -38,19 +41,24 @@ import {Lexer} from './expression_parser/lexer';
import {ViewResolver} from './view_resolver'; import {ViewResolver} from './view_resolver';
import {DirectiveResolver} from './directive_resolver'; import {DirectiveResolver} from './directive_resolver';
import {PipeResolver} from './pipe_resolver'; import {PipeResolver} from './pipe_resolver';
import {Console, Reflector, reflector, ReflectorReader} from '../core_private'; import {NgModuleResolver} from './ng_module_resolver';
import {Console, Reflector, reflector, ReflectorReader, ReflectionCapabilities} from '../core_private';
import {XHR} from './xhr'; import {XHR} from './xhr';
const _NO_XHR: XHR = {
get(url: string): Promise<string>{
throw new Error(`No XHR implementation has been provided. Can't read the url "${url}"`);}
};
/** /**
* A set of providers that provide `RuntimeCompiler` and its dependencies to use for * A set of providers that provide `RuntimeCompiler` and its dependencies to use for
* template compilation. * template compilation.
*/ */
export const COMPILER_PROVIDERS: Array<any|Type|{[k: string]: any}|any[]> = export const COMPILER_PROVIDERS: Array<any|Type|{[k: string]: any}|any[]> =
/*@ts2dart_const*/[ /*@ts2dart_const*/[
{provide: PLATFORM_DIRECTIVES, useValue: [], multi: true},
{provide: PLATFORM_PIPES, useValue: [], multi: true},
{provide: Reflector, useValue: reflector}, {provide: Reflector, useValue: reflector},
{provide: ReflectorReader, useExisting: Reflector}, {provide: ReflectorReader, useExisting: Reflector},
{provide: XHR, useValue: _NO_XHR},
Console, Console,
Lexer, Lexer,
Parser, Parser,
@ -61,112 +69,153 @@ export const COMPILER_PROVIDERS: Array<any|Type|{[k: string]: any}|any[]> =
DEFAULT_PACKAGE_URL_PROVIDER, DEFAULT_PACKAGE_URL_PROVIDER,
StyleCompiler, StyleCompiler,
ViewCompiler, ViewCompiler,
AppModuleCompiler, NgModuleCompiler,
/*@ts2dart_Provider*/ {provide: CompilerConfig, useValue: new CompilerConfig()}, /*@ts2dart_Provider*/ {provide: CompilerConfig, useValue: new CompilerConfig()},
RuntimeCompiler, RuntimeCompiler,
/*@ts2dart_Provider*/ {provide: ComponentResolver, useExisting: RuntimeCompiler},
/*@ts2dart_Provider*/ {provide: Compiler, useExisting: RuntimeCompiler}, /*@ts2dart_Provider*/ {provide: Compiler, useExisting: RuntimeCompiler},
DomElementSchemaRegistry, DomElementSchemaRegistry,
/*@ts2dart_Provider*/ {provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry}, /*@ts2dart_Provider*/ {provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry},
UrlResolver, UrlResolver,
ViewResolver, ViewResolver,
DirectiveResolver, DirectiveResolver,
PipeResolver PipeResolver,
NgModuleResolver
]; ];
export function analyzeAppProvidersForDeprecatedConfiguration(appProviders: any[] = []):
{compilerOptions: CompilerOptions, moduleDeclarations: Type[], deprecationMessages: string[]} {
let platformDirectives: any[] = [];
let platformPipes: any[] = [];
let compilerProviders: any[] = [];
let useDebug: boolean;
let useJit: boolean;
let defaultEncapsulation: ViewEncapsulation;
const deprecationMessages: string[] = [];
// Note: This is a hack to still support the old way
// of configuring platform directives / pipes and the compiler xhr.
// This will soon be deprecated!
const tempInj = ReflectiveInjector.resolveAndCreate(appProviders);
const compilerConfig: CompilerConfig = tempInj.get(CompilerConfig, null);
if (compilerConfig) {
platformDirectives = compilerConfig.platformDirectives;
platformPipes = compilerConfig.platformPipes;
useJit = compilerConfig.useJit;
useDebug = compilerConfig.genDebugInfo;
defaultEncapsulation = compilerConfig.defaultEncapsulation;
deprecationMessages.push(
`Passing CompilerConfig as a regular provider is deprecated. Use the "compilerOptions" parameter of "bootstrap()" or use a custom "CompilerFactory" platform provider instead.`);
} else {
// If nobody provided a CompilerConfig, use the
// PLATFORM_DIRECTIVES / PLATFORM_PIPES values directly if existing
platformDirectives = tempInj.get(PLATFORM_DIRECTIVES, []);
platformPipes = tempInj.get(PLATFORM_PIPES, []);
}
platformDirectives = ListWrapper.flatten(platformDirectives);
platformPipes = ListWrapper.flatten(platformPipes);
const xhr = tempInj.get(XHR, null);
if (xhr) {
compilerProviders.push([{provide: XHR, useValue: xhr}]);
deprecationMessages.push(
`Passing XHR as regular provider is deprecated. Pass the provider via "compilerOptions" instead.`);
}
if (platformDirectives.length > 0) {
deprecationMessages.push(
`The PLATFORM_DIRECTIVES provider and CompilerConfig.platformDirectives is deprecated. Add the directives to an NgModule instead! ` +
`(Directives: ${platformDirectives.map(type => stringify(type))})`);
}
if (platformPipes.length > 0) {
deprecationMessages.push(
`The PLATFORM_PIPES provider and CompilerConfig.platformPipes is deprecated. Add the pipes to an NgModule instead! ` +
`(Pipes: ${platformPipes.map(type => stringify(type))})`);
}
const compilerOptions: CompilerOptions = {
useJit: useJit,
useDebug: useDebug,
defaultEncapsulation: defaultEncapsulation,
providers: compilerProviders
};
// Declare a component that uses @Component.directives / pipes as these
// will be added to the module declarations only if they are not already
// imported by other modules.
@Component({directives: platformDirectives, pipes: platformPipes, template: ''})
class DynamicComponent {
}
return {
compilerOptions,
moduleDeclarations: [DynamicComponent],
deprecationMessages: deprecationMessages
};
}
@Injectable() @Injectable()
export class _RuntimeCompilerFactory extends CompilerFactory { export class RuntimeCompilerFactory implements CompilerFactory {
createCompiler(options: CompilerOptions): Compiler { private _defaultOptions: CompilerOptions[];
const deprecationMessages: string[] = []; constructor(@Inject(CompilerOptions) defaultOptions: CompilerOptions[]) {
let platformDirectivesFromAppProviders: any[] = []; this._defaultOptions = [<CompilerOptions>{
let platformPipesFromAppProviders: any[] = []; useDebug: isDevMode(),
let compilerProvidersFromAppProviders: any[] = []; useJit: true,
let useDebugFromAppProviders: boolean; defaultEncapsulation: ViewEncapsulation.Emulated
let useJitFromAppProviders: boolean; }].concat(defaultOptions);
let defaultEncapsulationFromAppProviders: ViewEncapsulation; }
createCompiler(options: CompilerOptions[] = []): Compiler {
if (options.deprecatedAppProviders && options.deprecatedAppProviders.length > 0) { const mergedOptions = _mergeOptions(this._defaultOptions.concat(options));
// Note: This is a hack to still support the old way
// of configuring platform directives / pipes and the compiler xhr.
// This will soon be deprecated!
const inj = ReflectiveInjector.resolveAndCreate(options.deprecatedAppProviders);
const compilerConfig: CompilerConfig = inj.get(CompilerConfig, null);
if (compilerConfig) {
platformDirectivesFromAppProviders = compilerConfig.deprecatedPlatformDirectives;
platformPipesFromAppProviders = compilerConfig.deprecatedPlatformPipes;
useJitFromAppProviders = compilerConfig.useJit;
useDebugFromAppProviders = compilerConfig.genDebugInfo;
defaultEncapsulationFromAppProviders = compilerConfig.defaultEncapsulation;
deprecationMessages.push(
`Passing a CompilerConfig to "bootstrap()" as provider is deprecated. Pass the provider via the new parameter "compilerOptions" of "bootstrap()" instead.`);
} else {
// If nobody provided a CompilerConfig, use the
// PLATFORM_DIRECTIVES / PLATFORM_PIPES values directly if existing
platformDirectivesFromAppProviders = inj.get(PLATFORM_DIRECTIVES, []);
if (platformDirectivesFromAppProviders.length > 0) {
deprecationMessages.push(
`Passing PLATFORM_DIRECTIVES to "bootstrap()" as provider is deprecated. Use the new parameter "directives" of "bootstrap()" instead.`);
}
platformPipesFromAppProviders = inj.get(PLATFORM_PIPES, []);
if (platformPipesFromAppProviders.length > 0) {
deprecationMessages.push(
`Passing PLATFORM_PIPES to "bootstrap()" as provider is deprecated. Use the new parameter "pipes" of "bootstrap()" instead.`);
}
}
const xhr = inj.get(XHR, null);
if (xhr) {
compilerProvidersFromAppProviders.push([{provide: XHR, useValue: xhr}]);
deprecationMessages.push(
`Passing an instance of XHR to "bootstrap()" as provider is deprecated. Pass the provider via the new parameter "compilerOptions" of "bootstrap()" instead.`);
}
// Need to copy console from deprecatedAppProviders to compiler providers
// as well so that we can test the above deprecation messages in old style bootstrap
// where we only have app providers!
const console = inj.get(Console, null);
if (console) {
compilerProvidersFromAppProviders.push([{provide: Console, useValue: console}]);
}
}
const injector = ReflectiveInjector.resolveAndCreate([ const injector = ReflectiveInjector.resolveAndCreate([
COMPILER_PROVIDERS, { COMPILER_PROVIDERS, {
provide: CompilerConfig, provide: CompilerConfig,
useFactory: (platformDirectives: any[], platformPipes: any[]) => { useFactory: () => {
return new CompilerConfig({ return new CompilerConfig({
deprecatedPlatformDirectives:
_mergeArrays(platformDirectivesFromAppProviders, platformDirectives),
deprecatedPlatformPipes: _mergeArrays(platformPipesFromAppProviders, platformPipes),
// let explicit values from the compiler options overwrite options // let explicit values from the compiler options overwrite options
// from the app providers. E.g. important for the testing platform. // from the app providers. E.g. important for the testing platform.
genDebugInfo: _firstDefined(options.useDebug, useDebugFromAppProviders, isDevMode()), genDebugInfo: mergedOptions.useDebug,
// let explicit values from the compiler options overwrite options // let explicit values from the compiler options overwrite options
// from the app providers // from the app providers
useJit: _firstDefined(options.useJit, useJitFromAppProviders, true), useJit: mergedOptions.useJit,
// let explicit values from the compiler options overwrite options // let explicit values from the compiler options overwrite options
// from the app providers // from the app providers
defaultEncapsulation: _firstDefined( defaultEncapsulation: mergedOptions.defaultEncapsulation,
options.defaultEncapsulation, defaultEncapsulationFromAppProviders, logBindingUpdate: mergedOptions.useDebug
ViewEncapsulation.Emulated)
}); });
}, },
deps: [PLATFORM_DIRECTIVES, PLATFORM_PIPES] deps: []
}, },
// options.providers will always contain a provider for XHR as well mergedOptions.providers
// (added by platforms). So allow compilerProvidersFromAppProviders to overwrite this
_mergeArrays(options.providers, compilerProvidersFromAppProviders)
]); ]);
const console: Console = injector.get(Console);
deprecationMessages.forEach((msg) => { console.warn(msg); });
return injector.get(Compiler); return injector.get(Compiler);
} }
} }
function _initReflector() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
}
export const RUNTIME_COMPILER_FACTORY = new _RuntimeCompilerFactory(); /**
* A platform that included corePlatform and the compiler.
*
* @experimental
*/
export const coreDynamicPlatform = createPlatformFactory(corePlatform, 'coreDynamic', [
{provide: CompilerOptions, useValue: {}, multi: true},
{provide: CompilerFactory, useClass: RuntimeCompilerFactory},
{provide: PLATFORM_INITIALIZER, useValue: _initReflector, multi: true},
]);
function _firstDefined<T>(...args: T[]): T { function _mergeOptions(optionsArr: CompilerOptions[]): CompilerOptions {
for (var i = 0; i < args.length; i++) { return {
useDebug: _lastDefined(optionsArr.map(options => options.useDebug)),
useJit: _lastDefined(optionsArr.map(options => options.useJit)),
defaultEncapsulation: _lastDefined(optionsArr.map(options => options.defaultEncapsulation)),
providers: _mergeArrays(optionsArr.map(options => options.providers))
};
}
function _lastDefined<T>(args: T[]): T {
for (var i = args.length - 1; i >= 0; i--) {
if (args[i] !== undefined) { if (args[i] !== undefined) {
return args[i]; return args[i];
} }
@ -174,7 +223,7 @@ function _firstDefined<T>(...args: T[]): T {
return undefined; return undefined;
} }
function _mergeArrays(...parts: any[][]): any[] { function _mergeArrays(parts: any[][]): any[] {
let result: any[] = []; let result: any[] = [];
parts.forEach((part) => result.push(...part)); parts.forEach((part) => result.push(...part));
return result; return result;

View File

@ -20,17 +20,15 @@ export class CompilerConfig {
private _logBindingUpdate: boolean; private _logBindingUpdate: boolean;
public useJit: boolean; public useJit: boolean;
/** /**
* @deprecated Providing platform directives via the {@link CompilerConfig} deprecated. Provide * @deprecated Providing platform directives via the {@link CompilerConfig} is deprecated. Provide
* platform * platform directives via an {@link NgModule} instead.
* directives via an {@link AppModule} instead.
*/ */
public deprecatedPlatformDirectives: any[]; public platformDirectives: any[];
/** /**
* @deprecated Providing platform pipes via the {@link CompilerConfig} deprecated. Provide * @deprecated Providing platform pipes via the {@link CompilerConfig} is deprecated. Provide
* platform pipes * platform pipes via an {@link NgModule} instead.
* via an {@link AppModule} instead.
*/ */
public deprecatedPlatformPipes: any[]; public platformPipes: any[];
constructor( constructor(
{renderTypes = new DefaultRenderTypes(), defaultEncapsulation = ViewEncapsulation.Emulated, {renderTypes = new DefaultRenderTypes(), defaultEncapsulation = ViewEncapsulation.Emulated,
@ -49,8 +47,8 @@ export class CompilerConfig {
this._genDebugInfo = genDebugInfo; this._genDebugInfo = genDebugInfo;
this._logBindingUpdate = logBindingUpdate; this._logBindingUpdate = logBindingUpdate;
this.useJit = useJit; this.useJit = useJit;
this.deprecatedPlatformDirectives = deprecatedPlatformDirectives; this.platformDirectives = deprecatedPlatformDirectives;
this.deprecatedPlatformPipes = deprecatedPlatformPipes; this.platformPipes = deprecatedPlatformPipes;
} }
get genDebugInfo(): boolean { get genDebugInfo(): boolean {

View File

@ -33,7 +33,7 @@ export class DirectiveResolver {
/** /**
* Return {@link DirectiveMetadata} for a given `Type`. * Return {@link DirectiveMetadata} for a given `Type`.
*/ */
resolve(type: Type): DirectiveMetadata { resolve(type: Type, throwIfNotFound = true): DirectiveMetadata {
var typeMetadata = this._reflector.annotations(resolveForwardRef(type)); var typeMetadata = this._reflector.annotations(resolveForwardRef(type));
if (isPresent(typeMetadata)) { if (isPresent(typeMetadata)) {
var metadata = typeMetadata.find(_isDirectiveMetadata); var metadata = typeMetadata.find(_isDirectiveMetadata);
@ -42,8 +42,10 @@ export class DirectiveResolver {
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, type); return this._mergeWithPropertyMetadata(metadata, propertyMetadata, type);
} }
} }
if (throwIfNotFound) {
throw new BaseException(`No Directive annotation found on ${stringify(type)}`); throw new BaseException(`No Directive annotation found on ${stringify(type)}`);
}
return null;
} }
private _mergeWithPropertyMetadata( private _mergeWithPropertyMetadata(

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ANALYZE_FOR_PRECOMPILE, AppModuleFactory, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ElementRef, Injector, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core'; import {ANALYZE_FOR_PRECOMPILE, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ElementRef, Injector, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
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_, StaticNodeDebugInfo, TemplateRef_, UNINITIALIZED, 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} from '../core_private'; import {AnimationGroupPlayer as AnimationGroupPlayer_, AnimationKeyframe as AnimationKeyframe_, AnimationSequencePlayer as AnimationSequencePlayer_, AnimationStyles as AnimationStyles_, AppElement, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, DebugAppView, DebugContext, EMPTY_ARRAY, EMPTY_MAP, NgModuleInjector, NoOpAnimationPlayer as NoOpAnimationPlayer_, StaticNodeDebugInfo, TemplateRef_, UNINITIALIZED, 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} from '../core_private';
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata'; import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
import {assetUrl} from './util'; import {assetUrl} from './util';
@ -118,15 +118,15 @@ export class Identifiers {
runtime: ComponentFactory, runtime: ComponentFactory,
moduleUrl: assetUrl('core', 'linker/component_factory') moduleUrl: assetUrl('core', 'linker/component_factory')
}); });
static AppModuleFactory = new CompileIdentifierMetadata({ static NgModuleFactory = new CompileIdentifierMetadata({
name: 'AppModuleFactory', name: 'NgModuleFactory',
runtime: AppModuleFactory, runtime: NgModuleFactory,
moduleUrl: assetUrl('core', 'linker/app_module_factory') moduleUrl: assetUrl('core', 'linker/ng_module_factory')
}); });
static AppModuleInjector = new CompileIdentifierMetadata({ static NgModuleInjector = new CompileIdentifierMetadata({
name: 'AppModuleInjector', name: 'NgModuleInjector',
runtime: AppModuleInjector, runtime: NgModuleInjector,
moduleUrl: assetUrl('core', 'linker/app_module_factory') moduleUrl: assetUrl('core', 'linker/ng_module_factory')
}); });
static ValueUnwrapper = new CompileIdentifierMetadata( static ValueUnwrapper = new CompileIdentifierMetadata(
{name: 'ValueUnwrapper', moduleUrl: CD_MODULE_URL, runtime: impValueUnwrapper}); {name: 'ValueUnwrapper', moduleUrl: CD_MODULE_URL, runtime: impValueUnwrapper});

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, AppModuleMetadata, AttributeMetadata, ChangeDetectionStrategy, 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, AttributeMetadata, ChangeDetectionStrategy, ComponentMetadata, HostMetadata, Inject, InjectMetadata, Injectable, NgModule, NgModuleMetadata, Optional, OptionalMetadata, Provider, QueryMetadata, SelfMetadata, SkipSelfMetadata, ViewMetadata, ViewQueryMetadata, resolveForwardRef} from '@angular/core';
import {LIFECYCLE_HOOKS_VALUES, ReflectorReader, createProvider, isProviderLiteral, reflector} from '../core_private'; import {Console, LIFECYCLE_HOOKS_VALUES, ReflectorReader, createProvider, isProviderLiteral, reflector} from '../core_private';
import {StringMapWrapper} from '../src/facade/collection'; import {MapWrapper, StringMapWrapper} from '../src/facade/collection';
import {BaseException} from '../src/facade/exceptions'; import {BaseException} from '../src/facade/exceptions';
import {Type, isArray, isBlank, isPresent, isString, isStringMap, stringify} from '../src/facade/lang'; import {Type, isArray, isBlank, isPresent, isString, isStringMap, stringify} from '../src/facade/lang';
@ -19,6 +19,7 @@ import {CompilerConfig} from './config';
import {hasLifecycleHook} from './directive_lifecycle_reflector'; import {hasLifecycleHook} from './directive_lifecycle_reflector';
import {DirectiveResolver} from './directive_resolver'; import {DirectiveResolver} from './directive_resolver';
import {Identifiers, identifierToken} from './identifiers'; import {Identifiers, identifierToken} from './identifiers';
import {NgModuleResolver} from './ng_module_resolver';
import {PipeResolver} from './pipe_resolver'; import {PipeResolver} from './pipe_resolver';
import {getUrlScheme} from './url_resolver'; import {getUrlScheme} from './url_resolver';
import {MODULE_SUFFIX, ValueTransformer, sanitizeIdentifier, visitValue} from './util'; import {MODULE_SUFFIX, ValueTransformer, sanitizeIdentifier, visitValue} from './util';
@ -28,13 +29,15 @@ import {ViewResolver} from './view_resolver';
export class CompileMetadataResolver { 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 _appModuleCache = new Map<Type, cpl.CompileAppModuleMetadata>(); private _ngModuleCache = new Map<Type, cpl.CompileNgModuleMetadata>();
private _ngModuleOfTypes = new Map<Type, Type>();
private _anonymousTypes = new Map<Object, number>(); private _anonymousTypes = new Map<Object, number>();
private _anonymousTypeIndex = 0; private _anonymousTypeIndex = 0;
constructor( constructor(
private _directiveResolver: DirectiveResolver, private _pipeResolver: PipeResolver, private _ngModuleResolver: NgModuleResolver, private _directiveResolver: DirectiveResolver,
private _viewResolver: ViewResolver, private _config: CompilerConfig, private _pipeResolver: PipeResolver, private _viewResolver: ViewResolver,
private _config: CompilerConfig, private _console: Console,
private _reflector: ReflectorReader = reflector) {} private _reflector: ReflectorReader = reflector) {}
private sanitizeTokenName(token: any): string { private sanitizeTokenName(token: any): string {
@ -54,13 +57,16 @@ export class CompileMetadataResolver {
clearCacheFor(type: Type) { clearCacheFor(type: Type) {
this._directiveCache.delete(type); this._directiveCache.delete(type);
this._pipeCache.delete(type); this._pipeCache.delete(type);
this._appModuleCache.delete(type); this._ngModuleOfTypes.delete(type);
// Clear all of the NgModuleMetadata as they contain transitive information!
this._ngModuleCache.clear();
} }
clearCache() { clearCache() {
this._directiveCache.clear(); this._directiveCache.clear();
this._pipeCache.clear(); this._pipeCache.clear();
this._appModuleCache.clear(); this._ngModuleCache.clear();
this._ngModuleOfTypes.clear();
} }
getAnimationEntryMetadata(entry: AnimationEntryMetadata): cpl.CompileAnimationEntryMetadata { getAnimationEntryMetadata(entry: AnimationEntryMetadata): cpl.CompileAnimationEntryMetadata {
@ -105,11 +111,14 @@ export class CompileMetadataResolver {
return null; return null;
} }
getDirectiveMetadata(directiveType: Type): cpl.CompileDirectiveMetadata { getDirectiveMetadata(directiveType: Type, throwIfNotFound = true): cpl.CompileDirectiveMetadata {
directiveType = resolveForwardRef(directiveType); directiveType = resolveForwardRef(directiveType);
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, throwIfNotFound);
if (!dirMeta) {
return null;
}
var templateMeta: cpl.CompileTemplateMetadata = null; var templateMeta: cpl.CompileTemplateMetadata = null;
var changeDetectionStrategy: ChangeDetectionStrategy = null; var changeDetectionStrategy: ChangeDetectionStrategy = null;
var viewProviders: Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> = []; var viewProviders: Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> = [];
@ -182,83 +191,254 @@ export class CompileMetadataResolver {
return meta; return meta;
} }
getAppModuleMetadata(moduleType: any, meta: AppModuleMetadata = null): getNgModuleMetadata(moduleType: any, throwIfNotFound = true): cpl.CompileNgModuleMetadata {
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); moduleType = resolveForwardRef(moduleType);
var compileMeta = this._appModuleCache.get(moduleType); var compileMeta = this._ngModuleCache.get(moduleType);
if (isBlank(compileMeta) || !useCache) { if (!compileMeta) {
const meta = this._ngModuleResolver.resolve(moduleType, throwIfNotFound);
if (!meta) { if (!meta) {
meta = this._reflector.annotations(moduleType) return null;
.find((meta) => meta instanceof AppModuleMetadata);
} }
if (!meta) { const declaredDirectives: cpl.CompileDirectiveMetadata[] = [];
throw new BaseException( const exportedDirectives: cpl.CompileDirectiveMetadata[] = [];
`Could not compile '${stringify(moduleType)}' because it is not an AppModule.`); const declaredPipes: cpl.CompilePipeMetadata[] = [];
} const exportedPipes: cpl.CompilePipeMetadata[] = [];
let modules: cpl.CompileTypeMetadata[] = []; const importedModules: cpl.CompileNgModuleMetadata[] = [];
let providers: any[] = []; const exportedModules: cpl.CompileNgModuleMetadata[] = [];
let directives: cpl.CompileTypeMetadata[] = [];
let pipes: cpl.CompileTypeMetadata[] = []; if (meta.imports) {
let precompile: cpl.CompileTypeMetadata[] = []; flattenArray(meta.imports).forEach((importedType) => {
if (meta.modules) { if (!isValidType(importedType)) {
flattenArray(meta.modules).forEach((moduleType) => { throw new BaseException(
var meta = this.getAppModuleMetadata(moduleType); `Unexpected value '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`);
providers.push(...meta.providers); }
directives.push(...meta.directives); let importedModuleMeta: cpl.CompileNgModuleMetadata;
pipes.push(...meta.pipes); if (importedModuleMeta = this.getNgModuleMetadata(importedType, false)) {
precompile.push(...meta.precompile); importedModules.push(importedModuleMeta);
modules.push(meta.type); } else {
modules.push(...meta.modules); throw new BaseException(
`Unexpected value '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`);
}
}); });
} }
if (meta.exports) {
flattenArray(meta.exports).forEach((exportedType) => {
if (!isValidType(exportedType)) {
throw new BaseException(
`Unexpected value '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`);
}
let exportedDirMeta: cpl.CompileDirectiveMetadata;
let exportedPipeMeta: cpl.CompilePipeMetadata;
let exportedModuleMeta: cpl.CompileNgModuleMetadata;
if (exportedDirMeta = this.getDirectiveMetadata(exportedType, false)) {
exportedDirectives.push(exportedDirMeta);
} else if (exportedPipeMeta = this.getPipeMetadata(exportedType, false)) {
exportedPipes.push(exportedPipeMeta);
} else if (exportedModuleMeta = this.getNgModuleMetadata(exportedType, false)) {
exportedModules.push(exportedModuleMeta);
} else {
throw new BaseException(
`Unexpected value '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`);
}
});
}
// Note: This will be modified later, so we rely on
// getting a new instance every time!
const transitiveModule =
this._getTransitiveNgModuleMetadata(importedModules, exportedModules);
if (meta.declarations) {
flattenArray(meta.declarations).forEach((declaredType) => {
if (!isValidType(declaredType)) {
throw new BaseException(
`Unexpected value '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`);
}
let declaredDirMeta: cpl.CompileDirectiveMetadata;
let declaredPipeMeta: cpl.CompilePipeMetadata;
if (declaredDirMeta = this.getDirectiveMetadata(declaredType, false)) {
this._addDirectiveToModule(
declaredDirMeta, moduleType, transitiveModule, declaredDirectives, true);
// Collect @Component.directives/pipes/precompile into our declared directives/pipes.
this._getTransitiveViewDirectivesAndPipes(
declaredDirMeta, moduleType, transitiveModule, declaredDirectives, declaredPipes);
} else if (declaredPipeMeta = this.getPipeMetadata(declaredType, false)) {
this._addPipeToModule(
declaredPipeMeta, moduleType, transitiveModule, declaredPipes, true);
} else {
throw new BaseException(
`Unexpected value '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`);
}
});
}
const providers: any[] = [];
const precompile: cpl.CompileTypeMetadata[] = [];
if (meta.providers) { if (meta.providers) {
providers.push(...this.getProvidersMetadata(meta.providers, precompile)); providers.push(...this.getProvidersMetadata(meta.providers, precompile));
} }
if (meta.directives) {
directives.push(...flattenArray(meta.directives)
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
}
if (meta.pipes) {
pipes.push(...flattenArray(meta.pipes)
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
}
if (meta.precompile) { if (meta.precompile) {
precompile.push(...flattenArray(meta.precompile) precompile.push(...flattenArray(meta.precompile)
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type)))); .map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
} }
compileMeta = new cpl.CompileAppModuleMetadata({ transitiveModule.precompile.push(...precompile);
transitiveModule.providers.push(...providers);
compileMeta = new cpl.CompileNgModuleMetadata({
type: this.getTypeMetadata(moduleType, staticTypeModuleUrl(moduleType)), type: this.getTypeMetadata(moduleType, staticTypeModuleUrl(moduleType)),
providers: providers, providers: providers,
directives: directives,
pipes: pipes,
precompile: precompile, precompile: precompile,
modules: modules declaredDirectives: declaredDirectives,
exportedDirectives: exportedDirectives,
declaredPipes: declaredPipes,
exportedPipes: exportedPipes,
importedModules: importedModules,
exportedModules: exportedModules,
transitiveModule: transitiveModule
}); });
if (useCache) { transitiveModule.modules.push(compileMeta);
this._appModuleCache.set(moduleType, compileMeta); this._verifyModule(compileMeta);
} this._ngModuleCache.set(moduleType, compileMeta);
} }
return compileMeta; return compileMeta;
} }
/** addComponentToModule(moduleType: Type, compType: Type) {
* @param someType a symbol which may or may not be a directive type const moduleMeta = this.getNgModuleMetadata(moduleType);
* @returns {cpl.CompileDirectiveMetadata} if possible, otherwise null. // Collect @Component.directives/pipes/precompile into our declared directives/pipes.
*/ const compMeta = this.getDirectiveMetadata(compType, false);
maybeGetDirectiveMetadata(someType: Type): cpl.CompileDirectiveMetadata { this._addDirectiveToModule(
try { compMeta, moduleMeta.type.runtime, moduleMeta.transitiveModule,
return this.getDirectiveMetadata(someType); moduleMeta.declaredDirectives);
} catch (e) { this._getTransitiveViewDirectivesAndPipes(
if (e.message.indexOf('No Directive annotation') !== -1) { compMeta, moduleMeta.type.runtime, moduleMeta.transitiveModule,
return null; moduleMeta.declaredDirectives, moduleMeta.declaredPipes);
moduleMeta.transitiveModule.precompile.push(compMeta.type);
moduleMeta.precompile.push(compMeta.type);
this._verifyModule(moduleMeta);
}
private _verifyModule(moduleMeta: cpl.CompileNgModuleMetadata) {
moduleMeta.exportedDirectives.forEach((dirMeta) => {
if (!moduleMeta.transitiveModule.directivesSet.has(dirMeta.type.runtime)) {
throw new BaseException(
`Can't export directive ${stringify(dirMeta.type.runtime)} from ${stringify(moduleMeta.type.runtime)} as it was neither declared nor imported!`);
} }
throw e; });
moduleMeta.exportedPipes.forEach((pipeMeta) => {
if (!moduleMeta.transitiveModule.pipesSet.has(pipeMeta.type.runtime)) {
throw new BaseException(
`Can't export pipe ${stringify(pipeMeta.type.runtime)} from ${stringify(moduleMeta.type.runtime)} as it was neither declared nor imported!`);
}
});
moduleMeta.declaredDirectives.forEach((dirMeta) => {
dirMeta.precompile.forEach((precompileComp) => {
if (!moduleMeta.transitiveModule.directivesSet.has(precompileComp.runtime)) {
throw new BaseException(
`Component ${stringify(dirMeta.type.runtime)} in NgModule ${stringify(moduleMeta.type.runtime)} uses ${stringify(precompileComp.runtime)} via "precompile" but it was neither declared nor imported into the module!`);
}
});
});
moduleMeta.precompile.forEach((precompileType) => {
if (!moduleMeta.transitiveModule.directivesSet.has(precompileType.runtime)) {
throw new BaseException(
`NgModule ${stringify(moduleMeta.type.runtime)} uses ${stringify(precompileType.runtime)} via "precompile" but it was neither declared nor imported!`);
}
});
}
private _addTypeToModule(type: Type, moduleType: Type) {
const oldModule = this._ngModuleOfTypes.get(type);
if (oldModule && oldModule !== moduleType) {
throw new BaseException(
`Type ${stringify(type)} is part of the declarations of 2 modules: ${stringify(oldModule)} and ${stringify(moduleType)}!`);
} }
this._ngModuleOfTypes.set(type, moduleType);
}
private _getTransitiveViewDirectivesAndPipes(
compMeta: cpl.CompileDirectiveMetadata, moduleType: any,
transitiveModule: cpl.TransitiveCompileNgModuleMetadata,
declaredDirectives: cpl.CompileDirectiveMetadata[],
declaredPipes: cpl.CompilePipeMetadata[]) {
if (!compMeta.isComponent) {
return;
}
const addPipe = (pipeType: Type) => {
if (!pipeType) {
throw new BaseException(
`Unexpected pipe value '${pipeType}' on the View of component '${stringify(compMeta.type.runtime)}'`);
}
const pipeMeta = this.getPipeMetadata(pipeType);
this._addPipeToModule(pipeMeta, moduleType, transitiveModule, declaredPipes);
};
const addDirective = (dirType: Type) => {
if (!dirType) {
throw new BaseException(
`Unexpected directive value '${dirType}' on the View of component '${stringify(compMeta.type.runtime)}'`);
}
const dirMeta = this.getDirectiveMetadata(dirType);
if (this._addDirectiveToModule(dirMeta, moduleType, transitiveModule, declaredDirectives)) {
this._getTransitiveViewDirectivesAndPipes(
dirMeta, moduleType, transitiveModule, declaredDirectives, declaredPipes);
}
};
const view = this._viewResolver.resolve(compMeta.type.runtime);
if (view.pipes) {
flattenArray(view.pipes).forEach(addPipe);
}
if (view.directives) {
flattenArray(view.directives).forEach(addDirective);
}
}
private _getTransitiveNgModuleMetadata(
importedModules: cpl.CompileNgModuleMetadata[],
exportedModules: cpl.CompileNgModuleMetadata[]): cpl.TransitiveCompileNgModuleMetadata {
// collect `providers` / `precompile` from all imported and all exported modules
const transitiveModules = getTransitiveModules(importedModules.concat(exportedModules), true);
const providers = flattenArray(transitiveModules.map((ngModule) => ngModule.providers));
const precompile = flattenArray(transitiveModules.map((ngModule) => ngModule.precompile));
const transitiveExportedModules = getTransitiveModules(importedModules, false);
const directives =
flattenArray(transitiveExportedModules.map((ngModule) => ngModule.exportedDirectives));
const pipes = flattenArray(transitiveExportedModules.map((ngModule) => ngModule.exportedPipes));
return new cpl.TransitiveCompileNgModuleMetadata(
transitiveModules, providers, precompile, directives, pipes);
}
private _addDirectiveToModule(
dirMeta: cpl.CompileDirectiveMetadata, moduleType: any,
transitiveModule: cpl.TransitiveCompileNgModuleMetadata,
declaredDirectives: cpl.CompileDirectiveMetadata[], force: boolean = false): boolean {
if (force || !transitiveModule.directivesSet.has(dirMeta.type.runtime)) {
transitiveModule.directivesSet.add(dirMeta.type.runtime);
transitiveModule.directives.push(dirMeta);
declaredDirectives.push(dirMeta);
this._addTypeToModule(dirMeta.type.runtime, moduleType);
return true;
}
return false;
}
private _addPipeToModule(
pipeMeta: cpl.CompilePipeMetadata, moduleType: any,
transitiveModule: cpl.TransitiveCompileNgModuleMetadata,
declaredPipes: cpl.CompilePipeMetadata[], force: boolean = false): boolean {
if (force || !transitiveModule.pipesSet.has(pipeMeta.type.runtime)) {
transitiveModule.pipesSet.add(pipeMeta.type.runtime);
transitiveModule.pipes.push(pipeMeta);
declaredPipes.push(pipeMeta);
this._addTypeToModule(pipeMeta.type.runtime, moduleType);
return true;
}
return false;
} }
getTypeMetadata(type: Type, moduleUrl: string, dependencies: any[] = null): getTypeMetadata(type: Type, moduleUrl: string, dependencies: any[] = null):
@ -283,11 +463,14 @@ export class CompileMetadataResolver {
}); });
} }
getPipeMetadata(pipeType: Type): cpl.CompilePipeMetadata { getPipeMetadata(pipeType: Type, throwIfNotFound = true): cpl.CompilePipeMetadata {
pipeType = resolveForwardRef(pipeType); pipeType = resolveForwardRef(pipeType);
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, throwIfNotFound);
if (!pipeMeta) {
return null;
}
meta = new cpl.CompilePipeMetadata({ meta = new cpl.CompilePipeMetadata({
type: this.getTypeMetadata(pipeType, staticTypeModuleUrl(pipeType)), type: this.getTypeMetadata(pipeType, staticTypeModuleUrl(pipeType)),
name: pipeMeta.name, name: pipeMeta.name,
@ -299,30 +482,6 @@ export class CompileMetadataResolver {
return meta; return meta;
} }
getViewDirectivesMetadata(component: Type): cpl.CompileDirectiveMetadata[] {
var view = this._viewResolver.resolve(component);
var directives = flattenDirectives(view, this._config.deprecatedPlatformDirectives);
for (var i = 0; i < directives.length; i++) {
if (!isValidType(directives[i])) {
throw new BaseException(
`Unexpected directive value '${stringify(directives[i])}' on the View of component '${stringify(component)}'`);
}
}
return directives.map(type => this.getDirectiveMetadata(type));
}
getViewPipesMetadata(component: Type): cpl.CompilePipeMetadata[] {
var view = this._viewResolver.resolve(component);
var pipes = flattenPipes(view, this._config.deprecatedPlatformPipes);
for (var i = 0; i < pipes.length; i++) {
if (!isValidType(pipes[i])) {
throw new BaseException(
`Unexpected piped value '${stringify(pipes[i])}' on the View of component '${stringify(component)}'`);
}
}
return pipes.map(type => this.getPipeMetadata(type));
}
getDependenciesMetadata(typeOrFunc: Type|Function, dependencies: any[]): getDependenciesMetadata(typeOrFunc: Type|Function, dependencies: any[]):
cpl.CompileDiDependencyMetadata[] { cpl.CompileDiDependencyMetadata[] {
let hasUnknownDeps = false; let hasUnknownDeps = false;
@ -454,7 +613,7 @@ export class CompileMetadataResolver {
} }
convertToCompileValue(provider.useValue, collectedIdentifiers); convertToCompileValue(provider.useValue, collectedIdentifiers);
collectedIdentifiers.forEach((identifier) => { collectedIdentifiers.forEach((identifier) => {
let dirMeta = this.maybeGetDirectiveMetadata(identifier.runtime); let dirMeta = this.getDirectiveMetadata(identifier.runtime, false);
if (dirMeta) { if (dirMeta) {
components.push(dirMeta.type); components.push(dirMeta.type);
} }
@ -523,35 +682,35 @@ export class CompileMetadataResolver {
} }
} }
function flattenDirectives(view: ViewMetadata, platformDirectives: any[]): Type[] { function getTransitiveModules(
let directives: Type[] = []; modules: cpl.CompileNgModuleMetadata[], includeImports: boolean,
if (isPresent(platformDirectives)) { targetModules: cpl.CompileNgModuleMetadata[] = [],
flattenArray(platformDirectives, directives); visitedModules = new Set<Type>()): cpl.CompileNgModuleMetadata[] {
} modules.forEach((ngModule) => {
if (isPresent(view.directives)) { if (!visitedModules.has(ngModule.type.runtime)) {
flattenArray(view.directives, directives); visitedModules.add(ngModule.type.runtime);
} const nestedModules = includeImports ?
return directives; ngModule.importedModules.concat(ngModule.exportedModules) :
ngModule.exportedModules;
getTransitiveModules(nestedModules, includeImports, targetModules, visitedModules);
// Add after recursing so imported/exported modules are before the module itself.
// This is important for overwriting providers of imported modules!
targetModules.push(ngModule);
}
});
return targetModules;
} }
function flattenPipes(view: ViewMetadata, platformPipes: any[]): Type[] {
let pipes: Type[] = [];
if (isPresent(platformPipes)) {
flattenArray(platformPipes, pipes);
}
if (isPresent(view.pipes)) {
flattenArray(view.pipes, pipes);
}
return pipes;
}
function flattenArray(tree: any[], out: Array<Type> = []): Array<Type> { function flattenArray(tree: any[], out: Array<any> = []): Array<any> {
for (var i = 0; i < tree.length; i++) { if (tree) {
var item = resolveForwardRef(tree[i]); for (var i = 0; i < tree.length; i++) {
if (isArray(item)) { var item = resolveForwardRef(tree[i]);
flattenArray(item, out); if (isArray(item)) {
} else { flattenArray(item, out);
out.push(item); } else {
out.push(item);
}
} }
} }
return out; return out;

View File

@ -8,13 +8,13 @@
import {Injectable} from '@angular/core'; import {Injectable} from '@angular/core';
import {CompileAppModuleMetadata, CompileDiDependencyMetadata, CompileIdentifierMetadata, CompileProviderMetadata, CompileTokenMap, CompileTokenMetadata, CompileTypeMetadata} from './compile_metadata'; import {CompileDiDependencyMetadata, CompileIdentifierMap, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileProviderMetadata, CompileTokenMetadata} from './compile_metadata';
import {isBlank, isPresent} from './facade/lang'; import {isBlank, isPresent} from './facade/lang';
import {Identifiers, identifierToken} from './identifiers'; import {Identifiers, identifierToken} from './identifiers';
import * as o from './output/output_ast'; import * as o from './output/output_ast';
import {convertValueToOutputAst} from './output/value_util'; import {convertValueToOutputAst} from './output/value_util';
import {ParseLocation, ParseSourceFile, ParseSourceSpan} from './parse_util'; import {ParseLocation, ParseSourceFile, ParseSourceSpan} from './parse_util';
import {AppModuleProviderParser} from './provider_parser'; import {NgModuleProviderAnalyzer} from './provider_analyzer';
import {ProviderAst, ProviderAstType} from './template_ast'; import {ProviderAst, ProviderAstType} from './template_ast';
import {createDiTokenExpression} from './util'; import {createDiTokenExpression} from './util';
@ -23,57 +23,58 @@ export class ComponentFactoryDependency {
public comp: CompileIdentifierMetadata, public placeholder: CompileIdentifierMetadata) {} public comp: CompileIdentifierMetadata, public placeholder: CompileIdentifierMetadata) {}
} }
export class AppModuleCompileResult { export class NgModuleCompileResult {
constructor( constructor(
public statements: o.Statement[], public appModuleFactoryVar: string, public statements: o.Statement[], public ngModuleFactoryVar: string,
public dependencies: ComponentFactoryDependency[]) {} public dependencies: ComponentFactoryDependency[]) {}
} }
@Injectable() @Injectable()
export class AppModuleCompiler { export class NgModuleCompiler {
compile(appModuleMeta: CompileAppModuleMetadata): AppModuleCompileResult { compile(ngModuleMeta: CompileNgModuleMetadata, extraProviders: CompileProviderMetadata[]):
var sourceFileName = isPresent(appModuleMeta.type.moduleUrl) ? NgModuleCompileResult {
`in AppModule ${appModuleMeta.type.name} in ${appModuleMeta.type.moduleUrl}` : var sourceFileName = isPresent(ngModuleMeta.type.moduleUrl) ?
`in AppModule ${appModuleMeta.type.name}`; `in NgModule ${ngModuleMeta.type.name} in ${ngModuleMeta.type.moduleUrl}` :
`in NgModule ${ngModuleMeta.type.name}`;
var sourceFile = new ParseSourceFile('', sourceFileName); var sourceFile = new ParseSourceFile('', sourceFileName);
var sourceSpan = new ParseSourceSpan( var sourceSpan = new ParseSourceSpan(
new ParseLocation(sourceFile, null, null, null), new ParseLocation(sourceFile, null, null, null),
new ParseLocation(sourceFile, null, null, null)); new ParseLocation(sourceFile, null, null, null));
var deps: ComponentFactoryDependency[] = []; var deps: ComponentFactoryDependency[] = [];
var precompileComponents = appModuleMeta.precompile.map((precompileComp) => { var precompileComponents = ngModuleMeta.transitiveModule.precompile.map((precompileComp) => {
var id = new CompileIdentifierMetadata({name: precompileComp.name}); var id = new CompileIdentifierMetadata({name: precompileComp.name});
deps.push(new ComponentFactoryDependency(precompileComp, id)); deps.push(new ComponentFactoryDependency(precompileComp, id));
return id; return id;
}); });
var builder = new _InjectorBuilder(appModuleMeta, precompileComponents, sourceSpan); var builder = new _InjectorBuilder(ngModuleMeta, precompileComponents, sourceSpan);
var providerParser = new AppModuleProviderParser(appModuleMeta, sourceSpan); var providerParser = new NgModuleProviderAnalyzer(ngModuleMeta, extraProviders, sourceSpan);
providerParser.parse().forEach((provider) => builder.addProvider(provider)); providerParser.parse().forEach((provider) => builder.addProvider(provider));
var injectorClass = builder.build(); var injectorClass = builder.build();
var appModuleFactoryVar = `${appModuleMeta.type.name}NgFactory`; var ngModuleFactoryVar = `${ngModuleMeta.type.name}NgFactory`;
var appModuleFactoryStmt = var ngModuleFactoryStmt =
o.variable(appModuleFactoryVar) o.variable(ngModuleFactoryVar)
.set(o.importExpr(Identifiers.AppModuleFactory) .set(o.importExpr(Identifiers.NgModuleFactory)
.instantiate( .instantiate(
[o.variable(injectorClass.name), o.importExpr(appModuleMeta.type)], [o.variable(injectorClass.name), o.importExpr(ngModuleMeta.type)],
o.importType( o.importType(
Identifiers.AppModuleFactory, [o.importType(appModuleMeta.type)], Identifiers.NgModuleFactory, [o.importType(ngModuleMeta.type)],
[o.TypeModifier.Const]))) [o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]); .toDeclStmt(null, [o.StmtModifier.Final]);
return new AppModuleCompileResult( return new NgModuleCompileResult(
[injectorClass, appModuleFactoryStmt], appModuleFactoryVar, deps); [injectorClass, ngModuleFactoryStmt], ngModuleFactoryVar, deps);
} }
} }
class _InjectorBuilder { class _InjectorBuilder {
private _instances = new CompileTokenMap<o.Expression>(); private _instances = new CompileIdentifierMap<CompileTokenMetadata, o.Expression>();
private _fields: o.ClassField[] = []; private _fields: o.ClassField[] = [];
private _createStmts: o.Statement[] = []; private _createStmts: o.Statement[] = [];
private _getters: o.ClassGetter[] = []; private _getters: o.ClassGetter[] = [];
constructor( constructor(
private _appModuleMeta: CompileAppModuleMetadata, private _ngModuleMeta: CompileNgModuleMetadata,
private _precompileComponents: CompileIdentifierMetadata[], private _precompileComponents: CompileIdentifierMetadata[],
private _sourceSpan: ParseSourceSpan) {} private _sourceSpan: ParseSourceSpan) {}
@ -97,8 +98,8 @@ class _InjectorBuilder {
var methods = [ var methods = [
new o.ClassMethod( new o.ClassMethod(
'createInternal', [], this._createStmts.concat( 'createInternal', [], this._createStmts.concat(
new o.ReturnStatement(this._instances.get(identifierToken(this._appModuleMeta.type))) new o.ReturnStatement(this._instances.get(identifierToken(this._ngModuleMeta.type)))
), o.importType(this._appModuleMeta.type) ), o.importType(this._ngModuleMeta.type)
), ),
new o.ClassMethod( new o.ClassMethod(
'getInternal', 'getInternal',
@ -120,10 +121,10 @@ class _InjectorBuilder {
]) ])
.toStmt()]); .toStmt()]);
var injClassName = `${this._appModuleMeta.type.name}Injector`; var injClassName = `${this._ngModuleMeta.type.name}Injector`;
return new o.ClassStmt( return new o.ClassStmt(
injClassName, injClassName,
o.importExpr(Identifiers.AppModuleInjector, [o.importType(this._appModuleMeta.type)]), o.importExpr(Identifiers.NgModuleInjector, [o.importType(this._ngModuleMeta.type)]),
this._fields, this._getters, ctor, methods); this._fields, this._getters, ctor, methods);
} }

View File

@ -0,0 +1,39 @@
/**
* @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, NgModuleMetadata} from '@angular/core';
import {ReflectorReader, reflector} from '../core_private';
import {BaseException} from '../src/facade/exceptions';
import {Type, isBlank, isPresent, stringify} from '../src/facade/lang';
function _isNgModuleMetadata(obj: any): obj is NgModuleMetadata {
return obj instanceof NgModuleMetadata;
}
/**
* Resolves types to {@link NgModuleMetadata}.
*/
@Injectable()
export class NgModuleResolver {
constructor(private _reflector: ReflectorReader = reflector) {}
resolve(type: Type, throwIfNotFound = true): NgModuleMetadata {
const ngModuleMeta: NgModuleMetadata =
this._reflector.annotations(type).find(_isNgModuleMetadata);
if (isPresent(ngModuleMeta)) {
return ngModuleMeta;
} else {
if (throwIfNotFound) {
throw new BaseException(`No NgModule metadata found for '${stringify(type)}'.`);
}
return null;
}
}
}

View File

@ -6,13 +6,13 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AppModuleCompiler} from './app_module_compiler'; import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata';
import {DirectiveNormalizer} from './directive_normalizer'; import {DirectiveNormalizer} from './directive_normalizer';
import {ListWrapper} from './facade/collection'; import {ListWrapper} from './facade/collection';
import {BaseException} from './facade/exceptions'; import {BaseException} from './facade/exceptions';
import {Identifiers} from './identifiers'; import {Identifiers} from './identifiers';
import {CompileMetadataResolver} from './metadata_resolver'; import {CompileMetadataResolver} from './metadata_resolver';
import {NgModuleCompiler} from './ng_module_compiler';
import {OutputEmitter} from './output/abstract_emitter'; import {OutputEmitter} from './output/abstract_emitter';
import * as o from './output/output_ast'; import * as o from './output/output_ast';
import {CompiledStylesheet, StyleCompiler} from './style_compiler'; import {CompiledStylesheet, StyleCompiler} from './style_compiler';
@ -23,61 +23,29 @@ export class SourceModule {
constructor(public moduleUrl: string, public source: string) {} constructor(public moduleUrl: string, public source: string) {}
} }
export class AppModulesSummary { export class NgModulesSummary {
private _compAppModule = new Map<string, StaticSymbol>(); constructor(public ngModuleByComponent: Map<StaticSymbol, CompileNgModuleMetadata>) {}
private _hashKey(type: StaticSymbol) { return `${type.filePath}#${type.name}`; }
hasComponent(component: StaticSymbol): boolean {
return this._compAppModule.has(this._hashKey(component));
}
addComponent(module: StaticSymbol, component: StaticSymbol) {
this._compAppModule.set(this._hashKey(component), module);
}
getModule(comp: StaticSymbol): StaticSymbol {
return this._compAppModule.get(this._hashKey(comp));
}
} }
export class OfflineCompiler { export class OfflineCompiler {
constructor( constructor(
private _metadataResolver: CompileMetadataResolver, private _metadataResolver: CompileMetadataResolver,
private _directiveNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser, private _directiveNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler, private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
private _appModuleCompiler: AppModuleCompiler, private _outputEmitter: OutputEmitter) {} private _ngModuleCompiler: NgModuleCompiler, private _outputEmitter: OutputEmitter) {}
analyzeModules(appModules: StaticSymbol[]): AppModulesSummary { analyzeModules(ngModules: StaticSymbol[]): NgModulesSummary {
let result = new AppModulesSummary(); const ngModuleByComponent = new Map<StaticSymbol, CompileNgModuleMetadata>();
appModules.forEach((appModule) => {
let appModuleMeta = this._metadataResolver.getAppModuleMetadata(appModule);
appModuleMeta.precompile.forEach(
(precompileComp) =>
this._getTransitiveComponents(appModule, <any>precompileComp.runtime, result));
});
return result;
}
private _getTransitiveComponents( ngModules.forEach((ngModule) => {
appModule: StaticSymbol, component: StaticSymbol, const ngModuleMeta = this._metadataResolver.getNgModuleMetadata(<any>ngModule);
target: AppModulesSummary = new AppModulesSummary()): AppModulesSummary { ngModuleMeta.declaredDirectives.forEach((dirMeta) => {
var compMeta = this._metadataResolver.getDirectiveMetadata(<any>component); if (dirMeta.isComponent) {
// TODO(tbosch): preserve all modules per component, not just one. ngModuleByComponent.set(dirMeta.type.runtime, ngModuleMeta);
// Then run the template parser with the union and the intersection of the modules (regarding }
// directives/pipes) });
// and report an error if some directives/pipes are only matched with the union but not with the
// intersection!
// -> this means that a component is used in the wrong way!
if (!compMeta.isComponent || target.hasComponent(component)) {
return target;
}
target.addComponent(appModule, component);
this._metadataResolver.getViewDirectivesMetadata(<any>component).forEach((dirMeta) => {
this._getTransitiveComponents(appModule, <any>dirMeta.type.runtime);
}); });
compMeta.precompile.forEach((precompileComp) => { return new NgModulesSummary(ngModuleByComponent);
this._getTransitiveComponents(appModule, <any>precompileComp.type.runtime);
});
return target;
} }
clearCache() { clearCache() {
@ -86,55 +54,45 @@ export class OfflineCompiler {
} }
compile( compile(
moduleUrl: string, appModulesSummary: AppModulesSummary, components: StaticSymbol[], moduleUrl: string, ngModulesSummary: NgModulesSummary, components: StaticSymbol[],
appModules: StaticSymbol[]): Promise<SourceModule[]> { ngModules: StaticSymbol[]): Promise<SourceModule[]> {
let fileSuffix = _splitLastSuffix(moduleUrl)[1]; let fileSuffix = _splitLastSuffix(moduleUrl)[1];
let statements: o.Statement[] = []; let statements: o.Statement[] = [];
let exportedVars: string[] = []; let exportedVars: string[] = [];
let outputSourceModules: SourceModule[] = []; let outputSourceModules: SourceModule[] = [];
// compile app modules // compile all ng modules
exportedVars.push( exportedVars.push(
...appModules.map((appModule) => this._compileAppModule(appModule, statements))); ...ngModules.map((ngModuleType) => this._compileModule(ngModuleType, statements)));
// compile components // compile components
return Promise return Promise
.all(components.map((compType) => { .all(components.map((compType) => {
let appModule = appModulesSummary.getModule(compType); const compMeta = this._metadataResolver.getDirectiveMetadata(<any>compType);
let appModuleDirectives: CompileDirectiveMetadata[] = []; let ngModule = ngModulesSummary.ngModuleByComponent.get(compType);
let appModulePipes: CompilePipeMetadata[] = []; if (!ngModule) {
if (appModule) { throw new BaseException(
let appModuleMeta = this._metadataResolver.getAppModuleMetadata(appModule); `Cannot determine the module for component ${compMeta.type.name}!`);
appModuleDirectives.push(...appModuleMeta.directives.map(
type => this._metadataResolver.getDirectiveMetadata(type.runtime)));
appModulePipes.push(...appModuleMeta.pipes.map(
type => this._metadataResolver.getPipeMetadata(type.runtime)));
} }
return Promise return Promise
.all([ .all([compMeta, ...ngModule.transitiveModule.directives].map(
this._metadataResolver.getDirectiveMetadata(<any>compType), ...appModuleDirectives, dirMeta => this._directiveNormalizer.normalizeDirective(dirMeta).asyncResult))
...this._metadataResolver.getViewDirectivesMetadata(<any>compType)
].map(dirMeta => this._directiveNormalizer.normalizeDirective(dirMeta).asyncResult))
.then((normalizedCompWithDirectives) => { .then((normalizedCompWithDirectives) => {
let compMeta = normalizedCompWithDirectives[0]; const compMeta = normalizedCompWithDirectives[0];
let dirMetas = normalizedCompWithDirectives.slice(1); const dirMetas = normalizedCompWithDirectives.slice(1);
_assertComponent(compMeta); _assertComponent(compMeta);
// compile styles // compile styles
let stylesCompileResults = this._styleCompiler.compileComponent(compMeta); const stylesCompileResults = this._styleCompiler.compileComponent(compMeta);
stylesCompileResults.externalStylesheets.forEach((compiledStyleSheet) => { stylesCompileResults.externalStylesheets.forEach((compiledStyleSheet) => {
outputSourceModules.push(this._codgenStyles(compiledStyleSheet, fileSuffix)); outputSourceModules.push(this._codgenStyles(compiledStyleSheet, fileSuffix));
}); });
// compile components // compile components
exportedVars.push(this._compileComponentFactory(compMeta, fileSuffix, statements)); exportedVars.push(this._compileComponentFactory(compMeta, fileSuffix, statements));
let pipeMetas = [
...appModulePipes,
...this._metadataResolver.getViewPipesMetadata(compMeta.type.runtime)
];
exportedVars.push(this._compileComponent( exportedVars.push(this._compileComponent(
compMeta, dirMetas, pipeMetas, stylesCompileResults.componentStylesheet, compMeta, dirMetas, ngModule.transitiveModule.pipes,
fileSuffix, statements)); stylesCompileResults.componentStylesheet, fileSuffix, statements));
}); });
})) }))
.then(() => { .then(() => {
@ -146,21 +104,21 @@ export class OfflineCompiler {
}); });
} }
private _compileAppModule(appModuleType: StaticSymbol, targetStatements: o.Statement[]): string { private _compileModule(ngModuleType: StaticSymbol, targetStatements: o.Statement[]): string {
let appModuleMeta = this._metadataResolver.getAppModuleMetadata(appModuleType); const ngModule = this._metadataResolver.getNgModuleMetadata(<any>ngModuleType);
let appCompileResult = this._appModuleCompiler.compile(appModuleMeta); let appCompileResult = this._ngModuleCompiler.compile(ngModule, []);
appCompileResult.dependencies.forEach((dep) => { appCompileResult.dependencies.forEach((dep) => {
dep.placeholder.name = _componentFactoryName(dep.comp); dep.placeholder.name = _componentFactoryName(dep.comp);
dep.placeholder.moduleUrl = _ngfactoryModuleUrl(dep.comp.moduleUrl); dep.placeholder.moduleUrl = _ngfactoryModuleUrl(dep.comp.moduleUrl);
}); });
targetStatements.push(...appCompileResult.statements); targetStatements.push(...appCompileResult.statements);
return appCompileResult.appModuleFactoryVar; return appCompileResult.ngModuleFactoryVar;
} }
private _compileComponentFactory( private _compileComponentFactory(
compMeta: CompileDirectiveMetadata, fileSuffix: string, compMeta: CompileDirectiveMetadata, fileSuffix: string,
targetStatements: o.Statement[]): string { targetStatements: o.Statement[]): string {
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector); var hostMeta = createHostComponentMeta(compMeta);
var hostViewFactoryVar = var hostViewFactoryVar =
this._compileComponent(hostMeta, [compMeta], [], null, fileSuffix, targetStatements); this._compileComponent(hostMeta, [compMeta], [], null, fileSuffix, targetStatements);
var compFactoryVar = _componentFactoryName(compMeta.type); var compFactoryVar = _componentFactoryName(compMeta.type);

View File

@ -30,7 +30,7 @@ export class PipeResolver {
/** /**
* Return {@link PipeMetadata} for a given `Type`. * Return {@link PipeMetadata} for a given `Type`.
*/ */
resolve(type: Type): PipeMetadata { resolve(type: Type, throwIfNotFound = true): PipeMetadata {
var metas = this._reflector.annotations(resolveForwardRef(type)); var metas = this._reflector.annotations(resolveForwardRef(type));
if (isPresent(metas)) { if (isPresent(metas)) {
var annotation = metas.find(_isPipeMetadata); var annotation = metas.find(_isPipeMetadata);
@ -38,6 +38,9 @@ export class PipeResolver {
return annotation; return annotation;
} }
} }
throw new BaseException(`No Pipe decorator found on ${stringify(type)}`); if (throwIfNotFound) {
throw new BaseException(`No Pipe decorator found on ${stringify(type)}`);
}
return null;
} }
} }

View File

@ -10,7 +10,7 @@ import {ListWrapper} from '../src/facade/collection';
import {BaseException} from '../src/facade/exceptions'; import {BaseException} from '../src/facade/exceptions';
import {isArray, isBlank, isPresent, normalizeBlank} from '../src/facade/lang'; import {isArray, isBlank, isPresent, normalizeBlank} from '../src/facade/lang';
import {CompileAppModuleMetadata, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMap, CompileTokenMetadata, CompileTypeMetadata} from './compile_metadata'; import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileIdentifierMap, CompileNgModuleMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata, CompileTypeMetadata} from './compile_metadata';
import {Identifiers, identifierToken} from './identifiers'; import {Identifiers, identifierToken} from './identifiers';
import {ParseError, ParseSourceSpan} from './parse_util'; import {ParseError, ParseSourceSpan} from './parse_util';
import {AttrAst, DirectiveAst, ProviderAst, ProviderAstType, ReferenceAst, VariableAst} from './template_ast'; import {AttrAst, DirectiveAst, ProviderAst, ProviderAstType, ReferenceAst, VariableAst} from './template_ast';
@ -23,16 +23,16 @@ export class ProviderViewContext {
/** /**
* @internal * @internal
*/ */
viewQueries: CompileTokenMap<CompileQueryMetadata[]>; viewQueries: CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]>;
/** /**
* @internal * @internal
*/ */
viewProviders: CompileTokenMap<boolean>; viewProviders: CompileIdentifierMap<CompileTokenMetadata, boolean>;
errors: ProviderError[] = []; errors: ProviderError[] = [];
constructor(public component: CompileDirectiveMetadata, public sourceSpan: ParseSourceSpan) { constructor(public component: CompileDirectiveMetadata, public sourceSpan: ParseSourceSpan) {
this.viewQueries = _getViewQueries(component); this.viewQueries = _getViewQueries(component);
this.viewProviders = new CompileTokenMap<boolean>(); this.viewProviders = new CompileIdentifierMap<CompileTokenMetadata, boolean>();
_normalizeProviders(component.viewProviders, sourceSpan, this.errors).forEach((provider) => { _normalizeProviders(component.viewProviders, sourceSpan, this.errors).forEach((provider) => {
if (isBlank(this.viewProviders.get(provider.token))) { if (isBlank(this.viewProviders.get(provider.token))) {
this.viewProviders.add(provider.token, true); this.viewProviders.add(provider.token, true);
@ -42,11 +42,11 @@ export class ProviderViewContext {
} }
export class ProviderElementContext { export class ProviderElementContext {
private _contentQueries: CompileTokenMap<CompileQueryMetadata[]>; private _contentQueries: CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]>;
private _transformedProviders = new CompileTokenMap<ProviderAst>(); private _transformedProviders = new CompileIdentifierMap<CompileTokenMetadata, ProviderAst>();
private _seenProviders = new CompileTokenMap<boolean>(); private _seenProviders = new CompileIdentifierMap<CompileTokenMetadata, boolean>();
private _allProviders: CompileTokenMap<ProviderAst>; private _allProviders: CompileIdentifierMap<CompileTokenMetadata, ProviderAst>;
private _attrs: {[key: string]: string}; private _attrs: {[key: string]: string};
private _hasViewContainer: boolean = false; private _hasViewContainer: boolean = false;
@ -60,7 +60,7 @@ export class ProviderElementContext {
this._allProviders = this._allProviders =
_resolveProvidersFromDirectives(directivesMeta, _sourceSpan, _viewContext.errors); _resolveProvidersFromDirectives(directivesMeta, _sourceSpan, _viewContext.errors);
this._contentQueries = _getContentQueries(directivesMeta); this._contentQueries = _getContentQueries(directivesMeta);
var queriedTokens = new CompileTokenMap<boolean>(); var queriedTokens = new CompileIdentifierMap<CompileTokenMetadata, boolean>();
this._allProviders.values().forEach( this._allProviders.values().forEach(
(provider) => { this._addQueryReadsTo(provider.token, queriedTokens); }); (provider) => { this._addQueryReadsTo(provider.token, queriedTokens); });
refs.forEach((refAst) => { refs.forEach((refAst) => {
@ -100,7 +100,9 @@ export class ProviderElementContext {
get transformedHasViewContainer(): boolean { return this._hasViewContainer; } get transformedHasViewContainer(): boolean { return this._hasViewContainer; }
private _addQueryReadsTo(token: CompileTokenMetadata, queryReadTokens: CompileTokenMap<boolean>) { private _addQueryReadsTo(
token: CompileTokenMetadata,
queryReadTokens: CompileIdentifierMap<CompileTokenMetadata, boolean>) {
this._getQueriesFor(token).forEach((query) => { this._getQueriesFor(token).forEach((query) => {
const queryReadToken = isPresent(query.read) ? query.read : token; const queryReadToken = isPresent(query.read) ? query.read : token;
if (isBlank(queryReadTokens.get(queryReadToken))) { if (isBlank(queryReadTokens.get(queryReadToken))) {
@ -272,24 +274,28 @@ export class ProviderElementContext {
} }
export class AppModuleProviderParser { export class NgModuleProviderAnalyzer {
private _transformedProviders = new CompileTokenMap<ProviderAst>(); private _transformedProviders = new CompileIdentifierMap<CompileTokenMetadata, ProviderAst>();
private _seenProviders = new CompileTokenMap<boolean>(); private _seenProviders = new CompileIdentifierMap<CompileTokenMetadata, boolean>();
private _unparsedProviders: any[] = []; private _unparsedProviders: any[] = [];
private _allProviders: CompileTokenMap<ProviderAst>; private _allProviders: CompileIdentifierMap<CompileTokenMetadata, ProviderAst>;
private _errors: ProviderError[] = []; private _errors: ProviderError[] = [];
constructor(appModule: CompileAppModuleMetadata, sourceSpan: ParseSourceSpan) { constructor(
this._allProviders = new CompileTokenMap<ProviderAst>(); ngModule: CompileNgModuleMetadata, extraProviders: CompileProviderMetadata[],
[appModule.type].concat(appModule.modules).forEach((appModuleType: CompileTypeMetadata) => { sourceSpan: ParseSourceSpan) {
const appModuleProvider = new CompileProviderMetadata( this._allProviders = new CompileIdentifierMap<CompileTokenMetadata, ProviderAst>();
{token: new CompileTokenMetadata({identifier: appModuleType}), useClass: appModuleType}); const ngModuleTypes = ngModule.transitiveModule.modules.map((moduleMeta) => moduleMeta.type);
ngModuleTypes.forEach((ngModuleType: CompileTypeMetadata) => {
const ngModuleProvider = new CompileProviderMetadata(
{token: new CompileTokenMetadata({identifier: ngModuleType}), useClass: ngModuleType});
_resolveProviders( _resolveProviders(
[appModuleProvider], ProviderAstType.PublicService, true, sourceSpan, this._errors, [ngModuleProvider], ProviderAstType.PublicService, true, sourceSpan, this._errors,
this._allProviders); this._allProviders);
}); });
_resolveProviders( _resolveProviders(
_normalizeProviders(appModule.providers, sourceSpan, this._errors), _normalizeProviders(
ngModule.transitiveModule.providers.concat(extraProviders), sourceSpan, this._errors),
ProviderAstType.PublicService, false, sourceSpan, this._errors, this._allProviders); ProviderAstType.PublicService, false, sourceSpan, this._errors, this._allProviders);
} }
@ -436,8 +442,8 @@ function _normalizeProviders(
function _resolveProvidersFromDirectives( function _resolveProvidersFromDirectives(
directives: CompileDirectiveMetadata[], sourceSpan: ParseSourceSpan, directives: CompileDirectiveMetadata[], sourceSpan: ParseSourceSpan,
targetErrors: ParseError[]): CompileTokenMap<ProviderAst> { targetErrors: ParseError[]): CompileIdentifierMap<CompileTokenMetadata, ProviderAst> {
var providersByToken = new CompileTokenMap<ProviderAst>(); var providersByToken = new CompileIdentifierMap<CompileTokenMetadata, ProviderAst>();
directives.forEach((directive) => { directives.forEach((directive) => {
var dirProvider = new CompileProviderMetadata( var dirProvider = new CompileProviderMetadata(
{token: new CompileTokenMetadata({identifier: directive.type}), useClass: directive.type}); {token: new CompileTokenMetadata({identifier: directive.type}), useClass: directive.type});
@ -464,7 +470,7 @@ function _resolveProvidersFromDirectives(
function _resolveProviders( function _resolveProviders(
providers: CompileProviderMetadata[], providerType: ProviderAstType, eager: boolean, providers: CompileProviderMetadata[], providerType: ProviderAstType, eager: boolean,
sourceSpan: ParseSourceSpan, targetErrors: ParseError[], sourceSpan: ParseSourceSpan, targetErrors: ParseError[],
targetProvidersByToken: CompileTokenMap<ProviderAst>) { targetProvidersByToken: CompileIdentifierMap<CompileTokenMetadata, ProviderAst>) {
providers.forEach((provider) => { providers.forEach((provider) => {
var resolvedProvider = targetProvidersByToken.get(provider.token); var resolvedProvider = targetProvidersByToken.get(provider.token);
if (isPresent(resolvedProvider) && resolvedProvider.multiProvider !== provider.multi) { if (isPresent(resolvedProvider) && resolvedProvider.multiProvider !== provider.multi) {
@ -487,8 +493,8 @@ function _resolveProviders(
function _getViewQueries(component: CompileDirectiveMetadata): function _getViewQueries(component: CompileDirectiveMetadata):
CompileTokenMap<CompileQueryMetadata[]> { CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]> {
var viewQueries = new CompileTokenMap<CompileQueryMetadata[]>(); var viewQueries = new CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]>();
if (isPresent(component.viewQueries)) { if (isPresent(component.viewQueries)) {
component.viewQueries.forEach((query) => _addQueryToTokenMap(viewQueries, query)); component.viewQueries.forEach((query) => _addQueryToTokenMap(viewQueries, query));
} }
@ -501,8 +507,8 @@ function _getViewQueries(component: CompileDirectiveMetadata):
} }
function _getContentQueries(directives: CompileDirectiveMetadata[]): function _getContentQueries(directives: CompileDirectiveMetadata[]):
CompileTokenMap<CompileQueryMetadata[]> { CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]> {
var contentQueries = new CompileTokenMap<CompileQueryMetadata[]>(); var contentQueries = new CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]>();
directives.forEach(directive => { directives.forEach(directive => {
if (isPresent(directive.queries)) { if (isPresent(directive.queries)) {
directive.queries.forEach((query) => _addQueryToTokenMap(contentQueries, query)); directive.queries.forEach((query) => _addQueryToTokenMap(contentQueries, query));
@ -517,7 +523,8 @@ function _getContentQueries(directives: CompileDirectiveMetadata[]):
} }
function _addQueryToTokenMap( function _addQueryToTokenMap(
map: CompileTokenMap<CompileQueryMetadata[]>, query: CompileQueryMetadata) { map: CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]>,
query: CompileQueryMetadata) {
query.selectors.forEach((token: CompileTokenMetadata) => { query.selectors.forEach((token: CompileTokenMetadata) => {
var entry = map.get(token); var entry = map.get(token);
if (isBlank(entry)) { if (isBlank(entry)) {

View File

@ -6,19 +6,19 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AppModuleFactory, AppModuleMetadata, Compiler, ComponentFactory, ComponentResolver, ComponentStillLoadingError, Injectable, Injector, OptionalMetadata, Provider, SkipSelfMetadata} from '@angular/core'; import {Compiler, ComponentFactory, ComponentResolver, ComponentStillLoadingError, Injectable, Injector, NgModule, NgModuleFactory, NgModuleMetadata, OptionalMetadata, Provider, SkipSelfMetadata} from '@angular/core';
import {Console} from '../core_private';
import {Console} from '../core_private';
import {BaseException} from '../src/facade/exceptions'; import {BaseException} from '../src/facade/exceptions';
import {ConcreteType, IS_DART, Type, isBlank, isString, stringify} from '../src/facade/lang'; import {ConcreteType, IS_DART, Type, isBlank, isString, stringify} from '../src/facade/lang';
import {ListWrapper,} from '../src/facade/collection'; import {ListWrapper,} from '../src/facade/collection';
import {PromiseWrapper} from '../src/facade/async'; import {PromiseWrapper} from '../src/facade/async';
import {createHostComponentMeta, CompileDirectiveMetadata, CompilePipeMetadata, CompileIdentifierMetadata} from './compile_metadata'; import {createHostComponentMeta, CompileDirectiveMetadata, CompilePipeMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata} from './compile_metadata';
import {TemplateAst,} from './template_ast'; import {TemplateAst,} from './template_ast';
import {StyleCompiler, StylesCompileDependency, CompiledStylesheet} from './style_compiler'; import {StyleCompiler, StylesCompileDependency, CompiledStylesheet} from './style_compiler';
import {ViewCompiler, ViewCompileResult, ViewFactoryDependency, ComponentFactoryDependency} from './view_compiler/view_compiler'; import {ViewCompiler, ViewCompileResult, ViewFactoryDependency, ComponentFactoryDependency} from './view_compiler/view_compiler';
import {AppModuleCompiler} from './app_module_compiler'; import {NgModuleCompiler} from './ng_module_compiler';
import {TemplateParser} from './template_parser'; import {TemplateParser} from './template_parser';
import {DirectiveNormalizer} from './directive_normalizer'; import {DirectiveNormalizer} from './directive_normalizer';
import {CompileMetadataResolver} from './metadata_resolver'; import {CompileMetadataResolver} from './metadata_resolver';
@ -38,122 +38,123 @@ import {SyncAsyncResult} from './util';
* application to XSS risks. For more detail, see the [Security Guide](http://g.co/ng/security). * application to XSS risks. For more detail, see the [Security Guide](http://g.co/ng/security).
*/ */
@Injectable() @Injectable()
export class RuntimeCompiler implements ComponentResolver, Compiler { export class RuntimeCompiler implements Compiler {
private _compiledTemplateCache = new Map<Type, CompiledTemplate>(); private _compiledTemplateCache = new Map<Type, CompiledTemplate>();
private _compiledHostTemplateCache = new Map<Type, CompiledTemplate>(); private _compiledHostTemplateCache = new Map<Type, CompiledTemplate>();
private _compiledAppModuleCache = new Map<Type, AppModuleFactory<any>>(); private _compiledNgModuleCache = new Map<Type, NgModuleFactory<any>>();
private _warnOnComponentResolver = true;
constructor( constructor(
private _injector: Injector, private _metadataResolver: CompileMetadataResolver, private _injector: Injector, private _metadataResolver: CompileMetadataResolver,
private _templateNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser, private _templateNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler, private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
private _appModuleCompiler: AppModuleCompiler, private _genConfig: CompilerConfig, private _ngModuleCompiler: NgModuleCompiler, private _compilerConfig: CompilerConfig,
private _console: Console) { private _console: Console) {}
const flatDeprecatedPlatformDirectives =
ListWrapper.flatten(_genConfig.deprecatedPlatformDirectives);
if (flatDeprecatedPlatformDirectives.length > 0) {
this._console.warn(
`Providing platform directives via the PLATFORM_DIRECTIVES provider or the "CompilerConfig" is deprecated. Provide platform directives via an @AppModule instead. Directives: ` +
flatDeprecatedPlatformDirectives.map(stringify));
}
const flatDeprecatedPlatformPipes = ListWrapper.flatten(_genConfig.deprecatedPlatformPipes);
if (flatDeprecatedPlatformPipes.length > 0) {
this._console.warn(
`Providing platform pipes via the PLATFORM_PIPES provider or the "CompilerConfig" is deprecated. Provide platform pipes via an @AppModule instead. Pipes: ` +
flatDeprecatedPlatformPipes.map(stringify));
}
}
get injector(): Injector { return this._injector; } get injector(): Injector { return this._injector; }
resolveComponent(component: Type|string): Promise<ComponentFactory<any>> { compileModuleSync<T>(moduleType: ConcreteType<T>): NgModuleFactory<T> {
if (isString(component)) { return this._compileModuleAndComponents(moduleType, true).syncResult;
return PromiseWrapper.reject( }
new BaseException(`Cannot resolve component using '${component}'.`), null);
compileModuleAsync<T>(moduleType: ConcreteType<T>): Promise<NgModuleFactory<T>> {
return this._compileModuleAndComponents(moduleType, false).asyncResult;
}
compileComponentAsync<T>(compType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
Promise<ComponentFactory<T>> {
if (!ngModule) {
throw new BaseException(
`Calling compileComponentAsync on the root compiler without a module is not allowed! (Compiling component ${stringify(compType)})`);
} }
if (this._warnOnComponentResolver) { return this._compileComponentInModule(compType, false, ngModule).asyncResult;
this._console.warn(ComponentResolver.DynamicCompilationDeprecationMsg); }
this._warnOnComponentResolver = false;
compileComponentSync<T>(compType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
ComponentFactory<T> {
if (!ngModule) {
throw new BaseException(
`Calling compileComponentSync on the root compiler without a module is not allowed! (Compiling component ${stringify(compType)})`);
} }
return this.compileComponentAsync(<ConcreteType<any>>component); return this._compileComponentInModule(compType, true, ngModule).syncResult;
} }
compileAppModuleSync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null): private _compileModuleAndComponents<T>(moduleType: ConcreteType<T>, isSync: boolean):
AppModuleFactory<T> { SyncAsyncResult<NgModuleFactory<T>> {
return this._compileAppModule(moduleType, true, metadata).syncResult; const componentPromise = this._compileComponents(moduleType, isSync);
const ngModuleFactory = this._compileModule(moduleType);
return new SyncAsyncResult(ngModuleFactory, componentPromise.then(() => ngModuleFactory));
} }
compileAppModuleAsync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null): private _compileModule<T>(moduleType: ConcreteType<T>): NgModuleFactory<T> {
Promise<AppModuleFactory<T>> { let ngModuleFactory = this._compiledNgModuleCache.get(moduleType);
return this._compileAppModule(moduleType, false, metadata).asyncResult; if (!ngModuleFactory) {
} const moduleMeta = this._metadataResolver.getNgModuleMetadata(moduleType);
const transitiveModuleMeta = moduleMeta.transitiveModule;
private _compileAppModule<T>( let boundCompilerFactory = (parentResolver: ComponentResolver) =>
moduleType: ConcreteType<T>, isSync: boolean, new ModuleBoundCompiler(this, moduleMeta.type.runtime, parentResolver, this._console);
metadata: AppModuleMetadata = null): SyncAsyncResult<AppModuleFactory<T>> {
// Only cache if we read the metadata via the reflector,
// as we use the moduleType as cache key.
let useCache = !metadata;
let appModuleFactory = this._compiledAppModuleCache.get(moduleType);
let componentCompilePromises: Promise<any>[] = [];
if (!appModuleFactory || !useCache) {
var compileModuleMeta = this._metadataResolver.getAppModuleMetadata(moduleType, metadata);
let boundCompilerFactory = (parentResolver: ComponentResolver) => new BoundCompiler(
this, compileModuleMeta.directives.map(dir => dir.type.runtime),
compileModuleMeta.pipes.map((pipe) => pipe.type.runtime), parentResolver);
// Always provide a bound Compiler and ComponentResolver // Always provide a bound Compiler and ComponentResolver
compileModuleMeta.providers.push( const extraProviders = [
this._metadataResolver.getProviderMetadata(new Provider(Compiler, { this._metadataResolver.getProviderMetadata(new Provider(Compiler, {
useFactory: boundCompilerFactory, useFactory: boundCompilerFactory,
deps: [[new OptionalMetadata(), new SkipSelfMetadata(), ComponentResolver]] deps: [[new OptionalMetadata(), new SkipSelfMetadata(), ComponentResolver]]
}))); })),
compileModuleMeta.providers.push(this._metadataResolver.getProviderMetadata( this._metadataResolver.getProviderMetadata(
new Provider(ComponentResolver, {useExisting: Compiler}))); new Provider(ComponentResolver, {useExisting: Compiler}))
var compileResult = this._appModuleCompiler.compile(compileModuleMeta); ];
var compileResult = this._ngModuleCompiler.compile(moduleMeta, extraProviders);
compileResult.dependencies.forEach((dep) => { compileResult.dependencies.forEach((dep) => {
let compileResult = this._compileComponent( dep.placeholder.runtime =
dep.comp.runtime, isSync, this._assertComponentKnown(dep.comp.runtime, true).proxyComponentFactory;
compileModuleMeta.directives.map(compileType => <any>compileType.runtime),
compileModuleMeta.pipes.map(compileType => <any>compileType.runtime));
dep.placeholder.runtime = compileResult.syncResult;
componentCompilePromises.push(compileResult.asyncResult);
dep.placeholder.name = `compFactory_${dep.comp.name}`; dep.placeholder.name = `compFactory_${dep.comp.name}`;
}); });
if (IS_DART || !this._genConfig.useJit) { if (IS_DART || !this._compilerConfig.useJit) {
appModuleFactory = ngModuleFactory =
interpretStatements(compileResult.statements, compileResult.appModuleFactoryVar); interpretStatements(compileResult.statements, compileResult.ngModuleFactoryVar);
} else { } else {
appModuleFactory = jitStatements( ngModuleFactory = jitStatements(
`${compileModuleMeta.type.name}.ngfactory.js`, compileResult.statements, `${moduleMeta.type.name}.ngfactory.js`, compileResult.statements,
compileResult.appModuleFactoryVar); compileResult.ngModuleFactoryVar);
}
if (useCache) {
this._compiledAppModuleCache.set(moduleType, appModuleFactory);
} }
this._compiledNgModuleCache.set(moduleMeta.type.runtime, ngModuleFactory);
} }
return new SyncAsyncResult( return ngModuleFactory;
appModuleFactory, Promise.all(componentCompilePromises).then(() => appModuleFactory));
} }
compileComponentAsync<T>(compType: ConcreteType<T>): Promise<ComponentFactory<T>> { private _compileComponentInModule<T>(
return this._compileComponent(compType, false, [], []).asyncResult; compType: ConcreteType<T>, isSync: boolean,
} moduleType: ConcreteType<any>): SyncAsyncResult<ComponentFactory<T>> {
this._metadataResolver.addComponentToModule(moduleType, compType);
compileComponentSync<T>(compType: ConcreteType<T>): ComponentFactory<T> { const componentPromise = this._compileComponents(moduleType, isSync);
return this._compileComponent(compType, true, [], []).syncResult; const componentFactory: ComponentFactory<T> =
this._assertComponentKnown(compType, true).proxyComponentFactory;
return new SyncAsyncResult(componentFactory, componentPromise.then(() => componentFactory));
} }
/** /**
* @internal * @internal
*/ */
_compileComponent<T>( _compileComponents(mainModule: Type, isSync: boolean): Promise<any> {
compType: ConcreteType<T>, isSync: boolean, moduleDirectives: ConcreteType<any>[], const templates = new Set<CompiledTemplate>();
modulePipes: ConcreteType<any>[]): SyncAsyncResult<ComponentFactory<T>> {
var templates =
this._getTransitiveCompiledTemplates(compType, true, moduleDirectives, modulePipes);
var loadingPromises: Promise<any>[] = []; var loadingPromises: Promise<any>[] = [];
const ngModule = this._metadataResolver.getNgModuleMetadata(mainModule);
ngModule.transitiveModule.modules.forEach((localModuleMeta) => {
localModuleMeta.declaredDirectives.forEach((dirMeta) => {
if (dirMeta.isComponent) {
templates.add(this._createCompiledTemplate(
dirMeta, localModuleMeta.transitiveModule.directives,
localModuleMeta.transitiveModule.pipes));
dirMeta.precompile.forEach((precompileType) => {
templates.add(this._createCompiledHostTemplate(precompileType.runtime));
});
}
});
localModuleMeta.precompile.forEach((precompileType) => {
templates.add(this._createCompiledHostTemplate(precompileType.runtime));
});
});
templates.forEach((template) => { templates.forEach((template) => {
if (template.loading) { if (template.loading) {
if (isSync) { if (isSync) {
@ -167,16 +168,14 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
() => { templates.forEach((template) => { this._compileTemplate(template); }); }; () => { templates.forEach((template) => { this._compileTemplate(template); }); };
if (isSync) { if (isSync) {
compile(); compile();
return Promise.resolve(null);
} else {
return Promise.all(loadingPromises).then(compile);
} }
let result = this._compiledHostTemplateCache.get(compType).proxyComponentFactory;
return new SyncAsyncResult(result, Promise.all(loadingPromises).then(() => {
compile();
return result;
}));
} }
clearCacheFor(type: Type) { clearCacheFor(type: Type) {
this._compiledAppModuleCache.delete(type); this._compiledNgModuleCache.delete(type);
this._metadataResolver.clearCacheFor(type); this._metadataResolver.clearCacheFor(type);
this._compiledHostTemplateCache.delete(type); this._compiledHostTemplateCache.delete(type);
var compiledTemplate = this._compiledTemplateCache.get(type); var compiledTemplate = this._compiledTemplateCache.get(type);
@ -191,71 +190,54 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
this._compiledTemplateCache.clear(); this._compiledTemplateCache.clear();
this._compiledHostTemplateCache.clear(); this._compiledHostTemplateCache.clear();
this._templateNormalizer.clearCache(); this._templateNormalizer.clearCache();
this._compiledAppModuleCache.clear(); this._compiledNgModuleCache.clear();
} }
private _createCompiledHostTemplate(type: Type): CompiledTemplate { private _createCompiledHostTemplate(compType: Type): CompiledTemplate {
var compiledTemplate = this._compiledHostTemplateCache.get(type); var compiledTemplate = this._compiledHostTemplateCache.get(compType);
if (isBlank(compiledTemplate)) { if (isBlank(compiledTemplate)) {
var compMeta = this._metadataResolver.getDirectiveMetadata(type); var compMeta = this._metadataResolver.getDirectiveMetadata(compType);
assertComponent(compMeta); assertComponent(compMeta);
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector); var hostMeta = createHostComponentMeta(compMeta);
compiledTemplate = new CompiledTemplate( compiledTemplate = new CompiledTemplate(
true, compMeta.selector, compMeta.type, [], [type], [], [], true, compMeta.selector, compMeta.type, [compMeta], [],
this._templateNormalizer.normalizeDirective(hostMeta)); this._templateNormalizer.normalizeDirective(hostMeta));
this._compiledHostTemplateCache.set(type, compiledTemplate); this._compiledHostTemplateCache.set(compType, compiledTemplate);
} }
return compiledTemplate; return compiledTemplate;
} }
private _createCompiledTemplate( private _createCompiledTemplate(
type: Type, moduleDirectives: ConcreteType<any>[], compMeta: CompileDirectiveMetadata, directives: CompileDirectiveMetadata[],
modulePipes: ConcreteType<any>[]): CompiledTemplate { pipes: CompilePipeMetadata[]): CompiledTemplate {
var compiledTemplate = this._compiledTemplateCache.get(type); var compiledTemplate = this._compiledTemplateCache.get(compMeta.type.runtime);
if (isBlank(compiledTemplate)) { if (isBlank(compiledTemplate)) {
const compMeta = this._metadataResolver.getDirectiveMetadata(type);
assertComponent(compMeta); assertComponent(compMeta);
const viewDirectives: CompileDirectiveMetadata[] = [];
moduleDirectives.forEach(
(type) => viewDirectives.push(this._metadataResolver.getDirectiveMetadata(type)));
const viewComponentTypes: Type[] = [];
this._metadataResolver.getViewDirectivesMetadata(type).forEach(dirOrComp => {
if (dirOrComp.isComponent) {
viewComponentTypes.push(dirOrComp.type.runtime);
} else {
viewDirectives.push(dirOrComp);
}
});
const precompileComponentTypes = compMeta.precompile.map((typeMeta) => typeMeta.runtime);
const pipes = [
...modulePipes.map((type) => this._metadataResolver.getPipeMetadata(type)),
...this._metadataResolver.getViewPipesMetadata(type)
];
compiledTemplate = new CompiledTemplate( compiledTemplate = new CompiledTemplate(
false, compMeta.selector, compMeta.type, viewDirectives, viewComponentTypes, false, compMeta.selector, compMeta.type, directives, pipes,
precompileComponentTypes, pipes, this._templateNormalizer.normalizeDirective(compMeta)); this._templateNormalizer.normalizeDirective(compMeta));
this._compiledTemplateCache.set(type, compiledTemplate); this._compiledTemplateCache.set(compMeta.type.runtime, compiledTemplate);
} }
return compiledTemplate; return compiledTemplate;
} }
private _getTransitiveCompiledTemplates( private _assertComponentKnown(compType: any, isHost: boolean): CompiledTemplate {
compType: Type, isHost: boolean, moduleDirectives: ConcreteType<any>[], const compiledTemplate = isHost ? this._compiledHostTemplateCache.get(compType) :
modulePipes: ConcreteType<any>[], this._compiledTemplateCache.get(compType);
target: Set<CompiledTemplate> = new Set<CompiledTemplate>()): Set<CompiledTemplate> { if (!compiledTemplate) {
const template = isHost ? this._createCompiledHostTemplate(compType) : throw new BaseException(
this._createCompiledTemplate(compType, moduleDirectives, modulePipes); `Illegal state: CompiledTemplate for ${stringify(compType)} (isHost: ${isHost}) does not exist!`);
if (!target.has(template)) {
target.add(template);
template.viewComponentTypes.forEach((compType) => {
this._getTransitiveCompiledTemplates(
compType, false, moduleDirectives, modulePipes, target);
});
template.precompileHostComponentTypes.forEach((compType) => {
this._getTransitiveCompiledTemplates(compType, true, moduleDirectives, modulePipes, target);
});
} }
return target; return compiledTemplate;
}
private _assertComponentLoaded(compType: any, isHost: boolean): CompiledTemplate {
const compiledTemplate = this._assertComponentKnown(compType, isHost);
if (compiledTemplate.loading) {
throw new BaseException(
`Illegal state: CompiledTemplate for ${stringify(compType)} (isHost: ${isHost}) is still loading!`);
}
return compiledTemplate;
} }
private _compileTemplate(template: CompiledTemplate) { private _compileTemplate(template: CompiledTemplate) {
@ -270,7 +252,7 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
this._resolveStylesCompileResult( this._resolveStylesCompileResult(
stylesCompileResult.componentStylesheet, externalStylesheetsByModuleUrl); stylesCompileResult.componentStylesheet, externalStylesheetsByModuleUrl);
const viewCompMetas = template.viewComponentTypes.map( const viewCompMetas = template.viewComponentTypes.map(
(compType) => this._compiledTemplateCache.get(compType).normalizedCompMeta); (compType) => this._assertComponentLoaded(compType, false).normalizedCompMeta);
const parsedTemplate = this._templateParser.parse( const parsedTemplate = this._templateParser.parse(
compMeta, compMeta.template.template, template.viewDirectives.concat(viewCompMetas), compMeta, compMeta.template.template, template.viewDirectives.concat(viewCompMetas),
template.viewPipes, compMeta.type.name); template.viewPipes, compMeta.type.name);
@ -281,12 +263,12 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
let depTemplate: CompiledTemplate; let depTemplate: CompiledTemplate;
if (dep instanceof ViewFactoryDependency) { if (dep instanceof ViewFactoryDependency) {
let vfd = <ViewFactoryDependency>dep; let vfd = <ViewFactoryDependency>dep;
depTemplate = this._compiledTemplateCache.get(vfd.comp.runtime); depTemplate = this._assertComponentLoaded(vfd.comp.runtime, false);
vfd.placeholder.runtime = depTemplate.proxyViewFactory; vfd.placeholder.runtime = depTemplate.proxyViewFactory;
vfd.placeholder.name = `viewFactory_${vfd.comp.name}`; vfd.placeholder.name = `viewFactory_${vfd.comp.name}`;
} else if (dep instanceof ComponentFactoryDependency) { } else if (dep instanceof ComponentFactoryDependency) {
let cfd = <ComponentFactoryDependency>dep; let cfd = <ComponentFactoryDependency>dep;
depTemplate = this._compiledHostTemplateCache.get(cfd.comp.runtime); depTemplate = this._assertComponentLoaded(cfd.comp.runtime, true);
cfd.placeholder.runtime = depTemplate.proxyComponentFactory; cfd.placeholder.runtime = depTemplate.proxyComponentFactory;
cfd.placeholder.name = `compFactory_${cfd.comp.name}`; cfd.placeholder.name = `compFactory_${cfd.comp.name}`;
} }
@ -294,7 +276,7 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
const statements = const statements =
stylesCompileResult.componentStylesheet.statements.concat(compileResult.statements); stylesCompileResult.componentStylesheet.statements.concat(compileResult.statements);
let factory: any; let factory: any;
if (IS_DART || !this._genConfig.useJit) { if (IS_DART || !this._compilerConfig.useJit) {
factory = interpretStatements(statements, compileResult.viewFactoryVar); factory = interpretStatements(statements, compileResult.viewFactoryVar);
} else { } else {
factory = jitStatements( factory = jitStatements(
@ -318,7 +300,7 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
result: CompiledStylesheet, result: CompiledStylesheet,
externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>): string[] { externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>): string[] {
this._resolveStylesCompileResult(result, externalStylesheetsByModuleUrl); this._resolveStylesCompileResult(result, externalStylesheetsByModuleUrl);
if (IS_DART || !this._genConfig.useJit) { if (IS_DART || !this._compilerConfig.useJit) {
return interpretStatements(result.statements, result.stylesVar); return interpretStatements(result.statements, result.stylesVar);
} else { } else {
return jitStatements(`${result.meta.moduleUrl}.css.js`, result.statements, result.stylesVar); return jitStatements(`${result.meta.moduleUrl}.css.js`, result.statements, result.stylesVar);
@ -334,13 +316,28 @@ class CompiledTemplate {
private _normalizedCompMeta: CompileDirectiveMetadata = null; private _normalizedCompMeta: CompileDirectiveMetadata = null;
isCompiled = false; isCompiled = false;
isCompiledWithDeps = false; isCompiledWithDeps = false;
viewComponentTypes: Type[] = [];
viewDirectives: CompileDirectiveMetadata[] = [];
constructor( constructor(
public isHost: boolean, selector: string, public compType: CompileIdentifierMetadata, public isHost: boolean, selector: string, public compType: CompileIdentifierMetadata,
public viewDirectives: CompileDirectiveMetadata[], public viewComponentTypes: Type[], viewDirectivesAndComponents: CompileDirectiveMetadata[],
public precompileHostComponentTypes: Type[], public viewPipes: CompilePipeMetadata[], public viewPipes: CompilePipeMetadata[],
_normalizeResult: SyncAsyncResult<CompileDirectiveMetadata>) { _normalizeResult: SyncAsyncResult<CompileDirectiveMetadata>) {
this.proxyViewFactory = (...args: any[]) => this._viewFactory.apply(null, args); viewDirectivesAndComponents.forEach((dirMeta) => {
if (dirMeta.isComponent) {
this.viewComponentTypes.push(dirMeta.type.runtime);
} else {
this.viewDirectives.push(dirMeta);
}
});
this.proxyViewFactory = (...args: any[]) => {
if (!this._viewFactory) {
throw new BaseException(
`Illegal state: CompiledTemplate for ${stringify(this.compType)} is not compiled yet!`);
}
return this._viewFactory.apply(null, args);
};
this.proxyComponentFactory = isHost ? this.proxyComponentFactory = isHost ?
new ComponentFactory<any>(selector, this.proxyViewFactory, compType.runtime) : new ComponentFactory<any>(selector, this.proxyViewFactory, compType.runtime) :
null; null;
@ -376,13 +373,15 @@ function assertComponent(meta: CompileDirectiveMetadata) {
} }
/** /**
* A wrapper around `Compiler` and `ComponentResolver` that * Implements `Compiler` and `ComponentResolver` by delegating
* provides default patform directives / pipes. * to the RuntimeCompiler using a known module.
*/ */
class BoundCompiler implements Compiler, ComponentResolver { class ModuleBoundCompiler implements Compiler, ComponentResolver {
private _warnOnComponentResolver = true;
constructor( constructor(
private _delegate: RuntimeCompiler, private _directives: any[], private _pipes: any[], private _delegate: RuntimeCompiler, private _ngModule: ConcreteType<any>,
private _parentComponentResolver: ComponentResolver) {} private _parentComponentResolver: ComponentResolver, private _console: Console) {}
get injector(): Injector { return this._delegate.injector; } get injector(): Injector { return this._delegate.injector; }
@ -395,27 +394,29 @@ class BoundCompiler implements Compiler, ComponentResolver {
new BaseException(`Cannot resolve component using '${component}'.`), null); new BaseException(`Cannot resolve component using '${component}'.`), null);
} }
} }
if (this._warnOnComponentResolver) {
this._console.warn(ComponentResolver.DynamicCompilationDeprecationMsg);
this._warnOnComponentResolver = false;
}
return this.compileComponentAsync(<ConcreteType<any>>component); return this.compileComponentAsync(<ConcreteType<any>>component);
} }
compileComponentAsync<T>(compType: ConcreteType<T>): Promise<ComponentFactory<T>> { compileComponentAsync<T>(compType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
return this._delegate._compileComponent(compType, false, this._directives, this._pipes) Promise<ComponentFactory<T>> {
.asyncResult; return this._delegate.compileComponentAsync(compType, ngModule ? ngModule : this._ngModule);
} }
compileComponentSync<T>(compType: ConcreteType<T>): ComponentFactory<T> { compileComponentSync<T>(compType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
return this._delegate._compileComponent(compType, true, this._directives, this._pipes) ComponentFactory<T> {
.syncResult; return this._delegate.compileComponentSync(compType, ngModule ? ngModule : this._ngModule);
} }
compileAppModuleSync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null): compileModuleSync<T>(moduleType: ConcreteType<T>): NgModuleFactory<T> {
AppModuleFactory<T> { return this._delegate.compileModuleSync(moduleType);
return this._delegate.compileAppModuleSync(moduleType, metadata);
} }
compileAppModuleAsync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null): compileModuleAsync<T>(moduleType: ConcreteType<T>): Promise<NgModuleFactory<T>> {
Promise<AppModuleFactory<T>> { return this._delegate.compileModuleAsync(moduleType);
return this._delegate.compileAppModuleAsync(moduleType, metadata);
} }
/** /**
@ -429,7 +430,7 @@ class BoundCompiler implements Compiler, ComponentResolver {
} }
/** /**
* Clears the cache for the given component/appModule. * Clears the cache for the given component/ngModule.
*/ */
clearCacheFor(type: Type) { this._delegate.clearCacheFor(type); } clearCacheFor(type: Type) { this._delegate.clearCacheFor(type); }
} }

View File

@ -13,7 +13,7 @@ import {RegExpWrapper, isPresent, StringWrapper, isBlank} from '../src/facade/la
import {BaseException} from '../src/facade/exceptions'; import {BaseException} from '../src/facade/exceptions';
import {AST, Interpolation, ASTWithSource, TemplateBinding, RecursiveAstVisitor, BindingPipe, ParserError} from './expression_parser/ast'; import {AST, Interpolation, ASTWithSource, TemplateBinding, RecursiveAstVisitor, BindingPipe, ParserError} from './expression_parser/ast';
import {Parser} from './expression_parser/parser'; import {Parser} from './expression_parser/parser';
import {CompileDirectiveMetadata, CompilePipeMetadata, CompileMetadataWithType, CompileTokenMetadata,} from './compile_metadata'; import {CompileDirectiveMetadata, CompilePipeMetadata, CompileMetadataWithIdentifier, CompileTokenMetadata, CompileIdentifierMap, removeIdentifierDuplicates} from './compile_metadata';
import {HtmlParser, HtmlParseTreeResult} from './html_parser'; import {HtmlParser, HtmlParseTreeResult} from './html_parser';
import {splitNsName, mergeNsAndName} from './html_tags'; import {splitNsName, mergeNsAndName} from './html_tags';
import {ParseSourceSpan, ParseError, ParseErrorLevel} from './parse_util'; import {ParseSourceSpan, ParseError, ParseErrorLevel} from './parse_util';
@ -27,7 +27,7 @@ import {HtmlAstVisitor, HtmlElementAst, HtmlAttrAst, HtmlTextAst, HtmlCommentAst
import {splitAtColon} from './util'; import {splitAtColon} from './util';
import {identifierToken, Identifiers} from './identifiers'; import {identifierToken, Identifiers} from './identifiers';
import {expandNodes} from './expander'; import {expandNodes} from './expander';
import {ProviderElementContext, ProviderViewContext} from './provider_parser'; import {ProviderElementContext, ProviderViewContext} from './provider_analyzer';
// Group 1 = "bind-" // Group 1 = "bind-"
// Group 2 = "var-" // Group 2 = "var-"
@ -118,8 +118,8 @@ export class TemplateParser {
} }
if (htmlAstWithErrors.rootNodes.length > 0) { if (htmlAstWithErrors.rootNodes.length > 0) {
const uniqDirectives = <CompileDirectiveMetadata[]>removeDuplicates(directives); const uniqDirectives = removeIdentifierDuplicates(directives);
const uniqPipes = <CompilePipeMetadata[]>removeDuplicates(pipes); const uniqPipes = removeIdentifierDuplicates(pipes);
const providerViewContext = const providerViewContext =
new ProviderViewContext(component, htmlAstWithErrors.rootNodes[0].sourceSpan); new ProviderViewContext(component, htmlAstWithErrors.rootNodes[0].sourceSpan);
const parseVisitor = new TemplateParseVisitor( const parseVisitor = new TemplateParseVisitor(
@ -181,7 +181,6 @@ class TemplateParseVisitor implements HtmlAstVisitor {
const tempMeta = providerViewContext.component.template; const tempMeta = providerViewContext.component.template;
// TODO
if (isPresent(tempMeta) && isPresent(tempMeta.interpolation)) { if (isPresent(tempMeta) && isPresent(tempMeta.interpolation)) {
this._interpolationConfig = { this._interpolationConfig = {
start: tempMeta.interpolation[0], start: tempMeta.interpolation[0],
@ -1015,18 +1014,3 @@ export class PipeCollector extends RecursiveAstVisitor {
return null; return null;
} }
} }
function removeDuplicates(items: CompileMetadataWithType[]): CompileMetadataWithType[] {
let res: CompileMetadataWithType[] = [];
items.forEach(item => {
let hasMatch =
res.filter(
r => r.type.name == item.type.name && r.type.moduleUrl == item.type.moduleUrl &&
r.type.runtime == item.type.runtime)
.length > 0;
if (!hasMatch) {
res.push(item);
}
});
return res;
}

View File

@ -18,7 +18,7 @@ import {ProviderAst, ProviderAstType, ReferenceAst, TemplateAst} from '../templa
import {CompileView} from './compile_view'; import {CompileView} from './compile_view';
import {InjectMethodVars} from './constants'; import {InjectMethodVars} from './constants';
import {CompileTokenMap, CompileDirectiveMetadata, CompileTokenMetadata, CompileQueryMetadata, CompileProviderMetadata, CompileDiDependencyMetadata, CompileIdentifierMetadata,} from '../compile_metadata'; import {CompileIdentifierMap, CompileDirectiveMetadata, CompileTokenMetadata, CompileQueryMetadata, CompileProviderMetadata, CompileDiDependencyMetadata, CompileIdentifierMetadata,} from '../compile_metadata';
import {getPropertyInView, injectFromViewParentInjector} from './util'; import {getPropertyInView, injectFromViewParentInjector} from './util';
import {CompileQuery, createQueryList, addQueryToTokenMap} from './compile_query'; import {CompileQuery, createQueryList, addQueryToTokenMap} from './compile_query';
import {CompileMethod} from './compile_method'; import {CompileMethod} from './compile_method';
@ -43,11 +43,11 @@ export class CompileElement extends CompileNode {
public appElement: o.ReadPropExpr; public appElement: o.ReadPropExpr;
public elementRef: o.Expression; public elementRef: o.Expression;
public injector: o.Expression; public injector: o.Expression;
private _instances = new CompileTokenMap<o.Expression>(); private _instances = new CompileIdentifierMap<CompileTokenMetadata, o.Expression>();
private _resolvedProviders: CompileTokenMap<ProviderAst>; private _resolvedProviders: CompileIdentifierMap<CompileTokenMetadata, ProviderAst>;
private _queryCount = 0; private _queryCount = 0;
private _queries = new CompileTokenMap<CompileQuery[]>(); private _queries = new CompileIdentifierMap<CompileTokenMetadata, CompileQuery[]>();
private _componentConstructorViewQueryLists: o.Expression[] = []; private _componentConstructorViewQueryLists: o.Expression[] = [];
public contentNodesByNgContentIndex: Array<o.Expression>[] = null; public contentNodesByNgContentIndex: Array<o.Expression>[] = null;
@ -144,7 +144,7 @@ export class CompileElement extends CompileNode {
identifierToken(Identifiers.ViewContainerRef), this.appElement.prop('vcRef')); identifierToken(Identifiers.ViewContainerRef), this.appElement.prop('vcRef'));
} }
this._resolvedProviders = new CompileTokenMap<ProviderAst>(); this._resolvedProviders = new CompileIdentifierMap<CompileTokenMetadata, ProviderAst>();
this._resolvedProvidersArray.forEach( this._resolvedProvidersArray.forEach(
provider => this._resolvedProviders.add(provider.token, provider)); provider => this._resolvedProviders.add(provider.token, provider));

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {CompileQueryMetadata, CompileTokenMap} from '../compile_metadata'; import {CompileIdentifierMap, CompileQueryMetadata, CompileTokenMetadata} from '../compile_metadata';
import {ListWrapper} from '../facade/collection'; import {ListWrapper} from '../facade/collection';
import {isBlank, isPresent} from '../facade/lang'; import {isBlank, isPresent} from '../facade/lang';
import {Identifiers} from '../identifiers'; import {Identifiers} from '../identifiers';
@ -125,7 +125,8 @@ export function createQueryList(
return expr; return expr;
} }
export function addQueryToTokenMap(map: CompileTokenMap<CompileQuery[]>, query: CompileQuery) { export function addQueryToTokenMap(
map: CompileIdentifierMap<CompileTokenMetadata, CompileQuery[]>, query: CompileQuery) {
query.meta.selectors.forEach((selector) => { query.meta.selectors.forEach((selector) => {
var entry = map.get(selector); var entry = map.get(selector);
if (isBlank(entry)) { if (isBlank(entry)) {

View File

@ -8,7 +8,7 @@
import {ViewType} from '../../core_private'; import {ViewType} from '../../core_private';
import {CompiledAnimation} from '../animation/animation_compiler'; import {CompiledAnimation} from '../animation/animation_compiler';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeMetadata, CompileTokenMap} from '../compile_metadata'; import {CompileDirectiveMetadata, CompileIdentifierMap, CompileIdentifierMetadata, CompilePipeMetadata, CompileTokenMetadata} from '../compile_metadata';
import {CompilerConfig} from '../config'; import {CompilerConfig} from '../config';
import {ListWrapper} from '../facade/collection'; import {ListWrapper} from '../facade/collection';
import {isBlank, isPresent} from '../facade/lang'; import {isBlank, isPresent} from '../facade/lang';
@ -27,7 +27,7 @@ import {createPureProxy, getPropertyInView, getViewFactoryName, injectFromViewPa
export class CompileView implements NameResolver { export class CompileView implements NameResolver {
public viewType: ViewType; public viewType: ViewType;
public viewQueries: CompileTokenMap<CompileQuery[]>; public viewQueries: CompileIdentifierMap<CompileTokenMetadata, CompileQuery[]>;
public nodes: CompileNode[] = []; public nodes: CompileNode[] = [];
// root nodes or AppElements for ViewContainers // root nodes or AppElements for ViewContainers
@ -98,7 +98,7 @@ export class CompileView implements NameResolver {
this.componentContext = this.componentContext =
getPropertyInView(o.THIS_EXPR.prop('context'), this, this.componentView); getPropertyInView(o.THIS_EXPR.prop('context'), this, this.componentView);
var viewQueries = new CompileTokenMap<CompileQuery[]>(); var viewQueries = new CompileIdentifierMap<CompileTokenMetadata, CompileQuery[]>();
if (this.viewType === ViewType.COMPONENT) { if (this.viewType === ViewType.COMPONENT) {
var directiveInstance = o.THIS_EXPR.prop('context'); var directiveInstance = o.THIS_EXPR.prop('context');
ListWrapper.forEachWithIndex(this.component.viewQueries, (queryMeta, queryIndex) => { ListWrapper.forEachWithIndex(this.component.viewQueries, (queryMeta, queryIndex) => {

View File

@ -22,7 +22,7 @@ function _isComponentMetadata(obj: any): obj is ComponentMetadata {
export class ViewResolver { export class ViewResolver {
constructor(private _reflector: ReflectorReader = reflector) {} constructor(private _reflector: ReflectorReader = reflector) {}
resolve(component: Type): ViewMetadata { resolve(component: Type, throwIfNotFound = true): ViewMetadata {
const compMeta: ComponentMetadata = const compMeta: ComponentMetadata =
this._reflector.annotations(component).find(_isComponentMetadata); this._reflector.annotations(component).find(_isComponentMetadata);
@ -45,8 +45,11 @@ export class ViewResolver {
}); });
} }
} else { } else {
throw new BaseException( if (throwIfNotFound) {
`Could not compile '${stringify(component)}' because it is not a component.`); throw new BaseException(
`Could not compile '${stringify(component)}' because it is not a component.`);
}
return null;
} }
} }
} }

View File

@ -1,256 +0,0 @@
/**
* @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 {beforeEach, ddescribe, describe, expect, iit, inject, it, xit,} from '@angular/core/testing/testing_internal';
import {CompileDirectiveMetadata, CompileTypeMetadata, CompileTemplateMetadata, CompileProviderMetadata, CompileDiDependencyMetadata, CompileQueryMetadata, CompileIdentifierMetadata, CompileFactoryMetadata, CompileTokenMetadata, CompileAnimationEntryMetadata, CompileAnimationStyleMetadata, CompileAnimationAnimateMetadata, CompileAnimationSequenceMetadata, CompileAnimationStateTransitionMetadata, CompileAnimationKeyframesSequenceMetadata, CompileAnimationGroupMetadata} from '@angular/compiler/src/compile_metadata';
import {ViewEncapsulation} from '@angular/core/src/metadata/view';
import {ChangeDetectionStrategy} from '@angular/core/src/change_detection';
import {LifecycleHooks} from '@angular/core/src/metadata/lifecycle_hooks';
export function main() {
describe('CompileMetadata', () => {
var fullTypeMeta: CompileTypeMetadata;
var fullTemplateMeta: CompileTemplateMetadata;
var fullDirectiveMeta: CompileDirectiveMetadata;
beforeEach(() => {
var diDep = new CompileDiDependencyMetadata({
isAttribute: true,
isSelf: true,
isHost: true,
isSkipSelf: true,
isOptional: true,
token: new CompileTokenMetadata({value: 'someToken'}),
query: new CompileQueryMetadata({
selectors: [new CompileTokenMetadata({value: 'one'})],
descendants: true,
first: true,
propertyName: 'one'
}),
viewQuery: new CompileQueryMetadata({
selectors: [new CompileTokenMetadata({value: 'one'})],
descendants: true,
first: true,
propertyName: 'one'
})
});
fullTypeMeta = new CompileTypeMetadata(
{name: 'SomeType', moduleUrl: 'someUrl', isHost: true, diDeps: [diDep]});
fullTemplateMeta = new CompileTemplateMetadata({
encapsulation: ViewEncapsulation.Emulated,
template: '<a></a>',
templateUrl: 'someTemplateUrl',
styles: ['someStyle'],
styleUrls: ['someStyleUrl'],
animations: [new CompileAnimationEntryMetadata(
'animation',
[new CompileAnimationStateTransitionMetadata(
'* => *', new CompileAnimationSequenceMetadata([
new CompileAnimationStyleMetadata(0, [{'opacity': 0}]),
new CompileAnimationAnimateMetadata(
1000, new CompileAnimationStyleMetadata(0, [{'opacity': 1}]))
]))])],
ngContentSelectors: ['*'],
interpolation: ['{{', '}}']
});
fullDirectiveMeta = CompileDirectiveMetadata.create({
selector: 'someSelector',
isComponent: true,
type: fullTypeMeta,
template: fullTemplateMeta,
changeDetection: ChangeDetectionStrategy.Default,
inputs: ['someProp'],
outputs: ['someEvent'],
host: {'(event1)': 'handler1', '[prop1]': 'expr1', 'attr1': 'attrValue2'},
lifecycleHooks: [LifecycleHooks.OnChanges],
providers: [new CompileProviderMetadata({
token: new CompileTokenMetadata({value: 'token'}),
multi: true,
useClass: fullTypeMeta,
useExisting: new CompileTokenMetadata({
identifier: new CompileIdentifierMetadata({name: 'someName'}),
identifierIsInstance: true
}),
useFactory: new CompileFactoryMetadata({name: 'someName', diDeps: [diDep]}),
useValue: 'someValue',
})],
viewProviders: [new CompileProviderMetadata({
token: new CompileTokenMetadata({value: 'token'}),
useClass: fullTypeMeta,
useExisting: new CompileTokenMetadata(
{identifier: new CompileIdentifierMetadata({name: 'someName'})}),
useFactory: new CompileFactoryMetadata({name: 'someName', diDeps: [diDep]}),
useValue: 'someValue'
})],
queries: [new CompileQueryMetadata({
selectors: [new CompileTokenMetadata({value: 'selector'})],
descendants: true,
first: false,
propertyName: 'prop',
read: new CompileTokenMetadata({value: 'readToken'})
})],
viewQueries: [new CompileQueryMetadata({
selectors: [new CompileTokenMetadata({value: 'selector'})],
descendants: true,
first: false,
propertyName: 'prop',
read: new CompileTokenMetadata({value: 'readToken'})
})]
});
});
describe('CompileIdentifierMetadata', () => {
it('should serialize with full data', () => {
let full = new CompileIdentifierMetadata(
{name: 'name', moduleUrl: 'module', value: ['one', ['two']]});
expect(CompileIdentifierMetadata.fromJson(full.toJson())).toEqual(full);
});
it('should serialize with no data', () => {
let empty = new CompileIdentifierMetadata();
expect(CompileIdentifierMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
describe('DirectiveMetadata', () => {
it('should serialize with full data', () => {
expect(CompileDirectiveMetadata.fromJson(fullDirectiveMeta.toJson()))
.toEqual(fullDirectiveMeta);
});
it('should serialize with no data', () => {
var empty = CompileDirectiveMetadata.create();
expect(CompileDirectiveMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
describe('TypeMetadata', () => {
it('should serialize with full data', () => {
expect(CompileTypeMetadata.fromJson(fullTypeMeta.toJson())).toEqual(fullTypeMeta);
});
it('should serialize with no data', () => {
var empty = new CompileTypeMetadata();
expect(CompileTypeMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
describe('TemplateMetadata', () => {
it('should serialize with full data', () => {
expect(CompileTemplateMetadata.fromJson(fullTemplateMeta.toJson()))
.toEqual(fullTemplateMeta);
});
it('should serialize with no data', () => {
var empty = new CompileTemplateMetadata();
expect(CompileTemplateMetadata.fromJson(empty.toJson())).toEqual(empty);
});
it('should throw an error with invalid interpolation symbols', () => {
expect(() => new CompileTemplateMetadata(<any>{interpolation: ['{{']}))
.toThrowError(`'interpolation' should have a start and an end symbol.`);
});
});
describe('CompileAnimationStyleMetadata', () => {
it('should serialize with full data', () => {
let full = new CompileAnimationStyleMetadata(0, [{'opacity': 0, 'color': 'red'}]);
expect(CompileAnimationStyleMetadata.fromJson(full.toJson())).toEqual(full);
});
it('should serialize with no data', () => {
let empty = new CompileAnimationStyleMetadata(0, []);
expect(CompileAnimationStyleMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
describe('CompileAnimationAnimateMetadata', () => {
it('should serialize with full data', () => {
let full = new CompileAnimationAnimateMetadata(
'1s linear', new CompileAnimationStyleMetadata(0, [{'opacity': 0.5, 'color': 'blue'}]));
expect(CompileAnimationAnimateMetadata.fromJson(full.toJson())).toEqual(full);
});
it('should serialize with no data', () => {
let empty = new CompileAnimationAnimateMetadata();
expect(CompileAnimationAnimateMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
describe('CompileAnimationSequenceMetadata', () => {
it('should serialize with full data', () => {
let full = new CompileAnimationSequenceMetadata([
new CompileAnimationStyleMetadata(0, [{'opacity': 0.5, 'width': 100}]),
new CompileAnimationAnimateMetadata(
1000, new CompileAnimationStyleMetadata(0, [{'opacity': 1, 'width': 0}]))
]);
expect(CompileAnimationSequenceMetadata.fromJson(full.toJson())).toEqual(full);
});
it('should serialize with no data', () => {
let empty = new CompileAnimationSequenceMetadata();
expect(CompileAnimationSequenceMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
describe('CompileAnimationGroupMetadata', () => {
it('should serialize with full data', () => {
let full = new CompileAnimationGroupMetadata([
new CompileAnimationStyleMetadata(0, [{'width': 100, 'border': '1px solid red'}]),
new CompileAnimationAnimateMetadata(
1000, new CompileAnimationStyleMetadata(
0, [{'width': 900, 'border': '10px solid blue'}]))
]);
expect(CompileAnimationGroupMetadata.fromJson(full.toJson())).toEqual(full);
});
it('should serialize with no data', () => {
let empty = new CompileAnimationGroupMetadata();
expect(CompileAnimationGroupMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
describe('CompileAnimationKeyframesSequenceMetadata', () => {
it('should serialize with full data', () => {
let full = new CompileAnimationKeyframesSequenceMetadata([
new CompileAnimationStyleMetadata(0, [{'width': 0}]),
new CompileAnimationStyleMetadata(0.5, [{'width': 100}]),
new CompileAnimationStyleMetadata(1, [{'width': 200}]),
]);
expect(CompileAnimationKeyframesSequenceMetadata.fromJson(full.toJson())).toEqual(full);
});
it('should serialize with no data', () => {
let empty = new CompileAnimationKeyframesSequenceMetadata();
expect(CompileAnimationKeyframesSequenceMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
describe('CompileAnimationEntryMetadata', () => {
it('should serialize with full data', () => {
let full = new CompileAnimationEntryMetadata(
'name', [new CompileAnimationStateTransitionMetadata(
'key => value', new CompileAnimationSequenceMetadata([
new CompileAnimationStyleMetadata(0, [{'color': 'red'}]),
new CompileAnimationAnimateMetadata(
1000, new CompileAnimationStyleMetadata(0, [{'color': 'blue'}]))
]))]);
expect(CompileAnimationEntryMetadata.fromJson(full.toJson())).toEqual(full);
});
it('should serialize with no data', () => {
let empty = new CompileAnimationEntryMetadata();
expect(CompileAnimationEntryMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
});
}

View File

@ -12,6 +12,7 @@ import {LIFECYCLE_HOOKS_VALUES} from '@angular/core/src/metadata/lifecycle_hooks
import {configureCompiler} from '@angular/core/testing'; import {configureCompiler} from '@angular/core/testing';
import {afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal'; import {afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {CompileNgModuleMetadata} from '../src/compile_metadata';
import {IS_DART, stringify} from '../src/facade/lang'; import {IS_DART, stringify} from '../src/facade/lang';
import {CompileMetadataResolver} from '../src/metadata_resolver'; import {CompileMetadataResolver} from '../src/metadata_resolver';
@ -22,7 +23,7 @@ export function main() {
describe('CompileMetadataResolver', () => { describe('CompileMetadataResolver', () => {
beforeEach(() => { configureCompiler({providers: TEST_COMPILER_PROVIDERS}); }); beforeEach(() => { configureCompiler({providers: TEST_COMPILER_PROVIDERS}); });
describe('getMetadata', () => { describe('getDirectiveMetadata', () => {
it('should read metadata', it('should read metadata',
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
var meta = resolver.getDirectiveMetadata(ComponentWithEverything); var meta = resolver.getDirectiveMetadata(ComponentWithEverything);
@ -102,35 +103,6 @@ export function main() {
})); }));
}); });
describe('getViewDirectivesMetadata', () => {
it('should return the directive metadatas',
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
expect(resolver.getViewDirectivesMetadata(ComponentWithEverything))
.toContain(resolver.getDirectiveMetadata(SomeDirective));
}));
describe('platform directives', () => {
beforeEach(() => {
configureCompiler({
providers: [{
provide: CompilerConfig,
useValue: new CompilerConfig(
{genDebugInfo: true, deprecatedPlatformDirectives: [ADirective]})
}]
});
});
it('should include platform directives when available',
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
expect(resolver.getViewDirectivesMetadata(ComponentWithEverything))
.toContain(resolver.getDirectiveMetadata(ADirective));
expect(resolver.getViewDirectivesMetadata(ComponentWithEverything))
.toContain(resolver.getDirectiveMetadata(SomeDirective));
}));
});
});
}); });
} }

View File

@ -0,0 +1,46 @@
/**
* @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 {beforeEach, ddescribe, describe, expect, iit, it, inject,} from '@angular/core/testing/testing_internal';
import {stringify, isBlank} from '../src/facade/lang';
import {MockNgModuleResolver} from '../testing';
import {NgModule, NgModuleMetadata, Injector} from '@angular/core';
export function main() {
describe('MockNgModuleResolver', () => {
var ngModuleResolver: MockNgModuleResolver;
beforeEach(inject([Injector], (injector: Injector) => {
ngModuleResolver = new MockNgModuleResolver(injector);
}));
describe('NgModule overriding', () => {
it('should fallback to the default NgModuleResolver when templates are not overridden',
() => {
var ngModule = ngModuleResolver.resolve(SomeNgModule);
expect(ngModule.declarations).toEqual([SomeDirective]);
});
it('should allow overriding the @NgModule', () => {
ngModuleResolver.setNgModule(
SomeNgModule, new NgModuleMetadata({declarations: [SomeOtherDirective]}));
var ngModule = ngModuleResolver.resolve(SomeNgModule);
expect(ngModule.declarations).toEqual([SomeOtherDirective]);
});
});
});
}
class SomeDirective {}
class SomeOtherDirective {}
@NgModule({declarations: [SomeDirective]})
class SomeNgModule {
}

View File

@ -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 {NgModuleResolver} from '@angular/compiler/src/ng_module_resolver';
import {NgModule, NgModuleMetadata} from '@angular/core/src/metadata';
import {stringify} from '../src/facade/lang';
class SomeClass1 {}
class SomeClass2 {}
class SomeClass3 {}
class SomeClass4 {}
class SomeClass5 {}
@NgModule({
declarations: [SomeClass1],
imports: [SomeClass2],
exports: [SomeClass3],
providers: [SomeClass4],
precompile: [SomeClass5]
})
class SomeModule {
}
class SimpleClass {}
export function main() {
describe('NgModuleResolver', () => {
var resolver: NgModuleResolver;
beforeEach(() => { resolver = new NgModuleResolver(); });
it('should read out the metadata from the class', () => {
var viewMetadata = resolver.resolve(SomeModule);
expect(viewMetadata).toEqual(new NgModuleMetadata({
declarations: [SomeClass1],
imports: [SomeClass2],
exports: [SomeClass3],
providers: [SomeClass4],
precompile: [SomeClass5]
}));
});
it('should throw when simple class has no component decorator', () => {
expect(() => resolver.resolve(SimpleClass))
.toThrowError(`No NgModule metadata found for '${stringify(SimpleClass)}'.`);
});
});
}

View File

@ -8,7 +8,7 @@
import {beforeEach, ddescribe, xdescribe, describe, iit, inject, beforeEachProviders, it, xit,} from '@angular/core/testing/testing_internal'; import {beforeEach, ddescribe, xdescribe, describe, iit, inject, beforeEachProviders, it, xit,} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers'; import {expect} from '@angular/platform-browser/testing/matchers';
import {Injectable, Component, Input, ViewMetadata, Compiler, ComponentFactory, Injector, AppModule, AppModuleMetadata, AppModuleFactory} from '@angular/core'; import {Injectable, Component, Input, ViewMetadata, Compiler, ComponentFactory, Injector, NgModule, NgModuleFactory} from '@angular/core';
import {ConcreteType, stringify} from '../src/facade/lang'; import {ConcreteType, stringify} from '../src/facade/lang';
import {fakeAsync, tick, TestComponentBuilder, ComponentFixture, configureCompiler} from '@angular/core/testing'; import {fakeAsync, tick, TestComponentBuilder, ComponentFixture, configureCompiler} from '@angular/core/testing';
import {XHR, ViewResolver} from '@angular/compiler'; import {XHR, ViewResolver} from '@angular/compiler';
@ -28,10 +28,6 @@ class SomeComp {
class SomeCompWithUrlTemplate { class SomeCompWithUrlTemplate {
} }
@AppModule({})
class SomeModule {
}
export function main() { export function main() {
describe('RuntimeCompiler', () => { describe('RuntimeCompiler', () => {
let compiler: Compiler; let compiler: Compiler;
@ -118,49 +114,61 @@ export function main() {
})); }));
}); });
describe('compileAppModuleAsync', () => { describe('compileModuleAsync', () => {
it('should allow to use templateUrl components', fakeAsync(() => { it('should allow to use templateUrl components', fakeAsync(() => {
@NgModule(
{declarations: [SomeCompWithUrlTemplate], precompile: [SomeCompWithUrlTemplate]})
class SomeModule {
}
xhr.spy('get').andCallFake(() => Promise.resolve('hello')); xhr.spy('get').andCallFake(() => Promise.resolve('hello'));
let appModuleFactory: AppModuleFactory<any>; let ngModuleFactory: NgModuleFactory<any>;
compiler compiler.compileModuleAsync(SomeModule).then((f) => ngModuleFactory = f);
.compileAppModuleAsync(
SomeModule, new AppModuleMetadata({precompile: [SomeCompWithUrlTemplate]}))
.then((f) => appModuleFactory = f);
tick(); tick();
expect(appModuleFactory.moduleType).toBe(SomeModule); expect(ngModuleFactory.moduleType).toBe(SomeModule);
})); }));
}); });
describe('compileAppModuleSync', () => { describe('compileModuleSync', () => {
it('should throw when using a templateUrl that has not been compiled before', () => { it('should throw when using a templateUrl that has not been compiled before', () => {
@NgModule({declarations: [SomeCompWithUrlTemplate], precompile: [SomeCompWithUrlTemplate]})
class SomeModule {
}
xhr.spy('get').andCallFake(() => Promise.resolve('')); xhr.spy('get').andCallFake(() => Promise.resolve(''));
expect( expect(() => compiler.compileModuleSync(SomeModule))
() => compiler.compileAppModuleSync(
SomeModule, new AppModuleMetadata({precompile: [SomeCompWithUrlTemplate]})))
.toThrowError( .toThrowError(
`Can't compile synchronously as ${stringify(SomeCompWithUrlTemplate)} is still being loaded!`); `Can't compile synchronously as ${stringify(SomeCompWithUrlTemplate)} is still being loaded!`);
}); });
it('should throw when using a templateUrl in a nested component that has not been compiled before', it('should throw when using a templateUrl in a nested component that has not been compiled before',
() => { () => {
@NgModule({declarations: [SomeComp], precompile: [SomeComp]})
class SomeModule {
}
xhr.spy('get').andCallFake(() => Promise.resolve('')); xhr.spy('get').andCallFake(() => Promise.resolve(''));
viewResolver.setView( viewResolver.setView(
SomeComp, new ViewMetadata({template: '', directives: [ChildComp]})); SomeComp, new ViewMetadata({template: '', directives: [ChildComp]}));
viewResolver.setView(ChildComp, new ViewMetadata({templateUrl: '/someTpl.html'})); viewResolver.setView(ChildComp, new ViewMetadata({templateUrl: '/someTpl.html'}));
expect( expect(() => compiler.compileModuleSync(SomeModule))
() => compiler.compileAppModuleSync(
SomeModule, new AppModuleMetadata({precompile: [SomeComp]})))
.toThrowError( .toThrowError(
`Can't compile synchronously as ${stringify(ChildComp)} is still being loaded!`); `Can't compile synchronously as ${stringify(ChildComp)} is still being loaded!`);
}); });
it('should allow to use templateUrl components that have been loaded before', it('should allow to use templateUrl components that have been loaded before',
fakeAsync(() => { fakeAsync(() => {
@NgModule(
{declarations: [SomeCompWithUrlTemplate], precompile: [SomeCompWithUrlTemplate]})
class SomeModule {
}
xhr.spy('get').andCallFake(() => Promise.resolve('hello')); xhr.spy('get').andCallFake(() => Promise.resolve('hello'));
tcb.createFakeAsync(SomeCompWithUrlTemplate); compiler.compileModuleAsync(SomeModule);
let appModuleFactory = compiler.compileAppModuleSync( tick();
SomeModule, new AppModuleMetadata({precompile: [SomeCompWithUrlTemplate]}));
expect(appModuleFactory).toBeTruthy(); let ngModuleFactory = compiler.compileModuleSync(SomeModule);
expect(ngModuleFactory).toBeTruthy();
})); }));
}); });
}); });

View File

@ -9,7 +9,7 @@
import {AsyncTestCompleter, beforeEach, ddescribe, xdescribe, describe, iit, inject, beforeEachProviders, it, xit,} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, beforeEach, ddescribe, xdescribe, describe, iit, inject, beforeEachProviders, it, xit,} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers'; import {expect} from '@angular/platform-browser/testing/matchers';
import {TestComponentBuilder, ComponentFixtureAutoDetect, ComponentFixtureNoNgZone, withProviders} from '@angular/core/testing'; import {TestComponentBuilder, ComponentFixtureAutoDetect, ComponentFixtureNoNgZone, withProviders} from '@angular/core/testing';
import {Injectable, Component, Input, ViewMetadata} from '@angular/core'; import {Injectable, Component, Input, ViewMetadata, Pipe, NgModule} from '@angular/core';
import {NgIf} from '@angular/common'; import {NgIf} from '@angular/common';
import {TimerWrapper} from '../src/facade/async'; import {TimerWrapper} from '../src/facade/async';
import {PromiseWrapper} from '../src/facade/promise'; import {PromiseWrapper} from '../src/facade/promise';
@ -327,6 +327,27 @@ export function main() {
expect(componentFixture.nativeElement).toHaveText('Mock'); expect(componentFixture.nativeElement).toHaveText('Mock');
})); }));
it('should create components synchronously with a custom module',
inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
@Pipe({name: 'somePipe'})
class SomePipe {
transform(value: any) { return `transformed ${value}`; }
}
@NgModule({declarations: [SomePipe]})
class SomeModule {
}
@Component({selector: 'comp', template: `{{'hello' | somePipe}}`})
class SomeComponent {
}
let componentFixture = tcb.createSync(SomeComponent, SomeModule);
componentFixture.detectChanges();
expect(componentFixture.nativeElement).toHaveText('transformed hello');
}));
describe('ComponentFixture', () => { describe('ComponentFixture', () => {
it('should auto detect changes if autoDetectChanges is called', it('should auto detect changes if autoDetectChanges is called',
inject( inject(

View File

@ -10,3 +10,29 @@ export * from './testing/schema_registry_mock';
export * from './testing/view_resolver_mock'; export * from './testing/view_resolver_mock';
export * from './testing/test_component_builder'; export * from './testing/test_component_builder';
export * from './testing/directive_resolver_mock'; export * from './testing/directive_resolver_mock';
export * from './testing/ng_module_resolver_mock';
import {createPlatformFactory, CompilerOptions, PlatformRef} from '@angular/core';
import {coreDynamicPlatform, DirectiveResolver, ViewResolver, NgModuleResolver} from './index';
import {MockViewResolver} from './testing/view_resolver_mock';
import {MockDirectiveResolver} from './testing/directive_resolver_mock';
import {MockNgModuleResolver} from './testing/ng_module_resolver_mock';
/**
* Platform for dynamic tests
*
* @experimental
*/
export const coreDynamicTestingPlatform =
createPlatformFactory(coreDynamicPlatform, 'coreDynamicTesting', [{
provide: CompilerOptions,
useValue: {
providers: [
{provide: DirectiveResolver, useClass: MockDirectiveResolver},
{provide: ViewResolver, useClass: MockViewResolver},
{provide: NgModuleResolver, useClass: MockNgModuleResolver}
]
},
multi: true
}]);

View File

@ -27,8 +27,11 @@ export class MockDirectiveResolver extends DirectiveResolver {
private get _compiler(): Compiler { return this._injector.get(Compiler); } private get _compiler(): Compiler { return this._injector.get(Compiler); }
resolve(type: Type): DirectiveMetadata { resolve(type: Type, throwIfNotFound = true): DirectiveMetadata {
var dm = super.resolve(type); var dm = super.resolve(type, throwIfNotFound);
if (!dm) {
return null;
}
var providerOverrides = this._providerOverrides.get(type); var providerOverrides = this._providerOverrides.get(type);
var viewProviderOverrides = this.viewProviderOverrides.get(type); var viewProviderOverrides = this.viewProviderOverrides.get(type);

View File

@ -0,0 +1,46 @@
/**
* @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 {Compiler, Injectable, Injector, NgModuleMetadata, Type} from '@angular/core';
import {NgModuleResolver} from '../index';
import {Map} from '../src/facade/collection';
@Injectable()
export class MockNgModuleResolver extends NgModuleResolver {
/** @internal */
_ngModules = new Map<Type, NgModuleMetadata>();
constructor(private _injector: Injector) { super(); }
private get _compiler(): Compiler { return this._injector.get(Compiler); }
private _clearCacheFor(component: Type) { this._compiler.clearCacheFor(component); }
/**
* Overrides the {@link NgModuleMetadata} for a module.
*/
setNgModule(type: Type, metadata: NgModuleMetadata): void {
this._ngModules.set(type, metadata);
this._clearCacheFor(type);
}
/**
* Returns the {@link NgModuleMetadata} for a module:
* - Set the {@link NgModuleMetadata} to the overridden view when it exists or fallback to the
* default
* `NgModuleResolver`, see `setNgModule`.
*/
resolve(type: Type, throwIfNotFound = true): NgModuleMetadata {
var metadata = this._ngModules.get(type);
if (!metadata) {
metadata = super.resolve(type, throwIfNotFound);
}
return metadata;
}
}

View File

@ -87,14 +87,16 @@ export class OverridingTestComponentBuilder extends TestComponentBuilder {
return clone; return clone;
} }
createAsync<T>(rootComponentType: ConcreteType<T>): Promise<ComponentFixture<T>> { createAsync<T>(rootComponentType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
Promise<ComponentFixture<T>> {
this._applyMetadataOverrides(); this._applyMetadataOverrides();
return super.createAsync(rootComponentType); return super.createAsync(rootComponentType, ngModule);
} }
createSync<T>(rootComponentType: ConcreteType<T>): ComponentFixture<T> { createSync<T>(rootComponentType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
ComponentFixture<T> {
this._applyMetadataOverrides(); this._applyMetadataOverrides();
return super.createSync(rootComponentType); return super.createSync(rootComponentType, ngModule);
} }
private _applyMetadataOverrides() { private _applyMetadataOverrides() {

View File

@ -72,10 +72,13 @@ export class MockViewResolver extends ViewResolver {
* - Override the directives, see `overrideViewDirective`. * - Override the directives, see `overrideViewDirective`.
* - Override the @View definition, see `setInlineTemplate`. * - Override the @View definition, see `setInlineTemplate`.
*/ */
resolve(component: Type): ViewMetadata { resolve(component: Type, throwIfNotFound = true): ViewMetadata {
var view = this._views.get(component); var view = this._views.get(component);
if (isBlank(view)) { if (isBlank(view)) {
view = super.resolve(component); view = super.resolve(component, throwIfNotFound);
if (!view) {
return null;
}
} }
var directives: any[] /** TODO #9100 */ = []; var directives: any[] /** TODO #9100 */ = [];

View File

@ -23,8 +23,8 @@ export {DebugElement, DebugNode, asNativeElements, getDebugNode} from './src/deb
export * from './src/testability/testability'; export * from './src/testability/testability';
export * from './src/change_detection'; export * from './src/change_detection';
export * from './src/platform_directives_and_pipes'; export * from './src/platform_directives_and_pipes';
export * from './src/platform_common_providers'; export * from './src/platform_core_providers';
export {APPLICATION_COMMON_PROVIDERS} from './src/application_common_providers'; export {APPLICATION_COMMON_PROVIDERS, ApplicationModule} from './src/application_module';
export {wtfCreateScope, wtfLeave, wtfStartTimeRange, wtfEndTimeRange, WtfScopeFn} from './src/profile/profile'; export {wtfCreateScope, wtfLeave, wtfStartTimeRange, wtfEndTimeRange, WtfScopeFn} from './src/profile/profile';
export {Type} from './src/facade/lang'; export {Type} from './src/facade/lang';

View File

@ -20,11 +20,11 @@ import * as console from './src/console';
import * as debug from './src/debug/debug_renderer'; import * as debug from './src/debug/debug_renderer';
import * as provider_util from './src/di/provider_util'; import * as provider_util from './src/di/provider_util';
import * as reflective_provider from './src/di/reflective_provider'; import * as reflective_provider from './src/di/reflective_provider';
import * as app_module_factory from './src/linker/app_module_factory';
import * as component_factory_resolver from './src/linker/component_factory_resolver'; import * as component_factory_resolver from './src/linker/component_factory_resolver';
import * as component_resolver from './src/linker/component_resolver'; import * as component_resolver from './src/linker/component_resolver';
import * as debug_context from './src/linker/debug_context'; import * as debug_context from './src/linker/debug_context';
import * as element from './src/linker/element'; import * as element from './src/linker/element';
import * as ng_module_factory from './src/linker/ng_module_factory';
import * as template_ref from './src/linker/template_ref'; import * as template_ref from './src/linker/template_ref';
import * as view from './src/linker/view'; import * as view from './src/linker/view';
import * as view_type from './src/linker/view_type'; import * as view_type from './src/linker/view_type';
@ -52,13 +52,12 @@ export declare namespace __core_private_types__ {
export var LIFECYCLE_HOOKS_VALUES: typeof lifecycle_hooks.LIFECYCLE_HOOKS_VALUES; export var LIFECYCLE_HOOKS_VALUES: typeof lifecycle_hooks.LIFECYCLE_HOOKS_VALUES;
export type ReflectorReader = reflector_reader.ReflectorReader; export type ReflectorReader = reflector_reader.ReflectorReader;
export var ReflectorReader: typeof reflector_reader.ReflectorReader; export var ReflectorReader: typeof reflector_reader.ReflectorReader;
export var ReflectorComponentResolver: typeof component_resolver.ReflectorComponentResolver;
export var CodegenComponentFactoryResolver: export var CodegenComponentFactoryResolver:
typeof component_factory_resolver.CodegenComponentFactoryResolver; typeof component_factory_resolver.CodegenComponentFactoryResolver;
export type AppElement = element.AppElement; export type AppElement = element.AppElement;
export var AppElement: typeof element.AppElement; export var AppElement: typeof element.AppElement;
export var AppView: typeof view.AppView; export var AppView: typeof view.AppView;
export var AppModuleInjector: typeof app_module_factory.AppModuleInjector; export var NgModuleInjector: typeof ng_module_factory.NgModuleInjector;
export type DebugAppView<T> = view.DebugAppView<T>; export type DebugAppView<T> = view.DebugAppView<T>;
export var DebugAppView: typeof view.DebugAppView; export var DebugAppView: typeof view.DebugAppView;
export type ViewType = view_type.ViewType; export type ViewType = view_type.ViewType;
@ -136,12 +135,11 @@ export var __core_private__ = {
LifecycleHooks: lifecycle_hooks.LifecycleHooks, LifecycleHooks: lifecycle_hooks.LifecycleHooks,
LIFECYCLE_HOOKS_VALUES: lifecycle_hooks.LIFECYCLE_HOOKS_VALUES, LIFECYCLE_HOOKS_VALUES: lifecycle_hooks.LIFECYCLE_HOOKS_VALUES,
ReflectorReader: reflector_reader.ReflectorReader, ReflectorReader: reflector_reader.ReflectorReader,
ReflectorComponentResolver: component_resolver.ReflectorComponentResolver,
CodegenComponentFactoryResolver: component_factory_resolver.CodegenComponentFactoryResolver, CodegenComponentFactoryResolver: component_factory_resolver.CodegenComponentFactoryResolver,
AppElement: element.AppElement, AppElement: element.AppElement,
AppView: view.AppView, AppView: view.AppView,
DebugAppView: view.DebugAppView, DebugAppView: view.DebugAppView,
AppModuleInjector: app_module_factory.AppModuleInjector, NgModuleInjector: ng_module_factory.NgModuleInjector,
ViewType: view_type.ViewType, ViewType: view_type.ViewType,
MAX_INTERPOLATION_VALUES: view_utils.MAX_INTERPOLATION_VALUES, MAX_INTERPOLATION_VALUES: view_utils.MAX_INTERPOLATION_VALUES,
checkBinding: view_utils.checkBinding, checkBinding: view_utils.checkBinding,

View File

@ -1,56 +0,0 @@
/**
* @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 {Type} from '../src/facade/lang';
import {APPLICATION_CORE_PROVIDERS} from './application_ref';
import {APP_ID_RANDOM_PROVIDER} from './application_tokens';
import {IterableDiffers, KeyValueDiffers, defaultIterableDiffers, defaultKeyValueDiffers} from './change_detection/change_detection';
import {ComponentFactoryResolver} from './linker/component_factory_resolver';
import {ComponentResolver, ReflectorComponentResolver} from './linker/component_resolver';
import {DynamicComponentLoader, DynamicComponentLoader_} from './linker/dynamic_component_loader';
import {ViewUtils} from './linker/view_utils';
let __unused: Type; // avoid unused import when Type union types are erased
export function _componentFactoryResolverFactory() {
return ComponentFactoryResolver.NULL;
}
export function _iterableDiffersFactory() {
return defaultIterableDiffers;
}
export function _keyValueDiffersFactory() {
return defaultKeyValueDiffers;
}
/**
* A default set of providers which should be included in any Angular
* application, regardless of the platform it runs onto.
* @stable
*/
export const APPLICATION_COMMON_PROVIDERS: Array<Type|{[k: string]: any}|any[]> =
/*@ts2dart_const*/[
APPLICATION_CORE_PROVIDERS,
/* @ts2dart_Provider */ {provide: ComponentResolver, useClass: ReflectorComponentResolver},
{provide: ComponentFactoryResolver, useFactory: _componentFactoryResolverFactory, deps: []},
APP_ID_RANDOM_PROVIDER,
ViewUtils,
/* @ts2dart_Provider */ {
provide: IterableDiffers,
useFactory: _iterableDiffersFactory,
deps: []
},
/* @ts2dart_Provider */ {
provide: KeyValueDiffers,
useFactory: _keyValueDiffersFactory,
deps: []
},
/* @ts2dart_Provider */ {provide: DynamicComponentLoader, useClass: DynamicComponentLoader_},
];

View File

@ -0,0 +1,84 @@
/**
* @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 {Type} from '../src/facade/lang';
import {ApplicationRef, ApplicationRef_, isDevMode} from './application_ref';
import {APP_ID_RANDOM_PROVIDER} from './application_tokens';
import {IterableDiffers, KeyValueDiffers, defaultIterableDiffers, defaultKeyValueDiffers} from './change_detection/change_detection';
import {OptionalMetadata, SkipSelfMetadata} from './di';
import {Compiler} from './linker/compiler';
import {ComponentFactoryResolver} from './linker/component_factory_resolver';
import {ComponentResolver} from './linker/component_resolver';
import {DynamicComponentLoader, DynamicComponentLoader_} from './linker/dynamic_component_loader';
import {ViewUtils} from './linker/view_utils';
import {NgModule} from './metadata';
import {NgZone} from './zone/ng_zone';
let __unused: Type; // avoid unused import when Type union types are erased
export function _componentFactoryResolverFactory() {
return ComponentFactoryResolver.NULL;
}
export function _iterableDiffersFactory() {
return defaultIterableDiffers;
}
export function _keyValueDiffersFactory() {
return defaultKeyValueDiffers;
}
export function createNgZone(parent: NgZone): NgZone {
// If an NgZone is already present in the parent injector,
// use that one. Creating the NgZone in the same injector as the
// application is dangerous as some services might get created before
// the NgZone has been created.
// We keep the NgZone factory in the application providers for
// backwards compatibility for now though.
if (parent) {
return parent;
}
return new NgZone({enableLongStackTrace: isDevMode()});
}
/**
* A default set of providers which should be included in any Angular
* application, regardless of the platform it runs onto.
*
* @deprecated Include `ApplicationModule` instead.
*/
export const APPLICATION_COMMON_PROVIDERS: Array<Type|{[k: string]: any}|any[]> = [];
/**
* This module includes the providers of @angular/core that are needed
* to bootstrap components via `ApplicationRef`.
*
* @experimental
*/
@NgModule({
providers: [
{
provide: NgZone,
useFactory: createNgZone,
deps: <any>[[new SkipSelfMetadata(), new OptionalMetadata(), NgZone]]
},
ApplicationRef_,
{provide: ApplicationRef, useExisting: ApplicationRef_},
Compiler,
{provide: ComponentResolver, useExisting: Compiler},
{provide: ComponentFactoryResolver, useFactory: _componentFactoryResolverFactory},
APP_ID_RANDOM_PROVIDER,
ViewUtils,
{provide: IterableDiffers, useFactory: _iterableDiffersFactory},
{provide: KeyValueDiffers, useFactory: _keyValueDiffersFactory},
{provide: DynamicComponentLoader, useClass: DynamicComponentLoader_},
]
})
export class ApplicationModule {
}

View File

@ -14,35 +14,16 @@ import {ConcreteType, IS_DART, Type, isBlank, isPresent, isPromise} from '../src
import {APP_INITIALIZER, PLATFORM_INITIALIZER} from './application_tokens'; import {APP_INITIALIZER, PLATFORM_INITIALIZER} from './application_tokens';
import {ChangeDetectorRef} from './change_detection/change_detector_ref'; import {ChangeDetectorRef} from './change_detection/change_detector_ref';
import {Console} from './console'; import {Console} from './console';
import {Inject, Injectable, Injector, OpaqueToken, Optional, OptionalMetadata, ReflectiveInjector, SkipSelf, SkipSelfMetadata, forwardRef} from './di'; import {Inject, Injectable, Injector, OpaqueToken, Optional, ReflectiveInjector, SkipSelf, forwardRef} from './di';
import {AppModuleFactory, AppModuleRef} from './linker/app_module_factory';
import {Compiler, CompilerFactory, CompilerOptions} from './linker/compiler'; import {Compiler, CompilerFactory, CompilerOptions} from './linker/compiler';
import {ComponentFactory, ComponentRef} from './linker/component_factory'; import {ComponentFactory, ComponentRef} from './linker/component_factory';
import {ComponentFactoryResolver} from './linker/component_factory_resolver'; import {ComponentFactoryResolver} from './linker/component_factory_resolver';
import {ComponentResolver} from './linker/component_resolver'; import {ComponentResolver} from './linker/component_resolver';
import {NgModuleFactory, NgModuleRef} from './linker/ng_module_factory';
import {WtfScopeFn, wtfCreateScope, wtfLeave} from './profile/profile'; import {WtfScopeFn, wtfCreateScope, wtfLeave} from './profile/profile';
import {Testability, TestabilityRegistry} from './testability/testability'; import {Testability, TestabilityRegistry} from './testability/testability';
import {NgZone, NgZoneError} from './zone/ng_zone'; import {NgZone, NgZoneError} from './zone/ng_zone';
/**
* Create an Angular zone.
* @experimental
*/
export function createNgZone(parent: NgZone): NgZone {
// If an NgZone is already present in the parent injector,
// use that one. Creating the NgZone in the same injector as the
// application is dangerous as some services might get created before
// the NgZone has been created.
// We keep the NgZone factory in the application providers for
// backwards compatibility for now though.
if (parent) {
return parent;
}
return new NgZone({enableLongStackTrace: isDevMode()});
}
var _devMode: boolean = true; var _devMode: boolean = true;
var _runModeLocked: boolean = false; var _runModeLocked: boolean = false;
var _platform: PlatformRef; var _platform: PlatformRef;
@ -113,17 +94,30 @@ export function createPlatform(injector: Injector): PlatformRef {
return _platform; return _platform;
} }
/**
* Factory for a platform.
*
* @experimental
*/
export type PlatformFactory = (extraProviders?: any[]) => PlatformRef;
/** /**
* Creates a fatory for a platform * Creates a fatory for a platform
* *
* @experimental APIs related to application bootstrap are currently under review. * @experimental APIs related to application bootstrap are currently under review.
*/ */
export function createPlatformFactory(name: string, providers: any[]): () => PlatformRef { export function createPlatformFactory(
parentPlaformFactory: PlatformFactory, name: string, providers: any[] = []): PlatformFactory {
const marker = new OpaqueToken(`Platform: ${name}`); const marker = new OpaqueToken(`Platform: ${name}`);
return () => { return (extraProviders: any[] = []) => {
if (!getPlatform()) { if (!getPlatform()) {
createPlatform( if (parentPlaformFactory) {
ReflectiveInjector.resolveAndCreate(providers.concat({provide: marker, useValue: true}))); parentPlaformFactory(
providers.concat(extraProviders).concat({provide: marker, useValue: true}));
} else {
createPlatform(ReflectiveInjector.resolveAndCreate(
providers.concat(extraProviders).concat({provide: marker, useValue: true})));
}
} }
return assertPlatform(marker); return assertPlatform(marker);
}; };
@ -168,7 +162,7 @@ export function getPlatform(): PlatformRef {
} }
/** /**
* Creates an instance of an `@AppModule` for the given platform * Creates an instance of an `@NgModule` for the given platform
* for offline compilation. * for offline compilation.
* *
* ## Simple Example * ## Simple Example
@ -176,8 +170,8 @@ export function getPlatform(): PlatformRef {
* ```typescript * ```typescript
* my_module.ts: * my_module.ts:
* *
* @AppModule({ * @NgModule({
* modules: [BrowserModule] * imports: [BrowserModule]
* }) * })
* class MyModule {} * class MyModule {}
* *
@ -192,11 +186,11 @@ export function getPlatform(): PlatformRef {
* @experimental APIs related to application bootstrap are currently under review. * @experimental APIs related to application bootstrap are currently under review.
*/ */
export function bootstrapModuleFactory<M>( export function bootstrapModuleFactory<M>(
moduleFactory: AppModuleFactory<M>, platform: PlatformRef): AppModuleRef<M> { moduleFactory: NgModuleFactory<M>, platform: PlatformRef): NgModuleRef<M> {
// Note: We need to create the NgZone _before_ we instantiate the module, // Note: We need to create the NgZone _before_ we instantiate the module,
// as instantiating the module creates some providers eagerly. // as instantiating the module creates some providers eagerly.
// So we create a mini parent injector that just contains the new NgZone and // So we create a mini parent injector that just contains the new NgZone and
// pass that as parent to the AppModuleFactory. // pass that as parent to the NgModuleFactory.
const ngZone = new NgZone({enableLongStackTrace: isDevMode()}); const ngZone = new NgZone({enableLongStackTrace: isDevMode()});
const ngZoneInjector = const ngZoneInjector =
ReflectiveInjector.resolveAndCreate([{provide: NgZone, useValue: ngZone}], platform.injector); ReflectiveInjector.resolveAndCreate([{provide: NgZone, useValue: ngZone}], platform.injector);
@ -204,13 +198,13 @@ export function bootstrapModuleFactory<M>(
} }
/** /**
* Creates an instance of an `@AppModule` for a given platform using the given runtime compiler. * Creates an instance of an `@NgModule` for a given platform using the given runtime compiler.
* *
* ## Simple Example * ## Simple Example
* *
* ```typescript * ```typescript
* @AppModule({ * @NgModule({
* modules: [BrowserModule] * imports: [BrowserModule]
* }) * })
* class MyModule {} * class MyModule {}
* *
@ -220,10 +214,11 @@ export function bootstrapModuleFactory<M>(
*/ */
export function bootstrapModule<M>( export function bootstrapModule<M>(
moduleType: ConcreteType<M>, platform: PlatformRef, moduleType: ConcreteType<M>, platform: PlatformRef,
compilerOptions: CompilerOptions = {}): Promise<AppModuleRef<M>> { compilerOptions: CompilerOptions | CompilerOptions[] = []): Promise<NgModuleRef<M>> {
const compilerFactory: CompilerFactory = platform.injector.get(CompilerFactory); const compilerFactory: CompilerFactory = platform.injector.get(CompilerFactory);
const compiler = compilerFactory.createCompiler(compilerOptions); const compiler = compilerFactory.createCompiler(
return compiler.compileAppModuleAsync(moduleType) compilerOptions instanceof Array ? compilerOptions : [compilerOptions]);
return compiler.compileModuleAsync(moduleType)
.then((moduleFactory) => bootstrapModuleFactory(moduleFactory, platform)) .then((moduleFactory) => bootstrapModuleFactory(moduleFactory, platform))
.then((moduleRef) => { .then((moduleRef) => {
const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef); const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
@ -239,10 +234,7 @@ export function bootstrapModule<M>(
*/ */
export function coreBootstrap<C>( export function coreBootstrap<C>(
componentFactory: ComponentFactory<C>, injector: Injector): ComponentRef<C> { componentFactory: ComponentFactory<C>, injector: Injector): ComponentRef<C> {
let console = injector.get(Console); throw new BaseException('coreBootstrap is deprecated. Use bootstrapModuleFactory instead.');
console.warn('coreBootstrap is deprecated. Use bootstrapModuleFactory instead.');
var appRef: ApplicationRef = injector.get(ApplicationRef);
return appRef.bootstrap(componentFactory);
} }
/** /**
@ -254,15 +246,7 @@ export function coreBootstrap<C>(
*/ */
export function coreLoadAndBootstrap( export function coreLoadAndBootstrap(
componentType: Type, injector: Injector): Promise<ComponentRef<any>> { componentType: Type, injector: Injector): Promise<ComponentRef<any>> {
let console = injector.get(Console); throw new BaseException('coreLoadAndBootstrap is deprecated. Use bootstrapModule instead.');
console.warn('coreLoadAndBootstrap is deprecated. Use bootstrapModule instead.');
var appRef: ApplicationRef = injector.get(ApplicationRef);
return appRef.run(() => {
var componentResolver: ComponentResolver = injector.get(ComponentResolver);
return PromiseWrapper
.all([componentResolver.resolveComponent(componentType), appRef.waitForAsyncInitializers()])
.then((arr) => appRef.bootstrap(arr[0]));
});
} }
/** /**
@ -592,20 +576,3 @@ export class ApplicationRef_ extends ApplicationRef {
get componentTypes(): Type[] { return this._rootComponentTypes; } get componentTypes(): Type[] { return this._rootComponentTypes; }
} }
export const PLATFORM_CORE_PROVIDERS =
/*@ts2dart_const*/[
PlatformRef_,
/*@ts2dart_const*/ (
/* @ts2dart_Provider */ {provide: PlatformRef, useExisting: PlatformRef_})
];
export const APPLICATION_CORE_PROVIDERS = /*@ts2dart_const*/[
/* @ts2dart_Provider */ {
provide: NgZone,
useFactory: createNgZone,
deps: <any>[[new SkipSelfMetadata(), new OptionalMetadata(), NgZone]]
},
ApplicationRef_,
/* @ts2dart_Provider */ {provide: ApplicationRef, useExisting: ApplicationRef_},
];

View File

@ -7,8 +7,6 @@
*/ */
// Public API for compiler // Public API for compiler
export {AppModuleFactory, AppModuleRef} from './linker/app_module_factory';
export {AppModuleFactoryLoader} from './linker/app_module_factory_loader';
export {Compiler, CompilerFactory, CompilerOptions, ComponentStillLoadingError} from './linker/compiler'; export {Compiler, CompilerFactory, CompilerOptions, ComponentStillLoadingError} from './linker/compiler';
export {ComponentFactory, ComponentRef} from './linker/component_factory'; export {ComponentFactory, ComponentRef} from './linker/component_factory';
export {ComponentFactoryResolver, NoComponentFactoryError} from './linker/component_factory_resolver'; export {ComponentFactoryResolver, NoComponentFactoryError} from './linker/component_factory_resolver';
@ -16,8 +14,10 @@ export {ComponentResolver} from './linker/component_resolver';
export {DynamicComponentLoader} from './linker/dynamic_component_loader'; export {DynamicComponentLoader} from './linker/dynamic_component_loader';
export {ElementRef} from './linker/element_ref'; export {ElementRef} from './linker/element_ref';
export {ExpressionChangedAfterItHasBeenCheckedException} from './linker/exceptions'; export {ExpressionChangedAfterItHasBeenCheckedException} from './linker/exceptions';
export {NgModuleFactory, NgModuleRef} from './linker/ng_module_factory';
export {NgModuleFactoryLoader} from './linker/ng_module_factory_loader';
export {QueryList} from './linker/query_list'; export {QueryList} from './linker/query_list';
export {SystemJsAppModuleLoader} from './linker/system_js_app_module_factory_loader'; export {SystemJsNgModuleLoader} from './linker/system_js_ng_module_factory_loader';
export {SystemJsCmpFactoryResolver, SystemJsComponentResolver} from './linker/systemjs_component_resolver'; export {SystemJsCmpFactoryResolver, SystemJsComponentResolver} from './linker/systemjs_component_resolver';
export {TemplateRef} from './linker/template_ref'; export {TemplateRef} from './linker/template_ref';
export {ViewContainerRef} from './linker/view_container_ref'; export {ViewContainerRef} from './linker/view_container_ref';

View File

@ -6,14 +6,15 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Injector} from '../di'; import {Injector, OpaqueToken} from '../di';
import {BaseException} from '../facade/exceptions'; import {BaseException} from '../facade/exceptions';
import {ConcreteType, Type, stringify} from '../facade/lang'; import {ConcreteType, Type, stringify} from '../facade/lang';
import {ViewEncapsulation} from '../metadata'; import {ViewEncapsulation} from '../metadata';
import {AppModuleMetadata} from '../metadata/app_module'; import {NgModuleMetadata} from '../metadata/ng_module';
import {AppModuleFactory} from './app_module_factory';
import {ComponentFactory} from './component_factory'; import {ComponentFactory} from './component_factory';
import {ComponentResolver} from './component_resolver';
import {NgModuleFactory} from './ng_module_factory';
/** /**
@ -32,14 +33,16 @@ export class ComponentStillLoadingError extends BaseException {
* to create {@link ComponentFactory}s, which * to create {@link ComponentFactory}s, which
* can later be used to create and render a Component instance. * can later be used to create and render a Component instance.
* *
* Each `@AppModule` provides an own `Compiler` to its injector, * Each `@NgModule` provides an own `Compiler` to its injector,
* that will use the directives/pipes of the app module for compilation * that will use the directives/pipes of the ng module for compilation
* of components. * of components.
* @stable * @stable
*/ */
export class Compiler { export class Compiler {
/** /**
* Returns the injector with which the compiler has been created. * Returns the injector with which the compiler has been created.
*
* @internal
*/ */
get injector(): Injector { get injector(): Injector {
throw new BaseException(`Runtime compiler is not loaded. Tried to read the injector.`); throw new BaseException(`Runtime compiler is not loaded. Tried to read the injector.`);
@ -48,7 +51,8 @@ export class Compiler {
/** /**
* Loads the template and styles of a component and returns the associated `ComponentFactory`. * Loads the template and styles of a component and returns the associated `ComponentFactory`.
*/ */
compileComponentAsync<T>(component: ConcreteType<T>): Promise<ComponentFactory<T>> { compileComponentAsync<T>(component: ConcreteType<T>, ngModule: Type = null):
Promise<ComponentFactory<T>> {
throw new BaseException( throw new BaseException(
`Runtime compiler is not loaded. Tried to compile ${stringify(component)}`); `Runtime compiler is not loaded. Tried to compile ${stringify(component)}`);
} }
@ -56,23 +60,21 @@ export class Compiler {
* Compiles the given component. All templates have to be either inline or compiled via * Compiles the given component. All templates have to be either inline or compiled via
* `compileComponentAsync` before. Otherwise throws a {@link ComponentStillLoadingError}. * `compileComponentAsync` before. Otherwise throws a {@link ComponentStillLoadingError}.
*/ */
compileComponentSync<T>(component: ConcreteType<T>): ComponentFactory<T> { compileComponentSync<T>(component: ConcreteType<T>, ngModule: Type = null): ComponentFactory<T> {
throw new BaseException( throw new BaseException(
`Runtime compiler is not loaded. Tried to compile ${stringify(component)}`); `Runtime compiler is not loaded. Tried to compile ${stringify(component)}`);
} }
/** /**
* Compiles the given App Module. All templates of the components listed in `precompile` * Compiles the given NgModule. All templates of the components listed in `precompile`
* have to be either inline or compiled before via `compileComponentAsync` / * have to be either inline or compiled before via `compileComponentAsync` /
* `compileAppModuleAsync`. Otherwise throws a {@link ComponentStillLoadingError}. * `compileModuleAsync`. Otherwise throws a {@link ComponentStillLoadingError}.
*/ */
compileAppModuleSync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null): compileModuleSync<T>(moduleType: ConcreteType<T>): NgModuleFactory<T> {
AppModuleFactory<T> {
throw new BaseException( throw new BaseException(
`Runtime compiler is not loaded. Tried to compile ${stringify(moduleType)}`); `Runtime compiler is not loaded. Tried to compile ${stringify(moduleType)}`);
} }
compileAppModuleAsync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null): compileModuleAsync<T>(moduleType: ConcreteType<T>): Promise<NgModuleFactory<T>> {
Promise<AppModuleFactory<T>> {
throw new BaseException( throw new BaseException(
`Runtime compiler is not loaded. Tried to compile ${stringify(moduleType)}`); `Runtime compiler is not loaded. Tried to compile ${stringify(moduleType)}`);
} }
@ -83,7 +85,7 @@ export class Compiler {
clearCache(): void {} clearCache(): void {}
/** /**
* Clears the cache for the given component/appModule. * Clears the cache for the given component/ngModule.
*/ */
clearCacheFor(type: Type) {} clearCacheFor(type: Type) {}
} }
@ -98,8 +100,14 @@ export type CompilerOptions = {
useJit?: boolean, useJit?: boolean,
defaultEncapsulation?: ViewEncapsulation, defaultEncapsulation?: ViewEncapsulation,
providers?: any[], providers?: any[],
deprecatedAppProviders?: any[] };
}
/**
* Token to provide CompilerOptions in the platform injector.
*
* @experimental
*/
export const CompilerOptions = new OpaqueToken('compilerOptions');
/** /**
* A factory for creating a Compiler * A factory for creating a Compiler
@ -107,44 +115,5 @@ export type CompilerOptions = {
* @experimental * @experimental
*/ */
export abstract class CompilerFactory { export abstract class CompilerFactory {
static mergeOptions(defaultOptions: CompilerOptions = {}, newOptions: CompilerOptions = {}): abstract createCompiler(options?: CompilerOptions[]): Compiler;
CompilerOptions {
return {
useDebug: _firstDefined(newOptions.useDebug, defaultOptions.useDebug),
useJit: _firstDefined(newOptions.useJit, defaultOptions.useJit),
defaultEncapsulation:
_firstDefined(newOptions.defaultEncapsulation, defaultOptions.defaultEncapsulation),
providers: _mergeArrays(defaultOptions.providers, newOptions.providers),
deprecatedAppProviders:
_mergeArrays(defaultOptions.deprecatedAppProviders, newOptions.deprecatedAppProviders)
};
}
withDefaults(options: CompilerOptions = {}): CompilerFactory {
return new _DefaultApplyingCompilerFactory(this, options);
}
abstract createCompiler(options?: CompilerOptions): Compiler;
}
class _DefaultApplyingCompilerFactory extends CompilerFactory {
constructor(private _delegate: CompilerFactory, private _options: CompilerOptions) { super(); }
createCompiler(options: CompilerOptions = {}): Compiler {
return this._delegate.createCompiler(CompilerFactory.mergeOptions(this._options, options));
}
}
function _firstDefined<T>(...args: T[]): T {
for (var i = 0; i < args.length; i++) {
if (args[i] !== undefined) {
return args[i];
}
}
return undefined;
}
function _mergeArrays(...parts: any[][]): any[] {
let result: any[] = [];
parts.forEach((part) => result.push.apply(result, part));
return result;
} }

View File

@ -6,12 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Console} from '../console'; import {Type} from '../facade/lang';
import {Injectable} from '../di/decorators';
import {PromiseWrapper} from '../facade/async';
import {BaseException} from '../facade/exceptions';
import {Type, isBlank, isString, stringify} from '../facade/lang';
import {reflector} from '../reflection/reflection';
import {ComponentFactory} from './component_factory'; import {ComponentFactory} from './component_factory';
/** /**
@ -19,43 +14,17 @@ import {ComponentFactory} from './component_factory';
* can later be used to create and render a Component instance. * can later be used to create and render a Component instance.
* *
* @deprecated Use {@link ComponentFactoryResolver} together with {@link * @deprecated Use {@link ComponentFactoryResolver} together with {@link
* AppModule}.precompile}/{@link Component}.precompile or * NgModule}.precompile}/{@link Component}.precompile or
* {@link ANALYZE_FOR_PRECOMPILE} provider for dynamic component creation. * {@link ANALYZE_FOR_PRECOMPILE} provider for dynamic component creation.
* Use {@link AppModuleFactoryLoader} for lazy loading. * Use {@link NgModuleFactoryLoader} for lazy loading.
*/ */
export abstract class ComponentResolver { export abstract class ComponentResolver {
static DynamicCompilationDeprecationMsg = static DynamicCompilationDeprecationMsg =
'ComponentResolver is deprecated for dynamic compilation. Use ComponentFactoryResolver together with @AppModule/@Component.precompile or ANALYZE_FOR_PRECOMPILE provider instead.'; 'ComponentResolver is deprecated for dynamic compilation. Use ComponentFactoryResolver together with @NgModule/@Component.precompile or ANALYZE_FOR_PRECOMPILE provider instead. For runtime compile only, you can also use Compiler.compileComponentSync/Async.';
static LazyLoadingDeprecationMsg = static LazyLoadingDeprecationMsg =
'ComponentResolver is deprecated for lazy loading. Use AppModuleFactoryLoader instead.'; 'ComponentResolver is deprecated for lazy loading. Use NgModuleFactoryLoader instead.';
abstract resolveComponent(component: Type|string): Promise<ComponentFactory<any>>; abstract resolveComponent(component: Type|string): Promise<ComponentFactory<any>>;
abstract clearCache(): void; abstract clearCache(): void;
} }
function _isComponentFactory(type: any): boolean {
return type instanceof ComponentFactory;
}
@Injectable()
export class ReflectorComponentResolver extends ComponentResolver {
constructor(private _console: Console) { super(); }
resolveComponent(component: Type|string): Promise<ComponentFactory<any>> {
if (isString(component)) {
return PromiseWrapper.reject(
new BaseException(`Cannot resolve component using '${component}'.`), null);
}
this._console.warn(ComponentResolver.DynamicCompilationDeprecationMsg);
var metadatas = reflector.annotations(<Type>component);
var componentFactory = metadatas.find(_isComponentFactory);
if (isBlank(componentFactory)) {
throw new BaseException(`No precompiled component ${stringify(component)} found`);
}
return PromiseWrapper.resolve(componentFactory);
}
clearCache() {}
}

View File

@ -8,13 +8,15 @@
import {Injectable, Injector, ReflectiveInjector, ResolvedReflectiveProvider} from '../di'; import {Injectable, Injector, ReflectiveInjector, ResolvedReflectiveProvider} from '../di';
import {Type, isPresent} from '../facade/lang'; import {Type, isPresent} from '../facade/lang';
import {Compiler} from './compiler';
import {ComponentRef} from './component_factory'; import {ComponentRef} from './component_factory';
import {ComponentResolver} from './component_resolver';
import {ViewContainerRef} from './view_container_ref'; import {ViewContainerRef} from './view_container_ref';
/** /**
* Use ComponentResolver and ViewContainerRef directly. * Use ComponentFactoryResolver and ViewContainerRef directly.
* *
* @deprecated * @deprecated
*/ */
@ -119,12 +121,12 @@ export abstract class DynamicComponentLoader {
@Injectable() @Injectable()
export class DynamicComponentLoader_ extends DynamicComponentLoader { export class DynamicComponentLoader_ extends DynamicComponentLoader {
constructor(private _compiler: ComponentResolver) { super(); } constructor(private _compiler: Compiler) { super(); }
loadAsRoot( loadAsRoot(
type: Type, overrideSelectorOrNode: string|any, injector: Injector, onDispose?: () => void, type: Type, overrideSelectorOrNode: string|any, injector: Injector, onDispose?: () => void,
projectableNodes?: any[][]): Promise<ComponentRef<any>> { projectableNodes?: any[][]): Promise<ComponentRef<any>> {
return this._compiler.resolveComponent(type).then(componentFactory => { return this._compiler.compileComponentAsync(<any>type).then(componentFactory => {
var componentRef = componentFactory.create( var componentRef = componentFactory.create(
injector, projectableNodes, injector, projectableNodes,
isPresent(overrideSelectorOrNode) ? overrideSelectorOrNode : componentFactory.selector); isPresent(overrideSelectorOrNode) ? overrideSelectorOrNode : componentFactory.selector);
@ -138,7 +140,7 @@ export class DynamicComponentLoader_ extends DynamicComponentLoader {
loadNextToLocation( loadNextToLocation(
type: Type, location: ViewContainerRef, providers: ResolvedReflectiveProvider[] = null, type: Type, location: ViewContainerRef, providers: ResolvedReflectiveProvider[] = null,
projectableNodes: any[][] = null): Promise<ComponentRef<any>> { projectableNodes: any[][] = null): Promise<ComponentRef<any>> {
return this._compiler.resolveComponent(type).then(componentFactory => { return this._compiler.compileComponentAsync(<any>type).then(componentFactory => {
var contextInjector = location.parentInjector; var contextInjector = location.parentInjector;
var childInjector = isPresent(providers) && providers.length > 0 ? var childInjector = isPresent(providers) && providers.length > 0 ?
ReflectiveInjector.fromResolvedProviders(providers, contextInjector) : ReflectiveInjector.fromResolvedProviders(providers, contextInjector) :

View File

@ -14,15 +14,16 @@ import {CodegenComponentFactoryResolver, ComponentFactoryResolver} from './compo
/** /**
* Represents an instance of an AppModule created via a {@link AppModuleFactory}. * Represents an instance of an NgModule created via a {@link NgModuleFactory}.
* *
* `AppModuleRef` provides access to the AppModule Instance as well other objects related to this * `NgModuleRef` provides access to the NgModule Instance as well other objects related to this
* AppModule Instance. * NgModule Instance.
* @stable *
* @experimental
*/ */
export abstract class AppModuleRef<T> { export abstract class NgModuleRef<T> {
/** /**
* The injector that contains all of the providers of the AppModule. * The injector that contains all of the providers of the NgModule.
*/ */
get injector(): Injector { return unimplemented(); } get injector(): Injector { return unimplemented(); }
@ -33,22 +34,22 @@ export abstract class AppModuleRef<T> {
get componentFactoryResolver(): ComponentFactoryResolver { return unimplemented(); } get componentFactoryResolver(): ComponentFactoryResolver { return unimplemented(); }
/** /**
* The AppModule instance. * The NgModule instance.
*/ */
get instance(): T { return unimplemented(); } get instance(): T { return unimplemented(); }
} }
/** /**
* @stable * @experimental
*/ */
export class AppModuleFactory<T> { export class NgModuleFactory<T> {
constructor( constructor(
private _injectorClass: {new (parentInjector: Injector): AppModuleInjector<T>}, private _injectorClass: {new (parentInjector: Injector): NgModuleInjector<T>},
private _moduleype: ConcreteType<T>) {} private _moduleype: ConcreteType<T>) {}
get moduleType(): ConcreteType<T> { return this._moduleype; } get moduleType(): ConcreteType<T> { return this._moduleype; }
create(parentInjector: Injector = null): AppModuleRef<T> { create(parentInjector: Injector): NgModuleRef<T> {
if (!parentInjector) { if (!parentInjector) {
parentInjector = Injector.NULL; parentInjector = Injector.NULL;
} }
@ -60,9 +61,9 @@ export class AppModuleFactory<T> {
const _UNDEFINED = new Object(); const _UNDEFINED = new Object();
export abstract class AppModuleInjector<T> extends CodegenComponentFactoryResolver implements export abstract class NgModuleInjector<T> extends CodegenComponentFactoryResolver implements
Injector, Injector,
AppModuleRef<T> { NgModuleRef<T> {
public instance: T; public instance: T;
constructor(public parent: Injector, factories: ComponentFactory<any>[]) { constructor(public parent: Injector, factories: ComponentFactory<any>[]) {

View File

@ -6,12 +6,12 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AppModuleFactory} from './app_module_factory'; import {NgModuleFactory} from './ng_module_factory';
/** /**
* Used to load app moduled factories. * Used to load ng moduled factories.
* @experimental * @experimental
*/ */
export abstract class AppModuleFactoryLoader { export abstract class NgModuleFactoryLoader {
abstract load(path: string): Promise<AppModuleFactory<any>>; abstract load(path: string): Promise<NgModuleFactory<any>>;
} }

View File

@ -10,9 +10,9 @@
import {Injectable, Optional} from '../di'; import {Injectable, Optional} from '../di';
import {global} from '../facade/lang'; import {global} from '../facade/lang';
import {AppModuleFactory} from './app_module_factory';
import {AppModuleFactoryLoader} from './app_module_factory_loader';
import {Compiler} from './compiler'; import {Compiler} from './compiler';
import {NgModuleFactory} from './ng_module_factory';
import {NgModuleFactoryLoader} from './ng_module_factory_loader';
const _SEPARATOR = '#'; const _SEPARATOR = '#';
@ -20,18 +20,18 @@ const FACTORY_MODULE_SUFFIX = '.ngfactory';
const FACTORY_CLASS_SUFFIX = 'NgFactory'; const FACTORY_CLASS_SUFFIX = 'NgFactory';
/** /**
* AppModuleFactoryLoader that uses SystemJS to load AppModuleFactory * NgModuleFactoryLoader that uses SystemJS to load NgModuleFactory
* @experimental * @experimental
*/ */
@Injectable() @Injectable()
export class SystemJsAppModuleLoader implements AppModuleFactoryLoader { export class SystemJsNgModuleLoader implements NgModuleFactoryLoader {
constructor(@Optional() private _compiler: Compiler) {} constructor(@Optional() private _compiler: Compiler) {}
load(path: string): Promise<AppModuleFactory<any>> { load(path: string): Promise<NgModuleFactory<any>> {
return this._compiler ? this.loadAndCompile(path) : this.loadFactory(path); return this._compiler ? this.loadAndCompile(path) : this.loadFactory(path);
} }
private loadAndCompile(path: string): Promise<AppModuleFactory<any>> { private loadAndCompile(path: string): Promise<NgModuleFactory<any>> {
let [module, exportName] = path.split(_SEPARATOR); let [module, exportName] = path.split(_SEPARATOR);
if (exportName === undefined) exportName = 'default'; if (exportName === undefined) exportName = 'default';
@ -39,10 +39,10 @@ export class SystemJsAppModuleLoader implements AppModuleFactoryLoader {
.System.import(module) .System.import(module)
.then((module: any) => module[exportName]) .then((module: any) => module[exportName])
.then((type: any) => checkNotEmpty(type, module, exportName)) .then((type: any) => checkNotEmpty(type, module, exportName))
.then((type: any) => this._compiler.compileAppModuleAsync(type)); .then((type: any) => this._compiler.compileModuleAsync(type));
} }
private loadFactory(path: string): Promise<AppModuleFactory<any>> { private loadFactory(path: string): Promise<NgModuleFactory<any>> {
let [module, exportName] = path.split(_SEPARATOR); let [module, exportName] = path.split(_SEPARATOR);
if (exportName === undefined) exportName = 'default'; if (exportName === undefined) exportName = 'default';
@ -58,4 +58,4 @@ function checkNotEmpty(value: any, modulePath: string, exportName: string): any
throw new Error(`Cannot find '${exportName}' in '${modulePath}'`); throw new Error(`Cannot find '${exportName}' in '${modulePath}'`);
} }
return value; return value;
} }

View File

@ -18,9 +18,9 @@ const _SEPARATOR = '#';
/** /**
* Component resolver that can load components lazily * Component resolver that can load components lazily
* *
* @deprecated Lazy loading of components is deprecated. Use {@link SystemJsAppModuleLoader} to lazy * @deprecated Lazy loading of components is deprecated. Use {@link SystemJsNgModuleLoader} to lazy
* load * load
* {@link AppModuleFactory}s instead. * {@link NgModuleFactory}s instead.
*/ */
@Injectable() @Injectable()
export class SystemJsComponentResolver implements ComponentResolver { export class SystemJsComponentResolver implements ComponentResolver {
@ -53,9 +53,9 @@ const FACTORY_CLASS_SUFFIX = 'NgFactory';
/** /**
* Component resolver that can load component factories lazily * Component resolver that can load component factories lazily
* *
* @deprecated Lazy loading of components is deprecated. Use {@link SystemJsAppModuleLoader} * @deprecated Lazy loading of components is deprecated. Use {@link SystemJsNgModuleLoader}
* to lazy * to lazy
* load {@link AppModuleFactory}s instead. * load {@link NgModuleFactory}s instead.
*/ */
@Injectable() @Injectable()
export class SystemJsCmpFactoryResolver implements ComponentResolver { export class SystemJsCmpFactoryResolver implements ComponentResolver {

View File

@ -14,15 +14,15 @@
import {ChangeDetectionStrategy} from '../src/change_detection/change_detection'; import {ChangeDetectionStrategy} from '../src/change_detection/change_detection';
import {AnimationEntryMetadata} from './animation/metadata'; import {AnimationEntryMetadata} from './animation/metadata';
import {AppModuleMetadata} from './metadata/app_module';
import {AttributeMetadata, ContentChildMetadata, ContentChildrenMetadata, QueryMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata} from './metadata/di'; import {AttributeMetadata, ContentChildMetadata, ContentChildrenMetadata, QueryMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata} from './metadata/di';
import {ComponentMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, InputMetadata, OutputMetadata, PipeMetadata} from './metadata/directives'; import {ComponentMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, InputMetadata, OutputMetadata, PipeMetadata} from './metadata/directives';
import {NgModuleMetadata} from './metadata/ng_module';
import {ViewEncapsulation, ViewMetadata} from './metadata/view'; import {ViewEncapsulation, ViewMetadata} from './metadata/view';
export {AppModuleMetadata} from './metadata/app_module';
export {ANALYZE_FOR_PRECOMPILE, AttributeMetadata, ContentChildMetadata, ContentChildrenMetadata, QueryMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata} from './metadata/di'; export {ANALYZE_FOR_PRECOMPILE, AttributeMetadata, ContentChildMetadata, ContentChildrenMetadata, QueryMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata} from './metadata/di';
export {ComponentMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, InputMetadata, OutputMetadata, PipeMetadata} from './metadata/directives'; export {ComponentMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, InputMetadata, OutputMetadata, PipeMetadata} from './metadata/directives';
export {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, OnChanges, OnDestroy, OnInit} from './metadata/lifecycle_hooks'; export {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, OnChanges, OnDestroy, OnInit} from './metadata/lifecycle_hooks';
export {NgModuleMetadata} from './metadata/ng_module';
export {ViewEncapsulation, ViewMetadata} from './metadata/view'; export {ViewEncapsulation, ViewMetadata} from './metadata/view';
import {makeDecorator, makeParamDecorator, makePropDecorator, TypeDecorator,} from './util/decorators'; import {makeDecorator, makeParamDecorator, makePropDecorator, TypeDecorator,} from './util/decorators';
@ -86,13 +86,13 @@ export interface ViewDecorator extends TypeDecorator {
} }
/** /**
* Interface for the {@link AppModuleMetadata} decorator function. * Interface for the {@link NgModuleMetadata} decorator function.
* *
* See {@link AppModuleMetadataFactory}. * See {@link NgModuleMetadataFactory}.
* *
* @stable * @stable
*/ */
export interface AppModuleDecorator extends TypeDecorator {} export interface NgModuleDecorator extends TypeDecorator {}
/** /**
@ -490,25 +490,25 @@ export interface HostListenerMetadataFactory {
} }
/** /**
* {@link AppModuleMetadata} factory for creating annotations, decorators or DSL. * {@link NgModuleMetadata} factory for creating annotations, decorators or DSL.
* *
* @stable * @experimental
*/ */
export interface AppModuleMetadataFactory { export interface NgModuleMetadataFactory {
(obj: { (obj?: {
providers?: any[], providers?: any[],
directives?: Array<Type|any[]>, declarations?: Array<Type|any[]>,
pipes?: Array<Type|any[]>, imports?: Array<Type|any[]>,
precompile?: Array<Type|any[]>, exports?: Array<Type|any[]>,
modules?: Array<Type|any[]>, precompile?: Array<Type|any[]>
}): AppModuleDecorator; }): NgModuleDecorator;
new (obj: { new (obj?: {
providers?: any[], providers?: any[],
directives?: Array<Type|any[]>, declarations?: Array<Type|any[]>,
pipes?: Array<Type|any[]>, imports?: Array<Type|any[]>,
precompile?: Array<Type|any[]>, exports?: Array<Type|any[]>,
modules?: Array<Type|any[]>, precompile?: Array<Type|any[]>
}): AppModuleMetadata; }): NgModuleMetadata;
} }
// TODO(alexeagle): remove the duplication of this doc. It is copied from ComponentMetadata. // TODO(alexeagle): remove the duplication of this doc. It is copied from ComponentMetadata.
@ -1537,9 +1537,9 @@ export var HostBinding: HostBindingMetadataFactory = makePropDecorator(HostBindi
export var HostListener: HostListenerMetadataFactory = makePropDecorator(HostListenerMetadata); export var HostListener: HostListenerMetadataFactory = makePropDecorator(HostListenerMetadata);
/** /**
* Declares an app module. * Declares an ng module.
* @stable * @experimental
* @Annotation * @Annotation
*/ */
export var AppModule: AppModuleMetadataFactory = export var NgModule: NgModuleMetadataFactory =
<AppModuleMetadataFactory>makeDecorator(AppModuleMetadata); <NgModuleMetadataFactory>makeDecorator(NgModuleMetadata);

View File

@ -13,13 +13,13 @@ import {StringWrapper, Type, isString, stringify} from '../facade/lang';
/** /**
* This token can be used to create a virtual provider that will populate the * This token can be used to create a virtual provider that will populate the
* `precompile` fields of components and app modules based on its `useValue`. * `precompile` fields of components and ng modules based on its `useValue`.
* All components that are referenced in the `useValue` value (either directly * All components that are referenced in the `useValue` value (either directly
* or in a nested array or map) will be added to the `precompile` property. * or in a nested array or map) will be added to the `precompile` property.
* *
* ### Example * ### Example
* The following example shows how the router can populate the `precompile` * The following example shows how the router can populate the `precompile`
* field of an AppModule based on the router configuration which refers * field of an NgModule based on the router configuration which refers
* to components. * to components.
* *
* ```typescript * ```typescript
@ -37,7 +37,7 @@ import {StringWrapper, Type, isString, stringify} from '../facade/lang';
* {path: /teams', component: TeamsComp} * {path: /teams', component: TeamsComp}
* ]; * ];
* *
* @AppModule({ * @NgModule({
* providers: [provideRoutes(routes)] * providers: [provideRoutes(routes)]
* }) * })
* class ModuleWithRoutes {} * class ModuleWithRoutes {}

View File

@ -10,10 +10,10 @@ import {InjectableMetadata} from '../di/metadata';
import {Type} from '../facade/lang'; import {Type} from '../facade/lang';
/** /**
* Declares an Application Module. * Declares an Angular Module.
* @stable * @experimental
*/ */
export class AppModuleMetadata extends InjectableMetadata { export class NgModuleMetadata extends InjectableMetadata {
/** /**
* Defines the set of injectable objects that are available in the injector * Defines the set of injectable objects that are available in the injector
* of this module. * of this module.
@ -29,7 +29,7 @@ export class AppModuleMetadata extends InjectableMetadata {
* } * }
* } * }
* *
* @AppModule({ * @NgModule({
* providers: [ * providers: [
* Greeter * Greeter
* ] * ]
@ -48,36 +48,52 @@ export class AppModuleMetadata extends InjectableMetadata {
/** /**
* Specifies a list of directives that can be used within the template * Specifies a list of directives/pipes that belong to this module.
* of any component that is part of this application module.
* *
* ### Example * ### Example
* *
* ```javascript * ```javascript
* @AppModule({ * @NgModule({
* directives: [NgFor] * declarations: [NgFor]
* }) * })
* class MyAppModule { * class CommonModule {
* } * }
* ``` * ```
*/ */
directives: Array<Type|any[]>; declarations: Array<Type|any[]>;
/** /**
* Specifies a list of pipes that can be used within the template * Specifies a list of modules whose exported directives/pipes
* of any component that is part of this application module. * should be available to templates in this module.
* *
* ### Example * ### Example
* *
* ```javascript * ```javascript
* @AppModule({ * @NgModule({
* pipes: [SomePipe] * imports: [CommonModule]
* }) * })
* class MyAppModule { * class MainModule {
* } * }
* ``` * ```
*/ */
pipes: Array<Type|any[]>; imports: Array<Type|any[]>;
/**
* Specifies a list of directives/pipes/module that can be used within the template
* of any component that is part of an angular module
* that imports this angular module.
*
* ### Example
*
* ```javascript
* @NgModule({
* exports: [NgFor]
* })
* class CommonModule {
* }
* ```
*/
exports: Array<Type|any[]>;
/** /**
* Defines the components that should be precompiled as well when * Defines the components that should be precompiled as well when
@ -87,27 +103,18 @@ export class AppModuleMetadata extends InjectableMetadata {
*/ */
precompile: Array<Type|any[]>; precompile: Array<Type|any[]>;
/** constructor({providers, declarations, imports, exports, precompile}: {
* Defines modules that should be included into this module.
* The providers / directives / pipes / precompile entries will be added
* to this module.
* Just like the main module, the modules listed here are also eagerly
* created and accessible via DI.
*/
modules: Array<Type|any[]>;
constructor({providers, directives, pipes, precompile, modules}: {
providers?: any[], providers?: any[],
directives?: Array<Type|any[]>, declarations?: Array<Type|any[]>,
pipes?: Array<Type|any[]>, imports?: Array<Type|any[]>,
precompile?: Array<Type|any[]>, exports?: Array<Type|any[]>,
modules?: Array<Type|any[]> precompile?: Array<Type|any[]>
} = {}) { } = {}) {
super(); super();
this._providers = providers; this._providers = providers;
this.directives = directives; this.declarations = declarations;
this.pipes = pipes; this.imports = imports;
this.exports = exports;
this.precompile = precompile; this.precompile = precompile;
this.modules = modules;
} }
} }

View File

@ -8,7 +8,7 @@
import {Type} from '../src/facade/lang'; import {Type} from '../src/facade/lang';
import {PLATFORM_CORE_PROVIDERS} from './application_ref'; import {PlatformRef, PlatformRef_, createPlatformFactory} from './application_ref';
import {Console} from './console'; import {Console} from './console';
import {Provider} from './di'; import {Provider} from './di';
import {Reflector, reflector} from './reflection/reflection'; import {Reflector, reflector} from './reflection/reflection';
@ -21,13 +21,22 @@ function _reflector(): Reflector {
var __unused: Type; // prevent missing use Dart warning. var __unused: Type; // prevent missing use Dart warning.
const _CORE_PLATFORM_PROVIDERS: Array<any|Type|Provider|any[]> = [
PlatformRef_, {provide: PlatformRef, useExisting: PlatformRef_},
{provide: Reflector, useFactory: _reflector, deps: []},
{provide: ReflectorReader, useExisting: Reflector}, TestabilityRegistry, Console
];
/** /**
* A default set of providers which should be included in any Angular platform. * This platform has to be included in any other platform
*
* @experimental * @experimental
*/ */
export const PLATFORM_COMMON_PROVIDERS: Array<any|Type|Provider|any[]> = /*@ts2dart_const*/[ export const corePlatform = createPlatformFactory(null, 'core', _CORE_PLATFORM_PROVIDERS);
PLATFORM_CORE_PROVIDERS,
/*@ts2dart_Provider*/ {provide: Reflector, useFactory: _reflector, deps: []}, /**
/*@ts2dart_Provider*/ {provide: ReflectorReader, useExisting: Reflector}, TestabilityRegistry, * A default set of providers which should be included in any Angular platform.
Console *
]; * @deprecated Create platforms via `createPlatformFactory(corePlatform, ...) instead!
*/
export const PLATFORM_COMMON_PROVIDERS = _CORE_PLATFORM_PROVIDERS;

View File

@ -34,7 +34,7 @@ import {OpaqueToken} from './di';
* ``` * ```
* *
* @deprecated Providing platform directives via a provider is deprecated. Provide platform * @deprecated Providing platform directives via a provider is deprecated. Provide platform
* directives via an {@link AppModule} instead. * directives via an {@link NgModule} instead.
*/ */
export const PLATFORM_DIRECTIVES: OpaqueToken = export const PLATFORM_DIRECTIVES: OpaqueToken =
/*@ts2dart_const*/ new OpaqueToken('Platform Directives'); /*@ts2dart_const*/ new OpaqueToken('Platform Directives');
@ -63,6 +63,6 @@ export const PLATFORM_DIRECTIVES: OpaqueToken =
* ``` * ```
* *
* @deprecated Providing platform pipes via a provider is deprecated. Provide platform pipes via an * @deprecated Providing platform pipes via a provider is deprecated. Provide platform pipes via an
* {@link AppModule} instead. * {@link NgModule} instead.
*/ */
export const PLATFORM_PIPES: OpaqueToken = /*@ts2dart_const*/ new OpaqueToken('Platform Pipes'); export const PLATFORM_PIPES: OpaqueToken = /*@ts2dart_const*/ new OpaqueToken('Platform Pipes');

View File

@ -8,8 +8,10 @@
import {AsyncTestCompleter, ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach, inject,} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach, inject,} from '@angular/core/testing/testing_internal';
import {SpyChangeDetectorRef} from './spies'; import {SpyChangeDetectorRef} from './spies';
import {ApplicationRef_, ApplicationRef, PLATFORM_CORE_PROVIDERS, APPLICATION_CORE_PROVIDERS} from '@angular/core/src/application_ref'; import {ConcreteType} from '../src/facade/lang';
import {Type, Injector, APP_INITIALIZER, Component, ReflectiveInjector, coreLoadAndBootstrap, PlatformRef, createPlatform, disposePlatform, ComponentResolver, ComponentFactoryResolver, ChangeDetectorRef} from '@angular/core'; import {ApplicationRef_, ApplicationRef} from '@angular/core/src/application_ref';
import {Type, NgModule, CompilerFactory, Injector, APP_INITIALIZER, Component, ReflectiveInjector, bootstrapModule, bootstrapModuleFactory, PlatformRef, disposePlatform, createPlatformFactory, ComponentResolver, ComponentFactoryResolver, ChangeDetectorRef, ApplicationModule} from '@angular/core';
import {coreDynamicPlatform} from '@angular/compiler';
import {Console} from '@angular/core/src/console'; import {Console} from '@angular/core/src/console';
import {BaseException} from '../src/facade/exceptions'; import {BaseException} from '../src/facade/exceptions';
import {PromiseWrapper, PromiseCompleter, TimerWrapper} from '../src/facade/async'; import {PromiseWrapper, PromiseCompleter, TimerWrapper} from '../src/facade/async';
@ -18,36 +20,48 @@ import {ExceptionHandler} from '../src/facade/exception_handler';
export function main() { export function main() {
describe('bootstrap', () => { describe('bootstrap', () => {
var platform: PlatformRef; var defaultPlatform: PlatformRef;
var errorLogger: _ArrayLogger; var errorLogger: _ArrayLogger;
var someCompFactory: ComponentFactory<any>; var someCompFactory: ComponentFactory<any>;
var appProviders: any[];
beforeEach(() => { beforeEach(() => {
errorLogger = new _ArrayLogger(); errorLogger = new _ArrayLogger();
disposePlatform(); disposePlatform();
platform = createPlatform(ReflectiveInjector.resolveAndCreate(PLATFORM_CORE_PROVIDERS)); defaultPlatform = createPlatformFactory(coreDynamicPlatform, 'test')();
someCompFactory = someCompFactory =
new _MockComponentFactory(new _MockComponentRef(ReflectiveInjector.resolveAndCreate([]))); new _MockComponentFactory(new _MockComponentRef(ReflectiveInjector.resolveAndCreate([])));
appProviders = [
{provide: Console, useValue: new _MockConsole()},
{provide: ExceptionHandler, useValue: new ExceptionHandler(errorLogger, false)},
{provide: ComponentResolver, useValue: new _MockComponentResolver(someCompFactory)}
];
}); });
afterEach(() => { disposePlatform(); }); afterEach(() => { disposePlatform(); });
function createApplication(providers: any[]): ApplicationRef_ { function createModule(providers: any[] = []): ConcreteType<any> {
var appInjector = ReflectiveInjector.resolveAndCreate( @NgModule({providers: [appProviders, providers], imports: [ApplicationModule]})
[ class MyModule {
APPLICATION_CORE_PROVIDERS, {provide: Console, useValue: new _MockConsole()}, }
{provide: ExceptionHandler, useValue: new ExceptionHandler(errorLogger, false)},
{provide: ComponentResolver, useValue: new _MockComponentResolver(someCompFactory)}, return MyModule;
{provide: ComponentFactoryResolver, useValue: ComponentFactoryResolver.NULL}, providers }
],
platform.injector); function createApplication(
providers: any[] = [], platform: PlatformRef = defaultPlatform): ApplicationRef_ {
const compilerFactory: CompilerFactory = platform.injector.get(CompilerFactory);
const compiler = compilerFactory.createCompiler();
const appInjector =
bootstrapModuleFactory(compiler.compileModuleSync(createModule(providers)), platform)
.injector;
return appInjector.get(ApplicationRef); return appInjector.get(ApplicationRef);
} }
describe('ApplicationRef', () => { describe('ApplicationRef', () => {
it('should throw when reentering tick', () => { it('should throw when reentering tick', () => {
var cdRef = <any>new SpyChangeDetectorRef(); var cdRef = <any>new SpyChangeDetectorRef();
var ref = createApplication([]); var ref = createApplication();
try { try {
ref.registerChangeDetector(cdRef); ref.registerChangeDetector(cdRef);
cdRef.spy('detectChanges').andCallFake(() => ref.tick()); cdRef.spy('detectChanges').andCallFake(() => ref.tick());
@ -59,14 +73,14 @@ export function main() {
describe('run', () => { describe('run', () => {
it('should rethrow errors even if the exceptionHandler is not rethrowing', () => { it('should rethrow errors even if the exceptionHandler is not rethrowing', () => {
var ref = createApplication([]); var ref = createApplication();
expect(() => ref.run(() => { throw new BaseException('Test'); })).toThrowError('Test'); expect(() => ref.run(() => { throw new BaseException('Test'); })).toThrowError('Test');
}); });
it('should return a promise with rejected errors even if the exceptionHandler is not rethrowing', it('should return a promise with rejected errors even if the exceptionHandler is not rethrowing',
inject( inject(
[AsyncTestCompleter, Injector], (async: AsyncTestCompleter, injector: Injector) => { [AsyncTestCompleter, Injector], (async: AsyncTestCompleter, injector: Injector) => {
var ref = createApplication([]); var ref = createApplication();
var promise = ref.run(() => PromiseWrapper.reject('Test', null)); var promise = ref.run(() => PromiseWrapper.reject('Test', null));
PromiseWrapper.catchError(promise, (e) => { PromiseWrapper.catchError(promise, (e) => {
expect(e).toEqual('Test'); expect(e).toEqual('Test');
@ -76,7 +90,7 @@ export function main() {
}); });
}); });
describe('coreLoadAndBootstrap', () => { describe('bootstrapModule', () => {
it('should wait for asynchronous app initializers', it('should wait for asynchronous app initializers',
inject([AsyncTestCompleter, Injector], (async: AsyncTestCompleter, injector: Injector) => { inject([AsyncTestCompleter, Injector], (async: AsyncTestCompleter, injector: Injector) => {
let completer: PromiseCompleter<any> = PromiseWrapper.completer(); let completer: PromiseCompleter<any> = PromiseWrapper.completer();
@ -85,16 +99,19 @@ export function main() {
completer.resolve(true); completer.resolve(true);
initializerDone = true; initializerDone = true;
}, 1); }, 1);
var app = createApplication(
[{provide: APP_INITIALIZER, useValue: () => completer.promise, multi: true}]); bootstrapModule(
coreLoadAndBootstrap(MyComp6, app.injector).then(_ => { createModule(
expect(initializerDone).toBe(true); [{provide: APP_INITIALIZER, useValue: () => completer.promise, multi: true}]),
async.done(); defaultPlatform)
}); .then(_ => {
expect(initializerDone).toBe(true);
async.done();
});
})); }));
}); });
describe('coreBootstrap', () => { describe('ApplicationRef.bootstrap', () => {
it('should throw if an APP_INITIIALIZER is not yet resolved', it('should throw if an APP_INITIIALIZER is not yet resolved',
inject([Injector], (injector: Injector) => { inject([Injector], (injector: Injector) => {
var app = createApplication([{ var app = createApplication([{

View File

@ -87,14 +87,13 @@ export function main() {
expect(log.result()).toEqual('1; 2'); expect(log.result()).toEqual('1; 2');
})); }));
// TODO(vicb): check why this doesn't work in JS - linked to open issues on GH ? it('should complain if the test throws an exception during async calls', () => {
xit('should complain if the test throws an exception during async calls', () => {
expect(() => { expect(() => {
fakeAsync(() => { fakeAsync(() => {
PromiseWrapper.resolve(null).then((_) => { throw new BaseException('async'); }); PromiseWrapper.resolve(null).then((_) => { throw new BaseException('async'); });
flushMicrotasks(); flushMicrotasks();
})(); })();
}).toThrowError('async'); }).toThrowError('Uncaught (in promise): async');
}); });
it('should complain if a test throws an exception', () => { it('should complain if a test throws an exception', () => {

View File

@ -1,557 +0,0 @@
/**
* @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 {ANALYZE_FOR_PRECOMPILE, AppModule, AppModuleMetadata, Compiler, Component, ComponentFactoryResolver, ComponentRef, ComponentResolver, DebugElement, Directive, Host, Inject, Injectable, Injector, Input, OpaqueToken, Optional, Pipe, Provider, ReflectiveInjector, SelfMetadata, SkipSelf, SkipSelfMetadata, forwardRef, getDebugNode, provide} from '@angular/core';
import {ComponentFixture, configureCompiler} from '@angular/core/testing';
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers';
import {BaseException} from '../../src/facade/exceptions';
import {ConcreteType, IS_DART, Type, stringify} from '../../src/facade/lang';
class Engine {}
class BrokenEngine {
constructor() { throw new BaseException('Broken Engine'); }
}
class DashboardSoftware {}
@Injectable()
class Dashboard {
constructor(software: DashboardSoftware) {}
}
class TurboEngine extends Engine {}
@Injectable()
class Car {
engine: Engine;
constructor(engine: Engine) { this.engine = engine; }
}
@Injectable()
class CarWithOptionalEngine {
engine: Engine;
constructor(@Optional() engine: Engine) { this.engine = engine; }
}
@Injectable()
class CarWithDashboard {
engine: Engine;
dashboard: Dashboard;
constructor(engine: Engine, dashboard: Dashboard) {
this.engine = engine;
this.dashboard = dashboard;
}
}
@Injectable()
class SportsCar extends Car {
engine: Engine;
constructor(engine: Engine) { super(engine); }
}
@Injectable()
class CarWithInject {
engine: Engine;
constructor(@Inject(TurboEngine) engine: Engine) { this.engine = engine; }
}
@Injectable()
class CyclicEngine {
constructor(car: Car) {}
}
class NoAnnotations {
constructor(secretDependency: any) {}
}
function factoryFn(a: any) {}
@Injectable()
class SomeService {
}
@AppModule({})
class SomeModule {
}
@AppModule({providers: [{provide: 'someToken', useValue: 'someValue'}]})
class ModuleWithProvider {
}
@Component({selector: 'comp', template: ''})
class SomeComp {
}
@AppModule({precompile: [SomeComp]})
class ModuleWithPrecompile {
}
@AppModule({
providers:
[{provide: ANALYZE_FOR_PRECOMPILE, multi: true, useValue: [{a: 'b', component: SomeComp}]}]
})
class ModuleWithAnalyzePrecompileProvider {
}
@Directive({selector: '[someDir]', host: {'[title]': 'someDir'}})
class SomeDirective {
@Input()
someDir: string;
}
@Pipe({name: 'somePipe'})
class SomePipe {
transform(value: string): any { return `transformed ${value}`; }
}
@Component({selector: 'comp', template: `<div [someDir]="'someValue' | somePipe"></div>`})
class CompUsingModuleDirectiveAndPipe {
}
@Component(
{selector: 'parent', template: `<comp></comp>`, directives: [CompUsingModuleDirectiveAndPipe]})
class ParentCompUsingModuleDirectiveAndPipe {
}
@AppModule(
{directives: [SomeDirective], pipes: [SomePipe], precompile: [CompUsingModuleDirectiveAndPipe]})
class ModuleWithDirectivesAndPipes {
}
export function main() {
if (IS_DART) {
declareTests({useJit: false});
} else {
describe('jit', () => { declareTests({useJit: true}); });
describe('no jit', () => { declareTests({useJit: false}); });
}
}
function declareTests({useJit}: {useJit: boolean}) {
describe('AppModule', () => {
var compiler: Compiler;
var injector: Injector;
beforeEach(() => { configureCompiler({useJit: useJit}); });
beforeEach(inject([Compiler, Injector], (_compiler: Compiler, _injector: Injector) => {
compiler = _compiler;
injector = _injector;
}));
describe('precompile', function() {
it('should resolve ComponentFactories', () => {
let appModule = compiler.compileAppModuleSync(ModuleWithPrecompile).create();
expect(appModule.componentFactoryResolver.resolveComponentFactory(SomeComp).componentType)
.toBe(SomeComp);
expect(appModule.injector.get(ComponentFactoryResolver)
.resolveComponentFactory(SomeComp)
.componentType)
.toBe(SomeComp);
});
it('should resolve ComponentFactories via ANALYZE_FOR_PRECOMPILE', () => {
let appModule = compiler.compileAppModuleSync(ModuleWithAnalyzePrecompileProvider).create();
expect(appModule.componentFactoryResolver.resolveComponentFactory(SomeComp).componentType)
.toBe(SomeComp);
expect(appModule.injector.get(ComponentFactoryResolver)
.resolveComponentFactory(SomeComp)
.componentType)
.toBe(SomeComp);
});
it('should resolve ComponentFactories for nested modules', () => {
let appModule =
compiler
.compileAppModuleSync(
SomeModule, new AppModuleMetadata({modules: [ModuleWithPrecompile]}))
.create();
expect(appModule.componentFactoryResolver.resolveComponentFactory(SomeComp).componentType)
.toBe(SomeComp);
expect(appModule.injector.get(ComponentFactoryResolver)
.resolveComponentFactory(SomeComp)
.componentType)
.toBe(SomeComp);
});
});
describe('directives and pipes', () => {
function createComp<T>(
compType: ConcreteType<T>, moduleType: ConcreteType<any>,
moduleMeta: AppModuleMetadata = null): ComponentFixture<T> {
let appModule = compiler.compileAppModuleSync(moduleType, moduleMeta).create();
var cf = appModule.componentFactoryResolver.resolveComponentFactory(compType);
return new ComponentFixture(cf.create(injector), null, false);
}
it('should support module directives and pipes', () => {
let compFixture = createComp(CompUsingModuleDirectiveAndPipe, ModuleWithDirectivesAndPipes);
compFixture.detectChanges();
expect(compFixture.debugElement.children[0].properties['title'])
.toBe('transformed someValue');
});
it('should support module directives and pipes for nested modules', () => {
let compFixture = createComp(
CompUsingModuleDirectiveAndPipe, SomeModule,
new AppModuleMetadata({modules: [ModuleWithDirectivesAndPipes]}));
compFixture.detectChanges();
expect(compFixture.debugElement.children[0].properties['title'])
.toBe('transformed someValue');
});
it('should support module directives and pipes in nested components', () => {
let compFixture =
createComp(ParentCompUsingModuleDirectiveAndPipe, SomeModule, new AppModuleMetadata({
directives: [SomeDirective],
pipes: [SomePipe],
precompile: [ParentCompUsingModuleDirectiveAndPipe]
}));
compFixture.detectChanges();
expect(compFixture.debugElement.children[0].children[0].properties['title'])
.toBe('transformed someValue');
});
it('should provide a Compiler instance that uses the directives/pipes of the module', () => {
let appModule = compiler.compileAppModuleSync(ModuleWithDirectivesAndPipes).create();
let boundCompiler: Compiler = appModule.injector.get(Compiler);
var cf = boundCompiler.compileComponentSync(CompUsingModuleDirectiveAndPipe);
let compFixture = new ComponentFixture(cf.create(injector), null, false);
compFixture.detectChanges();
expect(compFixture.debugElement.children[0].properties['title'])
.toBe('transformed someValue');
});
it('should provide a ComponentResolver instance that uses the directives/pipes of the module',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let appModule = compiler.compileAppModuleSync(ModuleWithDirectivesAndPipes).create();
let boundCompiler: ComponentResolver = appModule.injector.get(ComponentResolver);
boundCompiler.resolveComponent(CompUsingModuleDirectiveAndPipe).then((cf) => {
let compFixture = new ComponentFixture(cf.create(injector), null, false);
compFixture.detectChanges();
expect(compFixture.debugElement.children[0].properties['title'])
.toBe('transformed someValue');
async.done();
});
}));
it('should provide a ComponentResolver instance that delegates to the parent ComponentResolver for strings',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let parentResolver: any =
jasmine.createSpyObj('resolver', ['resolveComponent', 'clearCache']);
let appModule = compiler.compileAppModuleSync(ModuleWithDirectivesAndPipes)
.create(ReflectiveInjector.resolveAndCreate(
[{provide: ComponentResolver, useValue: parentResolver}]));
parentResolver.resolveComponent.and.returnValue(
Promise.resolve('someFactoryFromParent'));
let boundCompiler: ComponentResolver = appModule.injector.get(ComponentResolver);
boundCompiler.resolveComponent('someString').then((result) => {
expect(parentResolver.resolveComponent).toHaveBeenCalledWith('someString');
expect(result).toBe('someFactoryFromParent');
async.done();
});
}));
});
describe('providers', function() {
function createInjector(providers: any[], parent: Injector = null): Injector {
return compiler
.compileAppModuleSync(SomeModule, new AppModuleMetadata({providers: providers}))
.create(parent)
.injector;
}
it('should provide the module',
() => { expect(createInjector([]).get(SomeModule)).toBeAnInstanceOf(SomeModule); });
it('should instantiate a class without dependencies', () => {
var injector = createInjector([Engine]);
var engine = injector.get(Engine);
expect(engine).toBeAnInstanceOf(Engine);
});
it('should resolve dependencies based on type information', () => {
var injector = createInjector([Engine, Car]);
var car = injector.get(Car);
expect(car).toBeAnInstanceOf(Car);
expect(car.engine).toBeAnInstanceOf(Engine);
});
it('should resolve dependencies based on @Inject annotation', () => {
var injector = createInjector([TurboEngine, Engine, CarWithInject]);
var car = injector.get(CarWithInject);
expect(car).toBeAnInstanceOf(CarWithInject);
expect(car.engine).toBeAnInstanceOf(TurboEngine);
});
it('should throw when no type and not @Inject (class case)', () => {
expect(() => createInjector([NoAnnotations]))
.toThrowError('Can\'t resolve all parameters for NoAnnotations: (?).');
});
it('should throw when no type and not @Inject (factory case)', () => {
expect(() => createInjector([provide('someToken', {useFactory: factoryFn})]))
.toThrowError('Can\'t resolve all parameters for factoryFn: (?).');
});
it('should cache instances', () => {
var injector = createInjector([Engine]);
var e1 = injector.get(Engine);
var e2 = injector.get(Engine);
expect(e1).toBe(e2);
});
it('should provide to a value', () => {
var injector = createInjector([provide(Engine, {useValue: 'fake engine'})]);
var engine = injector.get(Engine);
expect(engine).toEqual('fake engine');
});
it('should provide to a factory', () => {
function sportsCarFactory(e: Engine) { return new SportsCar(e); }
var injector =
createInjector([Engine, provide(Car, {useFactory: sportsCarFactory, deps: [Engine]})]);
var car = injector.get(Car);
expect(car).toBeAnInstanceOf(SportsCar);
expect(car.engine).toBeAnInstanceOf(Engine);
});
it('should supporting provider to null', () => {
var injector = createInjector([provide(Engine, {useValue: null})]);
var engine = injector.get(Engine);
expect(engine).toBeNull();
});
it('should provide to an alias', () => {
var injector = createInjector([
Engine, provide(SportsCar, {useClass: SportsCar}),
provide(Car, {useExisting: SportsCar})
]);
var car = injector.get(Car);
var sportsCar = injector.get(SportsCar);
expect(car).toBeAnInstanceOf(SportsCar);
expect(car).toBe(sportsCar);
});
it('should support multiProviders', () => {
var injector = createInjector([
Engine, provide(Car, {useClass: SportsCar, multi: true}),
provide(Car, {useClass: CarWithOptionalEngine, multi: true})
]);
var cars = injector.get(Car);
expect(cars.length).toEqual(2);
expect(cars[0]).toBeAnInstanceOf(SportsCar);
expect(cars[1]).toBeAnInstanceOf(CarWithOptionalEngine);
});
it('should support multiProviders that are created using useExisting', () => {
var injector = createInjector(
[Engine, SportsCar, provide(Car, {useExisting: SportsCar, multi: true})]);
var cars = injector.get(Car);
expect(cars.length).toEqual(1);
expect(cars[0]).toBe(injector.get(SportsCar));
});
it('should throw when the aliased provider does not exist', () => {
var injector = createInjector([provide('car', {useExisting: SportsCar})]);
var e = `No provider for ${stringify(SportsCar)}!`;
expect(() => injector.get('car')).toThrowError(e);
});
it('should handle forwardRef in useExisting', () => {
var injector = createInjector([
provide('originalEngine', {useClass: forwardRef(() => Engine)}),
provide('aliasedEngine', {useExisting: <any>forwardRef(() => 'originalEngine')})
]);
expect(injector.get('aliasedEngine')).toBeAnInstanceOf(Engine);
});
it('should support overriding factory dependencies', () => {
var injector = createInjector(
[Engine, provide(Car, {useFactory: (e: Engine) => new SportsCar(e), deps: [Engine]})]);
var car = injector.get(Car);
expect(car).toBeAnInstanceOf(SportsCar);
expect(car.engine).toBeAnInstanceOf(Engine);
});
it('should support optional dependencies', () => {
var injector = createInjector([CarWithOptionalEngine]);
var car = injector.get(CarWithOptionalEngine);
expect(car.engine).toEqual(null);
});
it('should flatten passed-in providers', () => {
var injector = createInjector([[[Engine, Car]]]);
var car = injector.get(Car);
expect(car).toBeAnInstanceOf(Car);
});
it('should use the last provider when there are multiple providers for same token', () => {
var injector = createInjector(
[provide(Engine, {useClass: Engine}), provide(Engine, {useClass: TurboEngine})]);
expect(injector.get(Engine)).toBeAnInstanceOf(TurboEngine);
});
it('should use non-type tokens', () => {
var injector = createInjector([provide('token', {useValue: 'value'})]);
expect(injector.get('token')).toEqual('value');
});
it('should throw when given invalid providers', () => {
expect(() => createInjector(<any>['blah']))
.toThrowError(
'Invalid provider - only instances of Provider and Type are allowed, got: blah');
});
it('should provide itself', () => {
var parent = createInjector([]);
var child = createInjector([], parent);
expect(child.get(Injector)).toBe(child);
});
it('should throw when no provider defined', () => {
var injector = createInjector([]);
expect(() => injector.get('NonExisting')).toThrowError('No provider for NonExisting!');
});
it('should throw when trying to instantiate a cyclic dependency', () => {
expect(() => createInjector([Car, provide(Engine, {useClass: CyclicEngine})]))
.toThrowError(/Cannot instantiate cyclic dependency! Car/g);
});
it('should support null values', () => {
var injector = createInjector([provide('null', {useValue: null})]);
expect(injector.get('null')).toBe(null);
});
describe('child', () => {
it('should load instances from parent injector', () => {
var parent = createInjector([Engine]);
var child = createInjector([], parent);
var engineFromParent = parent.get(Engine);
var engineFromChild = child.get(Engine);
expect(engineFromChild).toBe(engineFromParent);
});
it('should not use the child providers when resolving the dependencies of a parent provider',
() => {
var parent = createInjector([Car, Engine]);
var child = createInjector([provide(Engine, {useClass: TurboEngine})], parent);
var carFromChild = child.get(Car);
expect(carFromChild.engine).toBeAnInstanceOf(Engine);
});
it('should create new instance in a child injector', () => {
var parent = createInjector([Engine]);
var child = createInjector([provide(Engine, {useClass: TurboEngine})], parent);
var engineFromParent = parent.get(Engine);
var engineFromChild = child.get(Engine);
expect(engineFromParent).not.toBe(engineFromChild);
expect(engineFromChild).toBeAnInstanceOf(TurboEngine);
});
});
describe('depedency resolution', () => {
describe('@Self()', () => {
it('should return a dependency from self', () => {
var inj = createInjector([
Engine,
provide(
Car,
{useFactory: (e: Engine) => new Car(e), deps: [[Engine, new SelfMetadata()]]})
]);
expect(inj.get(Car)).toBeAnInstanceOf(Car);
});
it('should throw when not requested provider on self', () => {
expect(() => createInjector([provide(Car, {
useFactory: (e: Engine) => new Car(e),
deps: [[Engine, new SelfMetadata()]]
})]))
.toThrowError(/No provider for Engine/g);
});
});
describe('default', () => {
it('should not skip self', () => {
var parent = createInjector([Engine]);
var child = createInjector(
[
provide(Engine, {useClass: TurboEngine}),
provide(Car, {useFactory: (e: Engine) => new Car(e), deps: [Engine]})
],
parent);
expect(child.get(Car).engine).toBeAnInstanceOf(TurboEngine);
});
});
});
describe('nested modules', () => {
it('should merge the providers of nested modules', () => {
var injector =
compiler
.compileAppModuleSync(SomeModule, new AppModuleMetadata({
providers: [{provide: 'a', useValue: 'aValue'}],
modules: [ModuleWithProvider]
}))
.create()
.injector;
expect(injector.get(SomeModule)).toBeAnInstanceOf(SomeModule);
expect(injector.get(ModuleWithProvider)).toBeAnInstanceOf(ModuleWithProvider);
expect(injector.get('a')).toBe('aValue');
expect(injector.get('someToken')).toBe('someValue');
});
it('should override the providers of nested modules', () => {
var injector = compiler
.compileAppModuleSync(
SomeModule, new AppModuleMetadata({
providers: [{provide: 'someToken', useValue: 'someNewValue'}],
modules: [ModuleWithProvider]
}))
.create()
.injector;
expect(injector.get('someToken')).toBe('someNewValue');
});
});
});
});
}

View File

@ -1775,17 +1775,6 @@ function declareTests({useJit}: {useJit: boolean}) {
}); });
describe('logging property updates', () => { describe('logging property updates', () => {
beforeEach(() => {
configureCompiler({
providers: [{
provide: CompilerConfig,
// Note: we are testing the `genDebugInfo` flag here, so we
// need to set it explicitely!
useValue: new CompilerConfig({genDebugInfo: true, useJit: useJit})
}]
});
});
it('should reflect property values as attributes', it('should reflect property values as attributes',
inject( inject(
[TestComponentBuilder, AsyncTestCompleter], [TestComponentBuilder, AsyncTestCompleter],

File diff suppressed because it is too large Load Diff

View File

@ -7,8 +7,9 @@
*/ */
import {AsyncTestCompleter, beforeEach, ddescribe, xdescribe, describe, expect, iit, inject, beforeEachProviders, it, xit,} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, beforeEach, ddescribe, xdescribe, describe, expect, iit, inject, beforeEachProviders, it, xit,} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder} from '@angular/core/testing'; import {TestComponentBuilder, configureModule} from '@angular/core/testing';
import {Component, ComponentFactoryResolver, NoComponentFactoryError, forwardRef, ANALYZE_FOR_PRECOMPILE} from '@angular/core'; import {Component, ComponentFactoryResolver, NoComponentFactoryError, forwardRef, ANALYZE_FOR_PRECOMPILE, ViewMetadata} from '@angular/core';
import {stringify} from '../../src/facade/lang';
export function main() { export function main() {
describe('jit', () => { declareTests({useJit: true}); }); describe('jit', () => { declareTests({useJit: true}); });
@ -17,19 +18,33 @@ export function main() {
function declareTests({useJit}: {useJit: boolean}) { function declareTests({useJit}: {useJit: boolean}) {
describe('@Component.precompile', function() { describe('@Component.precompile', function() {
beforeEach(() => { configureModule({declarations: [MainComp, ChildComp, NestedChildComp]}); });
it('should error if the component was not declared nor imported by the module',
inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
@Component({selector: 'child', template: ''})
class ChildComp {
}
@Component({template: 'comp', precompile: [ChildComp]})
class SomeComp {
}
expect(() => tcb.createSync(SomeComp))
.toThrowError(
`Component ${stringify(SomeComp)} in NgModule DynamicTestModule uses ${stringify(ChildComp)} via "precompile" but it was neither declared nor imported into the module!`);
}));
it('should resolve ComponentFactories from the same component', it('should resolve ComponentFactories from the same component',
inject( inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
[TestComponentBuilder, AsyncTestCompleter], const compFixture = tcb.createSync(MainComp);
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => { let mainComp: MainComp = compFixture.componentInstance;
tcb.createAsync(MainComp).then((compFixture) => { expect(compFixture.componentRef.injector.get(ComponentFactoryResolver)).toBe(mainComp.cfr);
let mainComp: MainComp = compFixture.componentInstance; var cf = mainComp.cfr.resolveComponentFactory(ChildComp);
expect(compFixture.debugElement.injector.get(ComponentFactoryResolver)) expect(cf.componentType).toBe(ChildComp);
.toBe(mainComp.cfr); }));
var cf = mainComp.cfr.resolveComponentFactory(ChildComp);
expect(cf.componentType).toBe(ChildComp);
async.done();
});
}));
it('should resolve ComponentFactories via ANALYZE_FOR_PRECOMPILE', it('should resolve ComponentFactories via ANALYZE_FOR_PRECOMPILE',
@ -37,63 +52,52 @@ function declareTests({useJit}: {useJit: boolean}) {
let compFixture = tcb.createSync(CompWithAnalyzePrecompileProvider); let compFixture = tcb.createSync(CompWithAnalyzePrecompileProvider);
let mainComp: CompWithAnalyzePrecompileProvider = compFixture.componentInstance; let mainComp: CompWithAnalyzePrecompileProvider = compFixture.componentInstance;
let cfr: ComponentFactoryResolver = let cfr: ComponentFactoryResolver =
compFixture.debugElement.injector.get(ComponentFactoryResolver); compFixture.componentRef.injector.get(ComponentFactoryResolver);
expect(cfr.resolveComponentFactory(ChildComp).componentType).toBe(ChildComp); expect(cfr.resolveComponentFactory(ChildComp).componentType).toBe(ChildComp);
expect(cfr.resolveComponentFactory(NestedChildComp).componentType).toBe(NestedChildComp); expect(cfr.resolveComponentFactory(NestedChildComp).componentType).toBe(NestedChildComp);
})); }));
it('should be able to get a component form a parent component (view hiearchy)', it('should be able to get a component form a parent component (view hiearchy)',
inject( inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
[TestComponentBuilder, AsyncTestCompleter], const compFixture =
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView(
tcb.overrideTemplate(MainComp, '<child></child>') MainComp,
.createAsync(MainComp) new ViewMetadata({template: '<child></child>', directives: [ChildComp]}))
.then((compFixture) => { .createSync(MainComp);
let childCompEl = compFixture.debugElement.children[0]; let childCompEl = compFixture.debugElement.children[0];
let childComp: ChildComp = childCompEl.componentInstance; let childComp: ChildComp = childCompEl.componentInstance;
// declared on ChildComp directly // declared on ChildComp directly
expect(childComp.cfr.resolveComponentFactory(NestedChildComp).componentType) expect(childComp.cfr.resolveComponentFactory(NestedChildComp).componentType)
.toBe(NestedChildComp); .toBe(NestedChildComp);
// inherited from MainComp // inherited from MainComp
expect(childComp.cfr.resolveComponentFactory(ChildComp).componentType) expect(childComp.cfr.resolveComponentFactory(ChildComp).componentType).toBe(ChildComp);
.toBe(ChildComp); }));
async.done();
});
}));
it('should not be able to get components from a parent component (content hierarchy)', it('should not be able to get components from a parent component (content hierarchy)',
inject( inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
[TestComponentBuilder, AsyncTestCompleter], const compFixture = tcb.overrideView(MainComp, new ViewMetadata({
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => { template: '<child><nested></nested></child>',
tcb.overrideTemplate(MainComp, '<child><nested></nested></child>') directives: [ChildComp, NestedChildComp]
.overrideTemplate(ChildComp, '<ng-content></ng-content>') }))
.createAsync(MainComp) .overrideTemplate(ChildComp, '<ng-content></ng-content>')
.then((compFixture) => { .createSync(MainComp);
let nestedChildCompEl = compFixture.debugElement.children[0].children[0]; let nestedChildCompEl = compFixture.debugElement.children[0].children[0];
let nestedChildComp: NestedChildComp = nestedChildCompEl.componentInstance; let nestedChildComp: NestedChildComp = nestedChildCompEl.componentInstance;
expect(nestedChildComp.cfr.resolveComponentFactory(ChildComp).componentType) expect(nestedChildComp.cfr.resolveComponentFactory(ChildComp).componentType)
.toBe(ChildComp); .toBe(ChildComp);
expect(() => nestedChildComp.cfr.resolveComponentFactory(NestedChildComp)) expect(() => nestedChildComp.cfr.resolveComponentFactory(NestedChildComp))
.toThrow(new NoComponentFactoryError(NestedChildComp)); .toThrow(new NoComponentFactoryError(NestedChildComp));
async.done(); }));
});
}));
}); });
} }
var DIRECTIVES: any[] = [ @Component({selector: 'nested', template: ''})
forwardRef(() => NestedChildComp),
forwardRef(() => ChildComp),
forwardRef(() => MainComp),
];
@Component({selector: 'nested', directives: DIRECTIVES, template: ''})
class NestedChildComp { class NestedChildComp {
constructor(public cfr: ComponentFactoryResolver) {} constructor(public cfr: ComponentFactoryResolver) {}
} }
@Component({selector: 'child', precompile: [NestedChildComp], directives: DIRECTIVES, template: ''}) @Component({selector: 'child', precompile: [NestedChildComp], template: ''})
class ChildComp { class ChildComp {
constructor(public cfr: ComponentFactoryResolver) {} constructor(public cfr: ComponentFactoryResolver) {}
} }
@ -101,7 +105,6 @@ class ChildComp {
@Component({ @Component({
selector: 'main', selector: 'main',
precompile: [ChildComp], precompile: [ChildComp],
directives: DIRECTIVES,
template: '', template: '',
}) })
class MainComp { class MainComp {

View File

@ -1,50 +0,0 @@
/**
* @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 {ComponentFactory} from '@angular/core/src/linker/component_factory';
import {ComponentResolver, ReflectorComponentResolver} from '@angular/core/src/linker/component_resolver';
import {ReflectionInfo, reflector} from '@angular/core/src/reflection/reflection';
import {AsyncTestCompleter, afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {Console} from '../../src/console';
class DummyConsole implements Console {
log(message: string) {}
warn(message: string) {}
}
export function main() {
describe('Compiler', () => {
var someCompFactory: any /** TODO #9100 */;
var compiler: ComponentResolver;
beforeEach(() => {
someCompFactory = new ComponentFactory(null, null, null);
reflector.registerType(SomeComponent, new ReflectionInfo([someCompFactory]));
compiler = new ReflectorComponentResolver(new DummyConsole());
});
it('should read the template from an annotation',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
compiler.resolveComponent(SomeComponent).then((compFactory: ComponentFactory<any>) => {
expect(compFactory).toBe(someCompFactory);
async.done();
return null;
});
}));
it('should throw when given a string',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
compiler.resolveComponent('someString').catch((e) => {
expect(e.message).toContain('Cannot resolve component using \'someString\'.');
async.done();
});
}));
});
}
class SomeComponent {}

View File

@ -26,7 +26,7 @@ function declareTests({useJit}: {useJit: boolean}) {
describe('platform pipes', () => { describe('platform pipes', () => {
beforeEach(() => { beforeEach(() => {
configureCompiler({useJit: useJit}); configureCompiler({useJit: useJit});
configureModule({pipes: [PlatformPipe]}); configureModule({declarations: [PlatformPipe]});
}); });
it('should overwrite them by custom pipes', it('should overwrite them by custom pipes',

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AppModule, AppModuleFactory, AppModuleMetadata, AppModuleRef, Compiler, CompilerFactory, ComponentStillLoadingError, Injector, PlatformRef, Provider, ReflectiveInjector, Type, assertPlatform, createPlatform, getPlatform} from '../index'; import {Compiler, CompilerFactory, CompilerOptions, ComponentStillLoadingError, Injector, NgModule, NgModuleFactory, NgModuleMetadata, NgModuleRef, PlatformRef, Provider, ReflectiveInjector, Type, assertPlatform, createPlatform, getPlatform} from '../index';
import {ListWrapper} from '../src/facade/collection'; import {ListWrapper} from '../src/facade/collection';
import {BaseException} from '../src/facade/exceptions'; import {BaseException} from '../src/facade/exceptions';
import {FunctionWrapper, isPresent, stringify} from '../src/facade/lang'; import {ConcreteType, FunctionWrapper, isPresent, stringify} from '../src/facade/lang';
import {AsyncTestCompleter} from './async_test_completer'; import {AsyncTestCompleter} from './async_test_completer';
@ -22,105 +22,87 @@ export class TestBed implements Injector {
private _instantiated: boolean = false; private _instantiated: boolean = false;
private _compiler: Compiler = null; private _compiler: Compiler = null;
private _moduleRef: AppModuleRef<any> = null; private _moduleRef: NgModuleRef<any> = null;
private _appModuleFactory: AppModuleFactory<any> = null; private _ngModuleFactory: NgModuleFactory<any> = null;
private _compilerProviders: Array<Type|Provider|any[]|any> = []; private _compilerOptions: CompilerOptions[] = [];
private _compilerUseJit: boolean = true;
private _providers: Array<Type|Provider|any[]|any> = []; private _providers: Array<Type|Provider|any[]|any> = [];
private _directives: Array<Type|any[]|any> = []; private _declarations: Array<Type|any[]|any> = [];
private _pipes: Array<Type|any[]|any> = []; private _imports: Array<Type|any[]|any> = [];
private _modules: Array<Type|any[]|any> = [];
private _precompile: Array<Type|any[]|any> = []; private _precompile: Array<Type|any[]|any> = [];
reset() { reset() {
this._compiler = null; this._compiler = null;
this._moduleRef = null; this._moduleRef = null;
this._appModuleFactory = null; this._ngModuleFactory = null;
this._compilerProviders = []; this._compilerOptions = [];
this._compilerUseJit = true;
this._providers = []; this._providers = [];
this._directives = []; this._declarations = [];
this._pipes = []; this._imports = [];
this._modules = [];
this._precompile = []; this._precompile = [];
this._instantiated = false; this._instantiated = false;
} }
platform: PlatformRef = null; platform: PlatformRef = null;
appModule: Type = null; ngModule: Type = null;
configureCompiler(config: {providers?: any[], useJit?: boolean}) { configureCompiler(config: {providers?: any[], useJit?: boolean}) {
if (this._instantiated) { if (this._instantiated) {
throw new BaseException('Cannot add configuration after test injector is instantiated'); throw new BaseException('Cannot add configuration after test injector is instantiated');
} }
if (config.providers) { this._compilerOptions.push(config);
this._compilerProviders = ListWrapper.concat(this._compilerProviders, config.providers);
}
if (config.useJit !== undefined) {
this._compilerUseJit = config.useJit;
}
} }
configureModule(moduleDef: { configureModule(
providers?: any[], moduleDef: {providers?: any[], declarations?: any[], imports?: any[], precompile?: any[]}) {
directives?: any[],
pipes?: any[],
precompile?: any[],
modules?: any[]
}) {
if (this._instantiated) { if (this._instantiated) {
throw new BaseException('Cannot add configuration after test injector is instantiated'); throw new BaseException('Cannot add configuration after test injector is instantiated');
} }
if (moduleDef.providers) { if (moduleDef.providers) {
this._providers = ListWrapper.concat(this._providers, moduleDef.providers); this._providers = ListWrapper.concat(this._providers, moduleDef.providers);
} }
if (moduleDef.directives) { if (moduleDef.declarations) {
this._directives = ListWrapper.concat(this._directives, moduleDef.directives); this._declarations = ListWrapper.concat(this._declarations, moduleDef.declarations);
} }
if (moduleDef.pipes) { if (moduleDef.imports) {
this._pipes = ListWrapper.concat(this._pipes, moduleDef.pipes); this._imports = ListWrapper.concat(this._imports, moduleDef.imports);
} }
if (moduleDef.precompile) { if (moduleDef.precompile) {
this._precompile = ListWrapper.concat(this._precompile, moduleDef.precompile); this._precompile = ListWrapper.concat(this._precompile, moduleDef.precompile);
} }
if (moduleDef.modules) {
this._modules = ListWrapper.concat(this._modules, moduleDef.modules);
}
} }
createAppModuleFactory(): Promise<AppModuleFactory<any>> { createModuleFactory(): Promise<NgModuleFactory<any>> {
if (this._instantiated) { if (this._instantiated) {
throw new BaseException( throw new BaseException(
'Cannot run precompilation when the test AppModule has already been instantiated. ' + 'Cannot run precompilation when the test NgModule has already been instantiated. ' +
'Make sure you are not using `inject` before `doAsyncPrecompilation`.'); 'Make sure you are not using `inject` before `doAsyncPrecompilation`.');
} }
if (this._appModuleFactory) { if (this._ngModuleFactory) {
return Promise.resolve(this._appModuleFactory); return Promise.resolve(this._ngModuleFactory);
} }
let moduleMeta = this._createCompilerAndModuleMeta(); const moduleType = this._createCompilerAndModule();
return this._compiler.compileAppModuleAsync(_NoopModule, moduleMeta) return this._compiler.compileModuleAsync(moduleType).then((ngModuleFactory) => {
.then((appModuleFactory) => { this._ngModuleFactory = ngModuleFactory;
this._appModuleFactory = appModuleFactory; return ngModuleFactory;
return appModuleFactory; });
});
} }
initTestAppModule() { initTestModule() {
if (this._instantiated) { if (this._instantiated) {
return; return;
} }
if (this._appModuleFactory) { if (this._ngModuleFactory) {
this._createFromModuleFactory(this._appModuleFactory); this._createFromModuleFactory(this._ngModuleFactory);
} else { } else {
let moduleMeta = this._createCompilerAndModuleMeta(); let moduleType = this._createCompilerAndModule();
this._createFromModuleFactory(this._compiler.compileAppModuleSync(_NoopModule, moduleMeta)); this._createFromModuleFactory(this._compiler.compileModuleSync(moduleType));
} }
} }
@ -131,31 +113,34 @@ export class TestBed implements Injector {
if (this._instantiated) { if (this._instantiated) {
return Promise.resolve(this); return Promise.resolve(this);
} }
let moduleMeta = this._createCompilerAndModuleMeta(); let ngModule = this._createCompilerAndModule();
return this._compiler.compileAppModuleAsync(_NoopModule, moduleMeta) return this._compiler.compileModuleAsync(ngModule).then(
.then((appModuleFactory) => this._createFromModuleFactory(appModuleFactory)); (ngModuleFactory) => this._createFromModuleFactory(ngModuleFactory));
} }
private _createCompilerAndModuleMeta(): AppModuleMetadata { private _createCompilerAndModule(): ConcreteType<any> {
const providers = this._providers.concat([{provide: TestBed, useValue: this}]);
const declarations = this._declarations;
const imports = [this.ngModule, this._imports];
const precompile = this._precompile;
@NgModule({
providers: providers,
declarations: declarations,
imports: imports,
precompile: precompile
})
class DynamicTestModule {
}
const compilerFactory: CompilerFactory = this.platform.injector.get(CompilerFactory); const compilerFactory: CompilerFactory = this.platform.injector.get(CompilerFactory);
this._compiler = compilerFactory.createCompiler({ this._compiler =
providers: this._compilerProviders, compilerFactory.createCompiler(this._compilerOptions.concat([{useDebug: true}]));
useJit: this._compilerUseJit, return DynamicTestModule;
deprecatedAppProviders: this._providers
});
const moduleMeta = new AppModuleMetadata({
providers: this._providers.concat([{provide: TestBed, useValue: this}]),
modules: this._modules.concat([this.appModule]),
directives: this._directives,
pipes: this._pipes,
precompile: this._precompile
});
return moduleMeta;
} }
private _createFromModuleFactory(appModuleFactory: AppModuleFactory<any>): Injector { private _createFromModuleFactory(ngModuleFactory: NgModuleFactory<any>): Injector {
this._moduleRef = appModuleFactory.create(this.platform.injector); this._moduleRef = ngModuleFactory.create(this.platform.injector);
this._instantiated = true; this._instantiated = true;
return this; return this;
} }
@ -163,13 +148,13 @@ export class TestBed implements Injector {
get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND) { get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND) {
if (!this._instantiated) { if (!this._instantiated) {
throw new BaseException( throw new BaseException(
'Illegal state: The test bed\'s injector has not yet been created. Call initTestAppModule first!'); 'Illegal state: The test bed\'s injector has not yet been created. Call initTestNgModule first!');
} }
if (token === TestBed) { if (token === TestBed) {
return this; return this;
} }
// Tests can inject things from the app module and from the compiler, // Tests can inject things from the ng module and from the compiler,
// but the app module can't inject things from the compiler and vice versa. // but the ng module can't inject things from the compiler and vice versa.
let result = this._moduleRef.injector.get(token, UNDEFINED); let result = this._moduleRef.injector.get(token, UNDEFINED);
return result === UNDEFINED ? this._compiler.injector.get(token, notFoundValue) : result; return result === UNDEFINED ? this._compiler.injector.get(token, notFoundValue) : result;
} }
@ -177,7 +162,7 @@ export class TestBed implements Injector {
execute(tokens: any[], fn: Function): any { execute(tokens: any[], fn: Function): any {
if (!this._instantiated) { if (!this._instantiated) {
throw new BaseException( throw new BaseException(
'Illegal state: The test bed\'s injector has not yet been created. Call initTestAppModule first!'); 'Illegal state: The test bed\'s injector has not yet been created. Call initTestNgModule first!');
} }
var params = tokens.map(t => this.get(t)); var params = tokens.map(t => this.get(t));
return FunctionWrapper.apply(fn, params); return FunctionWrapper.apply(fn, params);
@ -219,20 +204,17 @@ export function getTestInjector() {
export function setBaseTestProviders( export function setBaseTestProviders(
platformProviders: Array<Type|Provider|any[]>, platformProviders: Array<Type|Provider|any[]>,
applicationProviders: Array<Type|Provider|any[]>) { applicationProviders: Array<Type|Provider|any[]>) {
// Create a platform based on the Platform Providers. if (platformProviders.length === 1 && typeof platformProviders[0] === 'function') {
var platformRef = createPlatform(ReflectiveInjector.resolveAndCreate(platformProviders)); (<any>platformProviders[0])(applicationProviders);
} else {
// Create an AppModule based on the application providers. throw new Error(
@AppModule({providers: applicationProviders}) `setBaseTestProviders is deprecated and only supports platformProviders that are predefined by Angular. Use 'initTestEnvironment' instead.`);
class TestAppModule {
} }
initTestEnvironment(TestAppModule, platformRef);
} }
/** /**
* Initialize the environment for testing with a compiler factory, a PlatformRef, and an * Initialize the environment for testing with a compiler factory, a PlatformRef, and an
* application module. These are common to every test in the suite. * angular module. These are common to every test in the suite.
* *
* This may only be called once, to set up the common providers for the current test * This may only be called once, to set up the common providers for the current test
* suite on the current platform. If you absolutely need to change the providers, * suite on the current platform. If you absolutely need to change the providers,
@ -243,13 +225,15 @@ export function setBaseTestProviders(
* *
* @experimental * @experimental
*/ */
export function initTestEnvironment(appModule: Type, platform: PlatformRef) { export function initTestEnvironment(ngModule: Type, platform: PlatformRef): Injector {
var testBed = getTestBed(); var testBed = getTestBed();
if (testBed.platform || testBed.appModule) { if (testBed.platform || testBed.ngModule) {
throw new BaseException('Cannot set base providers because it has already been called'); throw new BaseException('Cannot set base providers because it has already been called');
} }
testBed.platform = platform; testBed.platform = platform;
testBed.appModule = appModule; testBed.ngModule = ngModule;
return testBed;
} }
/** /**
@ -269,20 +253,20 @@ export function resetBaseTestProviders() {
export function resetTestEnvironment() { export function resetTestEnvironment() {
var testBed = getTestBed(); var testBed = getTestBed();
testBed.platform = null; testBed.platform = null;
testBed.appModule = null; testBed.ngModule = null;
testBed.reset(); testBed.reset();
} }
/** /**
* Run asynchronous precompilation for the test's AppModule. It is necessary to call this function * Run asynchronous precompilation for the test's NgModule. It is necessary to call this function
* if your test is using an AppModule which has precompiled components that require an asynchronous * if your test is using an NgModule which has precompiled components that require an asynchronous
* call, such as an XHR. Should be called once before the test case. * call, such as an XHR. Should be called once before the test case.
* *
* @experimental * @experimental
*/ */
export function doAsyncPrecompilation(): Promise<any> { export function doAsyncPrecompilation(): Promise<any> {
let testBed = getTestBed(); let testBed = getTestBed();
return testBed.createAppModuleFactory(); return testBed.createModuleFactory();
} }
/** /**
@ -324,7 +308,7 @@ export function inject(tokens: any[], fn: Function): () => any {
} else { } else {
return () => { return () => {
try { try {
testBed.initTestAppModule(); testBed.initTestModule();
} catch (e) { } catch (e) {
if (e instanceof ComponentStillLoadingError) { if (e instanceof ComponentStillLoadingError) {
throw new Error( throw new Error(
@ -343,13 +327,9 @@ export function inject(tokens: any[], fn: Function): () => any {
* @experimental * @experimental
*/ */
export class InjectSetupWrapper { export class InjectSetupWrapper {
constructor(private _moduleDef: () => { constructor(
providers?: any[], private _moduleDef:
directives?: any[], () => {providers?: any[], declarations?: any[], imports?: any[], precompile?: any[]}) {}
pipes?: any[],
precompile?: any[],
modules?: any[]
}) {}
private _addModule() { private _addModule() {
var moduleDef = this._moduleDef(); var moduleDef = this._moduleDef();
@ -378,12 +358,9 @@ export function withProviders(providers: () => any) {
*/ */
export function withModule(moduleDef: () => { export function withModule(moduleDef: () => {
providers?: any[], providers?: any[],
directives?: any[], declarations?: any[],
pipes?: any[], imports?: any[],
precompile?: any[], precompile?: any[]
modules?: any[]
}) { }) {
return new InjectSetupWrapper(moduleDef); return new InjectSetupWrapper(moduleDef);
} }
class _NoopModule {}

View File

@ -119,25 +119,27 @@ export class TestComponentBuilder {
/** /**
* Builds and returns a ComponentFixture. * Builds and returns a ComponentFixture.
*/ */
createAsync<T>(rootComponentType: ConcreteType<T>): Promise<ComponentFixture<T>> { createAsync<T>(rootComponentType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
Promise<ComponentFixture<T>> {
let noNgZone = IS_DART || this._injector.get(ComponentFixtureNoNgZone, false); let noNgZone = IS_DART || this._injector.get(ComponentFixtureNoNgZone, false);
let ngZone: NgZone = noNgZone ? null : this._injector.get(NgZone, null); let ngZone: NgZone = noNgZone ? null : this._injector.get(NgZone, null);
let compiler: Compiler = this._injector.get(Compiler); let compiler: Compiler = this._injector.get(Compiler);
let initComponent = () => { let initComponent = () => {
let promise: Promise<ComponentFactory<any>> = let promise: Promise<ComponentFactory<any>> =
compiler.compileComponentAsync(rootComponentType); compiler.compileComponentAsync(rootComponentType, ngModule);
return promise.then(componentFactory => this.createFromFactory(ngZone, componentFactory)); return promise.then(componentFactory => this.createFromFactory(ngZone, componentFactory));
}; };
return ngZone == null ? initComponent() : ngZone.run(initComponent); return ngZone == null ? initComponent() : ngZone.run(initComponent);
} }
createFakeAsync<T>(rootComponentType: ConcreteType<T>): ComponentFixture<T> { createFakeAsync<T>(rootComponentType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
ComponentFixture<T> {
let result: any /** TODO #9100 */; let result: any /** TODO #9100 */;
let error: any /** TODO #9100 */; let error: any /** TODO #9100 */;
PromiseWrapper.then( PromiseWrapper.then(
this.createAsync(rootComponentType), (_result) => { result = _result; }, this.createAsync(rootComponentType, ngModule), (_result) => { result = _result; },
(_error) => { error = _error; }); (_error) => { error = _error; });
tick(); tick();
if (isPresent(error)) { if (isPresent(error)) {
@ -146,14 +148,15 @@ export class TestComponentBuilder {
return result; return result;
} }
createSync<T>(rootComponentType: ConcreteType<T>): ComponentFixture<T> { createSync<T>(rootComponentType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
ComponentFixture<T> {
let noNgZone = IS_DART || this._injector.get(ComponentFixtureNoNgZone, false); let noNgZone = IS_DART || this._injector.get(ComponentFixtureNoNgZone, false);
let ngZone: NgZone = noNgZone ? null : this._injector.get(NgZone, null); let ngZone: NgZone = noNgZone ? null : this._injector.get(NgZone, null);
let compiler: Compiler = this._injector.get(Compiler); let compiler: Compiler = this._injector.get(Compiler);
let initComponent = () => { let initComponent = () => {
return this.createFromFactory( return this.createFromFactory(
ngZone, this._injector.get(Compiler).compileComponentSync(rootComponentType)); ngZone, compiler.compileComponentSync(rootComponentType, ngModule));
}; };
return ngZone == null ? initComponent() : ngZone.run(initComponent); return ngZone == null ? initComponent() : ngZone.run(initComponent);

View File

@ -49,13 +49,9 @@ export function addProviders(providers: Array<any>): void {
* *
* @stable * @stable
*/ */
export function configureModule(moduleDef: { export function configureModule(
providers?: any[], moduleDef: {providers?: any[], declarations?: any[], imports?: any[], precompile?: any[]}):
directives?: any[], void {
pipes?: any[],
precompile?: any[],
modules?: any[]
}): void {
if (!moduleDef) return; if (!moduleDef) return;
try { try {
testBed.configureModule(moduleDef); testBed.configureModule(moduleDef);

View File

@ -6,8 +6,9 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Component, ReflectiveInjector, coreLoadAndBootstrap, createPlatform} from '@angular/core'; import {Component, ReflectiveInjector, bootstrapModule, createPlatformFactory} from '@angular/core';
import {BROWSER_APP_PROVIDERS, BROWSER_PLATFORM_PROVIDERS} from '@angular/platform-browser'; import {BrowserModule} from '@angular/platform-browser';
import {browserDynamicPlatform} from '@angular/platform-browser-dynamic';
var appProviders: any[] = []; var appProviders: any[] = [];
@ -16,8 +17,6 @@ var appProviders: any[] = [];
class MyApp { class MyApp {
} }
var platform = createPlatform(ReflectiveInjector.resolveAndCreate(BROWSER_PLATFORM_PROVIDERS)); var myPlatformFactory = createPlatformFactory(browserDynamicPlatform, 'myPlatform');
var appInjector = bootstrapModule(MyApp, myPlatformFactory());
ReflectiveInjector.resolveAndCreate([BROWSER_APP_PROVIDERS, appProviders], platform.injector);
coreLoadAndBootstrap(MyApp, appInjector);
// #enddocregion // #enddocregion

View File

@ -155,12 +155,12 @@ export function stringify(token: any): string {
return '' + token; return '' + token;
} }
if (token.name) {
return token.name;
}
if (token.overriddenName) { if (token.overriddenName) {
return token.overriddenName; return token.overriddenName;
} }
if (token.name) {
return token.name;
}
var res = token.toString(); var res = token.toString();
var newLineIndex = res.indexOf('\n'); var newLineIndex = res.indexOf('\n');

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Type} from '@angular/core'; import {NgModule, Type} from '@angular/core';
import {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor'; import {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
import {DefaultValueAccessor} from './directives/default_value_accessor'; import {DefaultValueAccessor} from './directives/default_value_accessor';
@ -83,3 +83,10 @@ export const FORM_DIRECTIVES: Type[][] =
export const REACTIVE_FORM_DIRECTIVES: Type[][] = export const REACTIVE_FORM_DIRECTIVES: Type[][] =
/*@ts2dart_const*/[REACTIVE_DRIVEN_DIRECTIVES, SHARED_FORM_DIRECTIVES]; /*@ts2dart_const*/[REACTIVE_DRIVEN_DIRECTIVES, SHARED_FORM_DIRECTIVES];
/**
* Internal module used for sharing directives between FormsModule and ReactiveFormsModule
*/
@NgModule({declarations: SHARED_FORM_DIRECTIVES, exports: SHARED_FORM_DIRECTIVES})
export class InternalFormsSharedModule {
}

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AppModule, PLATFORM_DIRECTIVES, Type} from '@angular/core'; import {NgModule, PLATFORM_DIRECTIVES, Type} from '@angular/core';
import {FORM_DIRECTIVES, REACTIVE_FORM_DIRECTIVES} from './directives'; import {FORM_DIRECTIVES, InternalFormsSharedModule, REACTIVE_DRIVEN_DIRECTIVES, REACTIVE_FORM_DIRECTIVES, SHARED_FORM_DIRECTIVES, TEMPLATE_DRIVEN_DIRECTIVES} from './directives';
import {RadioControlRegistry} from './directives/radio_control_value_accessor'; import {RadioControlRegistry} from './directives/radio_control_value_accessor';
import {FormBuilder} from './form_builder'; import {FormBuilder} from './form_builder';
@ -28,18 +28,26 @@ export const REACTIVE_FORM_PROVIDERS: Type[] =
/*@ts2dart_const*/[FormBuilder, RadioControlRegistry]; /*@ts2dart_const*/[FormBuilder, RadioControlRegistry];
/** /**
* The app module for forms. * The ng module for forms.
* @experimental * @experimental
*/ */
@AppModule({providers: [FORM_PROVIDERS], directives: FORM_DIRECTIVES, pipes: []}) @NgModule({
declarations: TEMPLATE_DRIVEN_DIRECTIVES,
providers: [FORM_PROVIDERS],
exports: [InternalFormsSharedModule, TEMPLATE_DRIVEN_DIRECTIVES]
})
export class FormsModule { export class FormsModule {
} }
/** /**
* The app module for reactive forms. * The ng module for reactive forms.
* @experimental * @experimental
*/ */
@AppModule({providers: [REACTIVE_FORM_PROVIDERS], directives: REACTIVE_FORM_DIRECTIVES, pipes: []}) @NgModule({
declarations: [REACTIVE_DRIVEN_DIRECTIVES],
providers: [REACTIVE_FORM_PROVIDERS],
exports: [InternalFormsSharedModule, REACTIVE_DRIVEN_DIRECTIVES]
})
export class ReactiveFormsModule { export class ReactiveFormsModule {
} }
@ -57,4 +65,4 @@ export function provideForms(): any[] {
return [ return [
{provide: PLATFORM_DIRECTIVES, useValue: FORM_DIRECTIVES, multi: true}, REACTIVE_FORM_PROVIDERS {provide: PLATFORM_DIRECTIVES, useValue: FORM_DIRECTIVES, multi: true}, REACTIVE_FORM_PROVIDERS
]; ];
} }

View File

@ -22,7 +22,7 @@ import {PromiseWrapper} from '../src/facade/promise';
export function main() { export function main() {
describe('reactive forms integration tests', () => { describe('reactive forms integration tests', () => {
beforeEach(() => { configureModule({modules: [FormsModule, ReactiveFormsModule]}); }); beforeEach(() => { configureModule({imports: [FormsModule, ReactiveFormsModule]}); });
it('should initialize DOM elements with the given form object', it('should initialize DOM elements with the given form object',
inject( inject(

View File

@ -20,7 +20,7 @@ import {ListWrapper} from '../src/facade/collection';
export function main() { export function main() {
describe('template-driven forms integration tests', () => { describe('template-driven forms integration tests', () => {
beforeEach(() => { configureModule({modules: [FormsModule]}); }); beforeEach(() => { configureModule({imports: [FormsModule]}); });
it('should support ngModel for single fields', it('should support ngModel for single fields',
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {

View File

@ -6,37 +6,24 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {COMMON_DIRECTIVES, COMMON_PIPES} from '@angular/common'; import {XHR, analyzeAppProvidersForDeprecatedConfiguration, coreDynamicPlatform} from '@angular/compiler';
import {COMPILER_PROVIDERS, CompilerConfig, XHR, RUNTIME_COMPILER_FACTORY,} from '@angular/compiler'; import {ApplicationRef, Compiler, CompilerFactory, CompilerOptions, ComponentRef, ComponentResolver, ExceptionHandler, NgModule, NgModuleRef, OpaqueToken, PLATFORM_DIRECTIVES, PLATFORM_INITIALIZER, PLATFORM_PIPES, PlatformRef, ReflectiveInjector, Type, assertPlatform, bootstrapModule, bootstrapModuleFactory, createPlatform, createPlatformFactory, getPlatform, isDevMode} from '@angular/core';
import {AppModule, AppModuleRef, ApplicationRef, Compiler, ComponentRef, ComponentResolver, ExceptionHandler, PLATFORM_DIRECTIVES, PLATFORM_PIPES, ReflectiveInjector, Type, coreLoadAndBootstrap, bootstrapModule, bootstrapModuleFactory, isDevMode, OpaqueToken, PlatformRef, getPlatform, assertPlatform, createPlatform, PLATFORM_INITIALIZER, CompilerOptions, CompilerFactory, createPlatformFactory} from '@angular/core'; import {BROWSER_PLATFORM_PROVIDERS, BrowserModule, WORKER_APP_PLATFORM_PROVIDERS, WORKER_SCRIPT, WorkerAppModule, browserPlatform, workerAppPlatform, workerUiPlatform} from '@angular/platform-browser';
import {BROWSER_APP_PROVIDERS, BrowserModule, WORKER_APP_APPLICATION_PROVIDERS, WORKER_SCRIPT, WORKER_UI_APPLICATION_PROVIDERS, browserPlatform, workerAppPlatform, workerUiPlatform, BROWSER_PLATFORM_PROVIDERS} from '@angular/platform-browser';
import {Console, ReflectionCapabilities, reflector} from './core_private'; import {Console} from './core_private';
import {getDOM, initDomAdapter} from './platform_browser_private';
import {PromiseWrapper} from './src/facade/async'; import {PromiseWrapper} from './src/facade/async';
import {ConcreteType, isPresent, stringify} from './src/facade/lang'; import {ConcreteType, isPresent, stringify} from './src/facade/lang';
import {INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS} from './src/platform_providers';
import {CachedXHR} from './src/xhr/xhr_cache'; import {CachedXHR} from './src/xhr/xhr_cache';
import {XHRImpl} from './src/xhr/xhr_impl'; import {XHRImpl} from './src/xhr/xhr_impl';
/** /**
* @deprecated The compiler providers are already included in the {@link CompilerFactory} that is * @deprecated The compiler providers are already included in the {@link CompilerFactory} that is
* contained the {@link browserDynamicPlatform}()`. * contained the {@link browserDynamicPlatform}()`.
*/ */
export const BROWSER_APP_COMPILER_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [ export const BROWSER_APP_COMPILER_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [];
COMPILER_PROVIDERS, {
provide: CompilerConfig,
useFactory: (platformDirectives: any[], platformPipes: any[]) => {
return new CompilerConfig({
deprecatedPlatformDirectives: platformDirectives,
deprecatedPlatformPipes: platformPipes
});
},
deps: [PLATFORM_DIRECTIVES, PLATFORM_PIPES]
},
{provide: XHR, useClass: XHRImpl},
{provide: PLATFORM_DIRECTIVES, useValue: COMMON_DIRECTIVES, multi: true},
{provide: PLATFORM_PIPES, useValue: COMMON_PIPES, multi: true}
];
/** /**
* @experimental * @experimental
@ -44,34 +31,11 @@ export const BROWSER_APP_COMPILER_PROVIDERS: Array<any /*Type | Provider | any[]
export const CACHED_TEMPLATE_PROVIDER: Array<any /*Type | Provider | any[]*/> = export const CACHED_TEMPLATE_PROVIDER: Array<any /*Type | Provider | any[]*/> =
[{provide: XHR, useClass: CachedXHR}]; [{provide: XHR, useClass: CachedXHR}];
function initReflector() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
}
/**
* CompilerFactory for the browser dynamic platform
*
* @experimental
*/
export const BROWSER_DYNAMIC_COMPILER_FACTORY =
RUNTIME_COMPILER_FACTORY.withDefaults({providers: [{provide: XHR, useClass: XHRImpl}]});
/**
* Providers for the browser dynamic platform
*
* @experimental
*/
export const BROWSER_DYNAMIC_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [
BROWSER_PLATFORM_PROVIDERS,
{provide: CompilerFactory, useValue: BROWSER_DYNAMIC_COMPILER_FACTORY},
{provide: PLATFORM_INITIALIZER, useValue: initReflector, multi: true},
];
/** /**
* @experimental API related to bootstrapping are still under review. * @experimental API related to bootstrapping are still under review.
*/ */
export const browserDynamicPlatform = export const browserDynamicPlatform = createPlatformFactory(
createPlatformFactory('browserDynamic', BROWSER_DYNAMIC_PLATFORM_PROVIDERS); coreDynamicPlatform, 'browserDynamic', INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS);
/** /**
* Bootstrapping for Angular applications. * Bootstrapping for Angular applications.
@ -142,8 +106,9 @@ export const browserDynamicPlatform =
* ## API (version 2) * ## API (version 2)
* - `appComponentType`: The root component which should act as the application. This is * - `appComponentType`: The root component which should act as the application. This is
* a reference to a `Type` which is annotated with `@Component(...)`. * a reference to a `Type` which is annotated with `@Component(...)`.
* - `providers`, `directives`, `pipes`, `modules`, `precompile`: Defines the properties * - `providers`, `declarations`, `imports`, `precompile`: Defines the properties
* of the dynamically created module that is used to bootstrap the module. * of the dynamically created module that is used to bootstrap the module.
* - to configure the compiler, use the `compilerOptions` parameter.
* *
* Returns a `Promise` of {@link ComponentRef}. * Returns a `Promise` of {@link ComponentRef}.
* *
@ -156,11 +121,10 @@ export function bootstrap<C>(
customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ComponentRef<C>>; customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ComponentRef<C>>;
export function bootstrap<C>( export function bootstrap<C>(
appComponentType: ConcreteType<C>, appComponentType: ConcreteType<C>,
{providers, directives, pipes, modules, precompile, compilerOptions}?: { {providers, imports, declarations, precompile, compilerOptions}?: {
providers?: Array<any /*Type | Provider | any[]*/>, providers?: Array<any /*Type | Provider | any[]*/>,
directives?: any[], declarations?: any[],
pipes?: any[], imports?: any[],
modules?: any[],
precompile?: any[], precompile?: any[],
compilerOptions?: CompilerOptions compilerOptions?: CompilerOptions
}): Promise<ComponentRef<C>>; }): Promise<ComponentRef<C>>;
@ -168,112 +132,107 @@ export function bootstrap<C>(
appComponentType: ConcreteType<C>, appComponentType: ConcreteType<C>,
customProvidersOrDynamicModule?: Array<any /*Type | Provider | any[]*/>| { customProvidersOrDynamicModule?: Array<any /*Type | Provider | any[]*/>| {
providers: Array<any /*Type | Provider | any[]*/>, providers: Array<any /*Type | Provider | any[]*/>,
directives: any[], declarations?: any[],
pipes: any[], imports: any[],
modules: any[],
precompile: any[], precompile: any[],
compilerOptions: CompilerOptions compilerOptions: CompilerOptions
}): Promise<ComponentRef<C>> { }): Promise<ComponentRef<C>> {
let compilerOptions: CompilerOptions; let compilerOptions: CompilerOptions;
let compilerProviders: any = [];
let providers: any[] = []; let providers: any[] = [];
let directives: any[] = []; let declarations: any[] = [];
let pipes: any[] = []; let imports: any[] = [];
let modules: any[] = [];
let precompile: any[] = []; let precompile: any[] = [];
let deprecationMessages: string[] = [];
if (customProvidersOrDynamicModule instanceof Array) { if (customProvidersOrDynamicModule instanceof Array) {
providers = customProvidersOrDynamicModule; providers = customProvidersOrDynamicModule;
const deprecatedConfiguration = analyzeAppProvidersForDeprecatedConfiguration(providers);
declarations = deprecatedConfiguration.moduleDeclarations.concat(declarations);
compilerOptions = deprecatedConfiguration.compilerOptions;
deprecationMessages = deprecatedConfiguration.deprecationMessages;
} else if (customProvidersOrDynamicModule) { } else if (customProvidersOrDynamicModule) {
providers = normalizeArray(customProvidersOrDynamicModule.providers); providers = normalizeArray(customProvidersOrDynamicModule.providers);
directives = normalizeArray(customProvidersOrDynamicModule.directives); declarations = normalizeArray(customProvidersOrDynamicModule.declarations);
pipes = normalizeArray(customProvidersOrDynamicModule.pipes); imports = normalizeArray(customProvidersOrDynamicModule.imports);
modules = normalizeArray(customProvidersOrDynamicModule.modules);
precompile = normalizeArray(customProvidersOrDynamicModule.precompile); precompile = normalizeArray(customProvidersOrDynamicModule.precompile);
compilerOptions = customProvidersOrDynamicModule.compilerOptions; compilerOptions = customProvidersOrDynamicModule.compilerOptions;
} }
@AppModule({ @NgModule({
providers: providers, providers: providers,
modules: modules.concat([BrowserModule]), declarations: declarations.concat([appComponentType]),
directives: directives, imports: [BrowserModule, imports],
pipes: pipes,
precompile: precompile.concat([appComponentType]) precompile: precompile.concat([appComponentType])
}) })
class DynamicModule { class DynamicModule {
} }
return bootstrapModule( return bootstrapModule(DynamicModule, browserDynamicPlatform(), compilerOptions)
DynamicModule, browserDynamicPlatform(),
CompilerFactory.mergeOptions(compilerOptions, {deprecatedAppProviders: providers}))
.then((moduleRef) => { .then((moduleRef) => {
const console = moduleRef.injector.get(Console);
deprecationMessages.forEach((msg) => console.warn(msg));
const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef); const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
return appRef.bootstrap(appComponentType); return appRef.bootstrap(appComponentType);
}); });
} }
/** /**
* @deprecated Create an {@link AppModule} that includes the {@link WorkerUiModule} and use {@link * Bootstraps the worker ui.
* bootstrapModule} *
* with the {@link workerUiPlatform}() instead. * @experimental
*/ */
export function bootstrapWorkerUi( export function bootstrapWorkerUi(
workerScriptUri: string, workerScriptUri: string,
customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ApplicationRef> { customProviders: Array<any /*Type | Provider | any[]*/> = []): Promise<PlatformRef> {
console.warn( // For now, just creates the worker ui platform...
'bootstrapWorkerUi is deprecated. Create an @AppModule that includes the `WorkerUiModule` and use `bootstrapModule` with the `workerUiPlatform()` instead.'); return Promise.resolve(workerUiPlatform([{
var app = ReflectiveInjector.resolveAndCreate( provide: WORKER_SCRIPT,
[ useValue: workerScriptUri,
WORKER_UI_APPLICATION_PROVIDERS, BROWSER_APP_COMPILER_PROVIDERS, }].concat(customProviders)));
{provide: WORKER_SCRIPT, useValue: workerScriptUri},
isPresent(customProviders) ? customProviders : []
],
workerUiPlatform().injector);
// Return a promise so that we keep the same semantics as Dart,
// and we might want to wait for the app side to come up
// in the future...
return PromiseWrapper.resolve(app.get(ApplicationRef));
} }
/** /**
* @deprecated The compiler providers are already included in the {@link CompilerFactory} that is * @experimental API related to bootstrapping are still under review.
* contained the {@link workerAppPlatform}().
*/ */
const WORKER_APP_COMPILER_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [ export const workerAppDynamicPlatform =
COMPILER_PROVIDERS, { createPlatformFactory(coreDynamicPlatform, 'workerAppDynamic', [{
provide: CompilerConfig, provide: CompilerOptions,
useFactory: (platformDirectives: any[], platformPipes: any[]) => { useValue: {providers: [{provide: XHR, useClass: XHRImpl}]},
return new CompilerConfig({ multi: true
deprecatedPlatformDirectives: platformDirectives, }]);
deprecatedPlatformPipes: platformPipes
});
},
deps: [PLATFORM_DIRECTIVES, PLATFORM_PIPES]
},
{provide: XHR, useClass: XHRImpl},
{provide: PLATFORM_DIRECTIVES, useValue: COMMON_DIRECTIVES, multi: true},
{provide: PLATFORM_PIPES, useValue: COMMON_PIPES, multi: true}
];
/** /**
* @deprecated Create an {@link AppModule} that includes the {@link WorkerAppModule} and use {@link * @deprecated Create an {@link NgModule} that includes the {@link WorkerAppModule} and use {@link
* bootstrapModule} * bootstrapModule}
* with the {@link workerAppPlatform}() instead. * with the {@link workerAppDynamicPlatform}() instead.
*/ */
export function bootstrapWorkerApp( export function bootstrapWorkerApp<T>(
appComponentType: Type, appComponentType: ConcreteType<T>,
customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ComponentRef<any>> { customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ComponentRef<T>> {
console.warn( console.warn(
'bootstrapWorkerApp is deprecated. Create an @AppModule that includes the `WorkerAppModule` and use `bootstrapModule` with the `workerAppPlatform()` instead.'); 'bootstrapWorkerApp is deprecated. Create an @NgModule that includes the `WorkerAppModule` and use `bootstrapModule` with the `workerAppDynamicPlatform()` instead.');
var appInjector = ReflectiveInjector.resolveAndCreate(
[ const deprecatedConfiguration = analyzeAppProvidersForDeprecatedConfiguration(customProviders);
WORKER_APP_APPLICATION_PROVIDERS, WORKER_APP_COMPILER_PROVIDERS, const declarations = [deprecatedConfiguration.moduleDeclarations.concat([appComponentType])];
isPresent(customProviders) ? customProviders : []
], @NgModule({
workerAppPlatform().injector); providers: customProviders,
return coreLoadAndBootstrap(appComponentType, appInjector); declarations: declarations,
imports: [WorkerAppModule],
precompile: [appComponentType]
})
class DynamicModule {
}
return bootstrapModule(
DynamicModule, workerAppDynamicPlatform(), deprecatedConfiguration.compilerOptions)
.then((moduleRef) => {
const console = moduleRef.injector.get(Console);
deprecatedConfiguration.deprecationMessages.forEach((msg) => console.warn(msg));
const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
return appRef.bootstrap(appComponentType);
});
} }
function normalizeArray(arr: any[]): any[] { function normalizeArray(arr: any[]): any[] {
return arr ? arr : []; return arr ? arr : [];
} }

View File

@ -8,5 +8,6 @@
import {__platform_browser_private__ as r, __platform_browser_private__ as t} from '@angular/platform-browser'; import {__platform_browser_private__ as r, __platform_browser_private__ as t} from '@angular/platform-browser';
export var INTERNAL_BROWSER_PLATFORM_PROVIDERS: typeof t.INTERNAL_BROWSER_PLATFORM_PROVIDERS =
r.INTERNAL_BROWSER_PLATFORM_PROVIDERS;
export var getDOM: typeof t.getDOM = r.getDOM; export var getDOM: typeof t.getDOM = r.getDOM;
export var initDomAdapter: typeof t.initDomAdapter = r.initDomAdapter;

View File

@ -0,0 +1,23 @@
/**
* @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 {XHR} from '@angular/compiler';
import {CompilerOptions} from '@angular/core';
import {INTERNAL_BROWSER_PLATFORM_PROVIDERS} from '../platform_browser_private';
import {XHRImpl} from './xhr/xhr_impl';
export const INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS: any[] = [
INTERNAL_BROWSER_PLATFORM_PROVIDERS,
{
provide: CompilerOptions,
useValue: {providers: [{provide: XHR, useClass: XHRImpl}]},
multi: true
},
];

View File

@ -6,90 +6,70 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {COMMON_DIRECTIVES, COMMON_PIPES} from '@angular/common'; import {CompilerConfig, DirectiveResolver, NgModuleResolver, ViewResolver, analyzeAppProvidersForDeprecatedConfiguration} from '@angular/compiler';
import {CompilerConfig, DirectiveResolver, ViewResolver} from '@angular/compiler'; import {OverridingTestComponentBuilder, coreDynamicTestingPlatform} from '@angular/compiler/testing';
import {MockDirectiveResolver, MockViewResolver, OverridingTestComponentBuilder} from '@angular/compiler/testing'; import {Compiler, CompilerFactory, CompilerOptions, NgModule, PlatformRef, Provider, ReflectiveInjector, Type, createPlatform, createPlatformFactory} from '@angular/core';
import {AppModule, Compiler, CompilerFactory, PLATFORM_DIRECTIVES, PLATFORM_PIPES, PlatformRef, Provider, ReflectiveInjector, Type, createPlatformFactory} from '@angular/core'; import {TestComponentBuilder, TestComponentRenderer, initTestEnvironment} from '@angular/core/testing';
import {TestComponentBuilder, TestComponentRenderer} from '@angular/core/testing'; import {BrowserTestingModule, browserTestingPlatform} from '@angular/platform-browser/testing';
import {BrowserTestModule, TEST_BROWSER_APPLICATION_PROVIDERS, TEST_BROWSER_PLATFORM_PROVIDERS} from '@angular/platform-browser/testing';
import {BROWSER_APP_COMPILER_PROVIDERS, BROWSER_DYNAMIC_COMPILER_FACTORY, BROWSER_DYNAMIC_PLATFORM_PROVIDERS} from './index'; import {Console} from './core_private';
import {browserDynamicPlatform} from './index';
import {INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS} from './src/platform_providers';
import {DOMTestComponentRenderer} from './testing/dom_test_component_renderer'; import {DOMTestComponentRenderer} from './testing/dom_test_component_renderer';
export * from './private_export_testing' export * from './private_export_testing'
/**
* CompilerFactory for browser dynamic test platform
*
* @experimental
*/
export const BROWSER_DYNAMIC_TEST_COMPILER_FACTORY = BROWSER_DYNAMIC_COMPILER_FACTORY.withDefaults({
providers: [
{provide: DirectiveResolver, useClass: MockDirectiveResolver},
{provide: ViewResolver, useClass: MockViewResolver}
]
});
/**
* Providers for the browser dynamic platform
*
* @experimental
*/
const BROWSER_DYNAMIC_TEST_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [
TEST_BROWSER_PLATFORM_PROVIDERS,
BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
{provide: CompilerFactory, useValue: BROWSER_DYNAMIC_TEST_COMPILER_FACTORY},
];
/** /**
* @experimental API related to bootstrapping are still under review. * @experimental API related to bootstrapping are still under review.
*/ */
export const browserDynamicTestPlatform = export const browserDynamicTestingPlatform = createPlatformFactory(
createPlatformFactory('browserDynamicTest', BROWSER_DYNAMIC_TEST_PLATFORM_PROVIDERS); coreDynamicTestingPlatform, 'browserDynamicTesting',
INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS);
/** /**
* AppModule for testing. * NgModule for testing.
* *
* @stable * @stable
*/ */
@AppModule({ @NgModule({
modules: [BrowserTestModule], exports: [BrowserTestingModule],
providers: [ providers: [
{provide: TestComponentBuilder, useClass: OverridingTestComponentBuilder}, {provide: TestComponentBuilder, useClass: OverridingTestComponentBuilder},
{provide: TestComponentRenderer, useClass: DOMTestComponentRenderer}, {provide: TestComponentRenderer, useClass: DOMTestComponentRenderer},
] ]
}) })
export class BrowserDynamicTestModule { export class BrowserDynamicTestingModule {
} }
// Used only as a shim until TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS is deprecated. /**
const BROWSER_DYNAMIC_TEST_COMPILER_FACTORY_OLD = BROWSER_DYNAMIC_COMPILER_FACTORY.withDefaults({ * @deprecated Use initTestEnvironment with browserDynamicTestingPlatform instead.
providers: [ */
{provide: DirectiveResolver, useClass: MockDirectiveResolver}, export const TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
{provide: ViewResolver, useClass: MockViewResolver} // Note: This is not a real provider but a hack to still support the deprecated
], // `setBaseTestProviders` method!
deprecatedAppProviders: [ [(appProviders: any[]) => {
{provide: PLATFORM_DIRECTIVES, useValue: COMMON_DIRECTIVES, multi: true}, const deprecatedConfiguration = analyzeAppProvidersForDeprecatedConfiguration(appProviders);
{provide: PLATFORM_PIPES, useValue: COMMON_PIPES, multi: true} const platformRef =
] createPlatformFactory(browserDynamicTestingPlatform, 'browserDynamicTestingDeprecated', [{
}); provide: CompilerOptions,
useValue: deprecatedConfiguration.compilerOptions,
multi: true
}])();
@NgModule({
exports: [BrowserDynamicTestingModule],
declarations: [deprecatedConfiguration.moduleDeclarations]
})
class DynamicTestModule {
}
const testInjector = initTestEnvironment(DynamicTestModule, platformRef);
const console: Console = testInjector.get(Console);
deprecatedConfiguration.deprecationMessages.forEach((msg) => console.warn(msg));
}];
/** /**
* @deprecated Use initTestEnvironment with browserDynamicTestPlatform instead. * @deprecated Use initTestEnvironment with BrowserDynamicTestingModule instead.
*/ */
export const TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [ export const TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
TEST_BROWSER_PLATFORM_PROVIDERS, [];
BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
{provide: CompilerFactory, useValue: BROWSER_DYNAMIC_TEST_COMPILER_FACTORY_OLD},
];
/**
* @deprecated Use initTestEnvironment with BrowserDynamicTestModule instead.
*/
export const TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [
TEST_BROWSER_APPLICATION_PROVIDERS,
{provide: TestComponentBuilder, useClass: OverridingTestComponentBuilder},
{provide: TestComponentRenderer, useClass: DOMTestComponentRenderer},
];

View File

@ -42,5 +42,6 @@ export var __platform_browser_private__ = {
SharedStylesHost: shared_styles_host.SharedStylesHost, SharedStylesHost: shared_styles_host.SharedStylesHost,
ELEMENT_PROBE_PROVIDERS: ng_proble.ELEMENT_PROBE_PROVIDERS, ELEMENT_PROBE_PROVIDERS: ng_proble.ELEMENT_PROBE_PROVIDERS,
DomEventsPlugin: dom_events.DomEventsPlugin, DomEventsPlugin: dom_events.DomEventsPlugin,
initDomAdapter: browser.initDomAdapter initDomAdapter: browser.initDomAdapter,
INTERNAL_BROWSER_PLATFORM_PROVIDERS: browser.INTERNAL_BROWSER_PLATFORM_PROVIDERS
}; };

View File

@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {COMMON_DIRECTIVES, COMMON_PIPES, PlatformLocation} from '@angular/common'; import {CommonModule, PlatformLocation} from '@angular/common';
import {APPLICATION_COMMON_PROVIDERS, AppModule, AppModuleFactory, AppModuleRef, ExceptionHandler, NgZone, OpaqueToken, PLATFORM_COMMON_PROVIDERS, PLATFORM_INITIALIZER, PlatformRef, ReflectiveInjector, RootRenderer, SanitizationService, Testability, assertPlatform, createPlatform, createPlatformFactory, getPlatform, isDevMode} from '@angular/core'; import {ApplicationModule, ExceptionHandler, NgModule, NgModuleFactory, NgModuleRef, NgZone, OpaqueToken, PLATFORM_COMMON_PROVIDERS, PLATFORM_INITIALIZER, PlatformRef, ReflectiveInjector, RootRenderer, SanitizationService, Testability, assertPlatform, corePlatform, createPlatform, createPlatformFactory, getPlatform, isDevMode} from '@angular/core';
import {wtfInit} from '../core_private'; import {wtfInit} from '../core_private';
import {AnimationDriver} from '../src/dom/animation_driver'; import {AnimationDriver} from '../src/dom/animation_driver';
@ -28,18 +28,21 @@ import {DomSharedStylesHost, SharedStylesHost} from './dom/shared_styles_host';
import {isBlank} from './facade/lang'; import {isBlank} from './facade/lang';
import {DomSanitizationService, DomSanitizationServiceImpl} from './security/dom_sanitization_service'; import {DomSanitizationService, DomSanitizationServiceImpl} from './security/dom_sanitization_service';
export const INTERNAL_BROWSER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [
{provide: PLATFORM_INITIALIZER, useValue: initDomAdapter, multi: true},
{provide: PlatformLocation, useClass: BrowserPlatformLocation}
];
/** /**
* A set of providers to initialize the Angular platform in a web browser. * A set of providers to initialize the Angular platform in a web browser.
* *
* Used automatically by `bootstrap`, or can be passed to `platform`. * Used automatically by `bootstrap`, or can be passed to `platform`.
* *
* @experimental API related to bootstrapping are still under review. * @deprecated Use `browserPlatform()` or create a custom platform factory via
* `createPlatformFactory(browserPlatform, ...)`
*/ */
export const BROWSER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [ export const BROWSER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
PLATFORM_COMMON_PROVIDERS, {provide: PLATFORM_INITIALIZER, useValue: initDomAdapter, multi: true}, [PLATFORM_COMMON_PROVIDERS, INTERNAL_BROWSER_PLATFORM_PROVIDERS];
{provide: PlatformLocation, useClass: BrowserPlatformLocation}
];
/** /**
* @security Replacing built-in sanitization providers exposes the application to XSS risks. * @security Replacing built-in sanitization providers exposes the application to XSS risks.
@ -58,27 +61,18 @@ export const BROWSER_SANITIZATION_PROVIDERS: Array<any> = [
* Used automatically by `bootstrap`, or can be passed to {@link PlatformRef * Used automatically by `bootstrap`, or can be passed to {@link PlatformRef
* PlatformRef.application}. * PlatformRef.application}.
* *
* @experimental API related to bootstrapping are still under review. * @deprecated Create a module that includes `BrowserModule` instead. This is empty for backwards
* compatibility,
* as all of our bootstrap methods add a module implicitly, i.e. keeping this filled would add the
* providers 2x.
*/ */
export const BROWSER_APP_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [ export const BROWSER_APP_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [];
APPLICATION_COMMON_PROVIDERS, BROWSER_SANITIZATION_PROVIDERS,
{provide: ExceptionHandler, useFactory: _exceptionHandler, deps: []},
{provide: DOCUMENT, useFactory: _document, deps: []},
{provide: EVENT_MANAGER_PLUGINS, useClass: DomEventsPlugin, multi: true},
{provide: EVENT_MANAGER_PLUGINS, useClass: KeyEventsPlugin, multi: true},
{provide: EVENT_MANAGER_PLUGINS, useClass: HammerGesturesPlugin, multi: true},
{provide: HAMMER_GESTURE_CONFIG, useClass: HammerGestureConfig},
{provide: DomRootRenderer, useClass: DomRootRenderer_},
{provide: RootRenderer, useExisting: DomRootRenderer},
{provide: SharedStylesHost, useExisting: DomSharedStylesHost},
{provide: AnimationDriver, useFactory: _resolveDefaultAnimationDriver}, DomSharedStylesHost,
Testability, EventManager, ELEMENT_PROBE_PROVIDERS
];
/** /**
* @experimental API related to bootstrapping are still under review. * @experimental API related to bootstrapping are still under review.
*/ */
export const browserPlatform = createPlatformFactory('browser', BROWSER_PLATFORM_PROVIDERS); export const browserPlatform =
createPlatformFactory(corePlatform, 'browser', INTERNAL_BROWSER_PLATFORM_PROVIDERS);
export function initDomAdapter() { export function initDomAdapter() {
BrowserDomAdapter.makeCurrent(); BrowserDomAdapter.makeCurrent();
@ -102,16 +96,26 @@ export function _resolveDefaultAnimationDriver(): AnimationDriver {
} }
/** /**
* The app module for the browser. * The ng module for the browser.
* *
* @experimental * @experimental
*/ */
@AppModule({ @NgModule({
providers: [ providers: [
BROWSER_APP_PROVIDERS, BROWSER_SANITIZATION_PROVIDERS,
{provide: ExceptionHandler, useFactory: _exceptionHandler, deps: []},
{provide: DOCUMENT, useFactory: _document, deps: []},
{provide: EVENT_MANAGER_PLUGINS, useClass: DomEventsPlugin, multi: true},
{provide: EVENT_MANAGER_PLUGINS, useClass: KeyEventsPlugin, multi: true},
{provide: EVENT_MANAGER_PLUGINS, useClass: HammerGesturesPlugin, multi: true},
{provide: HAMMER_GESTURE_CONFIG, useClass: HammerGestureConfig},
{provide: DomRootRenderer, useClass: DomRootRenderer_},
{provide: RootRenderer, useExisting: DomRootRenderer},
{provide: SharedStylesHost, useExisting: DomSharedStylesHost},
{provide: AnimationDriver, useFactory: _resolveDefaultAnimationDriver}, DomSharedStylesHost,
Testability, EventManager, ELEMENT_PROBE_PROVIDERS
], ],
directives: COMMON_DIRECTIVES, exports: [CommonModule, ApplicationModule]
pipes: COMMON_PIPES
}) })
export class BrowserModule { export class BrowserModule {
} }

View File

@ -6,13 +6,14 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {APP_INITIALIZER, Injector, NgZone} from '@angular/core'; import {Injector, NgZone, PLATFORM_INITIALIZER} from '@angular/core';
import {BrowserPlatformLocation} from '../../browser/location/browser_platform_location'; import {BrowserPlatformLocation} from '../../browser/location/browser_platform_location';
import {MessageBasedPlatformLocation} from './platform_location'; import {MessageBasedPlatformLocation} from './platform_location';
/** /**
* A list of {@link Provider}s. To use the router in a Worker enabled application you must * A list of {@link Provider}s. To use the router in a Worker enabled application you must
* include these providers when setting up the render thread. * include these providers when setting up the render thread.
@ -20,7 +21,7 @@ import {MessageBasedPlatformLocation} from './platform_location';
*/ */
export const WORKER_UI_LOCATION_PROVIDERS = [ export const WORKER_UI_LOCATION_PROVIDERS = [
MessageBasedPlatformLocation, BrowserPlatformLocation, MessageBasedPlatformLocation, BrowserPlatformLocation,
{provide: APP_INITIALIZER, useFactory: initUiLocation, multi: true, deps: [Injector]} {provide: PLATFORM_INITIALIZER, useFactory: initUiLocation, multi: true, deps: [Injector]}
]; ];
function initUiLocation(injector: Injector): () => void { function initUiLocation(injector: Injector): () => void {

View File

@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {COMMON_DIRECTIVES, COMMON_PIPES, FORM_PROVIDERS} from '@angular/common'; import {CommonModule, FORM_PROVIDERS} from '@angular/common';
import {APPLICATION_COMMON_PROVIDERS, APP_INITIALIZER, AppModule, ExceptionHandler, NgZone, OpaqueToken, PLATFORM_COMMON_PROVIDERS, PlatformRef, ReflectiveInjector, RootRenderer, assertPlatform, createPlatform, createPlatformFactory, getPlatform} from '@angular/core'; import {APP_INITIALIZER, ApplicationModule, ExceptionHandler, NgModule, NgZone, OpaqueToken, PLATFORM_COMMON_PROVIDERS, PlatformRef, ReflectiveInjector, RootRenderer, assertPlatform, corePlatform, createPlatform, createPlatformFactory, getPlatform} from '@angular/core';
import {BROWSER_SANITIZATION_PROVIDERS} from './browser'; import {BROWSER_SANITIZATION_PROVIDERS} from './browser';
import {isBlank, print} from './facade/lang'; import {isBlank, print} from './facade/lang';
@ -29,29 +29,24 @@ class PrintLogger {
} }
/** /**
* @experimental * @deprecated Use `workerAppPlatform()` or create a custom platform factory via
* `createPlatformFactory(workerAppPlatform, ...)`
*/ */
export const WORKER_APP_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = export const WORKER_APP_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
PLATFORM_COMMON_PROVIDERS; PLATFORM_COMMON_PROVIDERS;
/** /**
* @experimental * @deprecated Create a module that includes `WorkerAppModule` instead. This is empty for backwards
* compatibility,
* as all of our bootstrap methods add a module implicitly, i.e. keeping this filled would add the
* providers 2x.
*/ */
export const WORKER_APP_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [ export const WORKER_APP_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [];
APPLICATION_COMMON_PROVIDERS, FORM_PROVIDERS, BROWSER_SANITIZATION_PROVIDERS, Serializer,
{provide: ClientMessageBrokerFactory, useClass: ClientMessageBrokerFactory_},
{provide: ServiceMessageBrokerFactory, useClass: ServiceMessageBrokerFactory_},
WebWorkerRootRenderer, {provide: RootRenderer, useExisting: WebWorkerRootRenderer},
{provide: ON_WEB_WORKER, useValue: true}, RenderStore,
{provide: ExceptionHandler, useFactory: _exceptionHandler, deps: []},
{provide: MessageBus, useFactory: createMessageBus, deps: [NgZone]},
{provide: APP_INITIALIZER, useValue: setupWebWorker, multi: true}
];
/** /**
* @experimental * @experimental
*/ */
export const workerAppPlatform = createPlatformFactory('workerApp', WORKER_APP_PLATFORM_PROVIDERS); export const workerAppPlatform = createPlatformFactory(corePlatform, 'workerApp');
function _exceptionHandler(): ExceptionHandler { function _exceptionHandler(): ExceptionHandler {
return new ExceptionHandler(new PrintLogger()); return new ExceptionHandler(new PrintLogger());
@ -77,14 +72,22 @@ function setupWebWorker(): void {
} }
/** /**
* The app module for the worker app side. * The ng module for the worker app side.
* *
* @experimental * @experimental
*/ */
@AppModule({ @NgModule({
providers: WORKER_APP_APPLICATION_PROVIDERS, providers: [
directives: COMMON_DIRECTIVES, FORM_PROVIDERS, BROWSER_SANITIZATION_PROVIDERS, Serializer,
pipes: COMMON_PIPES {provide: ClientMessageBrokerFactory, useClass: ClientMessageBrokerFactory_},
{provide: ServiceMessageBrokerFactory, useClass: ServiceMessageBrokerFactory_},
WebWorkerRootRenderer, {provide: RootRenderer, useExisting: WebWorkerRootRenderer},
{provide: ON_WEB_WORKER, useValue: true}, RenderStore,
{provide: ExceptionHandler, useFactory: _exceptionHandler, deps: []},
{provide: MessageBus, useFactory: createMessageBus, deps: [NgZone]},
{provide: APP_INITIALIZER, useValue: setupWebWorker, multi: true}
],
exports: [CommonModule, ApplicationModule]
}) })
export class WorkerAppModule { export class WorkerAppModule {
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {APPLICATION_COMMON_PROVIDERS, APP_INITIALIZER, AppModule, ExceptionHandler, Injectable, Injector, NgZone, OpaqueToken, PLATFORM_COMMON_PROVIDERS, PLATFORM_INITIALIZER, PlatformRef, ReflectiveInjector, RootRenderer, Testability, assertPlatform, createPlatform, createPlatformFactory, getPlatform} from '@angular/core'; import {ExceptionHandler, Injectable, Injector, NgZone, OpaqueToken, PLATFORM_COMMON_PROVIDERS, PLATFORM_INITIALIZER, PlatformRef, ReflectiveInjector, RootRenderer, Testability, assertPlatform, corePlatform, createPlatform, createPlatformFactory, getPlatform, isDevMode} from '@angular/core';
import {wtfInit} from '../core_private'; import {wtfInit} from '../core_private';
@ -34,6 +34,7 @@ import {ServiceMessageBrokerFactory, ServiceMessageBrokerFactory_} from './web_w
import {MessageBasedRenderer} from './web_workers/ui/renderer'; import {MessageBasedRenderer} from './web_workers/ui/renderer';
/** /**
* Wrapper class that exposes the Worker * Wrapper class that exposes the Worker
* and underlying {@link MessageBus} for lower level message passing. * and underlying {@link MessageBus} for lower level message passing.
@ -70,16 +71,8 @@ export const WORKER_UI_STARTABLE_MESSAGING_SERVICE =
/** /**
* @experimental WebWorker support is currently experimental. * @experimental WebWorker support is currently experimental.
*/ */
export const WORKER_UI_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [ export const _WORKER_UI_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [
PLATFORM_COMMON_PROVIDERS, {provide: NgZone, useFactory: createNgZone, deps: []},
{provide: PLATFORM_INITIALIZER, useValue: initWebWorkerRenderPlatform, multi: true}
];
/**
* @experimental WebWorker support is currently experimental.
*/
export const WORKER_UI_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [
APPLICATION_COMMON_PROVIDERS,
MessageBasedRenderer, MessageBasedRenderer,
{provide: WORKER_UI_STARTABLE_MESSAGING_SERVICE, useExisting: MessageBasedRenderer, multi: true}, {provide: WORKER_UI_STARTABLE_MESSAGING_SERVICE, useExisting: MessageBasedRenderer, multi: true},
BROWSER_SANITIZATION_PROVIDERS, BROWSER_SANITIZATION_PROVIDERS,
@ -104,10 +97,27 @@ export const WORKER_UI_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[
Testability, Testability,
EventManager, EventManager,
WebWorkerInstance, WebWorkerInstance,
{provide: APP_INITIALIZER, useFactory: initWebWorkerAppFn, multi: true, deps: [Injector]}, {
provide: PLATFORM_INITIALIZER,
useFactory: initWebWorkerRenderPlatform,
multi: true,
deps: [Injector]
},
{provide: MessageBus, useFactory: messageBusFactory, deps: [WebWorkerInstance]} {provide: MessageBus, useFactory: messageBusFactory, deps: [WebWorkerInstance]}
]; ];
/**
* * @deprecated Use `workerUiPlatform()` or create a custom platform factory via
* `createPlatformFactory(workerUiPlatform, ...)`
*/
export const WORKER_UI_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
[PLATFORM_COMMON_PROVIDERS, _WORKER_UI_PLATFORM_PROVIDERS];
/**
* @deprecated Worker UI only has a platform but no application
*/
export const WORKER_UI_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [];
function initializeGenericWorkerRenderer(injector: Injector) { function initializeGenericWorkerRenderer(injector: Injector) {
var bus = injector.get(MessageBus); var bus = injector.get(MessageBus);
let zone = injector.get(NgZone); let zone = injector.get(NgZone);
@ -122,27 +132,11 @@ function messageBusFactory(instance: WebWorkerInstance): MessageBus {
return instance.bus; return instance.bus;
} }
function initWebWorkerRenderPlatform(): void { function initWebWorkerRenderPlatform(injector: Injector): () => void {
BrowserDomAdapter.makeCurrent();
wtfInit();
BrowserGetTestability.init();
}
/**
* @experimental WebWorker support is currently experimental.
*/
export const workerUiPlatform = createPlatformFactory('workerUi', WORKER_UI_PLATFORM_PROVIDERS);
function _exceptionHandler(): ExceptionHandler {
return new ExceptionHandler(getDOM());
}
function _document(): any {
return getDOM().defaultDoc();
}
function initWebWorkerAppFn(injector: Injector): () => void {
return () => { return () => {
BrowserDomAdapter.makeCurrent();
wtfInit();
BrowserGetTestability.init();
var scriptUri: string; var scriptUri: string;
try { try {
scriptUri = injector.get(WORKER_SCRIPT); scriptUri = injector.get(WORKER_SCRIPT);
@ -158,6 +152,24 @@ function initWebWorkerAppFn(injector: Injector): () => void {
}; };
} }
/**
* @experimental WebWorker support is currently experimental.
*/
export const workerUiPlatform =
createPlatformFactory(corePlatform, 'workerUi', _WORKER_UI_PLATFORM_PROVIDERS);
function _exceptionHandler(): ExceptionHandler {
return new ExceptionHandler(getDOM());
}
function _document(): any {
return getDOM().defaultDoc();
}
function createNgZone(): NgZone {
return new NgZone({enableLongStackTrace: isDevMode()});
}
/** /**
* Spawns a new class and initializes the WebWorkerInstance * Spawns a new class and initializes the WebWorkerInstance
*/ */
@ -175,14 +187,3 @@ function _resolveDefaultAnimationDriver(): AnimationDriver {
// work with animations just yet... // work with animations just yet...
return AnimationDriver.NOOP; return AnimationDriver.NOOP;
} }
/**
* The app module for the worker ui side.
* To use this, you need to create an own module that includes this module
* and provides the `WORKER_SCRIPT` token.
*
* @experimental
*/
@AppModule({providers: WORKER_UI_APPLICATION_PROVIDERS})
export class WorkerUiModule {
}

View File

@ -8,15 +8,15 @@
import {LowerCasePipe, NgIf} from '@angular/common'; import {LowerCasePipe, NgIf} from '@angular/common';
import {XHR} from '@angular/compiler'; import {XHR} from '@angular/compiler';
import {APP_INITIALIZER, Component, Directive, ExceptionHandler, Inject, Input, OnDestroy, PLATFORM_DIRECTIVES, PLATFORM_INITIALIZER, PLATFORM_PIPES, Pipe, ReflectiveInjector, coreLoadAndBootstrap, createPlatform, provide} from '@angular/core'; import {APP_INITIALIZER, Component, Directive, ExceptionHandler, Inject, Input, NgModule, OnDestroy, PLATFORM_DIRECTIVES, PLATFORM_INITIALIZER, PLATFORM_PIPES, Pipe, ReflectiveInjector, bootstrapModule, createPlatformFactory, provide} from '@angular/core';
import {ApplicationRef, disposePlatform} from '@angular/core/src/application_ref'; import {ApplicationRef, disposePlatform} from '@angular/core/src/application_ref';
import {Console} from '@angular/core/src/console'; import {Console} from '@angular/core/src/console';
import {ComponentRef} from '@angular/core/src/linker/component_factory'; import {ComponentRef} from '@angular/core/src/linker/component_factory';
import {Testability, TestabilityRegistry} from '@angular/core/src/testability/testability'; import {Testability, TestabilityRegistry} from '@angular/core/src/testability/testability';
import {ComponentFixture} from '@angular/core/testing'; import {ComponentFixture} from '@angular/core/testing';
import {AsyncTestCompleter, Log, afterEach, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, Log, afterEach, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it} from '@angular/core/testing/testing_internal';
import {BROWSER_APP_PROVIDERS, BROWSER_PLATFORM_PROVIDERS} from '@angular/platform-browser'; import {BrowserModule} from '@angular/platform-browser';
import {BROWSER_APP_COMPILER_PROVIDERS, bootstrap} from '@angular/platform-browser-dynamic'; import {bootstrap, browserDynamicPlatform} from '@angular/platform-browser-dynamic';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {DOCUMENT} from '@angular/platform-browser/src/dom/dom_tokens'; import {DOCUMENT} from '@angular/platform-browser/src/dom/dom_tokens';
import {expect} from '@angular/platform-browser/testing/matchers'; import {expect} from '@angular/platform-browser/testing/matchers';
@ -223,16 +223,10 @@ export function main() {
it('should unregister change detectors when components are disposed', it('should unregister change detectors when components are disposed',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var platform = bootstrap(HelloRootCmp, testProviders).then((ref) => {
createPlatform(ReflectiveInjector.resolveAndCreate(BROWSER_PLATFORM_PROVIDERS)); const appRef = ref.injector.get(ApplicationRef);
var app = ReflectiveInjector
.resolveAndCreate(
[BROWSER_APP_PROVIDERS, BROWSER_APP_COMPILER_PROVIDERS, testProviders],
platform.injector)
.get(ApplicationRef);
coreLoadAndBootstrap(HelloRootCmp, app.injector).then((ref) => {
ref.destroy(); ref.destroy();
expect(() => app.tick()).not.toThrow(); expect(() => appRef.tick()).not.toThrow();
async.done(); async.done();
}); });
})); }));
@ -258,24 +252,29 @@ export function main() {
}); });
})); }));
it('should run platform initializers', inject([Log], (log: Log) => { it('should run platform initializers',
let p = createPlatform(ReflectiveInjector.resolveAndCreate([ inject([Log, AsyncTestCompleter], (log: Log, async: AsyncTestCompleter) => {
BROWSER_PLATFORM_PROVIDERS, let p = createPlatformFactory(browserDynamicPlatform, 'someName', [
{provide: PLATFORM_INITIALIZER, useValue: log.fn('platform_init1'), multi: true}, {provide: PLATFORM_INITIALIZER, useValue: log.fn('platform_init1'), multi: true},
{provide: PLATFORM_INITIALIZER, useValue: log.fn('platform_init2'), multi: true} {provide: PLATFORM_INITIALIZER, useValue: log.fn('platform_init2'), multi: true}
])); ])();
@NgModule({
imports: [BrowserModule],
providers: [
{provide: APP_INITIALIZER, useValue: log.fn('app_init1'), multi: true},
{provide: APP_INITIALIZER, useValue: log.fn('app_init2'), multi: true}
]
})
class SomeModule {
}
expect(log.result()).toEqual('platform_init1; platform_init2'); expect(log.result()).toEqual('platform_init1; platform_init2');
log.clear(); log.clear();
var a = ReflectiveInjector.resolveAndCreate( bootstrapModule(SomeModule, p).then(() => {
[ expect(log.result()).toEqual('app_init1; app_init2');
BROWSER_APP_PROVIDERS, async.done();
{provide: APP_INITIALIZER, useValue: log.fn('app_init1'), multi: true}, });
{provide: APP_INITIALIZER, useValue: log.fn('app_init2'), multi: true}
],
p.injector);
a.get(ApplicationRef);
expect(log.result()).toEqual('app_init1; app_init2');
})); }));
it('should register each application with the testability registry', it('should register each application with the testability registry',
@ -305,7 +304,7 @@ export function main() {
])).then((compRef) => { ])).then((compRef) => {
expect(el).toHaveText('hello world!'); expect(el).toHaveText('hello world!');
expect(compilerConsole.warnings).toEqual([ expect(compilerConsole.warnings).toEqual([
'Passing an instance of XHR to "bootstrap()" as provider is deprecated. Pass the provider via the new parameter "compilerOptions" of "bootstrap()" instead.' 'Passing XHR as regular provider is deprecated. Pass the provider via "compilerOptions" instead.'
]); ]);
async.done(); async.done();
}); });
@ -325,10 +324,8 @@ export function main() {
.toBe('transformed someValue'); .toBe('transformed someValue');
expect(compilerConsole.warnings).toEqual([ expect(compilerConsole.warnings).toEqual([
'Passing PLATFORM_DIRECTIVES to "bootstrap()" as provider is deprecated. Use the new parameter "directives" of "bootstrap()" instead.', `The PLATFORM_DIRECTIVES provider and CompilerConfig.platformDirectives is deprecated. Add the directives to an NgModule instead! (Directives: ${stringify(SomeDirective)})`,
'Passing PLATFORM_PIPES to "bootstrap()" as provider is deprecated. Use the new parameter "pipes" of "bootstrap()" instead.', `The PLATFORM_PIPES provider and CompilerConfig.platformPipes is deprecated. Add the pipes to an NgModule instead! (Pipes: ${stringify(SomePipe)})`
`Providing platform directives via the PLATFORM_DIRECTIVES provider or the "CompilerConfig" is deprecated. Provide platform directives via an @AppModule instead. Directives: ${stringify(SomeDirective)}`,
`Providing platform pipes via the PLATFORM_PIPES provider or the "CompilerConfig" is deprecated. Provide platform pipes via an @AppModule instead. Pipes: ${stringify(SomePipe)}`
]); ]);
async.done(); async.done();
}); });

View File

@ -8,7 +8,7 @@
import {NgIf} from '@angular/common'; import {NgIf} from '@angular/common';
import {CompilerConfig, XHR} from '@angular/compiler'; import {CompilerConfig, XHR} from '@angular/compiler';
import {AppModule, Component, ComponentFactoryResolver, Directive, Injectable, Input, Pipe, ViewMetadata, provide} from '@angular/core'; import {Component, ComponentFactoryResolver, Directive, Injectable, Input, NgModule, Pipe, ViewMetadata, provide} from '@angular/core';
import {TestComponentBuilder, addProviders, async, configureCompiler, configureModule, doAsyncPrecompilation, fakeAsync, inject, tick, withModule, withProviders} from '@angular/core/testing'; import {TestComponentBuilder, addProviders, async, configureCompiler, configureModule, doAsyncPrecompilation, fakeAsync, inject, tick, withModule, withProviders} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/matchers'; import {expect} from '@angular/platform-browser/testing/matchers';
@ -112,8 +112,8 @@ class SomePipe {
class CompUsingModuleDirectiveAndPipe { class CompUsingModuleDirectiveAndPipe {
} }
@AppModule({}) @NgModule()
class SomeNestedModule { class SomeLibModule {
} }
@Component({ @Component({
@ -233,10 +233,9 @@ export function main() {
beforeEach(() => { beforeEach(() => {
moduleConfig = { moduleConfig = {
providers: [FancyService], providers: [FancyService],
directives: [SomeDirective], imports: [SomeLibModule],
pipes: [SomePipe], declarations: [SomeDirective, SomePipe, CompUsingModuleDirectiveAndPipe],
precompile: [CompUsingModuleDirectiveAndPipe], precompile: [CompUsingModuleDirectiveAndPipe]
modules: [SomeNestedModule]
}; };
}); });
@ -256,9 +255,9 @@ export function main() {
expect(el.children[0].properties['title']).toBe('transformed someValue'); expect(el.children[0].properties['title']).toBe('transformed someValue');
})); }));
it('should use set up nested modules', it('should use set up library modules',
inject([SomeNestedModule], (nestedModule: SomeNestedModule) => { inject([SomeLibModule], (libModule: SomeLibModule) => {
expect(nestedModule).toBeAnInstanceOf(SomeNestedModule); expect(libModule).toBeAnInstanceOf(SomeLibModule);
})); }));
it('should use set up precompile components', it('should use set up precompile components',
@ -284,11 +283,10 @@ export function main() {
expect(el.children[0].properties['title']).toBe('transformed someValue'); expect(el.children[0].properties['title']).toBe('transformed someValue');
})); }));
it('should use set up nested modules', it('should use set up library modules',
withModule(() => moduleConfig) withModule(() => moduleConfig).inject([SomeLibModule], (libModule: SomeLibModule) => {
.inject([SomeNestedModule], (nestedModule: SomeNestedModule) => { expect(libModule).toBeAnInstanceOf(SomeLibModule);
expect(nestedModule).toBeAnInstanceOf(SomeNestedModule); }));
}));
it('should use set up precompile components', it('should use set up precompile components',
withModule(() => moduleConfig) withModule(() => moduleConfig)
@ -301,7 +299,7 @@ export function main() {
describe('precompile components with template url', () => { describe('precompile components with template url', () => {
beforeEach(async(() => { beforeEach(async(() => {
configureModule({precompile: [CompWithUrlTemplate]}); configureModule({declarations: [CompWithUrlTemplate], precompile: [CompWithUrlTemplate]});
doAsyncPrecompilation(); doAsyncPrecompilation();
})); }));
@ -450,7 +448,12 @@ export function main() {
expect( expect(
() => () =>
it('should fail', it('should fail',
withModule(() => { return {precompile: [CompWithUrlTemplate]}; }) withModule(() => {
return {
declarations: [CompWithUrlTemplate],
precompile: [CompWithUrlTemplate]
};
})
.inject( .inject(
[ComponentFactoryResolver], [ComponentFactoryResolver],
(resolver: ComponentFactoryResolver) => { (resolver: ComponentFactoryResolver) => {

View File

@ -23,8 +23,8 @@ import {MessageBasedRenderer} from '@angular/platform-browser/src/web_workers/ui
import {createPairedMessageBuses, PairedMessageBuses} from '../shared/web_worker_test_util'; import {createPairedMessageBuses, PairedMessageBuses} from '../shared/web_worker_test_util';
import {ServiceMessageBrokerFactory_} from '@angular/platform-browser/src/web_workers/shared/service_message_broker'; import {ServiceMessageBrokerFactory_} from '@angular/platform-browser/src/web_workers/shared/service_message_broker';
import {dispatchEvent} from '../../../../platform-browser/testing/browser_util'; import {dispatchEvent} from '../../../../platform-browser/testing/browser_util';
import {BrowserTestModule} from '@angular/platform-browser/testing'; import {BrowserTestingModule} from '@angular/platform-browser/testing';
import {browserDynamicTestPlatform} from '@angular/platform-browser-dynamic/testing'; import {browserDynamicTestingPlatform} from '@angular/platform-browser-dynamic/testing';
export function main() { export function main() {
function createWebWorkerBrokerFactory( function createWebWorkerBrokerFactory(
@ -65,8 +65,8 @@ export function main() {
beforeEach(() => { beforeEach(() => {
uiRenderStore = new RenderStore(); uiRenderStore = new RenderStore();
var testUiInjector = new TestBed(); var testUiInjector = new TestBed();
testUiInjector.platform = browserDynamicTestPlatform(); testUiInjector.platform = browserDynamicTestingPlatform();
testUiInjector.appModule = BrowserTestModule; testUiInjector.ngModule = BrowserTestingModule;
testUiInjector.configureModule({ testUiInjector.configureModule({
providers: [ providers: [
Serializer, {provide: RenderStore, useValue: uiRenderStore}, Serializer, {provide: RenderStore, useValue: uiRenderStore},
@ -74,7 +74,7 @@ export function main() {
{provide: RootRenderer, useExisting: DomRootRenderer} {provide: RootRenderer, useExisting: DomRootRenderer}
] ]
}); });
testUiInjector.initTestAppModule(); testUiInjector.initTestModule();
var uiSerializer = testUiInjector.get(Serializer); var uiSerializer = testUiInjector.get(Serializer);
var domRootRenderer = testUiInjector.get(DomRootRenderer); var domRootRenderer = testUiInjector.get(DomRootRenderer);
workerRenderStore = new RenderStore(); workerRenderStore = new RenderStore();

View File

@ -7,9 +7,9 @@
*/ */
import {LocationStrategy} from '@angular/common'; import {LocationStrategy} from '@angular/common';
import {APP_ID, AppModule, NgZone, OpaqueToken, PLATFORM_COMMON_PROVIDERS, PLATFORM_INITIALIZER, PlatformRef, ReflectiveInjector, assertPlatform, createPlatform, createPlatformFactory, getPlatform} from '@angular/core'; import {APP_ID, NgModule, NgZone, OpaqueToken, PLATFORM_COMMON_PROVIDERS, PLATFORM_INITIALIZER, PlatformRef, ReflectiveInjector, assertPlatform, corePlatform, createPlatform, createPlatformFactory, getPlatform} from '@angular/core';
import {BROWSER_APP_PROVIDERS, BrowserModule} from '../src/browser'; import {BrowserModule} from '../src/browser';
import {BrowserDomAdapter} from '../src/browser/browser_adapter'; import {BrowserDomAdapter} from '../src/browser/browser_adapter';
import {AnimationDriver} from '../src/dom/animation_driver'; import {AnimationDriver} from '../src/dom/animation_driver';
import {ELEMENT_PROBE_PROVIDERS} from '../src/dom/debug/ng_probe'; import {ELEMENT_PROBE_PROVIDERS} from '../src/dom/debug/ng_probe';
@ -25,45 +25,46 @@ function createNgZone(): NgZone {
return new NgZone({enableLongStackTrace: true}); return new NgZone({enableLongStackTrace: true});
} }
const _TEST_BROWSER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
[{provide: PLATFORM_INITIALIZER, useValue: initBrowserTests, multi: true}];
/** /**
* Providers for the browser test platform * Providers for the browser test platform
* *
* @experimental * @deprecated Use `browserTestingPlatform()` or create a custom platform factory via
* `createPlatformFactory(browserTestingPlatform, ...)`
*/ */
export const TEST_BROWSER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [ export const TEST_BROWSER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
PLATFORM_COMMON_PROVIDERS, [PLATFORM_COMMON_PROVIDERS, _TEST_BROWSER_PLATFORM_PROVIDERS];
{provide: PLATFORM_INITIALIZER, useValue: initBrowserTests, multi: true}
];
/** /**
* @deprecated Use initTestEnvironment with BrowserTestModule instead. * @deprecated Use initTestEnvironment with BrowserTestModule instead. This is empty for backwards
* compatibility,
* as all of our bootstrap methods add a module implicitly, i.e. keeping this filled would add the
* providers 2x.
*/ */
export const TEST_BROWSER_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [ export const TEST_BROWSER_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [];
BROWSER_APP_PROVIDERS, {provide: APP_ID, useValue: 'a'}, ELEMENT_PROBE_PROVIDERS,
{provide: NgZone, useFactory: createNgZone},
{provide: AnimationDriver, useValue: AnimationDriver.NOOP}
];
/** /**
* Platform for testing * Platform for testing
* *
* @experimental API related to bootstrapping are still under review. * @experimental API related to bootstrapping are still under review.
*/ */
export const browserTestPlatform = export const browserTestingPlatform =
createPlatformFactory('browserTest', TEST_BROWSER_PLATFORM_PROVIDERS); createPlatformFactory(corePlatform, 'browserTesting', _TEST_BROWSER_PLATFORM_PROVIDERS);
/** /**
* AppModule for testing. * NgModule for testing.
* *
* @stable * @experimental
*/ */
@AppModule({ @NgModule({
modules: [BrowserModule], exports: [BrowserModule],
providers: [ providers: [
{provide: APP_ID, useValue: 'a'}, ELEMENT_PROBE_PROVIDERS, {provide: APP_ID, useValue: 'a'}, ELEMENT_PROBE_PROVIDERS,
{provide: NgZone, useFactory: createNgZone}, {provide: NgZone, useFactory: createNgZone},
{provide: AnimationDriver, useValue: AnimationDriver.NOOP} {provide: AnimationDriver, useValue: AnimationDriver.NOOP}
] ]
}) })
export class BrowserTestModule { export class BrowserTestingModule {
} }

View File

@ -11,3 +11,4 @@ import {__core_private__ as r, __core_private_types__ as t} from '@angular/core'
export var reflector: typeof t.reflector = r.reflector; export var reflector: typeof t.reflector = r.reflector;
export var ReflectionCapabilities: typeof t.ReflectionCapabilities = r.ReflectionCapabilities; export var ReflectionCapabilities: typeof t.ReflectionCapabilities = r.ReflectionCapabilities;
export var wtfInit: typeof t.wtfInit = r.wtfInit; export var wtfInit: typeof t.wtfInit = r.wtfInit;
export var Console: typeof t.Console = r.Console;

View File

@ -7,11 +7,13 @@
*/ */
import {PlatformLocation} from '@angular/common'; import {PlatformLocation} from '@angular/common';
import {CompilerFactory, ComponentRef, OpaqueToken, PLATFORM_COMMON_PROVIDERS, PLATFORM_INITIALIZER, PlatformRef, ReflectiveInjector, Type, assertPlatform, coreLoadAndBootstrap, createPlatform, createPlatformFactory, getPlatform} from '@angular/core'; import {analyzeAppProvidersForDeprecatedConfiguration, coreDynamicPlatform} from '@angular/compiler';
import {BROWSER_DYNAMIC_TEST_COMPILER_FACTORY} from '@angular/platform-browser-dynamic/testing'; import {ApplicationRef, CompilerFactory, ComponentRef, NgModule, OpaqueToken, PLATFORM_COMMON_PROVIDERS, PLATFORM_INITIALIZER, PlatformRef, ReflectiveInjector, Type, assertPlatform, bootstrapModule, corePlatform, createPlatform, createPlatformFactory, getPlatform} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {ReflectionCapabilities, reflector, wtfInit} from '../core_private'; import {Console, ReflectionCapabilities, reflector, wtfInit} from '../core_private';
import {ConcreteType} from './facade/lang';
import {Parse5DomAdapter} from './parse5_adapter'; import {Parse5DomAdapter} from './parse5_adapter';
function notSupported(feature: string): Error { function notSupported(feature: string): Error {
@ -31,23 +33,21 @@ class ServerPlatformLocation extends PlatformLocation {
back(): void { notSupported('back'); }; back(): void { notSupported('back'); };
} }
/** export const INTERNAL_SERVER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [
* A set of providers to initialize the Angular platform in a server.
*
* Used automatically by `serverBootstrap`, or can be passed to `platform`.
* @experimental
*/
export const SERVER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [
PLATFORM_COMMON_PROVIDERS,
{provide: PLATFORM_INITIALIZER, useValue: initParse5Adapter, multi: true}, {provide: PLATFORM_INITIALIZER, useValue: initParse5Adapter, multi: true},
{provide: PlatformLocation, useClass: ServerPlatformLocation}, {provide: PlatformLocation, useClass: ServerPlatformLocation},
]; ];
const SERVER_DYNAMIC_PROVIDERS: any[] = [
SERVER_PLATFORM_PROVIDERS,
{provide: CompilerFactory, useValue: BROWSER_DYNAMIC_TEST_COMPILER_FACTORY},
];
/**
* A set of providers to initialize the Angular platform in a server.
*
* Used automatically by `serverBootstrap`, or can be passed to `platform`.
* @deprecated Use `serverPlatform()` or create a custom platform factory via
* `createPlatformFactory(serverPlatform, ...)`
*/
export const SERVER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
[PLATFORM_COMMON_PROVIDERS, INTERNAL_SERVER_PLATFORM_PROVIDERS];
function initParse5Adapter() { function initParse5Adapter() {
Parse5DomAdapter.makeCurrent(); Parse5DomAdapter.makeCurrent();
@ -57,7 +57,8 @@ function initParse5Adapter() {
/** /**
* @experimental * @experimental
*/ */
export const serverPlatform = createPlatformFactory('server', SERVER_PLATFORM_PROVIDERS); export const serverPlatform =
createPlatformFactory(corePlatform, 'server', INTERNAL_SERVER_PLATFORM_PROVIDERS);
/** /**
* The server platform that supports the runtime compiler. * The server platform that supports the runtime compiler.
@ -65,7 +66,7 @@ export const serverPlatform = createPlatformFactory('server', SERVER_PLATFORM_PR
* @experimental * @experimental
*/ */
export const serverDynamicPlatform = export const serverDynamicPlatform =
createPlatformFactory('serverDynamic', SERVER_DYNAMIC_PROVIDERS); createPlatformFactory(coreDynamicPlatform, 'serverDynamic', INTERNAL_SERVER_PLATFORM_PROVIDERS);
/** /**
* Used to bootstrap Angular in server environment (such as node). * Used to bootstrap Angular in server environment (such as node).
@ -81,16 +82,35 @@ export const serverDynamicPlatform =
* serverBootstrap(..., [BROWSER_APP_PROVIDERS, BROWSER_APP_COMPILER_PROVIDERS]) * serverBootstrap(..., [BROWSER_APP_PROVIDERS, BROWSER_APP_COMPILER_PROVIDERS])
* ``` * ```
* *
* @deprecated create an {@link AppModule} and use {@link bootstrapModule} with the {@link * @deprecated create an {@link NgModule} and use {@link bootstrapModule} with the {@link
* serverDynamicPlatform}() * serverDynamicPlatform}()
* instead. * instead.
*/ */
export function serverBootstrap( export function serverBootstrap<T>(
appComponentType: Type, appComponentType: ConcreteType<T>,
providers: Array<any /*Type | Provider | any[]*/>): Promise<ComponentRef<any>> { customProviders: Array<any /*Type | Provider | any[]*/>): Promise<ComponentRef<T>> {
console.warn( console.warn(
'serverBootstrap is deprecated. Create an @AppModule and use `bootstrapModule` with the `serverDynamicPlatform()` instead.'); 'serverBootstrap is deprecated. Create an @NgModule and use `bootstrapModule` with the `serverDynamicPlatform()` instead.');
reflector.reflectionCapabilities = new ReflectionCapabilities(); reflector.reflectionCapabilities = new ReflectionCapabilities();
var appInjector = ReflectiveInjector.resolveAndCreate(providers, serverPlatform().injector);
return coreLoadAndBootstrap(appComponentType, appInjector); const deprecatedConfiguration = analyzeAppProvidersForDeprecatedConfiguration(customProviders);
const declarations = [deprecatedConfiguration.moduleDeclarations.concat([appComponentType])];
@NgModule({
providers: customProviders,
declarations: declarations,
imports: [BrowserModule],
precompile: [appComponentType]
})
class DynamicModule {
}
return bootstrapModule(
DynamicModule, serverDynamicPlatform(), deprecatedConfiguration.compilerOptions)
.then((moduleRef) => {
const console = moduleRef.injector.get(Console);
deprecatedConfiguration.deprecationMessages.forEach((msg) => console.warn(msg));
const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
return appRef.bootstrap(appComponentType);
});
} }

View File

@ -6,44 +6,67 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AppModule, CompilerFactory, OpaqueToken, PLATFORM_COMMON_PROVIDERS, PLATFORM_INITIALIZER, PlatformRef, ReflectiveInjector, assertPlatform, createPlatform, createPlatformFactory, getPlatform} from '@angular/core'; import {analyzeAppProvidersForDeprecatedConfiguration} from '@angular/compiler';
import {BROWSER_DYNAMIC_TEST_COMPILER_FACTORY, BrowserDynamicTestModule, TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS} from '@angular/platform-browser-dynamic/testing'; import {coreDynamicTestingPlatform} from '@angular/compiler/testing';
import {CompilerFactory, CompilerOptions, NgModule, OpaqueToken, PLATFORM_COMMON_PROVIDERS, PLATFORM_INITIALIZER, PlatformRef, ReflectiveInjector, assertPlatform, createPlatform, createPlatformFactory, getPlatform} from '@angular/core';
import {initTestEnvironment} from '@angular/core/testing';
import {BrowserDynamicTestingModule, TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS, browserDynamicTestingPlatform} from '@angular/platform-browser-dynamic/testing';
import {Console} from '../core_private';
import {serverPlatform} from '../index';
import {Parse5DomAdapter} from '../src/parse5_adapter'; import {Parse5DomAdapter} from '../src/parse5_adapter';
import {INTERNAL_SERVER_PLATFORM_PROVIDERS} from '../src/server';
function initServerTests() {
Parse5DomAdapter.makeCurrent();
}
/**
* @deprecated Use initTestEnvironment with serverTestPlatform instead.
*/
export const TEST_SERVER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
/*@ts2dart_const*/[
PLATFORM_COMMON_PROVIDERS,
/*@ts2dart_Provider*/ {provide: PLATFORM_INITIALIZER, useValue: initServerTests, multi: true},
{provide: CompilerFactory, useValue: BROWSER_DYNAMIC_TEST_COMPILER_FACTORY},
];
/** /**
* Platform for testing * Platform for testing
* *
* @experimental API related to bootstrapping are still under review. * @experimental API related to bootstrapping are still under review.
*/ */
export const serverTestPlatform = export const serverTestingPlatform = createPlatformFactory(
createPlatformFactory('serverTest', TEST_SERVER_PLATFORM_PROVIDERS); coreDynamicTestingPlatform, 'serverTesting', INTERNAL_SERVER_PLATFORM_PROVIDERS);
/** /**
* AppModule for testing. * NgModule for testing.
* *
* @stable * @experimental API related to bootstrapping are still under review.
*/ */
@AppModule({modules: [BrowserDynamicTestModule]}) @NgModule({exports: [BrowserDynamicTestingModule]})
export class ServerTestModule { export class ServerTestingModule {
} }
/** /**
* @deprecated Use initTestEnvironment with ServerTestModule instead. * Providers of the `serverTestingPlatform` to be used for creating own platform based on this.
*
* @deprecated Use `serverTestingPlatform()` or create a custom platform factory via
* `createPlatformFactory(serverTestingPlatform, ...)`
*/ */
export const TEST_SERVER_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> = export const TEST_SERVER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS; // Note: This is not a real provider but a hack to still support the deprecated
// `setBaseTestProviders` method!
[(appProviders: any[]) => {
const deprecatedConfiguration = analyzeAppProvidersForDeprecatedConfiguration(appProviders);
const platformRef = createPlatformFactory(serverTestingPlatform, 'serverTestingDeprecated', [{
provide: CompilerOptions,
useValue: deprecatedConfiguration.compilerOptions,
multi: true
}])();
@NgModule({
exports: [ServerTestingModule],
declarations: [deprecatedConfiguration.moduleDeclarations]
})
class DynamicTestModule {
}
const testInjector = initTestEnvironment(DynamicTestModule, platformRef);
const console: Console = testInjector.get(Console);
deprecatedConfiguration.deprecationMessages.forEach((msg) => console.warn(msg));
}];
/**
* @deprecated Use initTestEnvironment with ServerTestModule instead. This is empty for backwards
* compatibility,
* as all of our bootstrap methods add a module implicitly, i.e. keeping this filled would add the
* providers 2x.
*/
export const TEST_SERVER_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [];

View File

@ -9,4 +9,17 @@ The Angular router is designed to solve these problems. Using the router, you ca
Read the overview of the Router [here](http://victorsavkin.com/post/145672529346/angular-router). Read the overview of the Router [here](http://victorsavkin.com/post/145672529346/angular-router).
## Guide ## Guide
Read the dev guide [here](https://angular.io/docs/ts/latest/guide/router.html). Read the dev guide [here](https://angular.io/docs/ts/latest/guide/router.html).
## Local development
```
# keep @angular/router fresh
$ ./scripts/karma.sh
# keep @angular/core fresh
$ ../../../node_modules/.bin/tsc -p modules --emitDecoratorMetadata -w
# start karma
$ ./scripts/karma.sh
```

Some files were not shown because too many files have changed in this diff Show More