docs: add DI to public docs

This commit is contained in:
Misko Hevery 2015-04-15 22:35:38 +00:00
parent 487c4d23c1
commit 87ac100c66
17 changed files with 581 additions and 105 deletions

View File

@ -402,6 +402,7 @@ function createDocsTasks(public) {
var dgeni = new Dgeni([require(dgeniPackage)]);
return dgeni.generate();
} catch(x) {
console.log(x);
console.log(x.stack);
throw x;
}

View File

@ -2,7 +2,7 @@
* @module
* @public
* @description
* Define public API for Angular here.
* Define angular core API here.
*/
export * from './src/core/annotations/visibility';
export * from './src/core/compiler/interfaces';

View File

@ -1,5 +1,6 @@
/**
* @module
* @public
* @description
* This is a description
*/

7
modules/angular2/di_annotations.js vendored Normal file
View File

@ -0,0 +1,7 @@
/**
* @module
* @public
* @description
* This is a description
*/

7
modules/angular2/di_errors.js vendored Normal file
View File

@ -0,0 +1,7 @@
/**
* @module
* @public
* @description
* This is a description
*/

View File

@ -30,13 +30,13 @@ export class PropertySetter extends DependencyAnnotation {
*
* ## 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
* <input type="text">
* ```
*
* A decorator could inject string literal `text` like so:
* A decorator can inject string literal `text` like so:
*
* ```javascript
* @Decorator({
@ -71,7 +71,7 @@ export class Attribute extends DependencyAnnotation {
/**
* Specifies that a [QueryList] should be injected.
*
* See: [QueryList] for usage.
* See: [QueryList] for usage and example.
*
* @exportedAs angular2/annotations
*/

View File

@ -33,38 +33,57 @@ import {ABSTRACT, CONST, Type} from 'angular2/src/facade/lang';
* @exportedAs angular2/annotations
*/
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;
/**
* Specify an inline template for an angular component.
*
* NOTE: either `templateURL` or `template` should be used, but not both.
*/
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>;
formatters:any; //List<Type>;
source:any;//List<View>;
locale:any; //string
device:any; //string
@CONST()
constructor({
templateUrl,
template,
directives,
formatters,
source,
locale,
device
directives
}: {
templateUrl: string,
template: string,
directives: List<Type>,
formatters: List<Type>,
source: List<View>,
locale: string,
device: string
directives: List<Type>
})
{
this.templateUrl = templateUrl;
this.template = template;
this.directives = directives;
this.formatters = formatters;
this.source = source;
this.locale = locale;
this.device = device;
}
}

View File

@ -26,8 +26,6 @@ import {isPresent} from 'angular2/src/facade/lang';
* lifecycle.tick();
* });
* ```
*
*
* @exportedAs angular2/change_detection
*/
@Injectable()

View File

@ -5,10 +5,11 @@ import {CONST} from "angular2/src/facade/lang";
*
* ```
* class AComponent {
* constructor(@Inject('aServiceToken') aService) {}
* constructor(@Inject(MyService) aService:MyService) {}
* }
* ```
*
* @exportedAs angular2/di_annotations
*/
export class Inject {
token;
@ -23,12 +24,13 @@ export class Inject {
*
* ```
* class AComponent {
* constructor(@InjectPromise('aServiceToken') aServicePromise) {
* aServicePromise.then(aService => ...);
* constructor(@InjectPromise(MyService) aServicePromise:Promise<MyService>) {
* aServicePromise.then(aService:MyService => ...);
* }
* }
* ```
*
* @exportedAs angular2/di_annotations
*/
export class InjectPromise {
token;
@ -43,12 +45,13 @@ export class InjectPromise {
*
* ```
* class AComponent {
* constructor(@InjectLazy('aServiceToken') aServiceFn) {
* aService = aServiceFn();
* constructor(@InjectLazy(MyService) aServiceFn:Function) {
* var aService:MyService = aServiceFn();
* }
* }
* ```
*
* @exportedAs angular2/di_annotations
*/
export class InjectLazy {
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 {
* constructor(@Optional() dp:Dependency) {
* this.dp = dp;
* constructor(@Optional() aService:MyService) {
* this.aService = aService;
* }
* }
* ```
*
* @exportedAs angular2/di_annotations
*/
export class Optional {
@CONST()
@ -102,6 +105,7 @@ export class Optional {
* The framework can use `new Parent()` to handle the `aService` dependency
* in a specific way.
*
* @exportedAs angular2/di_annotations
*/
export class DependencyAnnotation {
@CONST()
@ -114,8 +118,8 @@ export class DependencyAnnotation {
}
/**
* A class annotation that marks a class as available to `Injector`s for
* creation.
* A marker annotation that marks a class as available to `Injector`s for creation. Used by tooling for generating
* constructor stubs.
*
* ```
* class NeedsService {
@ -125,6 +129,7 @@ export class DependencyAnnotation {
* @Injectable
* class UsefulService {}
* ```
* @exportedAs angular2/di_annotations
*/
export class Injectable {
@CONST()

View File

@ -5,6 +5,9 @@ import {Key} from './key';
import {Inject, InjectLazy, InjectPromise, Optional, DependencyAnnotation} from './annotations';
import {NoAnnotationError} from './exceptions';
/**
* @private
*/
export class Dependency {
key:Key;
asPromise:boolean;
@ -28,15 +31,168 @@ export class Dependency {
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 {
/**
* Token used when retriving this binding. Usually the [Type].
*/
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;
/**
* Bind a key to a value.
*
* ## Example
*
* ```javascript
* var injector = Injector.resolveAndCreate([
* new Binding(String, { toValue: 'Hello' })
* ]);
*
* expect(injector.get(String)).toEqual('Hello');
* ```
*/
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;
/**
* 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;
/**
* 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;
/**
* 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;
@CONST()
@ -59,6 +215,9 @@ export class Binding {
this.dependencies = deps;
}
/**
*
*/
resolve(): ResolvedBinding {
var factoryFn:Function;
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 {
/**
* A key, usually a [Type].
*/
key:Key;
/**
* Factory function which can return an instance of [key].
*/
factory:Function;
/**
* Arguments (dependencies) to the [factory] function.
*/
dependencies:List<Dependency>;
/**
* Specifies if the [factory] function returns an [Promise]
*/
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 {
return new BindingBuilder(token);
@ -114,6 +295,7 @@ export function bind(token):BindingBuilder {
/**
* Helper class for [bind] function.
* @exportedAs angular2/di
*/
export class BindingBuilder {
token;
@ -122,18 +304,107 @@ export class BindingBuilder {
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 {
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 {
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 {
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 {
return new Binding(this.token, {
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 {
return new Binding(this.token, {
toAsyncFactory: factoryFunction,

View File

@ -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 {
keys:List;
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 {
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
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 {
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
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 {
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
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 {
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
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 {
message:string;
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 {
message:string;
constructor(typeOrFunc) {

View File

@ -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 {
_bindings:List;
_instances:List;
@ -29,13 +67,16 @@ export class Injector {
_syncStrategy:_SyncInjectorStrategy;
/**
* Creates/looks up factory functions and dependencies from binding
* declarations and flattens bindings into a single [List].
* Turns a list of binding definitions into internal resolved list of resolved 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].
* A resolution is a process of flattening multiple nested lists and converting individual bindings into a
* list of [ResolvedBinding]s. The resolution can be cached for performance sensitive code.
*
* @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> {
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
* corresponding [fromResolvedBindings] because it needs to resolve bindings. Prefer [fromResolvedBindings]
* in performance-critical code that creates lots of injectors.
* corresponding [fromResolvedBindings] because it needs to resolve bindings first. See [Injector.resolve].
*
* 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}={}) {
return new Injector(Injector.resolve(bindings), null, defaultBindings);
}
/**
* Creates an injector from previously resolved bindings. This bypasses a lot
* of computation and is the recommended way to construct injectors in
* performance-sensitive parts.
* Creates an injector from previously resolved bindings. This bypasses resolution and flattening. This API is
* recommended way to construct injectors in 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}={}) {
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) {
this._bindings = bindings;
this._instances = this._createInstances();
@ -70,22 +122,60 @@ export class Injector {
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) {
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) {
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);
}
/**
* 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 {
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 {
return new Injector(bindings, this, false);
}
@ -283,7 +373,7 @@ function _resolveBindings(bindings:List): List {
} else if (unresolved instanceof Type) {
resolved = bind(unresolved).toClass(unresolved).resolve();
} else if (unresolved instanceof Binding) {
resolved = unresolved.resolve();
resolved = unresolved.resolve();
} else if (unresolved instanceof List) {
resolved = _resolveBindings(unresolved);
} else if (unresolved instanceof BindingBuilder) {

View File

@ -1,34 +1,48 @@
import {KeyMetadataError} from './exceptions';
import {MapWrapper, Map} from 'angular2/src/facade/collection';
import {int, isPresent} from 'angular2/src/facade/lang';
import {MapWrapper} from 'angular2/src/facade/collection';
//import {int} 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 {
token;
id:int;
id/* :int */;
metadata:any;
constructor(token, id:int) {
constructor(token, id/* :int */) {
this.token = token;
this.id = id;
this.metadata = null;
}
static setMetadata(key:Key, metadata):Key {
if (isPresent(key.metadata) && key.metadata !== metadata) {
throw new KeyMetadataError();
}
key.metadata = metadata;
return key;
}
/**
* Retrieve a [Key] for a token.
*/
static get(token):Key {
return _globalKeyRegistry.get(token);
}
static get numberOfKeys():int {
/**
* @returns number of [Key]s registered in the system.
*/
static get numberOfKeys()/* :int */ {
return _globalKeyRegistry.numberOfKeys;
}
}
/**
* @private
*/
export class KeyRegistry {
_allKeys:Map;
constructor() {
@ -47,7 +61,7 @@ export class KeyRegistry {
return newKey;
}
get numberOfKeys():int {
get numberOfKeys()/* :int */ {
return MapWrapper.size(this._allKeys);
}
}

View File

@ -1,3 +1,8 @@
/**
*
*
* @exportedAs angular2/di
*/
export class OpaqueToken {
_desc:string;

View File

@ -178,8 +178,6 @@ export class SwitchWhen {
*
* ```
* <template [switch-default]>...</template>
*
* @exportedAs angular2/directives
* ```
*
* @exportedAs angular2/directives

View File

@ -94,11 +94,7 @@ export class MockTemplateResolver extends TemplateResolver {
view = new View({
template: view.template,
templateUrl: view.templateUrl,
directives: directives,
formatters: view.formatters,
source: view.source,
locale: view.locale,
device: view.device
directives: directives
});
}
@ -107,11 +103,7 @@ export class MockTemplateResolver extends TemplateResolver {
view = new View({
template: inlineTemplate,
templateUrl: null,
directives: view.directives,
formatters: view.formatters,
source: view.source,
locale: view.locale,
device: view.device
directives: view.directives
});
}

View File

@ -21,31 +21,5 @@ export function main() {
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();
});
});
});
}