feat(core): introduce @AppModule

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

View File

@ -6,16 +6,27 @@
* found in the LICENSE file at https://angular.io/license
*/
import {unimplemented} from '../facade/exceptions';
import {BaseException, unimplemented} from '../facade/exceptions';
import {stringify} from '../facade/lang';
const _THROW_IF_NOT_FOUND = /*@ts2dart_const*/ new Object();
export const THROW_IF_NOT_FOUND = /*@ts2dart_const*/ _THROW_IF_NOT_FOUND;
class _NullInjector implements Injector {
get(token: any, notFoundValue: any = _THROW_IF_NOT_FOUND): any {
if (notFoundValue === _THROW_IF_NOT_FOUND) {
throw new BaseException(`No provider for ${stringify(token)}!`);
}
return notFoundValue;
}
}
/**
* @stable
*/
export abstract class Injector {
static THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
static NULL: Injector = new _NullInjector();
/**
* Retrieves an instance from the injector based on the provided token.

View File

@ -7,6 +7,7 @@
*/
// Public API for compiler
export {AppModuleFactory, AppModuleRef} from './linker/app_module_factory';
export {Compiler} from './linker/compiler';
export {ComponentFactory, ComponentRef} from './linker/component_factory';
export {ComponentFactoryResolver, NoComponentFactoryError} from './linker/component_factory_resolver';

View File

@ -0,0 +1,90 @@
/**
* @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 {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
import {unimplemented} from '../facade/exceptions';
import {ConcreteType} from '../facade/lang';
import {ComponentFactory} from './component_factory';
import {CodegenComponentFactoryResolver, ComponentFactoryResolver} from './component_factory_resolver';
/**
* Represents an instance of an AppModule created via a {@link AppModuleFactory}.
*
* `AppModuleRef` provides access to the AppModule Instance as well other objects related to this
* AppModule Instance.
* @stable
*/
export abstract class AppModuleRef<T> {
/**
* The injector that contains all of the providers of the AppModule.
*/
get injector(): Injector { return unimplemented(); }
/**
* The ComponentFactoryResolver to get hold of the ComponentFactories
* delcared in the `precompile` property of the module.
*/
get componentFactoryResolver(): ComponentFactoryResolver { return unimplemented(); }
/**
* The AppModule instance.
*/
get instance(): T { return unimplemented(); }
}
/**
* @stable
*/
export class AppModuleFactory<T> {
constructor(
private _injectorClass: {new (parentInjector: Injector): AppModuleInjector<T>},
private _moduleype: ConcreteType<T>) {}
get moduleType(): ConcreteType<T> { return this._moduleype; }
create(parentInjector: Injector = null): AppModuleRef<T> {
if (!parentInjector) {
parentInjector = Injector.NULL;
}
var instance = new this._injectorClass(parentInjector);
instance.create();
return instance;
}
}
const _UNDEFINED = new Object();
export abstract class AppModuleInjector<T> extends CodegenComponentFactoryResolver implements
Injector,
AppModuleRef<T> {
public instance: T;
constructor(public parent: Injector, factories: ComponentFactory<any>[]) {
super(factories, parent.get(ComponentFactoryResolver, ComponentFactoryResolver.NULL));
}
create() { this.instance = this.createInternal(); }
abstract createInternal(): T;
get(token: any, notFoundValue: any = THROW_IF_NOT_FOUND): any {
if (token === Injector || token === ComponentFactoryResolver) {
return this;
}
var result = this.getInternal(token, _UNDEFINED);
return result === _UNDEFINED ? this.parent.get(token, notFoundValue) : result;
}
abstract getInternal(token: any, notFoundValue: any): any;
get injector(): Injector { return this; }
get componentFactoryResolver(): ComponentFactoryResolver { return this; }
}

View File

@ -8,7 +8,9 @@
import {BaseException} from '../facade/exceptions';
import {ConcreteType, Type, stringify} from '../facade/lang';
import {AppModuleMetadata} from '../metadata/app_module';
import {AppModuleFactory} from './app_module_factory';
import {ComponentFactory} from './component_factory';
@ -22,7 +24,10 @@ export class Compiler {
/**
* 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>, {moduleDirectives = [], modulePipes = []}: {
moduleDirectives?: ConcreteType<any>[],
modulePipes?: ConcreteType<any>[]
} = {}): Promise<ComponentFactory<T>> {
throw new BaseException(
`Runtime compiler is not loaded. Tried to compile ${stringify(component)}`);
}
@ -30,16 +35,37 @@ export class Compiler {
* Compiles the given component. All templates have to be either inline or compiled via
* `compileComponentAsync` before.
*/
compileComponentSync<T>(component: ConcreteType<T>): ComponentFactory<T> {
compileComponentSync<T>(component: ConcreteType<T>, {moduleDirectives = [], modulePipes = []}: {
moduleDirectives?: ConcreteType<any>[],
modulePipes?: ConcreteType<any>[]
} = {}): ComponentFactory<T> {
throw new BaseException(
`Runtime compiler is not loaded. Tried to compile ${stringify(component)}`);
}
/**
* Compiles the given App Module. All templates of the components listed in `precompile`
* have to be either inline or compiled before via `compileComponentAsync` /
* `compileAppModuleAsync`.
*/
compileAppModuleSync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null):
AppModuleFactory<T> {
throw new BaseException(
`Runtime compiler is not loaded. Tried to compile ${stringify(moduleType)}`);
}
compileAppModuleAsync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null):
Promise<AppModuleFactory<T>> {
throw new BaseException(
`Runtime compiler is not loaded. Tried to compile ${stringify(moduleType)}`);
}
/**
* Clears all caches
*/
clearCache(): void {}
/**
* Clears the cache for the given component.
* Clears the cache for the given component/appModule.
*/
clearCacheFor(compType: Type) {}
clearCacheFor(type: Type) {}
}

View File

@ -14,10 +14,12 @@
import {ChangeDetectionStrategy} from '../src/change_detection/change_detection';
import {AnimationEntryMetadata} from './animation/metadata';
import {AppModuleMetadata} from './metadata/app_module';
import {AttributeMetadata, ContentChildMetadata, ContentChildrenMetadata, QueryMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata} from './metadata/di';
import {ComponentMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, InputMetadata, OutputMetadata, PipeMetadata} from './metadata/directives';
import {ViewEncapsulation, ViewMetadata} from './metadata/view';
export {AppModuleMetadata} from './metadata/app_module';
export {AttributeMetadata, ContentChildMetadata, ContentChildrenMetadata, QueryMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata} from './metadata/di';
export {ComponentMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, InputMetadata, OutputMetadata, PipeMetadata} from './metadata/directives';
export {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, OnChanges, OnDestroy, OnInit} from './metadata/lifecycle_hooks';
@ -83,6 +85,16 @@ export interface ViewDecorator extends TypeDecorator {
}): ViewDecorator;
}
/**
* Interface for the {@link AppModuleMetadata} decorator function.
*
* See {@link AppModuleMetadataFactory}.
*
* @stable
*/
export interface AppModuleDecorator extends TypeDecorator {}
/**
* {@link DirectiveMetadata} factory for creating annotations, decorators or DSL.
*
@ -477,6 +489,28 @@ export interface HostListenerMetadataFactory {
new (eventName: string, args?: string[]): any;
}
/**
* {@link AppModuleMetadata} factory for creating annotations, decorators or DSL.
*
* @stable
*/
export interface AppModuleMetadataFactory {
(obj: {
providers?: any[],
directives?: Array<Type|any[]>,
pipes?: Array<Type|any[]>,
precompile?: Array<Type|any[]>,
modules?: Array<Type|any[]>,
}): AppModuleDecorator;
new (obj: {
providers?: any[],
directives?: Array<Type|any[]>,
pipes?: Array<Type|any[]>,
precompile?: Array<Type|any[]>,
modules?: Array<Type|any[]>,
}): AppModuleMetadata;
}
// TODO(alexeagle): remove the duplication of this doc. It is copied from ComponentMetadata.
/**
* Declare reusable UI building blocks for an application.
@ -1499,3 +1533,11 @@ export var HostBinding: HostBindingMetadataFactory = makePropDecorator(HostBindi
* @Annotation
*/
export var HostListener: HostListenerMetadataFactory = makePropDecorator(HostListenerMetadata);
/**
* Declares an app module.
* @stable
* @Annotation
*/
export var AppModule: AppModuleMetadataFactory =
<AppModuleMetadataFactory>makeDecorator(AppModuleMetadata);

View File

@ -0,0 +1,113 @@
/**
* @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 {InjectableMetadata} from '../di/metadata';
import {Type} from '../facade/lang';
/**
* Declares an Application Module.
* @stable
*/
export class AppModuleMetadata extends InjectableMetadata {
/**
* Defines the set of injectable objects that are available in the injector
* of this module.
*
* ## Simple Example
*
* Here is an example of a class that can be injected:
*
* ```
* class Greeter {
* greet(name:string) {
* return 'Hello ' + name + '!';
* }
* }
*
* @AppModule({
* providers: [
* Greeter
* ]
* })
* class HelloWorld {
* greeter:Greeter;
*
* constructor(greeter:Greeter) {
* this.greeter = greeter;
* }
* }
* ```
*/
get providers(): any[] { return this._providers; }
private _providers: any[];
/**
* Specifies a list of directives that can be used within the template
* of any component that is part of this application module.
*
* ### Example
*
* ```javascript
* @AppModule({
* directives: [NgFor]
* })
* class MyAppModule {
* }
* ```
*/
directives: Array<Type|any[]>;
/**
* Specifies a list of pipes that can be used within the template
* of any component that is part of this application module.
*
* ### Example
*
* ```javascript
* @AppModule({
* pipes: [SomePipe]
* })
* class MyAppModule {
* }
* ```
*/
pipes: Array<Type|any[]>;
/**
* Defines the components that should be precompiled as well when
* this component is defined. For each components listed here,
* Angular will create a {@link ComponentFactory ComponentFactory} and store it in the
* {@link ComponentFactoryResolver ComponentFactoryResolver}.
*/
precompile: Array<Type|any[]>;
/**
* 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[],
directives?: Array<Type|any[]>,
pipes?: Array<Type|any[]>,
precompile?: Array<Type|any[]>,
modules?: Array<Type|any[]>
} = {}) {
super();
this._providers = providers;
this.directives = directives;
this.pipes = pipes;
this.precompile = precompile;
this.modules = modules;
}
}