183 lines
5.3 KiB
TypeScript
Raw Normal View History

import {ListWrapper} from 'angular2/src/core/facade/collection';
2015-08-20 14:28:25 -07:00
import {stringify, BaseException, isBlank} from 'angular2/src/core/facade/lang';
import {Key} from './key';
import {Injector} from './injector';
function findFirstClosedCycle(keys: any[]): any[] {
var res = [];
for (var i = 0; i < keys.length; ++i) {
if (ListWrapper.contains(res, keys[i])) {
res.push(keys[i]);
return res;
} else {
res.push(keys[i]);
}
}
return res;
}
function constructResolvingPath(keys: any[]): string {
if (keys.length > 1) {
var reversed = findFirstClosedCycle(ListWrapper.reversed(keys));
var tokenStrs = ListWrapper.map(reversed, (k) => stringify(k.token));
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
*/
export class AbstractBindingError extends BaseException {
name: string;
message: string;
keys: Key[];
injectors: Injector[];
constructResolvingMessage: Function;
constructor(injector: Injector, key: Key, constructResolvingMessage: Function, originalException?,
originalStack?) {
super("DI Exception", originalException, originalStack, null);
this.keys = [key];
this.injectors = [injector];
this.constructResolvingMessage = constructResolvingMessage;
this.message = this.constructResolvingMessage(this.keys);
}
addKey(injector: Injector, key: Key): void {
this.injectors.push(injector);
this.keys.push(key);
this.message = this.constructResolvingMessage(this.keys);
}
2014-10-07 09:21:00 -04:00
get context() { return this.injectors[this.injectors.length - 1].debugContext(); }
toString(): string { return this.message; }
}
2015-04-15 22:35:38 +00: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
*/
export class NoBindingError extends AbstractBindingError {
constructor(injector: Injector, key: Key) {
super(injector, key, function(keys: any[]) {
var first = stringify(ListWrapper.first(keys).token);
return `No provider for ${first}!${constructResolvingPath(keys)}`;
});
}
}
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
*/
export class CyclicDependencyError extends AbstractBindingError {
constructor(injector: Injector, key: Key) {
super(injector, key, function(keys: any[]) {
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
*
* 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
*/
export class InstantiationError extends AbstractBindingError {
causeKey: Key;
constructor(injector: Injector, originalException, originalStack, key: Key) {
super(injector, key, function(keys: any[]) {
var first = stringify(ListWrapper.first(keys).token);
return `Error during instantiation of ${first}!${constructResolvingPath(keys)}.`;
}, originalException, originalStack);
this.causeKey = key;
}
}
2015-04-15 22:35:38 +00: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
*/
export class InvalidBindingError extends BaseException {
message: string;
2014-10-07 10:34:07 -04:00
constructor(binding) {
super();
this.message = "Invalid binding - only instances of Binding and Type are allowed, got: " +
binding.toString();
}
2014-10-07 09:21:00 -04:00
toString(): string { return this.message; }
}
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
*
* 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
*/
export class NoAnnotationError extends BaseException {
name: string;
message: string;
constructor(typeOrFunc, params: any[][]) {
super();
var signature = [];
for (var i = 0, ii = params.length; i < ii; i++) {
var parameter = params[i];
if (isBlank(parameter) || parameter.length == 0) {
signature.push('?');
} else {
signature.push(ListWrapper.map(parameter, stringify).join(' '));
}
}
this.message = "Cannot resolve all parameters for " + stringify(typeOrFunc) + "(" +
signature.join(', ') + "). " +
'Make sure they all have valid type or annotations.';
}
2014-10-07 09:21:00 -04:00
toString(): string { return this.message; }
2014-10-09 12:09:50 -04: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; }
}
/**
* Thrown when a multi binding and a regular binding are bound to the same token.
*/
export class MixingMultiBindingsWithRegularBindings extends BaseException {
message: string;
constructor(binding1, binding2) {
super();
this.message = "Cannot mix multi bindings and regular bindings, got: " + binding1.toString() +
" " + binding2.toString();
}
toString(): string { return this.message; }
}