2015-02-05 13:08:05 -08:00
|
|
|
import {ListWrapper, List} from 'angular2/src/facade/collection';
|
|
|
|
import {stringify} from 'angular2/src/facade/lang';
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2014-10-27 13:02:46 -04:00
|
|
|
function findFirstClosedCycle(keys:List) {
|
|
|
|
var res = [];
|
|
|
|
for(var i = 0; i < keys.length; ++i) {
|
|
|
|
if (ListWrapper.contains(res, keys[i])) {
|
|
|
|
ListWrapper.push(res, keys[i]);
|
|
|
|
return res;
|
|
|
|
} else {
|
|
|
|
ListWrapper.push(res, keys[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-10-07 10:34:07 -04:00
|
|
|
function constructResolvingPath(keys:List) {
|
2014-09-30 14:56:33 -04:00
|
|
|
if (keys.length > 1) {
|
2014-10-27 13:02:46 -04:00
|
|
|
var reversed = findFirstClosedCycle(ListWrapper.reversed(keys));
|
2014-10-03 17:26:49 -04:00
|
|
|
var tokenStrs = ListWrapper.map(reversed, (k) => stringify(k.token));
|
2014-09-30 14:56:33 -04:00
|
|
|
return " (" + tokenStrs.join(' -> ') + ")";
|
|
|
|
} else {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-20 15:17:06 -04:00
|
|
|
|
2015-04-15 22:35:38 +00:00
|
|
|
/**
|
2015-04-17 03:29:05 -07:00
|
|
|
* Base class for all errors arising from misconfigured bindings.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
|
|
|
* @exportedAs angular2/di_errors
|
|
|
|
*/
|
2015-04-17 19:18:29 +02:00
|
|
|
export class AbstractBindingError extends Error {
|
2014-11-21 21:19:23 -08:00
|
|
|
keys:List;
|
|
|
|
constructResolvingMessage:Function;
|
|
|
|
message;
|
2015-02-11 10:13:49 -08:00
|
|
|
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
|
|
|
constructor(key, constructResolvingMessage:Function) {
|
2015-02-06 13:38:52 -08:00
|
|
|
super();
|
2014-10-03 17:26:49 -04:00
|
|
|
this.keys = [key];
|
|
|
|
this.constructResolvingMessage = constructResolvingMessage;
|
|
|
|
this.message = this.constructResolvingMessage(this.keys);
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
|
|
|
|
2015-02-11 10:13:49 -08:00
|
|
|
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
|
|
|
addKey(key) {
|
2014-10-03 17:26:49 -04:00
|
|
|
ListWrapper.push(this.keys, key);
|
|
|
|
this.message = this.constructResolvingMessage(this.keys);
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
2014-10-07 09:21:00 -04:00
|
|
|
|
|
|
|
toString() {
|
|
|
|
return this.message;
|
|
|
|
}
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
|
|
|
|
2015-04-15 22:35:38 +00:00
|
|
|
/**
|
2015-04-17 03:29:05 -07:00
|
|
|
* Thrown when trying to retrieve a dependency by [Key] from [Injector], but the [Injector] does not have a [Binding]
|
|
|
|
* for [Key].
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
|
|
|
* @exportedAs angular2/di_errors
|
|
|
|
*/
|
2015-04-17 19:18:29 +02:00
|
|
|
export class NoBindingError extends AbstractBindingError {
|
2015-02-11 10:13:49 -08:00
|
|
|
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
|
|
|
constructor(key) {
|
2014-10-07 10:34:07 -04:00
|
|
|
super(key, function (keys:List) {
|
2014-10-03 17:26:49 -04:00
|
|
|
var first = stringify(ListWrapper.first(keys).token);
|
|
|
|
return `No provider for ${first}!${constructResolvingPath(keys)}`;
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
2014-10-03 17:26:49 -04:00
|
|
|
}
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-04-15 22:35:38 +00:00
|
|
|
/**
|
2015-04-17 03:29:05 -07:00
|
|
|
* Thrown when trying to retrieve an async [Binding] using the sync API.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
|
|
|
* ## 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);
|
|
|
|
* ```
|
|
|
|
*
|
2015-04-17 03:29:05 -07:00
|
|
|
* The above example throws because `String` depends on `Number` which is async. If any binding in the dependency
|
|
|
|
* graph is async then the graph can only be retrieved using the `asyncGet` API.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
|
|
|
* @exportedAs angular2/di_errors
|
|
|
|
*/
|
2015-04-17 19:18:29 +02:00
|
|
|
export class AsyncBindingError extends AbstractBindingError {
|
2015-02-11 10:13:49 -08:00
|
|
|
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
|
|
|
constructor(key) {
|
2014-10-07 10:34:07 -04:00
|
|
|
super(key, function (keys:List) {
|
2014-10-03 17:26:49 -04:00
|
|
|
var first = stringify(ListWrapper.first(keys).token);
|
|
|
|
return `Cannot instantiate ${first} synchronously. ` +
|
2014-10-10 15:44:56 -04:00
|
|
|
`It is provided as a promise!${constructResolvingPath(keys)}`;
|
2014-10-03 17:26:49 -04:00
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-15 22:35:38 +00:00
|
|
|
/**
|
2015-04-17 03:29:05 -07:00
|
|
|
* Thrown when dependencies form a cycle.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
|
|
|
* ## Example:
|
|
|
|
*
|
|
|
|
* ```javascript
|
|
|
|
* class A {
|
|
|
|
* constructor(b:B) {}
|
|
|
|
* }
|
|
|
|
* class B {
|
|
|
|
* constructor(a:A) {}
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
2015-04-17 03:29:05 -07:00
|
|
|
* Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
|
|
|
* @exportedAs angular2/di_errors
|
|
|
|
*/
|
2015-04-17 19:18:29 +02:00
|
|
|
export class CyclicDependencyError extends AbstractBindingError {
|
2015-02-11 10:13:49 -08:00
|
|
|
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
|
|
|
constructor(key) {
|
2014-10-07 10:34:07 -04:00
|
|
|
super(key, function (keys:List) {
|
2014-10-06 10:13:33 -04:00
|
|
|
return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-15 22:35:38 +00:00
|
|
|
/**
|
2015-04-17 03:29:05 -07:00
|
|
|
* Thrown when a constructing type returns with an Error.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
2015-04-17 03:29:05 -07:00
|
|
|
* The `InstantiationError` class contains the original error plus the dependency graph which caused this object to be
|
2015-04-15 22:35:38 +00:00
|
|
|
* instantiated.
|
|
|
|
*
|
|
|
|
* @exportedAs angular2/di_errors
|
|
|
|
*/
|
2015-04-17 19:18:29 +02:00
|
|
|
export class InstantiationError extends AbstractBindingError {
|
2015-02-11 10:13:49 -08:00
|
|
|
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
|
|
|
constructor(originalException, key) {
|
2014-10-07 10:34:07 -04:00
|
|
|
super(key, function (keys:List) {
|
2014-10-06 10:13:33 -04:00
|
|
|
var first = stringify(ListWrapper.first(keys).token);
|
2014-10-07 10:34:07 -04:00
|
|
|
return `Error during instantiation of ${first}!${constructResolvingPath(keys)}.` +
|
2014-10-06 10:13:33 -04:00
|
|
|
` ORIGINAL ERROR: ${originalException}`;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-15 22:35:38 +00:00
|
|
|
/**
|
2015-04-17 03:29:05 -07:00
|
|
|
* Thrown when an object other then [Binding] (or [Type]) is passed to [Injector] creation.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
|
|
|
* @exportedAs angular2/di_errors
|
|
|
|
*/
|
2014-10-07 09:21:00 -04:00
|
|
|
export class InvalidBindingError extends Error {
|
2014-11-21 21:19:23 -08:00
|
|
|
message:string;
|
2014-10-07 10:34:07 -04:00
|
|
|
constructor(binding) {
|
2015-02-06 13:38:52 -08:00
|
|
|
super();
|
2014-09-30 14:56:33 -04:00
|
|
|
this.message = `Invalid binding ${binding}`;
|
|
|
|
}
|
2014-10-07 09:21:00 -04:00
|
|
|
|
|
|
|
toString() {
|
|
|
|
return this.message;
|
|
|
|
}
|
2014-10-05 16:25:42 -04:00
|
|
|
}
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-04-15 22:35:38 +00:00
|
|
|
/**
|
2015-04-17 03:29:05 -07:00
|
|
|
* Thrown when the class has no annotation information.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
2015-04-17 03:29:05 -07:00
|
|
|
* Lack of annotation information prevents the [Injector] from determining which dependencies need to be injected into
|
|
|
|
* the constructor.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
|
|
|
* @exportedAs angular2/di_errors
|
|
|
|
*/
|
2014-10-07 09:21:00 -04:00
|
|
|
export class NoAnnotationError extends Error {
|
2014-11-21 21:19:23 -08:00
|
|
|
message:string;
|
2014-10-09 11:35:13 -04:00
|
|
|
constructor(typeOrFunc) {
|
2015-02-06 13:38:52 -08:00
|
|
|
super();
|
2015-04-13 10:05:11 -07:00
|
|
|
this.message = `Cannot resolve all parameters for ${stringify(typeOrFunc)}.` +
|
|
|
|
` Make sure they all have valid type or annotations.`;
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
2014-10-07 09:21:00 -04:00
|
|
|
|
|
|
|
toString() {
|
|
|
|
return this.message;
|
|
|
|
}
|
2014-10-09 12:09:50 -04:00
|
|
|
}
|