2015-02-05 13:08:05 -08:00
|
|
|
import {ListWrapper, List} from 'angular2/src/facade/collection';
|
2015-05-18 17:19:54 -07:00
|
|
|
import {stringify, BaseException, isBlank} from 'angular2/src/facade/lang';
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-04-24 15:19:11 -07:00
|
|
|
function findFirstClosedCycle(keys: List<any>): List<any> {
|
2014-10-27 13:02:46 -04:00
|
|
|
var res = [];
|
2015-04-24 15:19:11 -07:00
|
|
|
for (var i = 0; i < keys.length; ++i) {
|
2014-10-27 13:02:46 -04:00
|
|
|
if (ListWrapper.contains(res, keys[i])) {
|
2015-06-17 11:17:21 -07:00
|
|
|
res.push(keys[i]);
|
2014-10-27 13:02:46 -04:00
|
|
|
return res;
|
|
|
|
} else {
|
2015-06-17 11:17:21 -07:00
|
|
|
res.push(keys[i]);
|
2014-10-27 13:02:46 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2015-04-24 15:19:11 -07:00
|
|
|
function constructResolvingPath(keys: List<any>): string {
|
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
|
|
|
*/
|
2015-04-24 15:19:11 -07:00
|
|
|
export class AbstractBindingError extends BaseException {
|
|
|
|
name: string;
|
|
|
|
message: string;
|
|
|
|
keys: List<any>;
|
|
|
|
constructResolvingMessage: Function;
|
2015-02-11 10:13:49 -08:00
|
|
|
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
2015-06-27 20:01:05 -07:00
|
|
|
constructor(key, constructResolvingMessage: Function, originalException?, originalStack?) {
|
|
|
|
super(null, originalException, originalStack);
|
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!
|
2015-07-07 20:03:00 -07:00
|
|
|
addKey(key: any): void {
|
2015-06-17 11:17:21 -07:00
|
|
|
this.keys.push(key);
|
2014-10-03 17:26:49 -04:00
|
|
|
this.message = this.constructResolvingMessage(this.keys);
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
2014-10-07 09:21:00 -04:00
|
|
|
|
2015-04-24 15:19:11 -07:00
|
|
|
toString(): string { return this.message; }
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
|
|
|
|
2015-04-15 22:35:38 +00:00
|
|
|
/**
|
2015-04-24 15:19:11 -07:00
|
|
|
* Thrown when trying to retrieve a dependency by `Key` from {@link Injector}, but the
|
|
|
|
* {@link Injector} does not have a {@link Binding} for {@link Key}.
|
2015-04-15 22:35:38 +00:00
|
|
|
*/
|
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) {
|
2015-05-21 16:42:19 +02:00
|
|
|
super(key, function(keys: List<any>) {
|
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 13:01:07 -07:00
|
|
|
* Thrown when trying to retrieve an async {@link 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-24 15:19:11 -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
|
|
|
*/
|
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) {
|
2015-05-21 16:42:19 +02:00
|
|
|
super(key, function(keys: List<any>) {
|
2014-10-03 17:26:49 -04:00
|
|
|
var first = stringify(ListWrapper.first(keys).token);
|
2015-04-24 15:19:11 -07:00
|
|
|
return `Cannot instantiate ${first} synchronously. 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
|
|
|
*/
|
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) {
|
2015-05-21 16:42:19 +02:00
|
|
|
super(key, function(keys: List<any>) {
|
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-24 15:19:11 -07:00
|
|
|
* The `InstantiationError` class contains the original error plus the dependency graph which caused
|
|
|
|
* this object to be instantiated.
|
2015-04-15 22:35:38 +00:00
|
|
|
*/
|
2015-04-17 19:18:29 +02:00
|
|
|
export class InstantiationError extends AbstractBindingError {
|
2015-04-20 15:35:16 +02:00
|
|
|
causeKey;
|
2015-06-17 10:12:06 +02:00
|
|
|
|
2015-02-11 10:13:49 -08:00
|
|
|
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
2015-06-27 20:01:05 -07:00
|
|
|
constructor(originalException, originalStack, key) {
|
2015-05-21 16:42:19 +02:00
|
|
|
super(key, function(keys: List<any>) {
|
2014-10-06 10:13:33 -04:00
|
|
|
var first = stringify(ListWrapper.first(keys).token);
|
2015-06-27 20:01:05 -07:00
|
|
|
return `Error during instantiation of ${first}!${constructResolvingPath(keys)}.` +
|
2015-07-10 11:29:41 +02:00
|
|
|
` ORIGINAL ERROR: ${originalException}` + `\n\n ORIGINAL STACK: ${originalStack}`;
|
2015-06-27 20:01:05 -07:00
|
|
|
}, originalException, originalStack);
|
|
|
|
|
2015-04-20 15:35:16 +02:00
|
|
|
this.causeKey = key;
|
2014-10-06 10:13:33 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-15 22:35:38 +00:00
|
|
|
/**
|
2015-04-24 15:19:11 -07:00
|
|
|
* Thrown when an object other then {@link Binding} (or `Type`) is passed to {@link Injector}
|
|
|
|
* creation.
|
2015-04-15 22:35:38 +00:00
|
|
|
*/
|
2015-04-24 15:19:11 -07:00
|
|
|
export class InvalidBindingError extends BaseException {
|
|
|
|
message: string;
|
2014-10-07 10:34:07 -04:00
|
|
|
constructor(binding) {
|
2015-02-06 13:38:52 -08:00
|
|
|
super();
|
2015-04-24 15:19:11 -07:00
|
|
|
this.message = "Invalid binding - only instances of Binding and Type are allowed, got: " +
|
|
|
|
binding.toString();
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
2014-10-07 09:21:00 -04:00
|
|
|
|
2015-04-24 15:19:11 -07:00
|
|
|
toString(): string { 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-24 15:19:11 -07:00
|
|
|
* Lack of annotation information prevents the {@link Injector} from determining which dependencies
|
|
|
|
* need to be injected into the constructor.
|
2015-04-15 22:35:38 +00:00
|
|
|
*/
|
2015-04-24 15:19:11 -07:00
|
|
|
export class NoAnnotationError extends BaseException {
|
|
|
|
name: string;
|
|
|
|
message: string;
|
2015-05-18 17:19:54 -07:00
|
|
|
constructor(typeOrFunc, params: List<List<any>>) {
|
2015-02-06 13:38:52 -08:00
|
|
|
super();
|
2015-06-17 11:17:21 -07:00
|
|
|
var signature = [];
|
2015-05-18 17:19:54 -07:00
|
|
|
for (var i = 0, ii = params.length; i < ii; i++) {
|
|
|
|
var parameter = params[i];
|
|
|
|
if (isBlank(parameter) || parameter.length == 0) {
|
2015-06-17 11:17:21 -07:00
|
|
|
signature.push('?');
|
2015-05-18 17:19:54 -07:00
|
|
|
} else {
|
2015-06-17 11:17:21 -07:00
|
|
|
signature.push(ListWrapper.map(parameter, stringify).join(' '));
|
2015-05-18 17:19:54 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
this.message = "Cannot resolve all parameters for " + stringify(typeOrFunc) + "(" +
|
|
|
|
signature.join(', ') + "). " +
|
2015-04-24 15:19:11 -07:00
|
|
|
'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
|
|
|
|
2015-04-24 15:19:11 -07:00
|
|
|
toString(): string { return this.message; }
|
2014-10-09 12:09:50 -04:00
|
|
|
}
|
2015-06-26 15:59:18 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Thrown when getting an object by index.
|
|
|
|
*/
|
|
|
|
export class OutOfBoundsError extends BaseException {
|
|
|
|
message: string;
|
|
|
|
constructor(index) {
|
|
|
|
super();
|
|
|
|
this.message = `Index ${index} is out-of-bounds.`;
|
|
|
|
}
|
|
|
|
|
|
|
|
toString(): string { return this.message; }
|
|
|
|
}
|