repackaging: all the file moves
This commit is contained in:
46
modules/@angular/core/src/di/decorators.dart
Normal file
46
modules/@angular/core/src/di/decorators.dart
Normal file
@ -0,0 +1,46 @@
|
||||
library angular2.di.decorators;
|
||||
|
||||
import 'metadata.dart';
|
||||
export 'metadata.dart';
|
||||
|
||||
/**
|
||||
* {@link InjectMetadata}.
|
||||
*/
|
||||
class Inject extends InjectMetadata {
|
||||
const Inject(dynamic token) : super(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link OptionalMetadata}.
|
||||
*/
|
||||
class Optional extends OptionalMetadata {
|
||||
const Optional() : super();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link InjectableMetadata}.
|
||||
*/
|
||||
class Injectable extends InjectableMetadata {
|
||||
const Injectable() : super();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link SelfMetadata}.
|
||||
*/
|
||||
class Self extends SelfMetadata {
|
||||
const Self() : super();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link HostMetadata}.
|
||||
*/
|
||||
class Host extends HostMetadata {
|
||||
const Host() : super();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link SkipSelfMetadata}.
|
||||
*/
|
||||
class SkipSelf extends SkipSelfMetadata {
|
||||
const SkipSelf() : super();
|
||||
}
|
88
modules/@angular/core/src/di/decorators.ts
Normal file
88
modules/@angular/core/src/di/decorators.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import {
|
||||
InjectMetadata,
|
||||
OptionalMetadata,
|
||||
InjectableMetadata,
|
||||
SelfMetadata,
|
||||
HostMetadata,
|
||||
SkipSelfMetadata
|
||||
} from './metadata';
|
||||
import {makeDecorator, makeParamDecorator} from '../util/decorators';
|
||||
|
||||
/**
|
||||
* Factory for creating {@link InjectMetadata}.
|
||||
*/
|
||||
export interface InjectMetadataFactory {
|
||||
(token: any): any;
|
||||
new (token: any): InjectMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for creating {@link OptionalMetadata}.
|
||||
*/
|
||||
export interface OptionalMetadataFactory {
|
||||
(): any;
|
||||
new (): OptionalMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for creating {@link InjectableMetadata}.
|
||||
*/
|
||||
export interface InjectableMetadataFactory {
|
||||
(): any;
|
||||
new (): InjectableMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for creating {@link SelfMetadata}.
|
||||
*/
|
||||
export interface SelfMetadataFactory {
|
||||
(): any;
|
||||
new (): SelfMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for creating {@link HostMetadata}.
|
||||
*/
|
||||
export interface HostMetadataFactory {
|
||||
(): any;
|
||||
new (): HostMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for creating {@link SkipSelfMetadata}.
|
||||
*/
|
||||
export interface SkipSelfMetadataFactory {
|
||||
(): any;
|
||||
new (): SkipSelfMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for creating {@link InjectMetadata}.
|
||||
*/
|
||||
export var Inject: InjectMetadataFactory = makeParamDecorator(InjectMetadata);
|
||||
|
||||
/**
|
||||
* Factory for creating {@link OptionalMetadata}.
|
||||
*/
|
||||
export var Optional: OptionalMetadataFactory = makeParamDecorator(OptionalMetadata);
|
||||
|
||||
/**
|
||||
* Factory for creating {@link InjectableMetadata}.
|
||||
*/
|
||||
export var Injectable: InjectableMetadataFactory =
|
||||
<InjectableMetadataFactory>makeDecorator(InjectableMetadata);
|
||||
|
||||
/**
|
||||
* Factory for creating {@link SelfMetadata}.
|
||||
*/
|
||||
export var Self: SelfMetadataFactory = makeParamDecorator(SelfMetadata);
|
||||
|
||||
/**
|
||||
* Factory for creating {@link HostMetadata}.
|
||||
*/
|
||||
export var Host: HostMetadataFactory = makeParamDecorator(HostMetadata);
|
||||
|
||||
/**
|
||||
* Factory for creating {@link SkipSelfMetadata}.
|
||||
*/
|
||||
export var SkipSelf: SkipSelfMetadataFactory = makeParamDecorator(SkipSelfMetadata);
|
15
modules/@angular/core/src/di/forward_ref.dart
Normal file
15
modules/@angular/core/src/di/forward_ref.dart
Normal file
@ -0,0 +1,15 @@
|
||||
library angular2.di.forward_ref;
|
||||
|
||||
typedef dynamic ForwardRefFn();
|
||||
|
||||
/**
|
||||
* Dart does not have the forward ref problem, so this function is a noop.
|
||||
*/
|
||||
forwardRef(ForwardRefFn forwardRefFn) => forwardRefFn();
|
||||
|
||||
/**
|
||||
* Lazily retrieve the reference value.
|
||||
*
|
||||
* See: {@link forwardRef}
|
||||
*/
|
||||
resolveForwardRef(type) => type;
|
51
modules/@angular/core/src/di/forward_ref.ts
Normal file
51
modules/@angular/core/src/di/forward_ref.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import {Type, stringify, isFunction} from 'angular2/src/facade/lang';
|
||||
|
||||
/**
|
||||
* An interface that a function passed into {@link forwardRef} has to implement.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* {@example core/di/ts/forward_ref/forward_ref.ts region='forward_ref_fn'}
|
||||
*/
|
||||
export interface ForwardRefFn { (): any; }
|
||||
|
||||
/**
|
||||
* Allows to refer to references which are not yet defined.
|
||||
*
|
||||
* For instance, `forwardRef` is used when the `token` which we need to refer to for the purposes of
|
||||
* DI is declared,
|
||||
* but not yet defined. It is also used when the `token` which we use when creating a query is not
|
||||
* yet defined.
|
||||
*
|
||||
* ### Example
|
||||
* {@example core/di/ts/forward_ref/forward_ref.ts region='forward_ref'}
|
||||
*/
|
||||
export function forwardRef(forwardRefFn: ForwardRefFn): Type {
|
||||
(<any>forwardRefFn).__forward_ref__ = forwardRef;
|
||||
(<any>forwardRefFn).toString = function() { return stringify(this()); };
|
||||
return (<Type><any>forwardRefFn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily retrieves the reference value from a forwardRef.
|
||||
*
|
||||
* Acts as the identity function when given a non-forward-ref value.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/GU72mJrk1fiodChcmiDR?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* var ref = forwardRef(() => "refValue");
|
||||
* expect(resolveForwardRef(ref)).toEqual("refValue");
|
||||
* expect(resolveForwardRef("regularValue")).toEqual("regularValue");
|
||||
* ```
|
||||
*
|
||||
* See: {@link forwardRef}
|
||||
*/
|
||||
export function resolveForwardRef(type: any): any {
|
||||
if (isFunction(type) && type.hasOwnProperty('__forward_ref__') &&
|
||||
type.__forward_ref__ === forwardRef) {
|
||||
return (<ForwardRefFn>type)();
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
}
|
34
modules/@angular/core/src/di/injector.ts
Normal file
34
modules/@angular/core/src/di/injector.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import {unimplemented} from 'angular2/src/facade/exceptions';
|
||||
|
||||
const _THROW_IF_NOT_FOUND = /*@ts2dart_const*/ new Object();
|
||||
export const THROW_IF_NOT_FOUND = /*@ts2dart_const*/ _THROW_IF_NOT_FOUND;
|
||||
|
||||
export abstract class Injector {
|
||||
static THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
|
||||
|
||||
/**
|
||||
* Retrieves an instance from the injector based on the provided token.
|
||||
* If not found:
|
||||
* - Throws {@link NoProviderError} if no `notFoundValue` that is not equal to
|
||||
* Injector.THROW_IF_NOT_FOUND is given
|
||||
* - Returns the `notFoundValue` otherwise
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/HeXSHg?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* var injector = ReflectiveInjector.resolveAndCreate([
|
||||
* provide("validToken", {useValue: "Value"})
|
||||
* ]);
|
||||
* expect(injector.get("validToken")).toEqual("Value");
|
||||
* expect(() => injector.get("invalidToken")).toThrowError();
|
||||
* ```
|
||||
*
|
||||
* `Injector` returns itself when given `Injector` as a token.
|
||||
*
|
||||
* ```typescript
|
||||
* var injector = ReflectiveInjector.resolveAndCreate([]);
|
||||
* expect(injector.get(Injector)).toBe(injector);
|
||||
* ```
|
||||
*/
|
||||
get(token: any, notFoundValue?: any): any { return unimplemented(); }
|
||||
}
|
239
modules/@angular/core/src/di/metadata.ts
Normal file
239
modules/@angular/core/src/di/metadata.ts
Normal file
@ -0,0 +1,239 @@
|
||||
import {stringify, isBlank, isPresent} from "angular2/src/facade/lang";
|
||||
|
||||
/**
|
||||
* A parameter metadata that specifies a dependency.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/6uHYJK?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* class Engine {}
|
||||
*
|
||||
* @Injectable()
|
||||
* class Car {
|
||||
* engine;
|
||||
* constructor(@Inject("MyEngine") engine:Engine) {
|
||||
* this.engine = engine;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* provide("MyEngine", {useClass: Engine}),
|
||||
* Car
|
||||
* ]);
|
||||
*
|
||||
* expect(injector.get(Car).engine instanceof Engine).toBe(true);
|
||||
* ```
|
||||
*
|
||||
* When `@Inject()` is not present, {@link Injector} will use the type annotation of the parameter.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```typescript
|
||||
* class Engine {}
|
||||
*
|
||||
* @Injectable()
|
||||
* class Car {
|
||||
* constructor(public engine: Engine) {} //same as constructor(@Inject(Engine) engine:Engine)
|
||||
* }
|
||||
*
|
||||
* var injector = Injector.resolveAndCreate([Engine, Car]);
|
||||
* expect(injector.get(Car).engine instanceof Engine).toBe(true);
|
||||
* ```
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export class InjectMetadata {
|
||||
constructor(public token) {}
|
||||
toString(): string { return `@Inject(${stringify(this.token)})`; }
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameter metadata that marks a dependency as optional. {@link Injector} provides `null` if
|
||||
* the dependency is not found.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/AsryOm?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* class Engine {}
|
||||
*
|
||||
* @Injectable()
|
||||
* class Car {
|
||||
* engine;
|
||||
* constructor(@Optional() engine:Engine) {
|
||||
* this.engine = engine;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* var injector = Injector.resolveAndCreate([Car]);
|
||||
* expect(injector.get(Car).engine).toBeNull();
|
||||
* ```
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export class OptionalMetadata {
|
||||
toString(): string { return `@Optional()`; }
|
||||
}
|
||||
|
||||
/**
|
||||
* `DependencyMetadata` is used by the framework to extend DI.
|
||||
* This is internal to Angular and should not be used directly.
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export class DependencyMetadata {
|
||||
get token() { return null; }
|
||||
}
|
||||
|
||||
/**
|
||||
* A marker metadata that marks a class as available to {@link Injector} for creation.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Wk4DMQ?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* @Injectable()
|
||||
* class UsefulService {}
|
||||
*
|
||||
* @Injectable()
|
||||
* class NeedsService {
|
||||
* constructor(public service:UsefulService) {}
|
||||
* }
|
||||
*
|
||||
* var injector = Injector.resolveAndCreate([NeedsService, UsefulService]);
|
||||
* expect(injector.get(NeedsService).service instanceof UsefulService).toBe(true);
|
||||
* ```
|
||||
* {@link Injector} will throw {@link NoAnnotationError} when trying to instantiate a class that
|
||||
* does not have `@Injectable` marker, as shown in the example below.
|
||||
*
|
||||
* ```typescript
|
||||
* class UsefulService {}
|
||||
*
|
||||
* class NeedsService {
|
||||
* constructor(public service:UsefulService) {}
|
||||
* }
|
||||
*
|
||||
* var injector = Injector.resolveAndCreate([NeedsService, UsefulService]);
|
||||
* expect(() => injector.get(NeedsService)).toThrowError();
|
||||
* ```
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export class InjectableMetadata {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that an {@link Injector} should retrieve a dependency only from itself.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/NeagAg?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* class Dependency {
|
||||
* }
|
||||
*
|
||||
* @Injectable()
|
||||
* class NeedsDependency {
|
||||
* dependency;
|
||||
* constructor(@Self() dependency:Dependency) {
|
||||
* this.dependency = dependency;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* var inj = Injector.resolveAndCreate([Dependency, NeedsDependency]);
|
||||
* var nd = inj.get(NeedsDependency);
|
||||
*
|
||||
* expect(nd.dependency instanceof Dependency).toBe(true);
|
||||
*
|
||||
* var inj = Injector.resolveAndCreate([Dependency]);
|
||||
* var child = inj.resolveAndCreateChild([NeedsDependency]);
|
||||
* expect(() => child.get(NeedsDependency)).toThrowError();
|
||||
* ```
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export class SelfMetadata {
|
||||
toString(): string { return `@Self()`; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that the dependency resolution should start from the parent injector.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Wchdzb?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* class Dependency {
|
||||
* }
|
||||
*
|
||||
* @Injectable()
|
||||
* class NeedsDependency {
|
||||
* dependency;
|
||||
* constructor(@SkipSelf() dependency:Dependency) {
|
||||
* this.dependency = dependency;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* var parent = Injector.resolveAndCreate([Dependency]);
|
||||
* var child = parent.resolveAndCreateChild([NeedsDependency]);
|
||||
* expect(child.get(NeedsDependency).dependency instanceof Depedency).toBe(true);
|
||||
*
|
||||
* var inj = Injector.resolveAndCreate([Dependency, NeedsDependency]);
|
||||
* expect(() => inj.get(NeedsDependency)).toThrowError();
|
||||
* ```
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export class SkipSelfMetadata {
|
||||
toString(): string { return `@SkipSelf()`; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that an injector should retrieve a dependency from any injector until reaching the
|
||||
* closest host.
|
||||
*
|
||||
* In Angular, a component element is automatically declared as a host for all the injectors in
|
||||
* its view.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/GX79pV?p=preview))
|
||||
*
|
||||
* In the following example `App` contains `ParentCmp`, which contains `ChildDirective`.
|
||||
* So `ParentCmp` is the host of `ChildDirective`.
|
||||
*
|
||||
* `ChildDirective` depends on two services: `HostService` and `OtherService`.
|
||||
* `HostService` is defined at `ParentCmp`, and `OtherService` is defined at `App`.
|
||||
*
|
||||
*```typescript
|
||||
* class OtherService {}
|
||||
* class HostService {}
|
||||
*
|
||||
* @Directive({
|
||||
* selector: 'child-directive'
|
||||
* })
|
||||
* class ChildDirective {
|
||||
* constructor(@Optional() @Host() os:OtherService, @Optional() @Host() hs:HostService){
|
||||
* console.log("os is null", os);
|
||||
* console.log("hs is NOT null", hs);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'parent-cmp',
|
||||
* providers: [HostService],
|
||||
* template: `
|
||||
* Dir: <child-directive></child-directive>
|
||||
* `,
|
||||
* directives: [ChildDirective]
|
||||
* })
|
||||
* class ParentCmp {
|
||||
* }
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'app',
|
||||
* providers: [OtherService],
|
||||
* template: `
|
||||
* Parent: <parent-cmp></parent-cmp>
|
||||
* `,
|
||||
* directives: [ParentCmp]
|
||||
* })
|
||||
* class App {
|
||||
* }
|
||||
*
|
||||
* bootstrap(App);
|
||||
*```
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export class HostMetadata {
|
||||
toString(): string { return `@Host()`; }
|
||||
}
|
28
modules/@angular/core/src/di/opaque_token.ts
Normal file
28
modules/@angular/core/src/di/opaque_token.ts
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
/**
|
||||
* Creates a token that can be used in a DI Provider.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Ys9ezXpj2Mnoy3Uc8KBp?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* var t = new OpaqueToken("value");
|
||||
*
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* provide(t, {useValue: "bindingValue"})
|
||||
* ]);
|
||||
*
|
||||
* expect(injector.get(t)).toEqual("bindingValue");
|
||||
* ```
|
||||
*
|
||||
* Using an `OpaqueToken` is preferable to using strings as tokens because of possible collisions
|
||||
* caused by multiple providers using the same string as two different tokens.
|
||||
*
|
||||
* Using an `OpaqueToken` is preferable to using an `Object` as tokens because it provides better
|
||||
* error messages.
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export class OpaqueToken {
|
||||
constructor(private _desc: string) {}
|
||||
|
||||
toString(): string { return `Token ${this._desc}`; }
|
||||
}
|
411
modules/@angular/core/src/di/provider.ts
Normal file
411
modules/@angular/core/src/di/provider.ts
Normal file
@ -0,0 +1,411 @@
|
||||
import {
|
||||
normalizeBool,
|
||||
Type,
|
||||
isType,
|
||||
isBlank,
|
||||
isFunction,
|
||||
stringify
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
|
||||
/**
|
||||
* Describes how the {@link Injector} should instantiate a given token.
|
||||
*
|
||||
* See {@link provide}.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/GNAyj6K6PfYg2NBzgwZ5?p%3Dpreview&p=preview))
|
||||
*
|
||||
* ```javascript
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* new Provider("message", { useValue: 'Hello' })
|
||||
* ]);
|
||||
*
|
||||
* expect(injector.get("message")).toEqual('Hello');
|
||||
* ```
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export class Provider {
|
||||
/**
|
||||
* Token used when retrieving this provider. Usually, it is a type {@link Type}.
|
||||
*/
|
||||
token;
|
||||
|
||||
/**
|
||||
* Binds a DI token to an implementation class.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/RSTG86qgmoxCyj9SWPwY?p=preview))
|
||||
*
|
||||
* Because `useExisting` and `useClass` are often confused, the example contains
|
||||
* both use cases for easy comparison.
|
||||
*
|
||||
* ```typescript
|
||||
* class Vehicle {}
|
||||
*
|
||||
* class Car extends Vehicle {}
|
||||
*
|
||||
* var injectorClass = Injector.resolveAndCreate([
|
||||
* Car,
|
||||
* {provide: Vehicle, useClass: Car }
|
||||
* ]);
|
||||
* var injectorAlias = Injector.resolveAndCreate([
|
||||
* Car,
|
||||
* {provide: Vehicle, useExisting: Car }
|
||||
* ]);
|
||||
*
|
||||
* expect(injectorClass.get(Vehicle)).not.toBe(injectorClass.get(Car));
|
||||
* expect(injectorClass.get(Vehicle) instanceof Car).toBe(true);
|
||||
*
|
||||
* expect(injectorAlias.get(Vehicle)).toBe(injectorAlias.get(Car));
|
||||
* expect(injectorAlias.get(Vehicle) instanceof Car).toBe(true);
|
||||
* ```
|
||||
*/
|
||||
useClass: Type;
|
||||
|
||||
/**
|
||||
* Binds a DI token to a value.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/UFVsMVQIDe7l4waWziES?p=preview))
|
||||
*
|
||||
* ```javascript
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* new Provider("message", { useValue: 'Hello' })
|
||||
* ]);
|
||||
*
|
||||
* expect(injector.get("message")).toEqual('Hello');
|
||||
* ```
|
||||
*/
|
||||
useValue;
|
||||
|
||||
/**
|
||||
* Binds a DI token to an existing token.
|
||||
*
|
||||
* {@link Injector} returns the same instance as if the provided token was used.
|
||||
* This is in contrast to `useClass` where a separate instance of `useClass` is returned.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/QsatsOJJ6P8T2fMe9gr8?p=preview))
|
||||
*
|
||||
* Because `useExisting` and `useClass` are often confused the example contains
|
||||
* both use cases for easy comparison.
|
||||
*
|
||||
* ```typescript
|
||||
* class Vehicle {}
|
||||
*
|
||||
* class Car extends Vehicle {}
|
||||
*
|
||||
* var injectorAlias = Injector.resolveAndCreate([
|
||||
* Car,
|
||||
* {provide: Vehicle, useExisting: Car }
|
||||
* ]);
|
||||
* var injectorClass = Injector.resolveAndCreate([
|
||||
* Car,
|
||||
* {provide: Vehicle, useClass: Car }
|
||||
* ]);
|
||||
*
|
||||
* expect(injectorAlias.get(Vehicle)).toBe(injectorAlias.get(Car));
|
||||
* expect(injectorAlias.get(Vehicle) instanceof Car).toBe(true);
|
||||
*
|
||||
* expect(injectorClass.get(Vehicle)).not.toBe(injectorClass.get(Car));
|
||||
* expect(injectorClass.get(Vehicle) instanceof Car).toBe(true);
|
||||
* ```
|
||||
*/
|
||||
useExisting;
|
||||
|
||||
/**
|
||||
* Binds a DI token to a function which computes the value.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Scoxy0pJNqKGAPZY1VVC?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* {provide: Number, useFactory: () => { return 1+2; }},
|
||||
* new Provider(String, { useFactory: (value) => { return "Value: " + value; },
|
||||
* deps: [Number] })
|
||||
* ]);
|
||||
*
|
||||
* expect(injector.get(Number)).toEqual(3);
|
||||
* expect(injector.get(String)).toEqual('Value: 3');
|
||||
* ```
|
||||
*
|
||||
* Used in conjunction with dependencies.
|
||||
*/
|
||||
useFactory: Function;
|
||||
|
||||
/**
|
||||
* Specifies a set of dependencies
|
||||
* (as `token`s) which should be injected into the factory function.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Scoxy0pJNqKGAPZY1VVC?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* {provide: Number, useFactory: () => { return 1+2; }},
|
||||
* new Provider(String, { useFactory: (value) => { return "Value: " + value; },
|
||||
* deps: [Number] })
|
||||
* ]);
|
||||
*
|
||||
* expect(injector.get(Number)).toEqual(3);
|
||||
* expect(injector.get(String)).toEqual('Value: 3');
|
||||
* ```
|
||||
*
|
||||
* Used in conjunction with `useFactory`.
|
||||
*/
|
||||
dependencies: Object[];
|
||||
|
||||
/** @internal */
|
||||
_multi: boolean;
|
||||
|
||||
constructor(token, {useClass, useValue, useExisting, useFactory, deps, multi}: {
|
||||
useClass?: Type,
|
||||
useValue?: any,
|
||||
useExisting?: any,
|
||||
useFactory?: Function,
|
||||
deps?: Object[],
|
||||
multi?: boolean
|
||||
}) {
|
||||
this.token = token;
|
||||
this.useClass = useClass;
|
||||
this.useValue = useValue;
|
||||
this.useExisting = useExisting;
|
||||
this.useFactory = useFactory;
|
||||
this.dependencies = deps;
|
||||
this._multi = multi;
|
||||
}
|
||||
|
||||
// TODO: Provide a full working example after alpha38 is released.
|
||||
/**
|
||||
* Creates multiple providers matching the same token (a multi-provider).
|
||||
*
|
||||
* Multi-providers are used for creating pluggable service, where the system comes
|
||||
* with some default providers, and the user can register additional providers.
|
||||
* The combination of the default providers and the additional providers will be
|
||||
* used to drive the behavior of the system.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```typescript
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* new Provider("Strings", { useValue: "String1", multi: true}),
|
||||
* new Provider("Strings", { useValue: "String2", multi: true})
|
||||
* ]);
|
||||
*
|
||||
* expect(injector.get("Strings")).toEqual(["String1", "String2"]);
|
||||
* ```
|
||||
*
|
||||
* Multi-providers and regular providers cannot be mixed. The following
|
||||
* will throw an exception:
|
||||
*
|
||||
* ```typescript
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* new Provider("Strings", { useValue: "String1", multi: true }),
|
||||
* new Provider("Strings", { useValue: "String2"})
|
||||
* ]);
|
||||
* ```
|
||||
*/
|
||||
get multi(): boolean { return normalizeBool(this._multi); }
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link Provider} instead.
|
||||
*
|
||||
* @deprecated
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export class Binding extends Provider {
|
||||
constructor(token, {toClass, toValue, toAlias, toFactory, deps, multi}: {
|
||||
toClass?: Type,
|
||||
toValue?: any,
|
||||
toAlias?: any,
|
||||
toFactory: Function, deps?: Object[], multi?: boolean
|
||||
}) {
|
||||
super(token, {
|
||||
useClass: toClass,
|
||||
useValue: toValue,
|
||||
useExisting: toAlias,
|
||||
useFactory: toFactory,
|
||||
deps: deps,
|
||||
multi: multi
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
get toClass() { return this.useClass; }
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
get toAlias() { return this.useExisting; }
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
get toFactory() { return this.useFactory; }
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
get toValue() { return this.useValue; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Provider}.
|
||||
*
|
||||
* To construct a {@link Provider}, bind a `token` to either a class, a value, a factory function,
|
||||
* or
|
||||
* to an existing `token`.
|
||||
* See {@link ProviderBuilder} for more details.
|
||||
*
|
||||
* The `token` is most commonly a class or {@link OpaqueToken-class.html}.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
export function bind(token): ProviderBuilder {
|
||||
return new ProviderBuilder(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for the {@link bind} function.
|
||||
*/
|
||||
export class ProviderBuilder {
|
||||
constructor(public token) {}
|
||||
|
||||
/**
|
||||
* Binds a DI token to a class.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/ZpBCSYqv6e2ud5KXLdxQ?p=preview))
|
||||
*
|
||||
* Because `toAlias` and `toClass` are often confused, the example contains
|
||||
* both use cases for easy comparison.
|
||||
*
|
||||
* ```typescript
|
||||
* class Vehicle {}
|
||||
*
|
||||
* class Car extends Vehicle {}
|
||||
*
|
||||
* var injectorClass = Injector.resolveAndCreate([
|
||||
* Car,
|
||||
* provide(Vehicle, {useClass: Car})
|
||||
* ]);
|
||||
* var injectorAlias = Injector.resolveAndCreate([
|
||||
* Car,
|
||||
* provide(Vehicle, {useExisting: Car})
|
||||
* ]);
|
||||
*
|
||||
* expect(injectorClass.get(Vehicle)).not.toBe(injectorClass.get(Car));
|
||||
* expect(injectorClass.get(Vehicle) instanceof Car).toBe(true);
|
||||
*
|
||||
* expect(injectorAlias.get(Vehicle)).toBe(injectorAlias.get(Car));
|
||||
* expect(injectorAlias.get(Vehicle) instanceof Car).toBe(true);
|
||||
* ```
|
||||
*/
|
||||
toClass(type: Type): Provider {
|
||||
if (!isType(type)) {
|
||||
throw new BaseException(
|
||||
`Trying to create a class provider but "${stringify(type)}" is not a class!`);
|
||||
}
|
||||
return new Provider(this.token, {useClass: type});
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a DI token to a value.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/G024PFHmDL0cJFgfZK8O?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* provide('message', {useValue: 'Hello'})
|
||||
* ]);
|
||||
*
|
||||
* expect(injector.get('message')).toEqual('Hello');
|
||||
* ```
|
||||
*/
|
||||
toValue(value: any): Provider { return new Provider(this.token, {useValue: value}); }
|
||||
|
||||
/**
|
||||
* Binds a DI token to an existing token.
|
||||
*
|
||||
* Angular will return the same instance as if the provided token was used. (This is
|
||||
* in contrast to `useClass` where a separate instance of `useClass` will be returned.)
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/uBaoF2pN5cfc5AfZapNw?p=preview))
|
||||
*
|
||||
* Because `toAlias` and `toClass` are often confused, the example contains
|
||||
* both use cases for easy comparison.
|
||||
*
|
||||
* ```typescript
|
||||
* class Vehicle {}
|
||||
*
|
||||
* class Car extends Vehicle {}
|
||||
*
|
||||
* var injectorAlias = Injector.resolveAndCreate([
|
||||
* Car,
|
||||
* provide(Vehicle, {useExisting: Car})
|
||||
* ]);
|
||||
* var injectorClass = Injector.resolveAndCreate([
|
||||
* Car,
|
||||
* provide(Vehicle, {useClass: Car})
|
||||
* ]);
|
||||
*
|
||||
* expect(injectorAlias.get(Vehicle)).toBe(injectorAlias.get(Car));
|
||||
* expect(injectorAlias.get(Vehicle) instanceof Car).toBe(true);
|
||||
*
|
||||
* expect(injectorClass.get(Vehicle)).not.toBe(injectorClass.get(Car));
|
||||
* expect(injectorClass.get(Vehicle) instanceof Car).toBe(true);
|
||||
* ```
|
||||
*/
|
||||
toAlias(aliasToken: /*Type*/ any): Provider {
|
||||
if (isBlank(aliasToken)) {
|
||||
throw new BaseException(`Can not alias ${stringify(this.token)} to a blank value!`);
|
||||
}
|
||||
return new Provider(this.token, {useExisting: aliasToken});
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a DI token to a function which computes the value.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/OejNIfTT3zb1iBxaIYOb?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* provide(Number, {useFactory: () => { return 1+2; }}),
|
||||
* provide(String, {useFactory: (v) => { return "Value: " + v; }, deps: [Number]})
|
||||
* ]);
|
||||
*
|
||||
* expect(injector.get(Number)).toEqual(3);
|
||||
* expect(injector.get(String)).toEqual('Value: 3');
|
||||
* ```
|
||||
*/
|
||||
toFactory(factory: Function, dependencies?: any[]): Provider {
|
||||
if (!isFunction(factory)) {
|
||||
throw new BaseException(
|
||||
`Trying to create a factory provider but "${stringify(factory)}" is not a function!`);
|
||||
}
|
||||
return new Provider(this.token, {useFactory: factory, deps: dependencies});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Provider}.
|
||||
*
|
||||
* See {@link Provider} for more details.
|
||||
*
|
||||
* <!-- TODO: improve the docs -->
|
||||
*/
|
||||
export function provide(token, {useClass, useValue, useExisting, useFactory, deps, multi}: {
|
||||
useClass?: Type,
|
||||
useValue?: any,
|
||||
useExisting?: any,
|
||||
useFactory?: Function,
|
||||
deps?: Object[],
|
||||
multi?: boolean
|
||||
}): Provider {
|
||||
return new Provider(token, {
|
||||
useClass: useClass,
|
||||
useValue: useValue,
|
||||
useExisting: useExisting,
|
||||
useFactory: useFactory,
|
||||
deps: deps,
|
||||
multi: multi
|
||||
});
|
||||
}
|
268
modules/@angular/core/src/di/reflective_exceptions.ts
Normal file
268
modules/@angular/core/src/di/reflective_exceptions.ts
Normal file
@ -0,0 +1,268 @@
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {stringify, isBlank} from 'angular2/src/facade/lang';
|
||||
import {BaseException, WrappedException, unimplemented} from 'angular2/src/facade/exceptions';
|
||||
import {ReflectiveKey} from './reflective_key';
|
||||
import {ReflectiveInjector} from './reflective_injector';
|
||||
|
||||
function findFirstClosedCycle(keys: any[]): any[] {
|
||||
var res = [];
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
if (ListWrapper.contains(res, keys[i])) {
|
||||
res.push(keys[i]);
|
||||
return res;
|
||||
} else {
|
||||
res.push(keys[i]);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function constructResolvingPath(keys: any[]): string {
|
||||
if (keys.length > 1) {
|
||||
var reversed = findFirstClosedCycle(ListWrapper.reversed(keys));
|
||||
var tokenStrs = reversed.map(k => stringify(k.token));
|
||||
return " (" + tokenStrs.join(' -> ') + ")";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for all errors arising from misconfigured providers.
|
||||
*/
|
||||
export class AbstractProviderError extends BaseException {
|
||||
/** @internal */
|
||||
message: string;
|
||||
|
||||
/** @internal */
|
||||
keys: ReflectiveKey[];
|
||||
|
||||
/** @internal */
|
||||
injectors: ReflectiveInjector[];
|
||||
|
||||
/** @internal */
|
||||
constructResolvingMessage: Function;
|
||||
|
||||
constructor(injector: ReflectiveInjector, key: ReflectiveKey,
|
||||
constructResolvingMessage: Function) {
|
||||
super("DI Exception");
|
||||
this.keys = [key];
|
||||
this.injectors = [injector];
|
||||
this.constructResolvingMessage = constructResolvingMessage;
|
||||
this.message = this.constructResolvingMessage(this.keys);
|
||||
}
|
||||
|
||||
addKey(injector: ReflectiveInjector, key: ReflectiveKey): void {
|
||||
this.injectors.push(injector);
|
||||
this.keys.push(key);
|
||||
this.message = this.constructResolvingMessage(this.keys);
|
||||
}
|
||||
|
||||
get context() { return this.injectors[this.injectors.length - 1].debugContext(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when trying to retrieve a dependency by `Key` from {@link Injector}, but the
|
||||
* {@link Injector} does not have a {@link Provider} for {@link Key}.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/vq8D3FRB9aGbnWJqtEPE?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* class A {
|
||||
* constructor(b:B) {}
|
||||
* }
|
||||
*
|
||||
* expect(() => Injector.resolveAndCreate([A])).toThrowError();
|
||||
* ```
|
||||
*/
|
||||
export class NoProviderError extends AbstractProviderError {
|
||||
constructor(injector: ReflectiveInjector, key: ReflectiveKey) {
|
||||
super(injector, key, function(keys: any[]) {
|
||||
var first = stringify(ListWrapper.first(keys).token);
|
||||
return `No provider for ${first}!${constructResolvingPath(keys)}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when dependencies form a cycle.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/wYQdNos0Tzql3ei1EV9j?p=info))
|
||||
*
|
||||
* ```typescript
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* provide("one", {useFactory: (two) => "two", deps: [[new Inject("two")]]}),
|
||||
* provide("two", {useFactory: (one) => "one", deps: [[new Inject("one")]]})
|
||||
* ]);
|
||||
*
|
||||
* expect(() => injector.get("one")).toThrowError();
|
||||
* ```
|
||||
*
|
||||
* Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed.
|
||||
*/
|
||||
export class CyclicDependencyError extends AbstractProviderError {
|
||||
constructor(injector: ReflectiveInjector, key: ReflectiveKey) {
|
||||
super(injector, key, function(keys: any[]) {
|
||||
return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when a constructing type returns with an Error.
|
||||
*
|
||||
* The `InstantiationError` class contains the original error plus the dependency graph which caused
|
||||
* this object to be instantiated.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/7aWYdcqTQsP0eNqEdUAf?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* class A {
|
||||
* constructor() {
|
||||
* throw new Error('message');
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* var injector = Injector.resolveAndCreate([A]);
|
||||
|
||||
* try {
|
||||
* injector.get(A);
|
||||
* } catch (e) {
|
||||
* expect(e instanceof InstantiationError).toBe(true);
|
||||
* expect(e.originalException.message).toEqual("message");
|
||||
* expect(e.originalStack).toBeDefined();
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export class InstantiationError extends WrappedException {
|
||||
/** @internal */
|
||||
keys: ReflectiveKey[];
|
||||
|
||||
/** @internal */
|
||||
injectors: ReflectiveInjector[];
|
||||
|
||||
constructor(injector: ReflectiveInjector, originalException, originalStack, key: ReflectiveKey) {
|
||||
super("DI Exception", originalException, originalStack, null);
|
||||
this.keys = [key];
|
||||
this.injectors = [injector];
|
||||
}
|
||||
|
||||
addKey(injector: ReflectiveInjector, key: ReflectiveKey): void {
|
||||
this.injectors.push(injector);
|
||||
this.keys.push(key);
|
||||
}
|
||||
|
||||
get wrapperMessage(): string {
|
||||
var first = stringify(ListWrapper.first(this.keys).token);
|
||||
return `Error during instantiation of ${first}!${constructResolvingPath(this.keys)}.`;
|
||||
}
|
||||
|
||||
get causeKey(): ReflectiveKey { return this.keys[0]; }
|
||||
|
||||
get context() { return this.injectors[this.injectors.length - 1].debugContext(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when an object other then {@link Provider} (or `Type`) is passed to {@link Injector}
|
||||
* creation.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/YatCFbPAMCL0JSSQ4mvH?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* expect(() => Injector.resolveAndCreate(["not a type"])).toThrowError();
|
||||
* ```
|
||||
*/
|
||||
export class InvalidProviderError extends BaseException {
|
||||
constructor(provider) {
|
||||
super("Invalid provider - only instances of Provider and Type are allowed, got: " +
|
||||
provider.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when the class has no annotation information.
|
||||
*
|
||||
* Lack of annotation information prevents the {@link Injector} from determining which dependencies
|
||||
* need to be injected into the constructor.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/rHnZtlNS7vJOPQ6pcVkm?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* class A {
|
||||
* constructor(b) {}
|
||||
* }
|
||||
*
|
||||
* expect(() => Injector.resolveAndCreate([A])).toThrowError();
|
||||
* ```
|
||||
*
|
||||
* This error is also thrown when the class not marked with {@link Injectable} has parameter types.
|
||||
*
|
||||
* ```typescript
|
||||
* class B {}
|
||||
*
|
||||
* class A {
|
||||
* constructor(b:B) {} // no information about the parameter types of A is available at runtime.
|
||||
* }
|
||||
*
|
||||
* expect(() => Injector.resolveAndCreate([A,B])).toThrowError();
|
||||
* ```
|
||||
*/
|
||||
export class NoAnnotationError extends BaseException {
|
||||
constructor(typeOrFunc, params: any[][]) {
|
||||
super(NoAnnotationError._genMessage(typeOrFunc, params));
|
||||
}
|
||||
|
||||
private static _genMessage(typeOrFunc, params: any[][]) {
|
||||
var signature = [];
|
||||
for (var i = 0, ii = params.length; i < ii; i++) {
|
||||
var parameter = params[i];
|
||||
if (isBlank(parameter) || parameter.length == 0) {
|
||||
signature.push('?');
|
||||
} else {
|
||||
signature.push(parameter.map(stringify).join(' '));
|
||||
}
|
||||
}
|
||||
return "Cannot resolve all parameters for '" + stringify(typeOrFunc) + "'(" +
|
||||
signature.join(', ') + "). " +
|
||||
"Make sure that all the parameters are decorated with Inject or have valid type annotations and that '" +
|
||||
stringify(typeOrFunc) + "' is decorated with Injectable.";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when getting an object by index.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/bRs0SX2OTQiJzqvjgl8P?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* class A {}
|
||||
*
|
||||
* var injector = Injector.resolveAndCreate([A]);
|
||||
*
|
||||
* expect(() => injector.getAt(100)).toThrowError();
|
||||
* ```
|
||||
*/
|
||||
export class OutOfBoundsError extends BaseException {
|
||||
constructor(index) { super(`Index ${index} is out-of-bounds.`); }
|
||||
}
|
||||
|
||||
// TODO: add a working example after alpha38 is released
|
||||
/**
|
||||
* Thrown when a multi provider and a regular provider are bound to the same token.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```typescript
|
||||
* expect(() => Injector.resolveAndCreate([
|
||||
* new Provider("Strings", {useValue: "string1", multi: true}),
|
||||
* new Provider("Strings", {useValue: "string2", multi: false})
|
||||
* ])).toThrowError();
|
||||
* ```
|
||||
*/
|
||||
export class MixingMultiProvidersWithRegularProvidersError extends BaseException {
|
||||
constructor(provider1, provider2) {
|
||||
super("Cannot mix multi providers and regular providers, got: " + provider1.toString() + " " +
|
||||
provider2.toString());
|
||||
}
|
||||
}
|
889
modules/@angular/core/src/di/reflective_injector.ts
Normal file
889
modules/@angular/core/src/di/reflective_injector.ts
Normal file
@ -0,0 +1,889 @@
|
||||
import {Map, MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {Provider, ProviderBuilder, provide} from './provider';
|
||||
import {
|
||||
ResolvedReflectiveProvider,
|
||||
ReflectiveDependency,
|
||||
ResolvedReflectiveFactory,
|
||||
resolveReflectiveProviders
|
||||
} from './reflective_provider';
|
||||
import {
|
||||
AbstractProviderError,
|
||||
NoProviderError,
|
||||
CyclicDependencyError,
|
||||
InstantiationError,
|
||||
InvalidProviderError,
|
||||
OutOfBoundsError
|
||||
} from './reflective_exceptions';
|
||||
import {Type, isPresent} from 'angular2/src/facade/lang';
|
||||
import {BaseException, unimplemented} from 'angular2/src/facade/exceptions';
|
||||
import {ReflectiveKey} from './reflective_key';
|
||||
import {SelfMetadata, HostMetadata, SkipSelfMetadata} from './metadata';
|
||||
import {Injector, THROW_IF_NOT_FOUND} from './injector';
|
||||
|
||||
var __unused: Type; // avoid unused import when Type union types are erased
|
||||
|
||||
// Threshold for the dynamic version
|
||||
const _MAX_CONSTRUCTION_COUNTER = 10;
|
||||
const UNDEFINED = /*@ts2dart_const*/ new Object();
|
||||
|
||||
export interface ReflectiveProtoInjectorStrategy {
|
||||
getProviderAtIndex(index: number): ResolvedReflectiveProvider;
|
||||
createInjectorStrategy(inj: ReflectiveInjector_): ReflectiveInjectorStrategy;
|
||||
}
|
||||
|
||||
export class ReflectiveProtoInjectorInlineStrategy implements ReflectiveProtoInjectorStrategy {
|
||||
provider0: ResolvedReflectiveProvider = null;
|
||||
provider1: ResolvedReflectiveProvider = null;
|
||||
provider2: ResolvedReflectiveProvider = null;
|
||||
provider3: ResolvedReflectiveProvider = null;
|
||||
provider4: ResolvedReflectiveProvider = null;
|
||||
provider5: ResolvedReflectiveProvider = null;
|
||||
provider6: ResolvedReflectiveProvider = null;
|
||||
provider7: ResolvedReflectiveProvider = null;
|
||||
provider8: ResolvedReflectiveProvider = null;
|
||||
provider9: ResolvedReflectiveProvider = null;
|
||||
|
||||
keyId0: number = null;
|
||||
keyId1: number = null;
|
||||
keyId2: number = null;
|
||||
keyId3: number = null;
|
||||
keyId4: number = null;
|
||||
keyId5: number = null;
|
||||
keyId6: number = null;
|
||||
keyId7: number = null;
|
||||
keyId8: number = null;
|
||||
keyId9: number = null;
|
||||
|
||||
constructor(protoEI: ReflectiveProtoInjector, providers: ResolvedReflectiveProvider[]) {
|
||||
var length = providers.length;
|
||||
|
||||
if (length > 0) {
|
||||
this.provider0 = providers[0];
|
||||
this.keyId0 = providers[0].key.id;
|
||||
}
|
||||
if (length > 1) {
|
||||
this.provider1 = providers[1];
|
||||
this.keyId1 = providers[1].key.id;
|
||||
}
|
||||
if (length > 2) {
|
||||
this.provider2 = providers[2];
|
||||
this.keyId2 = providers[2].key.id;
|
||||
}
|
||||
if (length > 3) {
|
||||
this.provider3 = providers[3];
|
||||
this.keyId3 = providers[3].key.id;
|
||||
}
|
||||
if (length > 4) {
|
||||
this.provider4 = providers[4];
|
||||
this.keyId4 = providers[4].key.id;
|
||||
}
|
||||
if (length > 5) {
|
||||
this.provider5 = providers[5];
|
||||
this.keyId5 = providers[5].key.id;
|
||||
}
|
||||
if (length > 6) {
|
||||
this.provider6 = providers[6];
|
||||
this.keyId6 = providers[6].key.id;
|
||||
}
|
||||
if (length > 7) {
|
||||
this.provider7 = providers[7];
|
||||
this.keyId7 = providers[7].key.id;
|
||||
}
|
||||
if (length > 8) {
|
||||
this.provider8 = providers[8];
|
||||
this.keyId8 = providers[8].key.id;
|
||||
}
|
||||
if (length > 9) {
|
||||
this.provider9 = providers[9];
|
||||
this.keyId9 = providers[9].key.id;
|
||||
}
|
||||
}
|
||||
|
||||
getProviderAtIndex(index: number): ResolvedReflectiveProvider {
|
||||
if (index == 0) return this.provider0;
|
||||
if (index == 1) return this.provider1;
|
||||
if (index == 2) return this.provider2;
|
||||
if (index == 3) return this.provider3;
|
||||
if (index == 4) return this.provider4;
|
||||
if (index == 5) return this.provider5;
|
||||
if (index == 6) return this.provider6;
|
||||
if (index == 7) return this.provider7;
|
||||
if (index == 8) return this.provider8;
|
||||
if (index == 9) return this.provider9;
|
||||
throw new OutOfBoundsError(index);
|
||||
}
|
||||
|
||||
createInjectorStrategy(injector: ReflectiveInjector_): ReflectiveInjectorStrategy {
|
||||
return new ReflectiveInjectorInlineStrategy(injector, this);
|
||||
}
|
||||
}
|
||||
|
||||
export class ReflectiveProtoInjectorDynamicStrategy implements ReflectiveProtoInjectorStrategy {
|
||||
keyIds: number[];
|
||||
|
||||
constructor(protoInj: ReflectiveProtoInjector, public providers: ResolvedReflectiveProvider[]) {
|
||||
var len = providers.length;
|
||||
|
||||
this.keyIds = ListWrapper.createFixedSize(len);
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
this.keyIds[i] = providers[i].key.id;
|
||||
}
|
||||
}
|
||||
|
||||
getProviderAtIndex(index: number): ResolvedReflectiveProvider {
|
||||
if (index < 0 || index >= this.providers.length) {
|
||||
throw new OutOfBoundsError(index);
|
||||
}
|
||||
return this.providers[index];
|
||||
}
|
||||
|
||||
createInjectorStrategy(ei: ReflectiveInjector_): ReflectiveInjectorStrategy {
|
||||
return new ReflectiveInjectorDynamicStrategy(this, ei);
|
||||
}
|
||||
}
|
||||
|
||||
export class ReflectiveProtoInjector {
|
||||
static fromResolvedProviders(providers: ResolvedReflectiveProvider[]): ReflectiveProtoInjector {
|
||||
return new ReflectiveProtoInjector(providers);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_strategy: ReflectiveProtoInjectorStrategy;
|
||||
numberOfProviders: number;
|
||||
|
||||
constructor(providers: ResolvedReflectiveProvider[]) {
|
||||
this.numberOfProviders = providers.length;
|
||||
this._strategy = providers.length > _MAX_CONSTRUCTION_COUNTER ?
|
||||
new ReflectiveProtoInjectorDynamicStrategy(this, providers) :
|
||||
new ReflectiveProtoInjectorInlineStrategy(this, providers);
|
||||
}
|
||||
|
||||
getProviderAtIndex(index: number): ResolvedReflectiveProvider {
|
||||
return this._strategy.getProviderAtIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export interface ReflectiveInjectorStrategy {
|
||||
getObjByKeyId(keyId: number): any;
|
||||
getObjAtIndex(index: number): any;
|
||||
getMaxNumberOfObjects(): number;
|
||||
|
||||
resetConstructionCounter(): void;
|
||||
instantiateProvider(provider: ResolvedReflectiveProvider): any;
|
||||
}
|
||||
|
||||
export class ReflectiveInjectorInlineStrategy implements ReflectiveInjectorStrategy {
|
||||
obj0: any = UNDEFINED;
|
||||
obj1: any = UNDEFINED;
|
||||
obj2: any = UNDEFINED;
|
||||
obj3: any = UNDEFINED;
|
||||
obj4: any = UNDEFINED;
|
||||
obj5: any = UNDEFINED;
|
||||
obj6: any = UNDEFINED;
|
||||
obj7: any = UNDEFINED;
|
||||
obj8: any = UNDEFINED;
|
||||
obj9: any = UNDEFINED;
|
||||
|
||||
constructor(public injector: ReflectiveInjector_,
|
||||
public protoStrategy: ReflectiveProtoInjectorInlineStrategy) {}
|
||||
|
||||
resetConstructionCounter(): void { this.injector._constructionCounter = 0; }
|
||||
|
||||
instantiateProvider(provider: ResolvedReflectiveProvider): any {
|
||||
return this.injector._new(provider);
|
||||
}
|
||||
|
||||
getObjByKeyId(keyId: number): any {
|
||||
var p = this.protoStrategy;
|
||||
var inj = this.injector;
|
||||
|
||||
if (p.keyId0 === keyId) {
|
||||
if (this.obj0 === UNDEFINED) {
|
||||
this.obj0 = inj._new(p.provider0);
|
||||
}
|
||||
return this.obj0;
|
||||
}
|
||||
if (p.keyId1 === keyId) {
|
||||
if (this.obj1 === UNDEFINED) {
|
||||
this.obj1 = inj._new(p.provider1);
|
||||
}
|
||||
return this.obj1;
|
||||
}
|
||||
if (p.keyId2 === keyId) {
|
||||
if (this.obj2 === UNDEFINED) {
|
||||
this.obj2 = inj._new(p.provider2);
|
||||
}
|
||||
return this.obj2;
|
||||
}
|
||||
if (p.keyId3 === keyId) {
|
||||
if (this.obj3 === UNDEFINED) {
|
||||
this.obj3 = inj._new(p.provider3);
|
||||
}
|
||||
return this.obj3;
|
||||
}
|
||||
if (p.keyId4 === keyId) {
|
||||
if (this.obj4 === UNDEFINED) {
|
||||
this.obj4 = inj._new(p.provider4);
|
||||
}
|
||||
return this.obj4;
|
||||
}
|
||||
if (p.keyId5 === keyId) {
|
||||
if (this.obj5 === UNDEFINED) {
|
||||
this.obj5 = inj._new(p.provider5);
|
||||
}
|
||||
return this.obj5;
|
||||
}
|
||||
if (p.keyId6 === keyId) {
|
||||
if (this.obj6 === UNDEFINED) {
|
||||
this.obj6 = inj._new(p.provider6);
|
||||
}
|
||||
return this.obj6;
|
||||
}
|
||||
if (p.keyId7 === keyId) {
|
||||
if (this.obj7 === UNDEFINED) {
|
||||
this.obj7 = inj._new(p.provider7);
|
||||
}
|
||||
return this.obj7;
|
||||
}
|
||||
if (p.keyId8 === keyId) {
|
||||
if (this.obj8 === UNDEFINED) {
|
||||
this.obj8 = inj._new(p.provider8);
|
||||
}
|
||||
return this.obj8;
|
||||
}
|
||||
if (p.keyId9 === keyId) {
|
||||
if (this.obj9 === UNDEFINED) {
|
||||
this.obj9 = inj._new(p.provider9);
|
||||
}
|
||||
return this.obj9;
|
||||
}
|
||||
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
getObjAtIndex(index: number): any {
|
||||
if (index == 0) return this.obj0;
|
||||
if (index == 1) return this.obj1;
|
||||
if (index == 2) return this.obj2;
|
||||
if (index == 3) return this.obj3;
|
||||
if (index == 4) return this.obj4;
|
||||
if (index == 5) return this.obj5;
|
||||
if (index == 6) return this.obj6;
|
||||
if (index == 7) return this.obj7;
|
||||
if (index == 8) return this.obj8;
|
||||
if (index == 9) return this.obj9;
|
||||
throw new OutOfBoundsError(index);
|
||||
}
|
||||
|
||||
getMaxNumberOfObjects(): number { return _MAX_CONSTRUCTION_COUNTER; }
|
||||
}
|
||||
|
||||
|
||||
export class ReflectiveInjectorDynamicStrategy implements ReflectiveInjectorStrategy {
|
||||
objs: any[];
|
||||
|
||||
constructor(public protoStrategy: ReflectiveProtoInjectorDynamicStrategy,
|
||||
public injector: ReflectiveInjector_) {
|
||||
this.objs = ListWrapper.createFixedSize(protoStrategy.providers.length);
|
||||
ListWrapper.fill(this.objs, UNDEFINED);
|
||||
}
|
||||
|
||||
resetConstructionCounter(): void { this.injector._constructionCounter = 0; }
|
||||
|
||||
instantiateProvider(provider: ResolvedReflectiveProvider): any {
|
||||
return this.injector._new(provider);
|
||||
}
|
||||
|
||||
getObjByKeyId(keyId: number): any {
|
||||
var p = this.protoStrategy;
|
||||
|
||||
for (var i = 0; i < p.keyIds.length; i++) {
|
||||
if (p.keyIds[i] === keyId) {
|
||||
if (this.objs[i] === UNDEFINED) {
|
||||
this.objs[i] = this.injector._new(p.providers[i]);
|
||||
}
|
||||
|
||||
return this.objs[i];
|
||||
}
|
||||
}
|
||||
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
getObjAtIndex(index: number): any {
|
||||
if (index < 0 || index >= this.objs.length) {
|
||||
throw new OutOfBoundsError(index);
|
||||
}
|
||||
|
||||
return this.objs[index];
|
||||
}
|
||||
|
||||
getMaxNumberOfObjects(): number { return this.objs.length; }
|
||||
}
|
||||
|
||||
/**
|
||||
* A ReflectiveDependency injection container used for instantiating objects and resolving
|
||||
* dependencies.
|
||||
*
|
||||
* An `Injector` is a replacement for a `new` operator, which can automatically resolve the
|
||||
* constructor dependencies.
|
||||
*
|
||||
* In typical use, application code asks for the dependencies in the constructor and they are
|
||||
* resolved by the `Injector`.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/jzjec0?p=preview))
|
||||
*
|
||||
* The following example creates an `Injector` configured to create `Engine` and `Car`.
|
||||
*
|
||||
* ```typescript
|
||||
* @Injectable()
|
||||
* class Engine {
|
||||
* }
|
||||
*
|
||||
* @Injectable()
|
||||
* class Car {
|
||||
* constructor(public engine:Engine) {}
|
||||
* }
|
||||
*
|
||||
* var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
|
||||
* var car = injector.get(Car);
|
||||
* expect(car instanceof Car).toBe(true);
|
||||
* expect(car.engine instanceof Engine).toBe(true);
|
||||
* ```
|
||||
*
|
||||
* Notice, we don't use the `new` operator because we explicitly want to have the `Injector`
|
||||
* resolve all of the object's dependencies automatically.
|
||||
*/
|
||||
export abstract class ReflectiveInjector implements Injector {
|
||||
/**
|
||||
* Turns an array of provider definitions into an array of resolved providers.
|
||||
*
|
||||
* A resolution is a process of flattening multiple nested arrays and converting individual
|
||||
* providers into an array of {@link ResolvedReflectiveProvider}s.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/AiXTHi?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* @Injectable()
|
||||
* class Engine {
|
||||
* }
|
||||
*
|
||||
* @Injectable()
|
||||
* class Car {
|
||||
* constructor(public engine:Engine) {}
|
||||
* }
|
||||
*
|
||||
* var providers = ReflectiveInjector.resolve([Car, [[Engine]]]);
|
||||
*
|
||||
* expect(providers.length).toEqual(2);
|
||||
*
|
||||
* expect(providers[0] instanceof ResolvedReflectiveProvider).toBe(true);
|
||||
* expect(providers[0].key.displayName).toBe("Car");
|
||||
* expect(providers[0].dependencies.length).toEqual(1);
|
||||
* expect(providers[0].factory).toBeDefined();
|
||||
*
|
||||
* expect(providers[1].key.displayName).toBe("Engine");
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* See {@link ReflectiveInjector#fromResolvedProviders} for more info.
|
||||
*/
|
||||
static resolve(providers: Array<Type | Provider | {[k: string]: any} | any[]>):
|
||||
ResolvedReflectiveProvider[] {
|
||||
return resolveReflectiveProviders(providers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves an array of providers and creates an injector from those providers.
|
||||
*
|
||||
* The passed-in providers can be an array of `Type`, {@link Provider},
|
||||
* or a recursive array of more providers.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/ePOccA?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* @Injectable()
|
||||
* class Engine {
|
||||
* }
|
||||
*
|
||||
* @Injectable()
|
||||
* class Car {
|
||||
* constructor(public engine:Engine) {}
|
||||
* }
|
||||
*
|
||||
* var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
|
||||
* expect(injector.get(Car) instanceof Car).toBe(true);
|
||||
* ```
|
||||
*
|
||||
* This function is slower than the corresponding `fromResolvedProviders`
|
||||
* because it needs to resolve the passed-in providers first.
|
||||
* See {@link Injector#resolve} and {@link Injector#fromResolvedProviders}.
|
||||
*/
|
||||
static resolveAndCreate(providers: Array<Type | Provider | {[k: string]: any} | any[]>,
|
||||
parent: Injector = null): ReflectiveInjector {
|
||||
var ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
|
||||
return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an injector from previously resolved providers.
|
||||
*
|
||||
* This API is the recommended way to construct injectors in performance-sensitive parts.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/KrSMci?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* @Injectable()
|
||||
* class Engine {
|
||||
* }
|
||||
*
|
||||
* @Injectable()
|
||||
* class Car {
|
||||
* constructor(public engine:Engine) {}
|
||||
* }
|
||||
*
|
||||
* var providers = ReflectiveInjector.resolve([Car, Engine]);
|
||||
* var injector = ReflectiveInjector.fromResolvedProviders(providers);
|
||||
* expect(injector.get(Car) instanceof Car).toBe(true);
|
||||
* ```
|
||||
*/
|
||||
static fromResolvedProviders(providers: ResolvedReflectiveProvider[],
|
||||
parent: Injector = null): ReflectiveInjector {
|
||||
return new ReflectiveInjector_(ReflectiveProtoInjector.fromResolvedProviders(providers),
|
||||
parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
static fromResolvedBindings(providers: ResolvedReflectiveProvider[]): ReflectiveInjector {
|
||||
return ReflectiveInjector.fromResolvedProviders(providers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parent of this injector.
|
||||
*
|
||||
* <!-- TODO: Add a link to the section of the user guide talking about hierarchical injection.
|
||||
* -->
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/eosMGo?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* var parent = ReflectiveInjector.resolveAndCreate([]);
|
||||
* var child = parent.resolveAndCreateChild([]);
|
||||
* expect(child.parent).toBe(parent);
|
||||
* ```
|
||||
*/
|
||||
get parent(): Injector { return unimplemented(); }
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
debugContext(): any { return null; }
|
||||
|
||||
/**
|
||||
* Resolves an array of providers and creates a child injector from those providers.
|
||||
*
|
||||
* <!-- TODO: Add a link to the section of the user guide talking about hierarchical injection.
|
||||
* -->
|
||||
*
|
||||
* The passed-in providers can be an array of `Type`, {@link Provider},
|
||||
* or a recursive array of more providers.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/opB3T4?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* class ParentProvider {}
|
||||
* class ChildProvider {}
|
||||
*
|
||||
* var parent = ReflectiveInjector.resolveAndCreate([ParentProvider]);
|
||||
* var child = parent.resolveAndCreateChild([ChildProvider]);
|
||||
*
|
||||
* expect(child.get(ParentProvider) instanceof ParentProvider).toBe(true);
|
||||
* expect(child.get(ChildProvider) instanceof ChildProvider).toBe(true);
|
||||
* expect(child.get(ParentProvider)).toBe(parent.get(ParentProvider));
|
||||
* ```
|
||||
*
|
||||
* This function is slower than the corresponding `createChildFromResolved`
|
||||
* because it needs to resolve the passed-in providers first.
|
||||
* See {@link Injector#resolve} and {@link Injector#createChildFromResolved}.
|
||||
*/
|
||||
resolveAndCreateChild(
|
||||
providers: Array<Type | Provider | {[k: string]: any} | any[]>): ReflectiveInjector {
|
||||
return unimplemented();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child injector from previously resolved providers.
|
||||
*
|
||||
* <!-- TODO: Add a link to the section of the user guide talking about hierarchical injection.
|
||||
* -->
|
||||
*
|
||||
* This API is the recommended way to construct injectors in performance-sensitive parts.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/VhyfjN?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* class ParentProvider {}
|
||||
* class ChildProvider {}
|
||||
*
|
||||
* var parentProviders = ReflectiveInjector.resolve([ParentProvider]);
|
||||
* var childProviders = ReflectiveInjector.resolve([ChildProvider]);
|
||||
*
|
||||
* var parent = ReflectiveInjector.fromResolvedProviders(parentProviders);
|
||||
* var child = parent.createChildFromResolved(childProviders);
|
||||
*
|
||||
* expect(child.get(ParentProvider) instanceof ParentProvider).toBe(true);
|
||||
* expect(child.get(ChildProvider) instanceof ChildProvider).toBe(true);
|
||||
* expect(child.get(ParentProvider)).toBe(parent.get(ParentProvider));
|
||||
* ```
|
||||
*/
|
||||
createChildFromResolved(providers: ResolvedReflectiveProvider[]): ReflectiveInjector {
|
||||
return unimplemented();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a provider and instantiates an object in the context of the injector.
|
||||
*
|
||||
* The created object does not get cached by the injector.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/yvVXoB?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* @Injectable()
|
||||
* class Engine {
|
||||
* }
|
||||
*
|
||||
* @Injectable()
|
||||
* class Car {
|
||||
* constructor(public engine:Engine) {}
|
||||
* }
|
||||
*
|
||||
* var injector = ReflectiveInjector.resolveAndCreate([Engine]);
|
||||
*
|
||||
* var car = injector.resolveAndInstantiate(Car);
|
||||
* expect(car.engine).toBe(injector.get(Engine));
|
||||
* expect(car).not.toBe(injector.resolveAndInstantiate(Car));
|
||||
* ```
|
||||
*/
|
||||
resolveAndInstantiate(provider: Type | Provider): any { return unimplemented(); }
|
||||
|
||||
/**
|
||||
* Instantiates an object using a resolved provider in the context of the injector.
|
||||
*
|
||||
* The created object does not get cached by the injector.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/ptCImQ?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* @Injectable()
|
||||
* class Engine {
|
||||
* }
|
||||
*
|
||||
* @Injectable()
|
||||
* class Car {
|
||||
* constructor(public engine:Engine) {}
|
||||
* }
|
||||
*
|
||||
* var injector = ReflectiveInjector.resolveAndCreate([Engine]);
|
||||
* var carProvider = ReflectiveInjector.resolve([Car])[0];
|
||||
* var car = injector.instantiateResolved(carProvider);
|
||||
* expect(car.engine).toBe(injector.get(Engine));
|
||||
* expect(car).not.toBe(injector.instantiateResolved(carProvider));
|
||||
* ```
|
||||
*/
|
||||
instantiateResolved(provider: ResolvedReflectiveProvider): any { return unimplemented(); }
|
||||
|
||||
abstract get(token: any, notFoundValue?: any): any;
|
||||
}
|
||||
|
||||
export class ReflectiveInjector_ implements ReflectiveInjector {
|
||||
private _strategy: ReflectiveInjectorStrategy;
|
||||
/** @internal */
|
||||
_constructionCounter: number = 0;
|
||||
/** @internal */
|
||||
public _proto: any /* ProtoInjector */;
|
||||
/** @internal */
|
||||
public _parent: Injector;
|
||||
/**
|
||||
* Private
|
||||
*/
|
||||
constructor(_proto: any /* ProtoInjector */, _parent: Injector = null,
|
||||
private _debugContext: Function = null) {
|
||||
this._proto = _proto;
|
||||
this._parent = _parent;
|
||||
this._strategy = _proto._strategy.createInjectorStrategy(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
debugContext(): any { return this._debugContext(); }
|
||||
|
||||
get(token: any, notFoundValue: any = /*@ts2dart_const*/ THROW_IF_NOT_FOUND): any {
|
||||
return this._getByKey(ReflectiveKey.get(token), null, null, notFoundValue);
|
||||
}
|
||||
|
||||
getAt(index: number): any { return this._strategy.getObjAtIndex(index); }
|
||||
|
||||
get parent(): Injector { return this._parent; }
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Internal. Do not use.
|
||||
* We return `any` not to export the InjectorStrategy type.
|
||||
*/
|
||||
get internalStrategy(): any { return this._strategy; }
|
||||
|
||||
resolveAndCreateChild(providers: Array<Type | Provider | any[]>): ReflectiveInjector {
|
||||
var ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
|
||||
return this.createChildFromResolved(ResolvedReflectiveProviders);
|
||||
}
|
||||
|
||||
createChildFromResolved(providers: ResolvedReflectiveProvider[]): ReflectiveInjector {
|
||||
var proto = new ReflectiveProtoInjector(providers);
|
||||
var inj = new ReflectiveInjector_(proto);
|
||||
inj._parent = this;
|
||||
return inj;
|
||||
}
|
||||
|
||||
resolveAndInstantiate(provider: Type | Provider): any {
|
||||
return this.instantiateResolved(ReflectiveInjector.resolve([provider])[0]);
|
||||
}
|
||||
|
||||
instantiateResolved(provider: ResolvedReflectiveProvider): any {
|
||||
return this._instantiateProvider(provider);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_new(provider: ResolvedReflectiveProvider): any {
|
||||
if (this._constructionCounter++ > this._strategy.getMaxNumberOfObjects()) {
|
||||
throw new CyclicDependencyError(this, provider.key);
|
||||
}
|
||||
return this._instantiateProvider(provider);
|
||||
}
|
||||
|
||||
private _instantiateProvider(provider: ResolvedReflectiveProvider): any {
|
||||
if (provider.multiProvider) {
|
||||
var res = ListWrapper.createFixedSize(provider.resolvedFactories.length);
|
||||
for (var i = 0; i < provider.resolvedFactories.length; ++i) {
|
||||
res[i] = this._instantiate(provider, provider.resolvedFactories[i]);
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return this._instantiate(provider, provider.resolvedFactories[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private _instantiate(provider: ResolvedReflectiveProvider,
|
||||
ResolvedReflectiveFactory: ResolvedReflectiveFactory): any {
|
||||
var factory = ResolvedReflectiveFactory.factory;
|
||||
var deps = ResolvedReflectiveFactory.dependencies;
|
||||
var length = deps.length;
|
||||
|
||||
var d0: any;
|
||||
var d1: any;
|
||||
var d2: any;
|
||||
var d3: any;
|
||||
var d4: any;
|
||||
var d5: any;
|
||||
var d6: any;
|
||||
var d7: any;
|
||||
var d8: any;
|
||||
var d9: any;
|
||||
var d10: any;
|
||||
var d11: any;
|
||||
var d12: any;
|
||||
var d13: any;
|
||||
var d14: any;
|
||||
var d15: any;
|
||||
var d16: any;
|
||||
var d17: any;
|
||||
var d18: any;
|
||||
var d19: any;
|
||||
try {
|
||||
d0 = length > 0 ? this._getByReflectiveDependency(provider, deps[0]) : null;
|
||||
d1 = length > 1 ? this._getByReflectiveDependency(provider, deps[1]) : null;
|
||||
d2 = length > 2 ? this._getByReflectiveDependency(provider, deps[2]) : null;
|
||||
d3 = length > 3 ? this._getByReflectiveDependency(provider, deps[3]) : null;
|
||||
d4 = length > 4 ? this._getByReflectiveDependency(provider, deps[4]) : null;
|
||||
d5 = length > 5 ? this._getByReflectiveDependency(provider, deps[5]) : null;
|
||||
d6 = length > 6 ? this._getByReflectiveDependency(provider, deps[6]) : null;
|
||||
d7 = length > 7 ? this._getByReflectiveDependency(provider, deps[7]) : null;
|
||||
d8 = length > 8 ? this._getByReflectiveDependency(provider, deps[8]) : null;
|
||||
d9 = length > 9 ? this._getByReflectiveDependency(provider, deps[9]) : null;
|
||||
d10 = length > 10 ? this._getByReflectiveDependency(provider, deps[10]) : null;
|
||||
d11 = length > 11 ? this._getByReflectiveDependency(provider, deps[11]) : null;
|
||||
d12 = length > 12 ? this._getByReflectiveDependency(provider, deps[12]) : null;
|
||||
d13 = length > 13 ? this._getByReflectiveDependency(provider, deps[13]) : null;
|
||||
d14 = length > 14 ? this._getByReflectiveDependency(provider, deps[14]) : null;
|
||||
d15 = length > 15 ? this._getByReflectiveDependency(provider, deps[15]) : null;
|
||||
d16 = length > 16 ? this._getByReflectiveDependency(provider, deps[16]) : null;
|
||||
d17 = length > 17 ? this._getByReflectiveDependency(provider, deps[17]) : null;
|
||||
d18 = length > 18 ? this._getByReflectiveDependency(provider, deps[18]) : null;
|
||||
d19 = length > 19 ? this._getByReflectiveDependency(provider, deps[19]) : null;
|
||||
} catch (e) {
|
||||
if (e instanceof AbstractProviderError || e instanceof InstantiationError) {
|
||||
e.addKey(this, provider.key);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
var obj;
|
||||
try {
|
||||
switch (length) {
|
||||
case 0:
|
||||
obj = factory();
|
||||
break;
|
||||
case 1:
|
||||
obj = factory(d0);
|
||||
break;
|
||||
case 2:
|
||||
obj = factory(d0, d1);
|
||||
break;
|
||||
case 3:
|
||||
obj = factory(d0, d1, d2);
|
||||
break;
|
||||
case 4:
|
||||
obj = factory(d0, d1, d2, d3);
|
||||
break;
|
||||
case 5:
|
||||
obj = factory(d0, d1, d2, d3, d4);
|
||||
break;
|
||||
case 6:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5);
|
||||
break;
|
||||
case 7:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6);
|
||||
break;
|
||||
case 8:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7);
|
||||
break;
|
||||
case 9:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8);
|
||||
break;
|
||||
case 10:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9);
|
||||
break;
|
||||
case 11:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10);
|
||||
break;
|
||||
case 12:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11);
|
||||
break;
|
||||
case 13:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12);
|
||||
break;
|
||||
case 14:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13);
|
||||
break;
|
||||
case 15:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14);
|
||||
break;
|
||||
case 16:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15);
|
||||
break;
|
||||
case 17:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16);
|
||||
break;
|
||||
case 18:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16,
|
||||
d17);
|
||||
break;
|
||||
case 19:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16,
|
||||
d17, d18);
|
||||
break;
|
||||
case 20:
|
||||
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16,
|
||||
d17, d18, d19);
|
||||
break;
|
||||
default:
|
||||
throw new BaseException(
|
||||
`Cannot instantiate '${provider.key.displayName}' because it has more than 20 dependencies`);
|
||||
}
|
||||
} catch (e) {
|
||||
throw new InstantiationError(this, e, e.stack, provider.key);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private _getByReflectiveDependency(provider: ResolvedReflectiveProvider,
|
||||
dep: ReflectiveDependency): any {
|
||||
return this._getByKey(dep.key, dep.lowerBoundVisibility, dep.upperBoundVisibility,
|
||||
dep.optional ? null : THROW_IF_NOT_FOUND);
|
||||
}
|
||||
|
||||
private _getByKey(key: ReflectiveKey, lowerBoundVisibility: Object, upperBoundVisibility: Object,
|
||||
notFoundValue: any): any {
|
||||
if (key === INJECTOR_KEY) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (upperBoundVisibility instanceof SelfMetadata) {
|
||||
return this._getByKeySelf(key, notFoundValue);
|
||||
|
||||
} else {
|
||||
return this._getByKeyDefault(key, notFoundValue, lowerBoundVisibility);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_throwOrNull(key: ReflectiveKey, notFoundValue: any): any {
|
||||
if (notFoundValue !== THROW_IF_NOT_FOUND) {
|
||||
return notFoundValue;
|
||||
} else {
|
||||
throw new NoProviderError(this, key);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_getByKeySelf(key: ReflectiveKey, notFoundValue: any): any {
|
||||
var obj = this._strategy.getObjByKeyId(key.id);
|
||||
return (obj !== UNDEFINED) ? obj : this._throwOrNull(key, notFoundValue);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_getByKeyDefault(key: ReflectiveKey, notFoundValue: any, lowerBoundVisibility: Object): any {
|
||||
var inj: Injector;
|
||||
|
||||
if (lowerBoundVisibility instanceof SkipSelfMetadata) {
|
||||
inj = this._parent;
|
||||
} else {
|
||||
inj = this;
|
||||
}
|
||||
|
||||
while (inj instanceof ReflectiveInjector_) {
|
||||
var inj_ = <ReflectiveInjector_>inj;
|
||||
var obj = inj_._strategy.getObjByKeyId(key.id);
|
||||
if (obj !== UNDEFINED) return obj;
|
||||
inj = inj_._parent;
|
||||
}
|
||||
if (inj !== null) {
|
||||
return inj.get(key.token, notFoundValue);
|
||||
} else {
|
||||
return this._throwOrNull(key, notFoundValue);
|
||||
}
|
||||
}
|
||||
|
||||
get displayName(): string {
|
||||
return `ReflectiveInjector(providers: [${_mapProviders(this, (b: ResolvedReflectiveProvider) => ` "${b.key.displayName}" `).join(", ")}])`;
|
||||
}
|
||||
|
||||
toString(): string { return this.displayName; }
|
||||
}
|
||||
|
||||
var INJECTOR_KEY = ReflectiveKey.get(Injector);
|
||||
|
||||
function _mapProviders(injector: ReflectiveInjector_, fn: Function): any[] {
|
||||
var res = [];
|
||||
for (var i = 0; i < injector._proto.numberOfProviders; ++i) {
|
||||
res.push(fn(injector._proto.getProviderAtIndex(i)));
|
||||
}
|
||||
return res;
|
||||
}
|
69
modules/@angular/core/src/di/reflective_key.ts
Normal file
69
modules/@angular/core/src/di/reflective_key.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import {stringify, Type, isBlank} from 'angular2/src/facade/lang';
|
||||
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
||||
import {resolveForwardRef} from './forward_ref';
|
||||
|
||||
/**
|
||||
* A unique object used for retrieving items from the {@link ReflectiveInjector}.
|
||||
*
|
||||
* Keys have:
|
||||
* - a system-wide unique `id`.
|
||||
* - a `token`.
|
||||
*
|
||||
* `Key` is used internally by {@link ReflectiveInjector} because its system-wide unique `id` allows
|
||||
* the
|
||||
* injector to store created objects in a more efficient way.
|
||||
*
|
||||
* `Key` should not be created directly. {@link ReflectiveInjector} creates keys automatically when
|
||||
* resolving
|
||||
* providers.
|
||||
*/
|
||||
export class ReflectiveKey {
|
||||
/**
|
||||
* Private
|
||||
*/
|
||||
constructor(public token: Object, public id: number) {
|
||||
if (isBlank(token)) {
|
||||
throw new BaseException('Token must be defined!');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stringified token.
|
||||
*/
|
||||
get displayName(): string { return stringify(this.token); }
|
||||
|
||||
/**
|
||||
* Retrieves a `Key` for a token.
|
||||
*/
|
||||
static get(token: Object): ReflectiveKey {
|
||||
return _globalKeyRegistry.get(resolveForwardRef(token));
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the number of keys registered in the system.
|
||||
*/
|
||||
static get numberOfKeys(): number { return _globalKeyRegistry.numberOfKeys; }
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class KeyRegistry {
|
||||
private _allKeys = new Map<Object, ReflectiveKey>();
|
||||
|
||||
get(token: Object): ReflectiveKey {
|
||||
if (token instanceof ReflectiveKey) return token;
|
||||
|
||||
if (this._allKeys.has(token)) {
|
||||
return this._allKeys.get(token);
|
||||
}
|
||||
|
||||
var newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys);
|
||||
this._allKeys.set(token, newKey);
|
||||
return newKey;
|
||||
}
|
||||
|
||||
get numberOfKeys(): number { return this._allKeys.size; }
|
||||
}
|
||||
|
||||
var _globalKeyRegistry = new KeyRegistry();
|
289
modules/@angular/core/src/di/reflective_provider.ts
Normal file
289
modules/@angular/core/src/di/reflective_provider.ts
Normal file
@ -0,0 +1,289 @@
|
||||
import {Type, isBlank, isPresent, isArray, isType} from 'angular2/src/facade/lang';
|
||||
import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {reflector} from 'angular2/src/core/reflection/reflection';
|
||||
import {ReflectiveKey} from './reflective_key';
|
||||
import {
|
||||
InjectMetadata,
|
||||
InjectableMetadata,
|
||||
OptionalMetadata,
|
||||
SelfMetadata,
|
||||
HostMetadata,
|
||||
SkipSelfMetadata,
|
||||
DependencyMetadata
|
||||
} from './metadata';
|
||||
import {
|
||||
NoAnnotationError,
|
||||
MixingMultiProvidersWithRegularProvidersError,
|
||||
InvalidProviderError
|
||||
} from './reflective_exceptions';
|
||||
import {resolveForwardRef} from './forward_ref';
|
||||
import {Provider, ProviderBuilder, provide} from './provider';
|
||||
import {isProviderLiteral, createProvider} from './provider_util';
|
||||
|
||||
/**
|
||||
* `Dependency` is used by the framework to extend DI.
|
||||
* This is internal to Angular and should not be used directly.
|
||||
*/
|
||||
export class ReflectiveDependency {
|
||||
constructor(public key: ReflectiveKey, public optional: boolean, public lowerBoundVisibility: any,
|
||||
public upperBoundVisibility: any, public properties: any[]) {}
|
||||
|
||||
static fromKey(key: ReflectiveKey): ReflectiveDependency {
|
||||
return new ReflectiveDependency(key, false, null, null, []);
|
||||
}
|
||||
}
|
||||
|
||||
const _EMPTY_LIST = /*@ts2dart_const*/[];
|
||||
|
||||
/**
|
||||
* An internal resolved representation of a {@link Provider} used by the {@link Injector}.
|
||||
*
|
||||
* It is usually created automatically by `Injector.resolveAndCreate`.
|
||||
*
|
||||
* It can be created manually, as follows:
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/RfEnhh8kUEI0G3qsnIeT?p%3Dpreview&p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* var resolvedProviders = Injector.resolve([new Provider('message', {useValue: 'Hello'})]);
|
||||
* var injector = Injector.fromResolvedProviders(resolvedProviders);
|
||||
*
|
||||
* expect(injector.get('message')).toEqual('Hello');
|
||||
* ```
|
||||
*/
|
||||
export interface ResolvedReflectiveProvider {
|
||||
/**
|
||||
* A key, usually a `Type`.
|
||||
*/
|
||||
key: ReflectiveKey;
|
||||
|
||||
/**
|
||||
* Factory function which can return an instance of an object represented by a key.
|
||||
*/
|
||||
resolvedFactories: ResolvedReflectiveFactory[];
|
||||
|
||||
/**
|
||||
* Indicates if the provider is a multi-provider or a regular provider.
|
||||
*/
|
||||
multiProvider: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link ResolvedProvider} instead.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
export interface ResolvedReflectiveBinding extends ResolvedReflectiveProvider {}
|
||||
|
||||
export class ResolvedReflectiveProvider_ implements ResolvedReflectiveBinding {
|
||||
constructor(public key: ReflectiveKey, public resolvedFactories: ResolvedReflectiveFactory[],
|
||||
public multiProvider: boolean) {}
|
||||
|
||||
get resolvedFactory(): ResolvedReflectiveFactory { return this.resolvedFactories[0]; }
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal resolved representation of a factory function created by resolving {@link Provider}.
|
||||
*/
|
||||
export class ResolvedReflectiveFactory {
|
||||
constructor(
|
||||
/**
|
||||
* Factory function which can return an instance of an object represented by a key.
|
||||
*/
|
||||
public factory: Function,
|
||||
|
||||
/**
|
||||
* Arguments (dependencies) to the `factory` function.
|
||||
*/
|
||||
public dependencies: ReflectiveDependency[]) {}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolve a single provider.
|
||||
*/
|
||||
export function resolveReflectiveFactory(provider: Provider): ResolvedReflectiveFactory {
|
||||
var factoryFn: Function;
|
||||
var resolvedDeps;
|
||||
if (isPresent(provider.useClass)) {
|
||||
var useClass = resolveForwardRef(provider.useClass);
|
||||
factoryFn = reflector.factory(useClass);
|
||||
resolvedDeps = _dependenciesFor(useClass);
|
||||
} else if (isPresent(provider.useExisting)) {
|
||||
factoryFn = (aliasInstance) => aliasInstance;
|
||||
resolvedDeps = [ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting))];
|
||||
} else if (isPresent(provider.useFactory)) {
|
||||
factoryFn = provider.useFactory;
|
||||
resolvedDeps = constructDependencies(provider.useFactory, provider.dependencies);
|
||||
} else {
|
||||
factoryFn = () => provider.useValue;
|
||||
resolvedDeps = _EMPTY_LIST;
|
||||
}
|
||||
return new ResolvedReflectiveFactory(factoryFn, resolvedDeps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the {@link Provider} into {@link ResolvedProvider}.
|
||||
*
|
||||
* {@link Injector} internally only uses {@link ResolvedProvider}, {@link Provider} contains
|
||||
* convenience provider syntax.
|
||||
*/
|
||||
export function resolveReflectiveProvider(provider: Provider): ResolvedReflectiveProvider {
|
||||
return new ResolvedReflectiveProvider_(ReflectiveKey.get(provider.token),
|
||||
[resolveReflectiveFactory(provider)], provider.multi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a list of Providers.
|
||||
*/
|
||||
export function resolveReflectiveProviders(
|
||||
providers: Array<Type | Provider | {[k: string]: any} | any[]>): ResolvedReflectiveProvider[] {
|
||||
var normalized = _normalizeProviders(providers, []);
|
||||
var resolved = normalized.map(resolveReflectiveProvider);
|
||||
return MapWrapper.values(
|
||||
mergeResolvedReflectiveProviders(resolved, new Map<number, ResolvedReflectiveProvider>()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges a list of ResolvedProviders into a list where
|
||||
* each key is contained exactly once and multi providers
|
||||
* have been merged.
|
||||
*/
|
||||
export function mergeResolvedReflectiveProviders(
|
||||
providers: ResolvedReflectiveProvider[],
|
||||
normalizedProvidersMap: Map<number, ResolvedReflectiveProvider>):
|
||||
Map<number, ResolvedReflectiveProvider> {
|
||||
for (var i = 0; i < providers.length; i++) {
|
||||
var provider = providers[i];
|
||||
var existing = normalizedProvidersMap.get(provider.key.id);
|
||||
if (isPresent(existing)) {
|
||||
if (provider.multiProvider !== existing.multiProvider) {
|
||||
throw new MixingMultiProvidersWithRegularProvidersError(existing, provider);
|
||||
}
|
||||
if (provider.multiProvider) {
|
||||
for (var j = 0; j < provider.resolvedFactories.length; j++) {
|
||||
existing.resolvedFactories.push(provider.resolvedFactories[j]);
|
||||
}
|
||||
} else {
|
||||
normalizedProvidersMap.set(provider.key.id, provider);
|
||||
}
|
||||
} else {
|
||||
var resolvedProvider;
|
||||
if (provider.multiProvider) {
|
||||
resolvedProvider = new ResolvedReflectiveProvider_(
|
||||
provider.key, ListWrapper.clone(provider.resolvedFactories), provider.multiProvider);
|
||||
} else {
|
||||
resolvedProvider = provider;
|
||||
}
|
||||
normalizedProvidersMap.set(provider.key.id, resolvedProvider);
|
||||
}
|
||||
}
|
||||
return normalizedProvidersMap;
|
||||
}
|
||||
|
||||
function _normalizeProviders(
|
||||
providers: Array<Type | Provider | {[k: string]: any} | ProviderBuilder | any[]>,
|
||||
res: Provider[]): Provider[] {
|
||||
providers.forEach(b => {
|
||||
if (b instanceof Type) {
|
||||
res.push(provide(b, {useClass: b}));
|
||||
|
||||
} else if (b instanceof Provider) {
|
||||
res.push(b);
|
||||
|
||||
} else if (isProviderLiteral(b)) {
|
||||
res.push(createProvider(b));
|
||||
|
||||
} else if (b instanceof Array) {
|
||||
_normalizeProviders(b, res);
|
||||
|
||||
} else if (b instanceof ProviderBuilder) {
|
||||
throw new InvalidProviderError(b.token);
|
||||
|
||||
} else {
|
||||
throw new InvalidProviderError(b);
|
||||
}
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
export function constructDependencies(typeOrFunc: any,
|
||||
dependencies: any[]): ReflectiveDependency[] {
|
||||
if (isBlank(dependencies)) {
|
||||
return _dependenciesFor(typeOrFunc);
|
||||
} else {
|
||||
var params: any[][] = dependencies.map(t => [t]);
|
||||
return dependencies.map(t => _extractToken(typeOrFunc, t, params));
|
||||
}
|
||||
}
|
||||
|
||||
function _dependenciesFor(typeOrFunc: any): ReflectiveDependency[] {
|
||||
var params = reflector.parameters(typeOrFunc);
|
||||
if (isBlank(params)) return [];
|
||||
if (params.some(isBlank)) {
|
||||
throw new NoAnnotationError(typeOrFunc, params);
|
||||
}
|
||||
return params.map((p: any[]) => _extractToken(typeOrFunc, p, params));
|
||||
}
|
||||
|
||||
function _extractToken(typeOrFunc, metadata /*any[] | any*/,
|
||||
params: any[][]): ReflectiveDependency {
|
||||
var depProps = [];
|
||||
var token = null;
|
||||
var optional = false;
|
||||
|
||||
if (!isArray(metadata)) {
|
||||
if (metadata instanceof InjectMetadata) {
|
||||
return _createDependency(metadata.token, optional, null, null, depProps);
|
||||
} else {
|
||||
return _createDependency(metadata, optional, null, null, depProps);
|
||||
}
|
||||
}
|
||||
|
||||
var lowerBoundVisibility = null;
|
||||
var upperBoundVisibility = null;
|
||||
|
||||
for (var i = 0; i < metadata.length; ++i) {
|
||||
var paramMetadata = metadata[i];
|
||||
|
||||
if (paramMetadata instanceof Type) {
|
||||
token = paramMetadata;
|
||||
|
||||
} else if (paramMetadata instanceof InjectMetadata) {
|
||||
token = paramMetadata.token;
|
||||
|
||||
} else if (paramMetadata instanceof OptionalMetadata) {
|
||||
optional = true;
|
||||
|
||||
} else if (paramMetadata instanceof SelfMetadata) {
|
||||
upperBoundVisibility = paramMetadata;
|
||||
|
||||
} else if (paramMetadata instanceof HostMetadata) {
|
||||
upperBoundVisibility = paramMetadata;
|
||||
|
||||
} else if (paramMetadata instanceof SkipSelfMetadata) {
|
||||
lowerBoundVisibility = paramMetadata;
|
||||
|
||||
} else if (paramMetadata instanceof DependencyMetadata) {
|
||||
if (isPresent(paramMetadata.token)) {
|
||||
token = paramMetadata.token;
|
||||
}
|
||||
depProps.push(paramMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
token = resolveForwardRef(token);
|
||||
|
||||
if (isPresent(token)) {
|
||||
return _createDependency(token, optional, lowerBoundVisibility, upperBoundVisibility, depProps);
|
||||
} else {
|
||||
throw new NoAnnotationError(typeOrFunc, params);
|
||||
}
|
||||
}
|
||||
|
||||
function _createDependency(token, optional, lowerBoundVisibility, upperBoundVisibility,
|
||||
depProps): ReflectiveDependency {
|
||||
return new ReflectiveDependency(ReflectiveKey.get(token), optional, lowerBoundVisibility,
|
||||
upperBoundVisibility, depProps);
|
||||
}
|
Reference in New Issue
Block a user