docs: add DI to public docs
This commit is contained in:
@ -402,6 +402,7 @@ function createDocsTasks(public) {
|
|||||||
var dgeni = new Dgeni([require(dgeniPackage)]);
|
var dgeni = new Dgeni([require(dgeniPackage)]);
|
||||||
return dgeni.generate();
|
return dgeni.generate();
|
||||||
} catch(x) {
|
} catch(x) {
|
||||||
|
console.log(x);
|
||||||
console.log(x.stack);
|
console.log(x.stack);
|
||||||
throw x;
|
throw x;
|
||||||
}
|
}
|
||||||
|
2
modules/angular2/core.js
vendored
2
modules/angular2/core.js
vendored
@ -2,7 +2,7 @@
|
|||||||
* @module
|
* @module
|
||||||
* @public
|
* @public
|
||||||
* @description
|
* @description
|
||||||
* Define public API for Angular here.
|
* Define angular core API here.
|
||||||
*/
|
*/
|
||||||
export * from './src/core/annotations/visibility';
|
export * from './src/core/annotations/visibility';
|
||||||
export * from './src/core/compiler/interfaces';
|
export * from './src/core/compiler/interfaces';
|
||||||
|
1
modules/angular2/di.js
vendored
1
modules/angular2/di.js
vendored
@ -1,5 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @module
|
* @module
|
||||||
|
* @public
|
||||||
* @description
|
* @description
|
||||||
* This is a description
|
* This is a description
|
||||||
*/
|
*/
|
||||||
|
7
modules/angular2/di_annotations.js
vendored
Normal file
7
modules/angular2/di_annotations.js
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* @module
|
||||||
|
* @public
|
||||||
|
* @description
|
||||||
|
* This is a description
|
||||||
|
*/
|
||||||
|
|
7
modules/angular2/di_errors.js
vendored
Normal file
7
modules/angular2/di_errors.js
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* @module
|
||||||
|
* @public
|
||||||
|
* @description
|
||||||
|
* This is a description
|
||||||
|
*/
|
||||||
|
|
6
modules/angular2/src/core/annotations/di.js
vendored
6
modules/angular2/src/core/annotations/di.js
vendored
@ -30,13 +30,13 @@ export class PropertySetter extends DependencyAnnotation {
|
|||||||
*
|
*
|
||||||
* ## Example
|
* ## Example
|
||||||
*
|
*
|
||||||
* suppose we have an `<input>` element and would like to know its `type`.
|
* Suppose we have an `<input>` element and want to know its `type`.
|
||||||
*
|
*
|
||||||
* ```html
|
* ```html
|
||||||
* <input type="text">
|
* <input type="text">
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* A decorator could inject string literal `text` like so:
|
* A decorator can inject string literal `text` like so:
|
||||||
*
|
*
|
||||||
* ```javascript
|
* ```javascript
|
||||||
* @Decorator({
|
* @Decorator({
|
||||||
@ -71,7 +71,7 @@ export class Attribute extends DependencyAnnotation {
|
|||||||
/**
|
/**
|
||||||
* Specifies that a [QueryList] should be injected.
|
* Specifies that a [QueryList] should be injected.
|
||||||
*
|
*
|
||||||
* See: [QueryList] for usage.
|
* See: [QueryList] for usage and example.
|
||||||
*
|
*
|
||||||
* @exportedAs angular2/annotations
|
* @exportedAs angular2/annotations
|
||||||
*/
|
*/
|
||||||
|
55
modules/angular2/src/core/annotations/view.js
vendored
55
modules/angular2/src/core/annotations/view.js
vendored
@ -33,38 +33,57 @@ import {ABSTRACT, CONST, Type} from 'angular2/src/facade/lang';
|
|||||||
* @exportedAs angular2/annotations
|
* @exportedAs angular2/annotations
|
||||||
*/
|
*/
|
||||||
export class View {
|
export class View {
|
||||||
|
/**
|
||||||
|
* Specify a template URL for an angular component.
|
||||||
|
*
|
||||||
|
* NOTE: either `templateURL` or `template` should be used, but not both.
|
||||||
|
*/
|
||||||
templateUrl:any; //string;
|
templateUrl:any; //string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify an inline template for an angular component.
|
||||||
|
*
|
||||||
|
* NOTE: either `templateURL` or `template` should be used, but not both.
|
||||||
|
*/
|
||||||
template:any; //string;
|
template:any; //string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify a list of directives that are active within a template. [TODO: true?]
|
||||||
|
*
|
||||||
|
* Directives must be listed explicitly to provide proper component encapsulation.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* @Component({
|
||||||
|
* selector: 'my-component'
|
||||||
|
* })
|
||||||
|
* @View({
|
||||||
|
* directives: [For]
|
||||||
|
* template: '
|
||||||
|
* <ul>
|
||||||
|
* <li *for="item in items">{{item}}</li>
|
||||||
|
* </ul>'
|
||||||
|
* })
|
||||||
|
* class MyComponent {
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
directives:any; //List<Type>;
|
directives:any; //List<Type>;
|
||||||
formatters:any; //List<Type>;
|
|
||||||
source:any;//List<View>;
|
|
||||||
locale:any; //string
|
|
||||||
device:any; //string
|
|
||||||
@CONST()
|
@CONST()
|
||||||
constructor({
|
constructor({
|
||||||
templateUrl,
|
templateUrl,
|
||||||
template,
|
template,
|
||||||
directives,
|
directives
|
||||||
formatters,
|
|
||||||
source,
|
|
||||||
locale,
|
|
||||||
device
|
|
||||||
}: {
|
}: {
|
||||||
templateUrl: string,
|
templateUrl: string,
|
||||||
template: string,
|
template: string,
|
||||||
directives: List<Type>,
|
directives: List<Type>
|
||||||
formatters: List<Type>,
|
|
||||||
source: List<View>,
|
|
||||||
locale: string,
|
|
||||||
device: string
|
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
this.templateUrl = templateUrl;
|
this.templateUrl = templateUrl;
|
||||||
this.template = template;
|
this.template = template;
|
||||||
this.directives = directives;
|
this.directives = directives;
|
||||||
this.formatters = formatters;
|
|
||||||
this.source = source;
|
|
||||||
this.locale = locale;
|
|
||||||
this.device = device;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,6 @@ import {isPresent} from 'angular2/src/facade/lang';
|
|||||||
* lifecycle.tick();
|
* lifecycle.tick();
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
|
||||||
*
|
|
||||||
* @exportedAs angular2/change_detection
|
* @exportedAs angular2/change_detection
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
27
modules/angular2/src/di/annotations.js
vendored
27
modules/angular2/src/di/annotations.js
vendored
@ -5,10 +5,11 @@ import {CONST} from "angular2/src/facade/lang";
|
|||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* class AComponent {
|
* class AComponent {
|
||||||
* constructor(@Inject('aServiceToken') aService) {}
|
* constructor(@Inject(MyService) aService:MyService) {}
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
* @exportedAs angular2/di_annotations
|
||||||
*/
|
*/
|
||||||
export class Inject {
|
export class Inject {
|
||||||
token;
|
token;
|
||||||
@ -23,12 +24,13 @@ export class Inject {
|
|||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* class AComponent {
|
* class AComponent {
|
||||||
* constructor(@InjectPromise('aServiceToken') aServicePromise) {
|
* constructor(@InjectPromise(MyService) aServicePromise:Promise<MyService>) {
|
||||||
* aServicePromise.then(aService => ...);
|
* aServicePromise.then(aService:MyService => ...);
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
* @exportedAs angular2/di_annotations
|
||||||
*/
|
*/
|
||||||
export class InjectPromise {
|
export class InjectPromise {
|
||||||
token;
|
token;
|
||||||
@ -43,12 +45,13 @@ export class InjectPromise {
|
|||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* class AComponent {
|
* class AComponent {
|
||||||
* constructor(@InjectLazy('aServiceToken') aServiceFn) {
|
* constructor(@InjectLazy(MyService) aServiceFn:Function) {
|
||||||
* aService = aServiceFn();
|
* var aService:MyService = aServiceFn();
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
* @exportedAs angular2/di_annotations
|
||||||
*/
|
*/
|
||||||
export class InjectLazy {
|
export class InjectLazy {
|
||||||
token;
|
token;
|
||||||
@ -59,16 +62,16 @@ export class InjectLazy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A parameter annotation that marks a dependency as optional.
|
* A parameter annotation that marks a dependency as optional. (Injects `null` if not found.)
|
||||||
*
|
|
||||||
* ```
|
* ```
|
||||||
* class AComponent {
|
* class AComponent {
|
||||||
* constructor(@Optional() dp:Dependency) {
|
* constructor(@Optional() aService:MyService) {
|
||||||
* this.dp = dp;
|
* this.aService = aService;
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
* @exportedAs angular2/di_annotations
|
||||||
*/
|
*/
|
||||||
export class Optional {
|
export class Optional {
|
||||||
@CONST()
|
@CONST()
|
||||||
@ -102,6 +105,7 @@ export class Optional {
|
|||||||
* The framework can use `new Parent()` to handle the `aService` dependency
|
* The framework can use `new Parent()` to handle the `aService` dependency
|
||||||
* in a specific way.
|
* in a specific way.
|
||||||
*
|
*
|
||||||
|
* @exportedAs angular2/di_annotations
|
||||||
*/
|
*/
|
||||||
export class DependencyAnnotation {
|
export class DependencyAnnotation {
|
||||||
@CONST()
|
@CONST()
|
||||||
@ -114,8 +118,8 @@ export class DependencyAnnotation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class annotation that marks a class as available to `Injector`s for
|
* A marker annotation that marks a class as available to `Injector`s for creation. Used by tooling for generating
|
||||||
* creation.
|
* constructor stubs.
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* class NeedsService {
|
* class NeedsService {
|
||||||
@ -125,6 +129,7 @@ export class DependencyAnnotation {
|
|||||||
* @Injectable
|
* @Injectable
|
||||||
* class UsefulService {}
|
* class UsefulService {}
|
||||||
* ```
|
* ```
|
||||||
|
* @exportedAs angular2/di_annotations
|
||||||
*/
|
*/
|
||||||
export class Injectable {
|
export class Injectable {
|
||||||
@CONST()
|
@CONST()
|
||||||
|
298
modules/angular2/src/di/binding.js
vendored
298
modules/angular2/src/di/binding.js
vendored
@ -5,6 +5,9 @@ import {Key} from './key';
|
|||||||
import {Inject, InjectLazy, InjectPromise, Optional, DependencyAnnotation} from './annotations';
|
import {Inject, InjectLazy, InjectPromise, Optional, DependencyAnnotation} from './annotations';
|
||||||
import {NoAnnotationError} from './exceptions';
|
import {NoAnnotationError} from './exceptions';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
export class Dependency {
|
export class Dependency {
|
||||||
key:Key;
|
key:Key;
|
||||||
asPromise:boolean;
|
asPromise:boolean;
|
||||||
@ -28,15 +31,168 @@ export class Dependency {
|
|||||||
var _EMPTY_LIST = []; // TODO: make const when supported
|
var _EMPTY_LIST = []; // TODO: make const when supported
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Declaration of a dependency binding.
|
* Describes how the [Injector] should instantiate a given token.
|
||||||
|
*
|
||||||
|
* See [bind].
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* var injector = Injector.resolveAndCreate([
|
||||||
|
* new Binding(String, { toValue: 'Hello' })
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* expect(injector.get(String)).toEqual('Hello');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @exportedAs angular2/di
|
||||||
*/
|
*/
|
||||||
export class Binding {
|
export class Binding {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token used when retriving this binding. Usually the [Type].
|
||||||
|
*/
|
||||||
token;
|
token;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind an interface to an implementation / subclass.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* Becuse `toAlias` and `toClass` are often confused the example contains both use cases for easy comparison.
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
*
|
||||||
|
* class Vehicle {}
|
||||||
|
*
|
||||||
|
* class Car extends Vehicle {}
|
||||||
|
*
|
||||||
|
* var injectorClass = Injector.resolveAndCreate([
|
||||||
|
* Car,
|
||||||
|
* new Binding(Vehicle, { toClass: Car })
|
||||||
|
* ]);
|
||||||
|
* var injectorAlias = Injector.resolveAndCreate([
|
||||||
|
* Car,
|
||||||
|
* new Binding(Vehicle, { toAlias: 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;
|
toClass:Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a key to a value.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* var injector = Injector.resolveAndCreate([
|
||||||
|
* new Binding(String, { toValue: 'Hello' })
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* expect(injector.get(String)).toEqual('Hello');
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
toValue;
|
toValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a key to an alias of an existing key.
|
||||||
|
*
|
||||||
|
* An alias means that we will return the same instance as if the alias token was used. (This is in contrast to
|
||||||
|
* `toClass` where a separet instance of `toClass` will be returned.)
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* Becuse `toAlias` and `toClass` are often confused the example contains both use cases for easy comparison.
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
*
|
||||||
|
* class Vehicle {}
|
||||||
|
*
|
||||||
|
* class Car extends Vehicle {}
|
||||||
|
*
|
||||||
|
* var injectorAlias = Injector.resolveAndCreate([
|
||||||
|
* Car,
|
||||||
|
* new Binding(Vehicle, { toAlias: Car })
|
||||||
|
* ]);
|
||||||
|
* var injectorClass = Injector.resolveAndCreate([
|
||||||
|
* Car,
|
||||||
|
* new Binding(Vehicle, { toClass: 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;
|
toAlias;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a key to a function which computes the value.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* var injector = Injector.resolveAndCreate([
|
||||||
|
* new Binding(Number, { toFactory: () => { return 1+2; }}),
|
||||||
|
* new Binding(String, { toFactory: (value) => { return "Value: " + value; },
|
||||||
|
* dependencies: [String] })
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* expect(injector.get(Number)).toEqual(3);
|
||||||
|
* expect(injector.get(String)).toEqual('Value: 3');
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
toFactory:Function;
|
toFactory:Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a key to a function which computes the value asynchronously.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* var injector = Injector.resolveAndCreate([
|
||||||
|
* new Binding(Number, { toAsyncFactory: () => {
|
||||||
|
* return new Promise((resolve) => resolve(1 + 2));
|
||||||
|
* }}),
|
||||||
|
* new Binding(String, { toFactory: (value) => { return "Value: " + value; },
|
||||||
|
* dependencies: [String]})
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* injector.asyncGet(Number).then((v) => expect(v).toBe(3));
|
||||||
|
* injector.asyncGet(String).then((v) => expect(v).toBe('Value: 3'));
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The interesting thing to note is that event thougt `Numeber` has an async factory, the `String` factory
|
||||||
|
* function takes the resolved value. This shows that the [Injector] delays executing of the `String` factory
|
||||||
|
* until after the `Number` is resolved. This can only be done if the `token` is retrive
|
||||||
|
*/
|
||||||
toAsyncFactory:Function;
|
toAsyncFactory:Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in conjunction with `toFactory` or `toAsyncFactory` and specifies the `token`s which should be injected
|
||||||
|
* into the factory function.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* var injector = Injector.resolveAndCreate([
|
||||||
|
* new Binding(Number, { toFactory: () => { return 1+2; }}),
|
||||||
|
* new Binding(String, { toFactory: (value) => { return "Value: " + value; },
|
||||||
|
* dependencies: [String] })
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* expect(injector.get(Number)).toEqual(3);
|
||||||
|
* expect(injector.get(String)).toEqual('Value: 3');
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
dependencies:List;
|
dependencies:List;
|
||||||
|
|
||||||
@CONST()
|
@CONST()
|
||||||
@ -59,6 +215,9 @@ export class Binding {
|
|||||||
this.dependencies = deps;
|
this.dependencies = deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
resolve(): ResolvedBinding {
|
resolve(): ResolvedBinding {
|
||||||
var factoryFn:Function;
|
var factoryFn:Function;
|
||||||
var resolvedDeps;
|
var resolvedDeps;
|
||||||
@ -90,11 +249,31 @@ export class Binding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dependency binding with resolved keys and dependencies.
|
/**
|
||||||
|
* An internal resolved representaion of a [Binding] used by [Injector].
|
||||||
|
*
|
||||||
|
* A [Binding] is resolved when it has a factory fonction. Binding to a class, alias, or value, are just convenience
|
||||||
|
* methods, as [Injector] only operates on calling factory functions.
|
||||||
|
*/
|
||||||
export class ResolvedBinding {
|
export class ResolvedBinding {
|
||||||
|
/**
|
||||||
|
* A key, usually a [Type].
|
||||||
|
*/
|
||||||
key:Key;
|
key:Key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory function which can return an instance of [key].
|
||||||
|
*/
|
||||||
factory:Function;
|
factory:Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arguments (dependencies) to the [factory] function.
|
||||||
|
*/
|
||||||
dependencies:List<Dependency>;
|
dependencies:List<Dependency>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies if the [factory] function returns an [Promise]
|
||||||
|
*/
|
||||||
providedAsPromise:boolean;
|
providedAsPromise:boolean;
|
||||||
|
|
||||||
constructor(key:Key, factory:Function, dependencies:List<Dependency>, providedAsPromise:boolean) {
|
constructor(key:Key, factory:Function, dependencies:List<Dependency>, providedAsPromise:boolean) {
|
||||||
@ -106,7 +285,9 @@ export class ResolvedBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides fluent API for imperative construction of [Binding] objects.
|
* Provides fluent API for imperative construction of [Binding] objects. (JavaScript only.)
|
||||||
|
*
|
||||||
|
* @exportedAs angular2/di
|
||||||
*/
|
*/
|
||||||
export function bind(token):BindingBuilder {
|
export function bind(token):BindingBuilder {
|
||||||
return new BindingBuilder(token);
|
return new BindingBuilder(token);
|
||||||
@ -114,6 +295,7 @@ export function bind(token):BindingBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for [bind] function.
|
* Helper class for [bind] function.
|
||||||
|
* @exportedAs angular2/di
|
||||||
*/
|
*/
|
||||||
export class BindingBuilder {
|
export class BindingBuilder {
|
||||||
token;
|
token;
|
||||||
@ -122,18 +304,107 @@ export class BindingBuilder {
|
|||||||
this.token = token;
|
this.token = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind an interface to an implementation / subclass.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* Becuse `toAlias` and `toClass` are often confused the example contains both use cases for easy comparison.
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
*
|
||||||
|
* class Vehicle {}
|
||||||
|
*
|
||||||
|
* class Car extends Vehicle {}
|
||||||
|
*
|
||||||
|
* var injectorClass = Injector.resolveAndCreate([
|
||||||
|
* Car,
|
||||||
|
* bind(Vehicle).toClass(Car)
|
||||||
|
* ]);
|
||||||
|
* var injectorAlias = Injector.resolveAndCreate([
|
||||||
|
* Car,
|
||||||
|
* bind(Vehicle).toAlias(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):Binding {
|
toClass(type:Type):Binding {
|
||||||
return new Binding(this.token, {toClass: type});
|
return new Binding(this.token, {toClass: type});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a key to a value.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* var injector = Injector.resolveAndCreate([
|
||||||
|
* bind(String).toValue('Hello')
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* expect(injector.get(String)).toEqual('Hello');
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
toValue(value):Binding {
|
toValue(value):Binding {
|
||||||
return new Binding(this.token, {toValue: value});
|
return new Binding(this.token, {toValue: value});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a key to an alias of an existing key.
|
||||||
|
*
|
||||||
|
* An alias means that we will return the same instance as if the alias token was used. (This is in contrast to
|
||||||
|
* `toClass` where a separet instance of `toClass` will be returned.)
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* Becuse `toAlias` and `toClass` are often confused the example contains both use cases for easy comparison.
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
*
|
||||||
|
* class Vehicle {}
|
||||||
|
*
|
||||||
|
* class Car extends Vehicle {}
|
||||||
|
*
|
||||||
|
* var injectorAlias = Injector.resolveAndCreate([
|
||||||
|
* Car,
|
||||||
|
* bind(Vehicle).toAlias(Car)
|
||||||
|
* ]);
|
||||||
|
* var injectorClass = Injector.resolveAndCreate([
|
||||||
|
* Car,
|
||||||
|
* bind(Vehicle).toClass(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):Binding {
|
toAlias(aliasToken):Binding {
|
||||||
return new Binding(this.token, {toAlias: aliasToken});
|
return new Binding(this.token, {toAlias: aliasToken});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a key to a function which computes the value.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* var injector = Injector.resolveAndCreate([
|
||||||
|
* bind(Number).toFactory(() => { return 1+2; }}),
|
||||||
|
* bind(String).toFactory((v) => { return "Value: " + v; }, [String] })
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* expect(injector.get(Number)).toEqual(3);
|
||||||
|
* expect(injector.get(String)).toEqual('Value: 3');
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
toFactory(factoryFunction:Function, dependencies:List = null):Binding {
|
toFactory(factoryFunction:Function, dependencies:List = null):Binding {
|
||||||
return new Binding(this.token, {
|
return new Binding(this.token, {
|
||||||
toFactory: factoryFunction,
|
toFactory: factoryFunction,
|
||||||
@ -141,6 +412,27 @@ export class BindingBuilder {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a key to a function which computes the value asynchronously.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* var injector = Injector.resolveAndCreate([
|
||||||
|
* bind(Number).toAsyncFactory(() => {
|
||||||
|
* return new Promise((resolve) => resolve(1 + 2));
|
||||||
|
* }),
|
||||||
|
* bind(String).toFactory((v) => { return "Value: " + v; }, [String])
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* injector.asyncGet(Number).then((v) => expect(v).toBe(3));
|
||||||
|
* injector.asyncGet(String).then((v) => expect(v).toBe('Value: 3'));
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The interesting thing to note is that event thougt `Numeber` has an async factory, the `String` factory
|
||||||
|
* function takes the resolved value. This shows that the [Injector] delays executing of the `String` factory
|
||||||
|
* until after the `Number` is resolved. This can only be done if the `token` is retrive
|
||||||
|
*/
|
||||||
toAsyncFactory(factoryFunction:Function, dependencies:List = null):Binding {
|
toAsyncFactory(factoryFunction:Function, dependencies:List = null):Binding {
|
||||||
return new Binding(this.token, {
|
return new Binding(this.token, {
|
||||||
toAsyncFactory: factoryFunction,
|
toAsyncFactory: factoryFunction,
|
||||||
|
75
modules/angular2/src/di/exceptions.js
vendored
75
modules/angular2/src/di/exceptions.js
vendored
@ -24,8 +24,12 @@ function constructResolvingPath(keys:List) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class KeyMetadataError extends Error {}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all errors arising from missconfigured bindings.
|
||||||
|
*
|
||||||
|
* @exportedAs angular2/di_errors
|
||||||
|
*/
|
||||||
export class ProviderError extends Error {
|
export class ProviderError extends Error {
|
||||||
keys:List;
|
keys:List;
|
||||||
constructResolvingMessage:Function;
|
constructResolvingMessage:Function;
|
||||||
@ -49,6 +53,12 @@ export class ProviderError extends Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when trying to retrieve a dependency by [Key] from [Injector], but [Injector] does not have a [Binding] for
|
||||||
|
* said [Key].
|
||||||
|
*
|
||||||
|
* @exportedAs angular2/di_errors
|
||||||
|
*/
|
||||||
export class NoProviderError extends ProviderError {
|
export class NoProviderError extends ProviderError {
|
||||||
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
||||||
constructor(key) {
|
constructor(key) {
|
||||||
@ -59,6 +69,30 @@ export class NoProviderError extends ProviderError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw when trying to retrieve async [Binding] using sync API.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* var injector = Injector.resolveAndCreate([
|
||||||
|
* bind(Number).toAsyncFactory(() => {
|
||||||
|
* return new Promise((resolve) => resolve(1 + 2));
|
||||||
|
* }),
|
||||||
|
* bind(String).toFactory((v) => { return "Value: " + v; }, [String])
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* injector.asyncGet(String).then((v) => expect(v).toBe('Value: 3'));
|
||||||
|
* expect(() => {
|
||||||
|
* injector.get(String);
|
||||||
|
* }).toThrowError(AsycBindingError);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The above example throws because `String` dependes no `Numeber` which is async. If any binding in the dependency
|
||||||
|
* graph is async then the graph can only be retrieved using `asyncGet` API.
|
||||||
|
*
|
||||||
|
* @exportedAs angular2/di_errors
|
||||||
|
*/
|
||||||
export class AsyncBindingError extends ProviderError {
|
export class AsyncBindingError extends ProviderError {
|
||||||
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
||||||
constructor(key) {
|
constructor(key) {
|
||||||
@ -70,6 +104,24 @@ export class AsyncBindingError extends ProviderError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw when dependencies from a cyle.
|
||||||
|
*
|
||||||
|
* ## Example:
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* class A {
|
||||||
|
* constructor(b:B) {}
|
||||||
|
* }
|
||||||
|
* class B {
|
||||||
|
* constructor(a:A) {}
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Retrieving `A` or `B` will throw `CyclicDependencyError` as such a graph can not be constructed.
|
||||||
|
*
|
||||||
|
* @exportedAs angular2/di_errors
|
||||||
|
*/
|
||||||
export class CyclicDependencyError extends ProviderError {
|
export class CyclicDependencyError extends ProviderError {
|
||||||
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
||||||
constructor(key) {
|
constructor(key) {
|
||||||
@ -79,6 +131,14 @@ export class CyclicDependencyError extends ProviderError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when constructing type returns with an Error.
|
||||||
|
*
|
||||||
|
* The `InstantiationError` class contains the original error plus dependency graph which caused this object to be
|
||||||
|
* instantiated.
|
||||||
|
*
|
||||||
|
* @exportedAs angular2/di_errors
|
||||||
|
*/
|
||||||
export class InstantiationError extends ProviderError {
|
export class InstantiationError extends ProviderError {
|
||||||
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
||||||
constructor(originalException, key) {
|
constructor(originalException, key) {
|
||||||
@ -90,6 +150,11 @@ export class InstantiationError extends ProviderError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when object other then [Binding] (or [Type]) is passed to [Injector] creation.
|
||||||
|
*
|
||||||
|
* @exportedAs angular2/di_errors
|
||||||
|
*/
|
||||||
export class InvalidBindingError extends Error {
|
export class InvalidBindingError extends Error {
|
||||||
message:string;
|
message:string;
|
||||||
constructor(binding) {
|
constructor(binding) {
|
||||||
@ -102,6 +167,14 @@ export class InvalidBindingError extends Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when the class as no annotation information.
|
||||||
|
*
|
||||||
|
* Lack of annotation prevents the [Injector] from determininig what dependencies need to be injected int the
|
||||||
|
* constructor.
|
||||||
|
*
|
||||||
|
* @exportedAs angular2/di_errors
|
||||||
|
*/
|
||||||
export class NoAnnotationError extends Error {
|
export class NoAnnotationError extends Error {
|
||||||
message:string;
|
message:string;
|
||||||
constructor(typeOrFunc) {
|
constructor(typeOrFunc) {
|
||||||
|
116
modules/angular2/src/di/injector.js
vendored
116
modules/angular2/src/di/injector.js
vendored
@ -20,6 +20,44 @@ function _isWaiting(obj):boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dependency injection container used for 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:
|
||||||
|
*
|
||||||
|
* Suppose that we want to inject an `Engine` into class `Car`, we would define it like this:
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* class Engine {
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* class Car {
|
||||||
|
* constructor(@Inject(Engine) engine) {
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Next we need to write the code that creates and instantiates the `Injector`. We then ask for the `root` object,
|
||||||
|
* `Car`, so that the `Injector` can recursively build all of that object's dependencies.
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* main() {
|
||||||
|
* var injector = Injector.resolveAndCreate([Car, Engine]);
|
||||||
|
*
|
||||||
|
* // Get a reference to the `root` object, which will recursively instantiate the tree.
|
||||||
|
* var car = injector.get(Car);
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
* Notice that we don't use the `new` operator because we explicitly want to have the `Injector` resolve all of the
|
||||||
|
* object's dependencies automatically.
|
||||||
|
*
|
||||||
|
* @exportedAs angular2/di
|
||||||
|
*/
|
||||||
export class Injector {
|
export class Injector {
|
||||||
_bindings:List;
|
_bindings:List;
|
||||||
_instances:List;
|
_instances:List;
|
||||||
@ -29,13 +67,16 @@ export class Injector {
|
|||||||
_syncStrategy:_SyncInjectorStrategy;
|
_syncStrategy:_SyncInjectorStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates/looks up factory functions and dependencies from binding
|
* Turns a list of binding definitions into internal resolved list of resolved bindings.
|
||||||
* declarations and flattens bindings into a single [List].
|
|
||||||
*
|
*
|
||||||
* The returned list is sparse, indexed by [Key.id]. It is generally not
|
* A resolution is a process of flattening multiple nested lists and converting individual bindings into a
|
||||||
* useful to application code other than for passing it to [Injector]
|
* list of [ResolvedBinding]s. The resolution can be cached for performance sensitive code.
|
||||||
* functions that require resolved binding lists, such as
|
*
|
||||||
* [fromResolvedBindings] and [createChildFromResolved].
|
* @param [bindings] can be a list of [Type], [Binding], [ResolvedBinding], or a recursive list of more bindings.
|
||||||
|
*
|
||||||
|
* The returned list is sparse, indexed by [Key.id]. It is generally not useful to application code other than for
|
||||||
|
* passing it to [Injector] functions that require resolved binding lists, such as [fromResolvedBindings] and
|
||||||
|
* [createChildFromResolved].
|
||||||
*/
|
*/
|
||||||
static resolve(bindings:List/*<ResolvedBinding|Binding|Type|List>*/):List<ResolvedBinding> {
|
static resolve(bindings:List/*<ResolvedBinding|Binding|Type|List>*/):List<ResolvedBinding> {
|
||||||
var resolvedBindings = _resolveBindings(bindings);
|
var resolvedBindings = _resolveBindings(bindings);
|
||||||
@ -45,22 +86,33 @@ export class Injector {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves bindings and creates an injector based on those bindings. This function is slower than the
|
* Resolves bindings and creates an injector based on those bindings. This function is slower than the
|
||||||
* corresponding [fromResolvedBindings] because it needs to resolve bindings. Prefer [fromResolvedBindings]
|
* corresponding [fromResolvedBindings] because it needs to resolve bindings first. See [Injector.resolve].
|
||||||
* in performance-critical code that creates lots of injectors.
|
*
|
||||||
|
* Prefer [fromResolvedBindings] in performance-critical code that creates lots of injectors.
|
||||||
|
*
|
||||||
|
* @param [bindings] can be a list of [Type], [Binding], [ResolvedBinding], or a recursive list of more bindings.
|
||||||
|
* @param [defaultBindings] Setting to true will auto-create bindings.
|
||||||
*/
|
*/
|
||||||
static resolveAndCreate(bindings:List/*<ResolvedBinding|Binding|Type|List>*/, {defaultBindings=false}={}) {
|
static resolveAndCreate(bindings:List/*<ResolvedBinding|Binding|Type|List>*/, {defaultBindings=false}={}) {
|
||||||
return new Injector(Injector.resolve(bindings), null, defaultBindings);
|
return new Injector(Injector.resolve(bindings), null, defaultBindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an injector from previously resolved bindings. This bypasses a lot
|
* Creates an injector from previously resolved bindings. This bypasses resolution and flattening. This API is
|
||||||
* of computation and is the recommended way to construct injectors in
|
* recommended way to construct injectors in performance-sensitive parts.
|
||||||
* performance-sensitive parts.
|
*
|
||||||
|
* @param [bindings] A sparse list of [ResolvedBinding]s. See [Injector.resolve].
|
||||||
|
* @param [defaultBindings] Setting to true will auto-create bindings.
|
||||||
*/
|
*/
|
||||||
static fromResolvedBindings(bindings:List<ResolvedBinding>, {defaultBindings=false}={}) {
|
static fromResolvedBindings(bindings:List<ResolvedBinding>, {defaultBindings=false}={}) {
|
||||||
return new Injector(bindings, null, defaultBindings);
|
return new Injector(bindings, null, defaultBindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param [bindings] A sparse list of [ResolvedBinding]s. See [Injector.resolve].
|
||||||
|
* @param [parent] Parent Injector or `null` if root injector.
|
||||||
|
* @param [defaultBindings] Setting to true will auto-create bindings. (Only use with root injector.)
|
||||||
|
*/
|
||||||
constructor(bindings:List<ResolvedBinding>, parent:Injector, defaultBindings:boolean) {
|
constructor(bindings:List<ResolvedBinding>, parent:Injector, defaultBindings:boolean) {
|
||||||
this._bindings = bindings;
|
this._bindings = bindings;
|
||||||
this._instances = this._createInstances();
|
this._instances = this._createInstances();
|
||||||
@ -70,22 +122,60 @@ export class Injector {
|
|||||||
this._syncStrategy = new _SyncInjectorStrategy(this);
|
this._syncStrategy = new _SyncInjectorStrategy(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to retrieve an instance from the injector.
|
||||||
|
*
|
||||||
|
* @param [token] usually the [Type] of object. (Same as token used while setting up a binding).
|
||||||
|
* @returns an instance represented by the token. Throws if not found.
|
||||||
|
*/
|
||||||
get(token) {
|
get(token) {
|
||||||
|
|
||||||
return this._getByKey(Key.get(token), false, false, false);
|
return this._getByKey(Key.get(token), false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to retrieve an instance from the injector.
|
||||||
|
*
|
||||||
|
* @param [token] usually the [Type] of object. (Same as token used while setting up a binding).
|
||||||
|
* @returns an instance represented by the token. Returns `null` if not found.
|
||||||
|
*/
|
||||||
getOptional(token) {
|
getOptional(token) {
|
||||||
return this._getByKey(Key.get(token), false, false, true);
|
return this._getByKey(Key.get(token), false, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
asyncGet(token) {
|
/**
|
||||||
|
* Used to retrieve an instance from the injector asynchronously. Used with asynchronous bindings.
|
||||||
|
*
|
||||||
|
* @param [token] usually the [Type] of object. (Same as token used while setting up a binding).
|
||||||
|
* @returns a [Promise] which resolves to the instance represented by the token.
|
||||||
|
*/
|
||||||
|
asyncGet(token):Promise {
|
||||||
return this._getByKey(Key.get(token), true, false, false);
|
return this._getByKey(Key.get(token), true, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a child injector and load a new set of bindings into it.
|
||||||
|
*
|
||||||
|
* A resolution is a process of flattening multiple nested and converting individual bindings into a
|
||||||
|
* list of [ResolvedBinding]s. The resolution can be cached [Injector.resolve] for performance sensitive
|
||||||
|
* code.
|
||||||
|
*
|
||||||
|
* See: [Injector.resolve].
|
||||||
|
*
|
||||||
|
* @param [bindings] can be a list of [Type], [Binding], [ResolvedBinding], or a recursive list of more bindings.
|
||||||
|
* @returns a new child `Injector`.
|
||||||
|
*/
|
||||||
resolveAndCreateChild(bindings:List/*<ResolvedBinding|Binding|Type|List>*/):Injector {
|
resolveAndCreateChild(bindings:List/*<ResolvedBinding|Binding|Type|List>*/):Injector {
|
||||||
return new Injector(Injector.resolve(bindings), this, false);
|
return new Injector(Injector.resolve(bindings), this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a child injector and load a new set of [ResolvedBinding] into it.
|
||||||
|
*
|
||||||
|
* @param [bindings] A sparse list of [ResolvedBinding]s. See [Injector.resolve].
|
||||||
|
* @returns a new child `Injector`.
|
||||||
|
*/
|
||||||
createChildFromResolved(bindings:List<ResolvedBinding>):Injector {
|
createChildFromResolved(bindings:List<ResolvedBinding>):Injector {
|
||||||
return new Injector(bindings, this, false);
|
return new Injector(bindings, this, false);
|
||||||
}
|
}
|
||||||
@ -283,7 +373,7 @@ function _resolveBindings(bindings:List): List {
|
|||||||
} else if (unresolved instanceof Type) {
|
} else if (unresolved instanceof Type) {
|
||||||
resolved = bind(unresolved).toClass(unresolved).resolve();
|
resolved = bind(unresolved).toClass(unresolved).resolve();
|
||||||
} else if (unresolved instanceof Binding) {
|
} else if (unresolved instanceof Binding) {
|
||||||
resolved = unresolved.resolve();
|
resolved = unresolved.resolve();
|
||||||
} else if (unresolved instanceof List) {
|
} else if (unresolved instanceof List) {
|
||||||
resolved = _resolveBindings(unresolved);
|
resolved = _resolveBindings(unresolved);
|
||||||
} else if (unresolved instanceof BindingBuilder) {
|
} else if (unresolved instanceof BindingBuilder) {
|
||||||
|
44
modules/angular2/src/di/key.js
vendored
44
modules/angular2/src/di/key.js
vendored
@ -1,34 +1,48 @@
|
|||||||
import {KeyMetadataError} from './exceptions';
|
import {MapWrapper} from 'angular2/src/facade/collection';
|
||||||
import {MapWrapper, Map} from 'angular2/src/facade/collection';
|
//import {int} from 'angular2/src/facade/lang';
|
||||||
import {int, isPresent} from 'angular2/src/facade/lang';
|
|
||||||
|
|
||||||
|
// TODO: uncoment `int` once https://github.com/angular/angular/issues/1414 is fixed
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique object used for retrieving items from the Injector.
|
||||||
|
*
|
||||||
|
* [Key]s have:
|
||||||
|
* - system wide unique [id].
|
||||||
|
* - [token] usually the [Type] of the instance.
|
||||||
|
*
|
||||||
|
* [Key]s are used internaly in [Injector] becouse they have system wide unique [id]s which allow the injector to
|
||||||
|
* index in arrays rather ther look up items in maps.
|
||||||
|
*
|
||||||
|
* @exportedAs angular2/di
|
||||||
|
*/
|
||||||
export class Key {
|
export class Key {
|
||||||
token;
|
token;
|
||||||
id:int;
|
id/* :int */;
|
||||||
metadata:any;
|
metadata:any;
|
||||||
constructor(token, id:int) {
|
constructor(token, id/* :int */) {
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.metadata = null;
|
this.metadata = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static setMetadata(key:Key, metadata):Key {
|
/**
|
||||||
if (isPresent(key.metadata) && key.metadata !== metadata) {
|
* Retrieve a [Key] for a token.
|
||||||
throw new KeyMetadataError();
|
*/
|
||||||
}
|
|
||||||
key.metadata = metadata;
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get(token):Key {
|
static get(token):Key {
|
||||||
return _globalKeyRegistry.get(token);
|
return _globalKeyRegistry.get(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
static get numberOfKeys():int {
|
/**
|
||||||
|
* @returns number of [Key]s registered in the system.
|
||||||
|
*/
|
||||||
|
static get numberOfKeys()/* :int */ {
|
||||||
return _globalKeyRegistry.numberOfKeys;
|
return _globalKeyRegistry.numberOfKeys;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
export class KeyRegistry {
|
export class KeyRegistry {
|
||||||
_allKeys:Map;
|
_allKeys:Map;
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -47,7 +61,7 @@ export class KeyRegistry {
|
|||||||
return newKey;
|
return newKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
get numberOfKeys():int {
|
get numberOfKeys()/* :int */ {
|
||||||
return MapWrapper.size(this._allKeys);
|
return MapWrapper.size(this._allKeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
modules/angular2/src/di/opaque_token.js
vendored
5
modules/angular2/src/di/opaque_token.js
vendored
@ -1,3 +1,8 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @exportedAs angular2/di
|
||||||
|
*/
|
||||||
export class OpaqueToken {
|
export class OpaqueToken {
|
||||||
_desc:string;
|
_desc:string;
|
||||||
|
|
||||||
|
2
modules/angular2/src/directives/switch.js
vendored
2
modules/angular2/src/directives/switch.js
vendored
@ -178,8 +178,6 @@ export class SwitchWhen {
|
|||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* <template [switch-default]>...</template>
|
* <template [switch-default]>...</template>
|
||||||
*
|
|
||||||
* @exportedAs angular2/directives
|
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @exportedAs angular2/directives
|
* @exportedAs angular2/directives
|
||||||
|
@ -94,11 +94,7 @@ export class MockTemplateResolver extends TemplateResolver {
|
|||||||
view = new View({
|
view = new View({
|
||||||
template: view.template,
|
template: view.template,
|
||||||
templateUrl: view.templateUrl,
|
templateUrl: view.templateUrl,
|
||||||
directives: directives,
|
directives: directives
|
||||||
formatters: view.formatters,
|
|
||||||
source: view.source,
|
|
||||||
locale: view.locale,
|
|
||||||
device: view.device
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,11 +103,7 @@ export class MockTemplateResolver extends TemplateResolver {
|
|||||||
view = new View({
|
view = new View({
|
||||||
template: inlineTemplate,
|
template: inlineTemplate,
|
||||||
templateUrl: null,
|
templateUrl: null,
|
||||||
directives: view.directives,
|
directives: view.directives
|
||||||
formatters: view.formatters,
|
|
||||||
source: view.source,
|
|
||||||
locale: view.locale,
|
|
||||||
device: view.device
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
26
modules/angular2/test/di/key_spec.js
vendored
26
modules/angular2/test/di/key_spec.js
vendored
@ -21,31 +21,5 @@ export function main() {
|
|||||||
expect(registry.get(registry.get('car'))).toBe(registry.get('car'));
|
expect(registry.get(registry.get('car'))).toBe(registry.get('car'));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("metadata", function () {
|
|
||||||
it("should assign metadata to a key", function () {
|
|
||||||
var key = registry.get('car');
|
|
||||||
|
|
||||||
Key.setMetadata(key, "meta");
|
|
||||||
|
|
||||||
expect(key.metadata).toEqual("meta");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should allow assigning the same metadata twice", function () {
|
|
||||||
var key = registry.get('car');
|
|
||||||
|
|
||||||
Key.setMetadata(key, "meta");
|
|
||||||
Key.setMetadata(key, "meta");
|
|
||||||
|
|
||||||
expect(key.metadata).toEqual("meta");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw when assigning different metadata", function () {
|
|
||||||
var key = registry.get('car');
|
|
||||||
|
|
||||||
Key.setMetadata(key, "meta1");
|
|
||||||
|
|
||||||
expect(() => Key.setMetadata(key, "meta2")).toThrowError();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
Reference in New Issue
Block a user