diff --git a/gulpfile.js b/gulpfile.js
index 881ce83272..1d987656e7 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -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;
}
diff --git a/modules/angular2/core.js b/modules/angular2/core.js
index 8f1cb18d7f..4ed8c070e1 100644
--- a/modules/angular2/core.js
+++ b/modules/angular2/core.js
@@ -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';
diff --git a/modules/angular2/di.js b/modules/angular2/di.js
index ac0f07f165..7bab482ecf 100644
--- a/modules/angular2/di.js
+++ b/modules/angular2/di.js
@@ -1,5 +1,6 @@
/**
* @module
+ * @public
* @description
* This is a description
*/
diff --git a/modules/angular2/di_annotations.js b/modules/angular2/di_annotations.js
new file mode 100644
index 0000000000..c2aabbfc60
--- /dev/null
+++ b/modules/angular2/di_annotations.js
@@ -0,0 +1,7 @@
+/**
+ * @module
+ * @public
+ * @description
+ * This is a description
+ */
+
diff --git a/modules/angular2/di_errors.js b/modules/angular2/di_errors.js
new file mode 100644
index 0000000000..c2aabbfc60
--- /dev/null
+++ b/modules/angular2/di_errors.js
@@ -0,0 +1,7 @@
+/**
+ * @module
+ * @public
+ * @description
+ * This is a description
+ */
+
diff --git a/modules/angular2/src/core/annotations/di.js b/modules/angular2/src/core/annotations/di.js
index 2bcc97f0c9..975b7da942 100644
--- a/modules/angular2/src/core/annotations/di.js
+++ b/modules/angular2/src/core/annotations/di.js
@@ -30,13 +30,13 @@ export class PropertySetter extends DependencyAnnotation {
*
* ## Example
*
- * suppose we have an `` element and would like to know its `type`.
+ * Suppose we have an `` element and want to know its `type`.
*
* ```html
*
* ```
*
- * 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
*/
diff --git a/modules/angular2/src/core/annotations/view.js b/modules/angular2/src/core/annotations/view.js
index 68fcea319e..30f5b2fb03 100644
--- a/modules/angular2/src/core/annotations/view.js
+++ b/modules/angular2/src/core/annotations/view.js
@@ -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: '
+ *
+ *
{{item}}
+ *
'
+ * })
+ * class MyComponent {
+ * }
+ * ```
+ */
directives:any; //List;
- formatters:any; //List;
- source:any;//List;
- locale:any; //string
- device:any; //string
+
@CONST()
constructor({
templateUrl,
template,
- directives,
- formatters,
- source,
- locale,
- device
+ directives
}: {
templateUrl: string,
template: string,
- directives: List,
- formatters: List,
- source: List,
- locale: string,
- device: string
+ directives: List
})
{
this.templateUrl = templateUrl;
this.template = template;
this.directives = directives;
- this.formatters = formatters;
- this.source = source;
- this.locale = locale;
- this.device = device;
}
}
diff --git a/modules/angular2/src/core/life_cycle/life_cycle.js b/modules/angular2/src/core/life_cycle/life_cycle.js
index 2e08d5af19..b6fd82c7d1 100644
--- a/modules/angular2/src/core/life_cycle/life_cycle.js
+++ b/modules/angular2/src/core/life_cycle/life_cycle.js
@@ -26,8 +26,6 @@ import {isPresent} from 'angular2/src/facade/lang';
* lifecycle.tick();
* });
* ```
- *
- *
* @exportedAs angular2/change_detection
*/
@Injectable()
diff --git a/modules/angular2/src/di/annotations.js b/modules/angular2/src/di/annotations.js
index 1bc253637a..2a04a96153 100644
--- a/modules/angular2/src/di/annotations.js
+++ b/modules/angular2/src/di/annotations.js
@@ -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) {
+ * 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()
diff --git a/modules/angular2/src/di/binding.js b/modules/angular2/src/di/binding.js
index 10a284cf73..4cc995d139 100644
--- a/modules/angular2/src/di/binding.js
+++ b/modules/angular2/src/di/binding.js
@@ -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;
+
+ /**
+ * Specifies if the [factory] function returns an [Promise]
+ */
providedAsPromise:boolean;
constructor(key:Key, factory:Function, dependencies:List, 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,
diff --git a/modules/angular2/src/di/exceptions.js b/modules/angular2/src/di/exceptions.js
index c436d9f1e8..b31259377e 100644
--- a/modules/angular2/src/di/exceptions.js
+++ b/modules/angular2/src/di/exceptions.js
@@ -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) {
diff --git a/modules/angular2/src/di/injector.js b/modules/angular2/src/di/injector.js
index b5c00fed23..a51769b351 100644
--- a/modules/angular2/src/di/injector.js
+++ b/modules/angular2/src/di/injector.js
@@ -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/**/):List {
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/**/, {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, {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, 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/**/):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):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) {
diff --git a/modules/angular2/src/di/key.js b/modules/angular2/src/di/key.js
index 25704081c5..6d2c626b47 100644
--- a/modules/angular2/src/di/key.js
+++ b/modules/angular2/src/di/key.js
@@ -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);
}
}
diff --git a/modules/angular2/src/di/opaque_token.js b/modules/angular2/src/di/opaque_token.js
index 9706bce696..e84f127a86 100644
--- a/modules/angular2/src/di/opaque_token.js
+++ b/modules/angular2/src/di/opaque_token.js
@@ -1,3 +1,8 @@
+/**
+ *
+ *
+ * @exportedAs angular2/di
+ */
export class OpaqueToken {
_desc:string;
diff --git a/modules/angular2/src/directives/switch.js b/modules/angular2/src/directives/switch.js
index dc1ed4544f..22a1d80417 100644
--- a/modules/angular2/src/directives/switch.js
+++ b/modules/angular2/src/directives/switch.js
@@ -178,8 +178,6 @@ export class SwitchWhen {
*
* ```
* ...
- *
- * @exportedAs angular2/directives
* ```
*
* @exportedAs angular2/directives
diff --git a/modules/angular2/src/mock/template_resolver_mock.js b/modules/angular2/src/mock/template_resolver_mock.js
index dd71043f04..3a86598e79 100644
--- a/modules/angular2/src/mock/template_resolver_mock.js
+++ b/modules/angular2/src/mock/template_resolver_mock.js
@@ -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
});
}
diff --git a/modules/angular2/test/di/key_spec.js b/modules/angular2/test/di/key_spec.js
index 1ecf54cad4..62f5cee561 100644
--- a/modules/angular2/test/di/key_spec.js
+++ b/modules/angular2/test/di/key_spec.js
@@ -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();
- });
- });
});
}
\ No newline at end of file