chore(build): migrated di to TypeScript
This commit is contained in:
parent
649e276610
commit
cb87fa0970
|
@ -10,6 +10,18 @@ export * from './src/di/decorators';
|
|||
export {Injector} from './src/di/injector';
|
||||
export {Binding, ResolvedBinding, Dependency, bind} from './src/di/binding';
|
||||
export {Key, KeyRegistry} from './src/di/key';
|
||||
export {KeyMetadataError, NoBindingError, AbstractBindingError, AsyncBindingError, CyclicDependencyError,
|
||||
InstantiationError, InvalidBindingError, NoAnnotationError} from './src/di/exceptions';
|
||||
export {
|
||||
NoBindingError,
|
||||
AbstractBindingError,
|
||||
AsyncBindingError,
|
||||
CyclicDependencyError,
|
||||
InstantiationError,
|
||||
InvalidBindingError,
|
||||
NoAnnotationError
|
||||
} from './src/di/exceptions';
|
||||
export {OpaqueToken} from './src/di/opaque_token';
|
||||
|
||||
// HACK: workaround for Traceur behavior.
|
||||
// It expects all transpiled modules to contain this marker.
|
||||
// TODO: remove this when we no longer use traceur
|
||||
export var __esModule = true;
|
|
@ -1,6 +1,7 @@
|
|||
import {ProtoRecord} from './proto_record';
|
||||
import {BaseException} from "angular2/src/facade/lang";
|
||||
|
||||
export class ExpressionChangedAfterItHasBeenChecked extends Error {
|
||||
export class ExpressionChangedAfterItHasBeenChecked extends BaseException {
|
||||
message:string;
|
||||
|
||||
constructor(proto:ProtoRecord, change:any) {
|
||||
|
@ -14,7 +15,7 @@ export class ExpressionChangedAfterItHasBeenChecked extends Error {
|
|||
}
|
||||
}
|
||||
|
||||
export class ChangeDetectionError extends Error {
|
||||
export class ChangeDetectionError extends BaseException {
|
||||
message:string;
|
||||
originalException:any;
|
||||
location:string;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {Injectable} from 'angular2/src/di/annotations_impl';
|
||||
import {List, ListWrapper, SetWrapper} from "angular2/src/facade/collection";
|
||||
import {int, NumberWrapper, StringJoiner, StringWrapper} from "angular2/src/facade/lang";
|
||||
import {int, NumberWrapper, StringJoiner, StringWrapper, BaseException} from "angular2/src/facade/lang";
|
||||
|
||||
export const TOKEN_TYPE_CHARACTER = 1;
|
||||
export const TOKEN_TYPE_IDENTIFIER = 2;
|
||||
|
@ -176,7 +176,7 @@ export const $RBRACE = 125;
|
|||
const $NBSP = 160;
|
||||
|
||||
|
||||
export class ScannerError extends Error {
|
||||
export class ScannerError extends BaseException {
|
||||
message:string;
|
||||
constructor(message) {
|
||||
super();
|
||||
|
|
|
@ -966,7 +966,7 @@ export class ElementInjector extends TreeNode {
|
|||
}
|
||||
}
|
||||
|
||||
class OutOfBoundsAccess extends Error {
|
||||
class OutOfBoundsAccess extends BaseException {
|
||||
message:string;
|
||||
constructor(index) {
|
||||
super();
|
||||
|
@ -978,7 +978,7 @@ class OutOfBoundsAccess extends Error {
|
|||
}
|
||||
}
|
||||
|
||||
class QueryError extends Error {
|
||||
class QueryError extends BaseException {
|
||||
message:string;
|
||||
// TODO(rado): pass the names of the active directives.
|
||||
constructor() {
|
||||
|
|
|
@ -10,4 +10,4 @@ export {
|
|||
Optional as OptionalAnnotation,
|
||||
Injectable as InjectableAnnotation,
|
||||
DependencyAnnotation, // abstract base class, does not need a decorator
|
||||
} from './annotations_impl';
|
||||
} from './annotations_impl';
|
|
@ -1,5 +1,10 @@
|
|||
import {CONST} from "angular2/src/facade/lang";
|
||||
|
||||
// HACK: workaround for Traceur behavior.
|
||||
// It expects all transpiled modules to contain this marker.
|
||||
// TODO: remove this when we no longer use traceur
|
||||
export var __esModule = true;
|
||||
|
||||
/**
|
||||
* A parameter annotation that specifies a dependency.
|
||||
*
|
||||
|
@ -11,12 +16,10 @@ import {CONST} from "angular2/src/facade/lang";
|
|||
*
|
||||
* @exportedAs angular2/di_annotations
|
||||
*/
|
||||
|
||||
@CONST()
|
||||
export class Inject {
|
||||
token;
|
||||
@CONST()
|
||||
constructor(token) {
|
||||
this.token = token;
|
||||
}
|
||||
constructor(public token) {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,12 +35,9 @@ export class Inject {
|
|||
*
|
||||
* @exportedAs angular2/di_annotations
|
||||
*/
|
||||
@CONST()
|
||||
export class InjectPromise {
|
||||
token;
|
||||
@CONST()
|
||||
constructor(token) {
|
||||
this.token = token;
|
||||
}
|
||||
constructor(public token) {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,17 +53,14 @@ export class InjectPromise {
|
|||
*
|
||||
* @exportedAs angular2/di_annotations
|
||||
*/
|
||||
@CONST()
|
||||
export class InjectLazy {
|
||||
token;
|
||||
@CONST()
|
||||
constructor(token) {
|
||||
this.token = token;
|
||||
}
|
||||
constructor(public token) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameter annotation that marks a dependency as optional. {@link Injector} provides `null` if the dependency is not
|
||||
* found.
|
||||
* A parameter annotation that marks a dependency as optional. {@link Injector} provides `null` if
|
||||
* the dependency is not found.
|
||||
*
|
||||
* ```
|
||||
* class AComponent {
|
||||
|
@ -75,16 +72,15 @@ export class InjectLazy {
|
|||
*
|
||||
* @exportedAs angular2/di_annotations
|
||||
*/
|
||||
@CONST()
|
||||
export class Optional {
|
||||
@CONST()
|
||||
constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `DependencyAnnotation` is used by the framework to extend DI.
|
||||
*
|
||||
* Only annotations implementing `DependencyAnnotation` are added to the list of dependency properties.
|
||||
* Only annotations implementing `DependencyAnnotation` are added to the list of dependency
|
||||
* properties.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
|
@ -108,19 +104,14 @@ export class Optional {
|
|||
*
|
||||
* @exportedAs angular2/di_annotations
|
||||
*/
|
||||
@CONST()
|
||||
export class DependencyAnnotation {
|
||||
@CONST()
|
||||
constructor() {
|
||||
}
|
||||
|
||||
get token() {
|
||||
return null;
|
||||
}
|
||||
get token() { return null; }
|
||||
}
|
||||
|
||||
/**
|
||||
* A marker annotation that marks a class as available to `Injector` for creation. Used by tooling for
|
||||
* generating constructor stubs.
|
||||
* A marker annotation that marks a class as available to `Injector` for creation. Used by tooling
|
||||
* for generating constructor stubs.
|
||||
*
|
||||
* ```
|
||||
* class NeedsService {
|
||||
|
@ -132,8 +123,6 @@ export class DependencyAnnotation {
|
|||
* ```
|
||||
* @exportedAs angular2/di_annotations
|
||||
*/
|
||||
@CONST()
|
||||
export class Injectable {
|
||||
@CONST()
|
||||
constructor() {
|
||||
}
|
||||
}
|
|
@ -2,20 +2,21 @@ import {Type, isBlank, isPresent, CONST} from 'angular2/src/facade/lang';
|
|||
import {List, MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {reflector} from 'angular2/src/reflection/reflection';
|
||||
import {Key} from './key';
|
||||
import {Inject, InjectLazy, InjectPromise, Optional, DependencyAnnotation} from './annotations_impl';
|
||||
import {
|
||||
Inject,
|
||||
InjectLazy,
|
||||
InjectPromise,
|
||||
Optional,
|
||||
DependencyAnnotation
|
||||
} from './annotations_impl';
|
||||
import {NoAnnotationError} from './exceptions';
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export class Dependency {
|
||||
key:Key;
|
||||
asPromise:boolean;
|
||||
lazy:boolean;
|
||||
optional:boolean;
|
||||
properties:List;
|
||||
|
||||
constructor(key:Key, asPromise:boolean, lazy:boolean, optional:boolean, properties:List) {
|
||||
constructor(public key: Key, public asPromise: boolean, public lazy: boolean,
|
||||
public optional: boolean, public properties: List<any>) {
|
||||
this.key = key;
|
||||
this.asPromise = asPromise;
|
||||
this.lazy = lazy;
|
||||
|
@ -23,9 +24,7 @@ export class Dependency {
|
|||
this.properties = properties;
|
||||
}
|
||||
|
||||
static fromKey(key:Key) {
|
||||
return new Dependency(key, false, false, false, []);
|
||||
}
|
||||
static fromKey(key: Key) { return new Dependency(key, false, false, false, []); }
|
||||
}
|
||||
|
||||
var _EMPTY_LIST = []; // TODO: make const when supported
|
||||
|
@ -47,8 +46,8 @@ var _EMPTY_LIST = []; // TODO: make const when supported
|
|||
*
|
||||
* @exportedAs angular2/di
|
||||
*/
|
||||
@CONST()
|
||||
export class Binding {
|
||||
|
||||
/**
|
||||
* Token used when retrieving this binding. Usually the `Type`.
|
||||
*/
|
||||
|
@ -59,7 +58,8 @@ export class Binding {
|
|||
*
|
||||
* ## Example
|
||||
*
|
||||
* Becuse `toAlias` and `toClass` are often confused, the example contains both use cases for easy comparison.
|
||||
* Becuse `toAlias` and `toClass` are often confused, the example contains both use cases for easy
|
||||
* comparison.
|
||||
*
|
||||
* ```javascript
|
||||
*
|
||||
|
@ -83,7 +83,7 @@ export class Binding {
|
|||
* expect(injectorAlias.get(Vehicle) instanceof Car).toBe(true);
|
||||
* ```
|
||||
*/
|
||||
toClass:Type;
|
||||
toClass: Type;
|
||||
|
||||
/**
|
||||
* Binds a key to a value.
|
||||
|
@ -103,12 +103,13 @@ export class Binding {
|
|||
/**
|
||||
* Binds a key to the alias for an existing key.
|
||||
*
|
||||
* An alias means that {@link Injector} returns the same instance as if the alias token was used. This is in contrast to
|
||||
* `toClass` where a separate instance of `toClass` is returned.
|
||||
* An alias means that {@link Injector} returns the same instance as if the alias token was used.
|
||||
* This is in contrast to `toClass` where a separate instance of `toClass` is returned.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* Becuse `toAlias` and `toClass` are often confused the example contains both use cases for easy comparison.
|
||||
* Becuse `toAlias` and `toClass` are often confused the example contains both use cases for easy
|
||||
* comparison.
|
||||
*
|
||||
* ```javascript
|
||||
*
|
||||
|
@ -150,7 +151,7 @@ export class Binding {
|
|||
* expect(injector.get(String)).toEqual('Value: 3');
|
||||
* ```
|
||||
*/
|
||||
toFactory:Function;
|
||||
toFactory: Function;
|
||||
|
||||
/**
|
||||
* Binds a key to a function which computes the value asynchronously.
|
||||
|
@ -170,17 +171,19 @@ export class Binding {
|
|||
* injector.asyncGet(String).then((v) => expect(v).toBe('Value: 3'));
|
||||
* ```
|
||||
*
|
||||
* The interesting thing to note is that event though `Number` has an async factory, the `String` factory
|
||||
* function takes the resolved value. This shows that the {@link Injector} delays executing the `String` factory
|
||||
* until after the `Number` is resolved. This can only be done if the `token` is retrieved using the
|
||||
* `asyncGet` API in the {@link Injector}.
|
||||
* The interesting thing to note is that event though `Number` has an async factory, the `String`
|
||||
* factory function takes the resolved value. This shows that the {@link Injector} delays
|
||||
*executing the
|
||||
*`String` factory
|
||||
* until after the `Number` is resolved. This can only be done if the `token` is retrieved using
|
||||
* the `asyncGet` API in the {@link Injector}.
|
||||
*
|
||||
*/
|
||||
toAsyncFactory:Function;
|
||||
toAsyncFactory: Function;
|
||||
|
||||
/**
|
||||
* Used in conjunction with `toFactory` or `toAsyncFactory` and specifies a set of dependencies (as `token`s) which
|
||||
* should be injected into the factory function.
|
||||
* Used in conjunction with `toFactory` or `toAsyncFactory` and specifies a set of dependencies
|
||||
* (as `token`s) which should be injected into the factory function.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
|
@ -195,19 +198,11 @@ export class Binding {
|
|||
* expect(injector.get(String)).toEqual('Value: 3');
|
||||
* ```
|
||||
*/
|
||||
dependencies:List;
|
||||
dependencies: List<any>;
|
||||
|
||||
@CONST()
|
||||
constructor(
|
||||
token,
|
||||
{
|
||||
toClass,
|
||||
toValue,
|
||||
toAlias,
|
||||
toFactory,
|
||||
toAsyncFactory,
|
||||
deps
|
||||
}) {
|
||||
constructor(token, {toClass, toValue, toAlias, toFactory, toAsyncFactory, deps}: {
|
||||
toClass ?: Type, toValue ?: any, toAlias ?: any, toFactory ?: Function,
|
||||
toAsyncFactory ?: Function, deps ?: List<any>}) {
|
||||
this.token = token;
|
||||
this.toClass = toClass;
|
||||
this.toValue = toValue;
|
||||
|
@ -220,10 +215,11 @@ export class Binding {
|
|||
/**
|
||||
* Converts the {@link Binding} into {@link ResolvedBinding}.
|
||||
*
|
||||
* {@link Injector} internally only uses {@link ResolvedBinding}, {@link Binding} contains convenience binding syntax.
|
||||
* {@link Injector} internally only uses {@link ResolvedBinding}, {@link Binding} contains
|
||||
* convenience binding syntax.
|
||||
*/
|
||||
resolve(): ResolvedBinding {
|
||||
var factoryFn:Function;
|
||||
var factoryFn: Function;
|
||||
var resolvedDeps;
|
||||
var isAsync = false;
|
||||
if (isPresent(this.toClass)) {
|
||||
|
@ -244,20 +240,16 @@ export class Binding {
|
|||
resolvedDeps = _EMPTY_LIST;
|
||||
}
|
||||
|
||||
return new ResolvedBinding(
|
||||
Key.get(this.token),
|
||||
factoryFn,
|
||||
resolvedDeps,
|
||||
isAsync
|
||||
);
|
||||
return new ResolvedBinding(Key.get(this.token), factoryFn, resolvedDeps, isAsync);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal resolved representation of a {@link Binding} used by the {@link Injector}.
|
||||
*
|
||||
* A {@link Binding} is resolved when it has a factory function. Binding to a class, alias, or value, are just convenience
|
||||
* methods, as {@link Injector} only operates on calling factory functions.
|
||||
* A {@link Binding} is resolved when it has a factory function. Binding to a class, alias, or
|
||||
* value, are just convenience methods, as {@link Injector} only operates on calling factory
|
||||
* functions.
|
||||
*
|
||||
* @exportedAs angular2/di
|
||||
*/
|
||||
|
@ -265,24 +257,25 @@ export class ResolvedBinding {
|
|||
/**
|
||||
* A key, usually a `Type`.
|
||||
*/
|
||||
key:Key;
|
||||
key: Key;
|
||||
|
||||
/**
|
||||
* Factory function which can return an instance of an object represented by a key.
|
||||
*/
|
||||
factory:Function;
|
||||
factory: Function;
|
||||
|
||||
/**
|
||||
* Arguments (dependencies) to the `factory` function.
|
||||
*/
|
||||
dependencies:List<Dependency>;
|
||||
dependencies: List<Dependency>;
|
||||
|
||||
/**
|
||||
* Specifies whether the `factory` function returns a `Promise`.
|
||||
*/
|
||||
providedAsPromise:boolean;
|
||||
providedAsPromise: boolean;
|
||||
|
||||
constructor(key:Key, factory:Function, dependencies:List<Dependency>, providedAsPromise:boolean) {
|
||||
constructor(key: Key, factory: Function, dependencies: List<Dependency>,
|
||||
providedAsPromise: boolean) {
|
||||
this.key = key;
|
||||
this.factory = factory;
|
||||
this.dependencies = dependencies;
|
||||
|
@ -304,7 +297,7 @@ export class ResolvedBinding {
|
|||
*
|
||||
* @exportedAs angular2/di
|
||||
*/
|
||||
export function bind(token):BindingBuilder {
|
||||
export function bind(token): BindingBuilder {
|
||||
return new BindingBuilder(token);
|
||||
}
|
||||
|
||||
|
@ -316,16 +309,15 @@ export function bind(token):BindingBuilder {
|
|||
export class BindingBuilder {
|
||||
token;
|
||||
|
||||
constructor(token) {
|
||||
this.token = token;
|
||||
}
|
||||
constructor(token) { this.token = token; }
|
||||
|
||||
/**
|
||||
* Binds an interface to an implementation / subclass.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* Because `toAlias` and `toClass` are often confused, the example contains both use cases for easy comparison.
|
||||
* Because `toAlias` and `toClass` are often confused, the example contains both use cases for
|
||||
* easy comparison.
|
||||
*
|
||||
* ```javascript
|
||||
*
|
||||
|
@ -349,9 +341,7 @@ export class BindingBuilder {
|
|||
* expect(injectorAlias.get(Vehicle) instanceof Car).toBe(true);
|
||||
* ```
|
||||
*/
|
||||
toClass(type:Type):Binding {
|
||||
return new Binding(this.token, {toClass: type});
|
||||
}
|
||||
toClass(type: Type): Binding { return new Binding(this.token, {toClass: type}); }
|
||||
|
||||
/**
|
||||
* Binds a key to a value.
|
||||
|
@ -366,19 +356,18 @@ export class BindingBuilder {
|
|||
* expect(injector.get(String)).toEqual('Hello');
|
||||
* ```
|
||||
*/
|
||||
toValue(value):Binding {
|
||||
return new Binding(this.token, {toValue: value});
|
||||
}
|
||||
toValue(value): Binding { return new Binding(this.token, {toValue: value}); }
|
||||
|
||||
/**
|
||||
* Binds a key to the alias for 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.)
|
||||
* 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.
|
||||
* Becuse `toAlias` and `toClass` are often confused, the example contains both use cases for easy
|
||||
* comparison.
|
||||
*
|
||||
* ```javascript
|
||||
*
|
||||
|
@ -402,9 +391,7 @@ export class BindingBuilder {
|
|||
* expect(injectorClass.get(Vehicle) instanceof Car).toBe(true);
|
||||
* ```
|
||||
*/
|
||||
toAlias(aliasToken):Binding {
|
||||
return new Binding(this.token, {toAlias: aliasToken});
|
||||
}
|
||||
toAlias(aliasToken): Binding { return new Binding(this.token, {toAlias: aliasToken}); }
|
||||
|
||||
/**
|
||||
* Binds a key to a function which computes the value.
|
||||
|
@ -421,11 +408,8 @@ export class BindingBuilder {
|
|||
* expect(injector.get(String)).toEqual('Value: 3');
|
||||
* ```
|
||||
*/
|
||||
toFactory(factoryFunction:Function, dependencies:List = null):Binding {
|
||||
return new Binding(this.token, {
|
||||
toFactory: factoryFunction,
|
||||
deps: dependencies
|
||||
});
|
||||
toFactory(factoryFunction: Function, dependencies?: List<any>): Binding {
|
||||
return new Binding(this.token, {toFactory: factoryFunction, deps: dependencies});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -445,26 +429,24 @@ export class BindingBuilder {
|
|||
* injector.asyncGet(String).then((v) => expect(v).toBe('Value: 3'));
|
||||
* ```
|
||||
*
|
||||
* The interesting thing to note is that event though `Number` has an async factory, the `String` factory
|
||||
* function takes the resolved value. This shows that the {@link Injector} delays executing of the `String` factory
|
||||
* until after the `Number` is resolved. This can only be done if the `token` is retrieved using the
|
||||
* The interesting thing to note is that event though `Number` has an async factory, the `String`
|
||||
* factory function takes the resolved value. This shows that the {@link Injector} delays
|
||||
* executing of the `String` factory
|
||||
* until after the `Number` is resolved. This can only be done if the `token` is retrieved using
|
||||
* the `asyncGet` API in the {@link Injector}.
|
||||
*/
|
||||
toAsyncFactory(factoryFunction:Function, dependencies:List = null):Binding {
|
||||
return new Binding(this.token, {
|
||||
toAsyncFactory: factoryFunction,
|
||||
deps: dependencies
|
||||
});
|
||||
toAsyncFactory(factoryFunction: Function, dependencies?: List<any>): Binding {
|
||||
return new Binding(this.token, {toAsyncFactory: factoryFunction, deps: dependencies});
|
||||
}
|
||||
}
|
||||
|
||||
function _constructDependencies(factoryFunction:Function, dependencies:List) {
|
||||
function _constructDependencies(factoryFunction: Function, dependencies: List<any>) {
|
||||
return isBlank(dependencies) ?
|
||||
_dependenciesFor(factoryFunction) :
|
||||
ListWrapper.map(dependencies, (t) => Dependency.fromKey(Key.get(t)));
|
||||
_dependenciesFor(factoryFunction) :
|
||||
ListWrapper.map(dependencies, (t) => Dependency.fromKey(Key.get(t)));
|
||||
}
|
||||
|
||||
function _dependenciesFor(typeOrFunc):List {
|
||||
function _dependenciesFor(typeOrFunc): List<any> {
|
||||
var params = reflector.parameters(typeOrFunc);
|
||||
if (isBlank(params)) return [];
|
||||
if (ListWrapper.any(params, (p) => isBlank(p))) throw new NoAnnotationError(typeOrFunc);
|
||||
|
@ -500,10 +482,9 @@ function _extractToken(typeOrFunc, annotations) {
|
|||
|
||||
} else if (paramAnnotation instanceof DependencyAnnotation) {
|
||||
if (isPresent(paramAnnotation.token)) {
|
||||
token = paramAnnotation.token;
|
||||
token = paramAnnotation.token;
|
||||
}
|
||||
ListWrapper.push(depProps, paramAnnotation);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -514,6 +495,6 @@ function _extractToken(typeOrFunc, annotations) {
|
|||
}
|
||||
}
|
||||
|
||||
function _createDependency(token, asPromise, lazy, optional, depProps):Dependency {
|
||||
function _createDependency(token, asPromise, lazy, optional, depProps): Dependency {
|
||||
return new Dependency(Key.get(token), asPromise, lazy, optional, depProps);
|
||||
}
|
|
@ -3,7 +3,8 @@ import {
|
|||
InjectPromiseAnnotation,
|
||||
InjectLazyAnnotation,
|
||||
OptionalAnnotation,
|
||||
InjectableAnnotation} from './annotations';
|
||||
InjectableAnnotation
|
||||
} from './annotations';
|
||||
import {makeDecorator, makeParamDecorator} from '../util/decorators';
|
||||
|
||||
export var Inject = makeParamDecorator(InjectAnnotation);
|
|
@ -1,9 +1,9 @@
|
|||
import {ListWrapper, List} from 'angular2/src/facade/collection';
|
||||
import {stringify} from 'angular2/src/facade/lang';
|
||||
import {stringify, BaseException} from 'angular2/src/facade/lang';
|
||||
|
||||
function findFirstClosedCycle(keys:List):List {
|
||||
function findFirstClosedCycle(keys: List<any>): List<any> {
|
||||
var res = [];
|
||||
for(var i = 0; i < keys.length; ++i) {
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
if (ListWrapper.contains(res, keys[i])) {
|
||||
ListWrapper.push(res, keys[i]);
|
||||
return res;
|
||||
|
@ -14,7 +14,7 @@ function findFirstClosedCycle(keys:List):List {
|
|||
return res;
|
||||
}
|
||||
|
||||
function constructResolvingPath(keys:List):string {
|
||||
function constructResolvingPath(keys: List<any>): string {
|
||||
if (keys.length > 1) {
|
||||
var reversed = findFirstClosedCycle(ListWrapper.reversed(keys));
|
||||
var tokenStrs = ListWrapper.map(reversed, (k) => stringify(k.token));
|
||||
|
@ -30,12 +30,13 @@ function constructResolvingPath(keys:List):string {
|
|||
*
|
||||
* @exportedAs angular2/di_errors
|
||||
*/
|
||||
export class AbstractBindingError extends Error {
|
||||
keys:List;
|
||||
constructResolvingMessage:Function;
|
||||
message;
|
||||
export class AbstractBindingError extends BaseException {
|
||||
name: string;
|
||||
message: string;
|
||||
keys: List<any>;
|
||||
constructResolvingMessage: Function;
|
||||
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
||||
constructor(key, constructResolvingMessage:Function) {
|
||||
constructor(key, constructResolvingMessage: Function) {
|
||||
super();
|
||||
this.keys = [key];
|
||||
this.constructResolvingMessage = constructResolvingMessage;
|
||||
|
@ -43,26 +44,24 @@ export class AbstractBindingError extends Error {
|
|||
}
|
||||
|
||||
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
||||
addKey(key):void {
|
||||
addKey(key): void {
|
||||
ListWrapper.push(this.keys, key);
|
||||
this.message = this.constructResolvingMessage(this.keys);
|
||||
}
|
||||
|
||||
toString():string {
|
||||
return this.message;
|
||||
}
|
||||
toString(): string { return this.message; }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
* 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}.
|
||||
*
|
||||
* @exportedAs angular2/di_errors
|
||||
*/
|
||||
export class NoBindingError extends AbstractBindingError {
|
||||
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
||||
constructor(key) {
|
||||
super(key, function (keys:List) {
|
||||
super(key, function (keys:List<any>) {
|
||||
var first = stringify(ListWrapper.first(keys).token);
|
||||
return `No provider for ${first}!${constructResolvingPath(keys)}`;
|
||||
});
|
||||
|
@ -88,18 +87,17 @@ export class NoBindingError extends AbstractBindingError {
|
|||
* }).toThrowError(AsycBindingError);
|
||||
* ```
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* @exportedAs angular2/di_errors
|
||||
*/
|
||||
export class AsyncBindingError extends AbstractBindingError {
|
||||
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
||||
constructor(key) {
|
||||
super(key, function (keys:List) {
|
||||
super(key, function (keys:List<any>) {
|
||||
var first = stringify(ListWrapper.first(keys).token);
|
||||
return `Cannot instantiate ${first} synchronously. ` +
|
||||
`It is provided as a promise!${constructResolvingPath(keys)}`;
|
||||
return `Cannot instantiate ${first} synchronously. It is provided as a promise!${constructResolvingPath(keys)}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +123,7 @@ export class AsyncBindingError extends AbstractBindingError {
|
|||
export class CyclicDependencyError extends AbstractBindingError {
|
||||
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
||||
constructor(key) {
|
||||
super(key, function (keys:List) {
|
||||
super(key, function (keys:List<any>) {
|
||||
return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
|
||||
});
|
||||
}
|
||||
|
@ -134,8 +132,8 @@ export class CyclicDependencyError extends AbstractBindingError {
|
|||
/**
|
||||
* Thrown when a constructing type returns with an Error.
|
||||
*
|
||||
* The `InstantiationError` class contains the original error plus the dependency graph which caused this object to be
|
||||
* instantiated.
|
||||
* The `InstantiationError` class contains the original error plus the dependency graph which caused
|
||||
* this object to be instantiated.
|
||||
*
|
||||
* @exportedAs angular2/di_errors
|
||||
*/
|
||||
|
@ -144,10 +142,9 @@ export class InstantiationError extends AbstractBindingError {
|
|||
causeKey;
|
||||
// TODO(tbosch): Can't do key:Key as this results in a circular dependency!
|
||||
constructor(cause, key) {
|
||||
super(key, function (keys:List) {
|
||||
super(key, function (keys:List<any>) {
|
||||
var first = stringify(ListWrapper.first(keys).token);
|
||||
return `Error during instantiation of ${first}!${constructResolvingPath(keys)}.` +
|
||||
` ORIGINAL ERROR: ${cause}`;
|
||||
return `Error during instantiation of ${first}!${constructResolvingPath(keys)}. ORIGINAL ERROR: ${cause}`;
|
||||
});
|
||||
this.cause = cause;
|
||||
this.causeKey = key;
|
||||
|
@ -155,39 +152,38 @@ export class InstantiationError extends AbstractBindingError {
|
|||
}
|
||||
|
||||
/**
|
||||
* Thrown when an object other then {@link Binding} (or `Type`) is passed to {@link Injector} creation.
|
||||
* Thrown when an object other then {@link Binding} (or `Type`) is passed to {@link Injector}
|
||||
* creation.
|
||||
*
|
||||
* @exportedAs angular2/di_errors
|
||||
*/
|
||||
export class InvalidBindingError extends Error {
|
||||
message:string;
|
||||
export class InvalidBindingError extends BaseException {
|
||||
message: string;
|
||||
constructor(binding) {
|
||||
super();
|
||||
this.message = `Invalid binding - only instances of Binding and Type are allowed, got: ${binding}`;
|
||||
this.message = "Invalid binding - only instances of Binding and Type are allowed, got: " +
|
||||
binding.toString();
|
||||
}
|
||||
|
||||
toString():string {
|
||||
return this.message;
|
||||
}
|
||||
toString(): string { return this.message; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when the class has no annotation information.
|
||||
*
|
||||
* Lack of annotation information prevents the {@link Injector} from determining which dependencies need to be injected into
|
||||
* the constructor.
|
||||
* Lack of annotation information prevents the {@link Injector} from determining which dependencies
|
||||
* need to be injected into the constructor.
|
||||
*
|
||||
* @exportedAs angular2/di_errors
|
||||
*/
|
||||
export class NoAnnotationError extends Error {
|
||||
message:string;
|
||||
export class NoAnnotationError extends BaseException {
|
||||
name: string;
|
||||
message: string;
|
||||
constructor(typeOrFunc) {
|
||||
super();
|
||||
this.message = `Cannot resolve all parameters for ${stringify(typeOrFunc)}.` +
|
||||
` Make sure they all have valid type or annotations.`;
|
||||
this.message = "Cannot resolve all parameters for " + stringify(typeOrFunc) + ". " +
|
||||
'Make sure they all have valid type or annotations.';
|
||||
}
|
||||
|
||||
toString():string {
|
||||
return this.message;
|
||||
}
|
||||
toString(): string { return this.message; }
|
||||
}
|
|
@ -1,31 +1,37 @@
|
|||
/// <reference path="../../typings/es6-promise/es6-promise.d.ts" />
|
||||
|
||||
import {Map, List, MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {ResolvedBinding, Binding, BindingBuilder, bind} from './binding';
|
||||
import {AbstractBindingError, NoBindingError, AsyncBindingError, CyclicDependencyError,
|
||||
InstantiationError, InvalidBindingError} from './exceptions';
|
||||
import {
|
||||
AbstractBindingError,
|
||||
NoBindingError,
|
||||
AsyncBindingError,
|
||||
CyclicDependencyError,
|
||||
InstantiationError,
|
||||
InvalidBindingError
|
||||
} from './exceptions';
|
||||
import {FunctionWrapper, Type, isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
import {Key} from './key';
|
||||
|
||||
var _constructing = new Object();
|
||||
var _notFound = new Object();
|
||||
|
||||
class _Waiting {
|
||||
promise:Promise;
|
||||
constructor(promise:Promise) {
|
||||
this.promise = promise;
|
||||
}
|
||||
promise: Promise<any>;
|
||||
constructor(promise: Promise<any>) { this.promise = promise; }
|
||||
}
|
||||
function _isWaiting(obj):boolean {
|
||||
function _isWaiting(obj): boolean {
|
||||
return obj instanceof _Waiting;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
* 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:
|
||||
*
|
||||
|
@ -36,14 +42,15 @@ function _isWaiting(obj):boolean {
|
|||
* }
|
||||
*
|
||||
* class Car {
|
||||
* constructor(@Inject(Engine) engine) {
|
||||
* }
|
||||
* 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.
|
||||
* 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() {
|
||||
|
@ -53,71 +60,79 @@ function _isWaiting(obj):boolean {
|
|||
* 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.
|
||||
* 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;
|
||||
_parent:Injector;
|
||||
_defaultBindings:boolean;
|
||||
_bindings: List<any>;
|
||||
_instances: List<any>;
|
||||
_parent: Injector;
|
||||
_defaultBindings: boolean;
|
||||
_asyncStrategy: _AsyncInjectorStrategy;
|
||||
_syncStrategy:_SyncInjectorStrategy;
|
||||
_syncStrategy: _SyncInjectorStrategy;
|
||||
|
||||
/**
|
||||
* Turns a list of binding definitions into an internal resolved list of resolved bindings.
|
||||
*
|
||||
* A resolution is a process of flattening multiple nested lists and converting individual bindings into a
|
||||
* list of {@link ResolvedBinding}s. The resolution can be cached by `resolve` for the {@link Injector} for
|
||||
* performance-sensitive code.
|
||||
* A resolution is a process of flattening multiple nested lists and converting individual
|
||||
* bindings into a list of {@link ResolvedBinding}s. The resolution can be cached by `resolve`
|
||||
* for the {@link Injector} for performance-sensitive code.
|
||||
*
|
||||
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a recursive
|
||||
* list of more bindings.
|
||||
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a
|
||||
* recursive list of more bindings.
|
||||
*
|
||||
* The returned list is sparse, indexed by `id` for the {@link Key}. It is generally not useful to application code
|
||||
* other than for passing it to {@link Injector} functions that require resolved binding lists, such as
|
||||
* The returned list is sparse, indexed by `id` for the {@link Key}. It is generally not useful to
|
||||
*application code
|
||||
* other than for passing it to {@link Injector} functions that require resolved binding lists,
|
||||
*such as
|
||||
* `fromResolvedBindings` and `createChildFromResolved`.
|
||||
*/
|
||||
static resolve(bindings:List/*<ResolvedBinding|Binding|Type|List>*/):List<ResolvedBinding> {
|
||||
static resolve(bindings: List<any>): List<ResolvedBinding> {
|
||||
var resolvedBindings = _resolveBindings(bindings);
|
||||
var flatten = _flattenBindings(resolvedBindings, MapWrapper.create());
|
||||
return _createListOfBindings(flatten);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves bindings and creates an injector based on those bindings. This function is slower than the
|
||||
* corresponding `fromResolvedBindings` because it needs to resolve bindings first. See `resolve` for the
|
||||
* {@link 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 first. See
|
||||
*`resolve`
|
||||
* for the {@link Injector}.
|
||||
*
|
||||
* Prefer `fromResolvedBindings` in performance-critical code that creates lots of injectors.
|
||||
*
|
||||
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a recursive list of more
|
||||
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link 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}={}): Injector {
|
||||
static resolveAndCreate(bindings: List<any>, {defaultBindings = false}: any = {}): Injector {
|
||||
return new Injector(Injector.resolve(bindings), null, defaultBindings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an injector from previously resolved bindings. This bypasses resolution and flattening. This API 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 the recommended way to construct injectors in performance-sensitive parts.
|
||||
*
|
||||
* @param `bindings` A sparse list of {@link ResolvedBinding}s. See `resolve` for the {@link Injector}.
|
||||
* @param `bindings` A sparse list of {@link ResolvedBinding}s. See `resolve` for the {@link
|
||||
*Injector}.
|
||||
* @param `defaultBindings` Setting to true will auto-create bindings.
|
||||
*/
|
||||
static fromResolvedBindings(bindings:List<ResolvedBinding>, {defaultBindings=false}={}): Injector {
|
||||
static fromResolvedBindings(bindings: List<ResolvedBinding>,
|
||||
{defaultBindings = false}: any = {}): Injector {
|
||||
return new Injector(bindings, null, defaultBindings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param `bindings` A sparse list of {@link ResolvedBinding}s. See `resolve` for the {@link Injector}.
|
||||
* @param `bindings` A sparse list of {@link ResolvedBinding}s. See `resolve` for the {@link
|
||||
* Injector}.
|
||||
* @param `parent` Parent Injector or `null` if root Injector.
|
||||
* @param `defaultBindings` Setting to true will auto-create bindings. (Only use with root injector.)
|
||||
* @param `defaultBindings` Setting to true will auto-create bindings. (Only use with root
|
||||
* injector.)
|
||||
*/
|
||||
constructor(bindings:List<ResolvedBinding>, parent:Injector, defaultBindings:boolean) {
|
||||
constructor(bindings: List<ResolvedBinding>, parent: Injector, defaultBindings: boolean) {
|
||||
this._bindings = bindings;
|
||||
this._instances = this._createInstances();
|
||||
this._parent = parent;
|
||||
|
@ -129,12 +144,11 @@ export class Injector {
|
|||
/**
|
||||
* Retrieves an instance from the injector.
|
||||
*
|
||||
* @param `token`: usually the `Type` of an object. (Same as the token used while setting up a binding).
|
||||
* @param `token`: usually the `Type` of an object. (Same as the 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);
|
||||
}
|
||||
get(token) { return this._getByKey(Key.get(token), false, false, false); }
|
||||
|
||||
|
||||
/**
|
||||
|
@ -143,9 +157,7 @@ export class Injector {
|
|||
* @param `token`: usually a `Type`. (Same as the 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);
|
||||
}
|
||||
getOptional(token) { return this._getByKey(Key.get(token), false, false, true); }
|
||||
|
||||
/**
|
||||
* Retrieves an instance from the injector asynchronously. Used with asynchronous bindings.
|
||||
|
@ -153,40 +165,37 @@ export class Injector {
|
|||
* @param `token`: usually a `Type`. (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);
|
||||
}
|
||||
asyncGet(token): Promise<any> { return this._getByKey(Key.get(token), true, false, false); }
|
||||
|
||||
/**
|
||||
* Creates a child injector and loads a new set of bindings into it.
|
||||
*
|
||||
* A resolution is a process of flattening multiple nested lists and converting individual bindings into a
|
||||
* list of {@link ResolvedBinding}s. The resolution can be cached by `resolve` for the {@link Injector} for
|
||||
* performance-sensitive code.
|
||||
* A resolution is a process of flattening multiple nested lists and converting individual
|
||||
* bindings into a list of {@link ResolvedBinding}s. The resolution can be cached by `resolve`
|
||||
* for the {@link Injector} for performance-sensitive code.
|
||||
*
|
||||
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a recursive
|
||||
* list of more bindings.
|
||||
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a
|
||||
* recursive list of more bindings.
|
||||
*
|
||||
*/
|
||||
resolveAndCreateChild(bindings:List/*<ResolvedBinding|Binding|Type|List>*/):Injector {
|
||||
resolveAndCreateChild(bindings: List<any>): Injector {
|
||||
return new Injector(Injector.resolve(bindings), this, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child injector and loads a new set of {@link ResolvedBinding}s into it.
|
||||
*
|
||||
* @param `bindings`: A sparse list of {@link ResolvedBinding}s. See `resolve` for the {@link Injector}.
|
||||
* @param `bindings`: A sparse list of {@link ResolvedBinding}s.
|
||||
* See `resolve` for the {@link Injector}.
|
||||
* @returns a new child {@link Injector}.
|
||||
*/
|
||||
createChildFromResolved(bindings:List<ResolvedBinding>):Injector {
|
||||
createChildFromResolved(bindings: List<ResolvedBinding>): Injector {
|
||||
return new Injector(bindings, this, false);
|
||||
}
|
||||
|
||||
_createInstances():List {
|
||||
return ListWrapper.createFixedSize(Key.numberOfKeys + 1);
|
||||
}
|
||||
_createInstances(): List<any> { return ListWrapper.createFixedSize(Key.numberOfKeys + 1); }
|
||||
|
||||
_getByKey(key:Key, returnPromise:boolean, returnLazy:boolean, optional:boolean) {
|
||||
_getByKey(key: Key, returnPromise: boolean, returnLazy: boolean, optional: boolean) {
|
||||
if (returnLazy) {
|
||||
return () => this._getByKey(key, returnPromise, false, optional);
|
||||
}
|
||||
|
@ -210,7 +219,7 @@ export class Injector {
|
|||
}
|
||||
}
|
||||
|
||||
_resolveDependencies(key:Key, binding:ResolvedBinding, forceAsync:boolean):List {
|
||||
_resolveDependencies(key: Key, binding: ResolvedBinding, forceAsync: boolean): List<any> {
|
||||
try {
|
||||
var getDependency = d => this._getByKey(d.key, forceAsync || d.asPromise, d.lazy, d.optional);
|
||||
return ListWrapper.map(binding.dependencies, getDependency);
|
||||
|
@ -221,44 +230,35 @@ export class Injector {
|
|||
}
|
||||
}
|
||||
|
||||
_getInstance(key:Key) {
|
||||
_getInstance(key: Key) {
|
||||
if (this._instances.length <= key.id) return null;
|
||||
return ListWrapper.get(this._instances, key.id);
|
||||
}
|
||||
|
||||
_setInstance(key:Key, obj):void {
|
||||
ListWrapper.set(this._instances, key.id, obj);
|
||||
}
|
||||
_setInstance(key: Key, obj): void { ListWrapper.set(this._instances, key.id, obj); }
|
||||
|
||||
_getBinding(key:Key) {
|
||||
var binding = this._bindings.length <= key.id ?
|
||||
null :
|
||||
ListWrapper.get(this._bindings, key.id);
|
||||
_getBinding(key: Key) {
|
||||
var binding = this._bindings.length <= key.id ? null : ListWrapper.get(this._bindings, key.id);
|
||||
|
||||
if (isBlank(binding) && this._defaultBindings) {
|
||||
return bind(key.token).toClass(key.token).resolve();
|
||||
var token: any = key.token;
|
||||
return bind(key.token).toClass(token).resolve();
|
||||
} else {
|
||||
return binding;
|
||||
}
|
||||
}
|
||||
|
||||
_markAsConstructing(key:Key):void {
|
||||
this._setInstance(key, _constructing);
|
||||
}
|
||||
_markAsConstructing(key: Key): void { this._setInstance(key, _constructing); }
|
||||
|
||||
_clear(key:Key):void {
|
||||
this._setInstance(key, null);
|
||||
}
|
||||
_clear(key: Key): void { this._setInstance(key, null); }
|
||||
}
|
||||
|
||||
|
||||
class _SyncInjectorStrategy {
|
||||
injector:Injector;
|
||||
constructor(injector:Injector) {
|
||||
this.injector = injector;
|
||||
}
|
||||
injector: Injector;
|
||||
constructor(injector: Injector) { this.injector = injector; }
|
||||
|
||||
readFromCache(key:Key) {
|
||||
readFromCache(key: Key) {
|
||||
if (key.token === Injector) {
|
||||
return this.injector;
|
||||
}
|
||||
|
@ -274,20 +274,20 @@ class _SyncInjectorStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
instantiate(key:Key) {
|
||||
instantiate(key: Key) {
|
||||
var binding = this.injector._getBinding(key);
|
||||
if (isBlank(binding)) return _notFound;
|
||||
|
||||
if (binding.providedAsPromise) throw new AsyncBindingError(key);
|
||||
|
||||
//add a marker so we can detect cyclic dependencies
|
||||
// add a marker so we can detect cyclic dependencies
|
||||
this.injector._markAsConstructing(key);
|
||||
|
||||
var deps = this.injector._resolveDependencies(key, binding, false);
|
||||
return this._createInstance(key, binding, deps);
|
||||
}
|
||||
|
||||
_createInstance(key:Key, binding:ResolvedBinding, deps:List) {
|
||||
_createInstance(key: Key, binding: ResolvedBinding, deps: List<any>) {
|
||||
try {
|
||||
var instance = FunctionWrapper.apply(binding.factory, deps);
|
||||
this.injector._setInstance(key, instance);
|
||||
|
@ -301,12 +301,10 @@ class _SyncInjectorStrategy {
|
|||
|
||||
|
||||
class _AsyncInjectorStrategy {
|
||||
injector:Injector;
|
||||
constructor(injector:Injector) {
|
||||
this.injector = injector;
|
||||
}
|
||||
injector: Injector;
|
||||
constructor(injector: Injector) { this.injector = injector; }
|
||||
|
||||
readFromCache(key:Key) {
|
||||
readFromCache(key: Key) {
|
||||
if (key.token === Injector) {
|
||||
return PromiseWrapper.resolve(this.injector);
|
||||
}
|
||||
|
@ -324,31 +322,30 @@ class _AsyncInjectorStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
instantiate(key:Key) /* Promise?? */ {
|
||||
instantiate(key: Key) /* Promise?? */ {
|
||||
var binding = this.injector._getBinding(key);
|
||||
if (isBlank(binding)) return _notFound;
|
||||
|
||||
//add a marker so we can detect cyclic dependencies
|
||||
// add a marker so we can detect cyclic dependencies
|
||||
this.injector._markAsConstructing(key);
|
||||
|
||||
var deps = this.injector._resolveDependencies(key, binding, true);
|
||||
var depsPromise = PromiseWrapper.all(deps);
|
||||
|
||||
var promise = PromiseWrapper
|
||||
.then(depsPromise, null, (e) => this._errorHandler(key, e))
|
||||
.then(deps => this._findOrCreate(key, binding, deps))
|
||||
.then(instance => this._cacheInstance(key, instance));
|
||||
var promise = PromiseWrapper.then(depsPromise, null, (e) => this._errorHandler(key, e))
|
||||
.then(deps => this._findOrCreate(key, binding, deps))
|
||||
.then(instance => this._cacheInstance(key, instance));
|
||||
|
||||
this.injector._setInstance(key, new _Waiting(promise));
|
||||
return promise;
|
||||
}
|
||||
|
||||
_errorHandler(key:Key, e):Promise {
|
||||
_errorHandler(key: Key, e): Promise<any> {
|
||||
if (e instanceof AbstractBindingError) e.addKey(key);
|
||||
return PromiseWrapper.reject(e);
|
||||
}
|
||||
|
||||
_findOrCreate(key:Key, binding:ResolvedBinding, deps:List) {
|
||||
_findOrCreate(key: Key, binding: ResolvedBinding, deps: List<any>) {
|
||||
try {
|
||||
var instance = this.injector._getInstance(key);
|
||||
if (!_isWaiting(instance)) return instance;
|
||||
|
@ -365,7 +362,7 @@ class _AsyncInjectorStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
function _resolveBindings(bindings:List): List {
|
||||
function _resolveBindings(bindings: List<any>): List<ResolvedBinding> {
|
||||
var resolvedList = ListWrapper.createFixedSize(bindings.length);
|
||||
for (var i = 0; i < bindings.length; i++) {
|
||||
var unresolved = bindings[i];
|
||||
|
@ -379,7 +376,7 @@ function _resolveBindings(bindings:List): List {
|
|||
} else if (unresolved instanceof List) {
|
||||
resolved = _resolveBindings(unresolved);
|
||||
} else if (unresolved instanceof BindingBuilder) {
|
||||
throw new InvalidBindingError('BindingBuilder with ' + unresolved.token + ' token');
|
||||
throw new InvalidBindingError(unresolved.token);
|
||||
} else {
|
||||
throw new InvalidBindingError(unresolved);
|
||||
}
|
||||
|
@ -388,14 +385,15 @@ function _resolveBindings(bindings:List): List {
|
|||
return resolvedList;
|
||||
}
|
||||
|
||||
function _createListOfBindings(flattenedBindings):List {
|
||||
function _createListOfBindings(flattenedBindings): List<any> {
|
||||
var bindings = ListWrapper.createFixedSize(Key.numberOfKeys + 1);
|
||||
MapWrapper.forEach(flattenedBindings, (v, keyId) => bindings[keyId] = v);
|
||||
return bindings;
|
||||
}
|
||||
|
||||
function _flattenBindings(bindings:List, res:Map):Map {
|
||||
ListWrapper.forEach(bindings, function (b) {
|
||||
function _flattenBindings(bindings: List<ResolvedBinding /* | List<any>*/>,
|
||||
res: Map<number, ResolvedBinding>): Map<number, ResolvedBinding> {
|
||||
ListWrapper.forEach(bindings, function(b) {
|
||||
if (b instanceof ResolvedBinding) {
|
||||
MapWrapper.set(res, b.key.id, b);
|
||||
} else if (b instanceof List) {
|
|
@ -16,42 +16,34 @@ import {stringify} from 'angular2/src/facade/lang';
|
|||
* @exportedAs angular2/di
|
||||
*/
|
||||
export class Key {
|
||||
token;
|
||||
id/* :int */;
|
||||
constructor(token, id/* :int */) {
|
||||
token: Object;
|
||||
id: number;
|
||||
constructor(token: Object, id: number) {
|
||||
this.token = token;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
get displayName() {
|
||||
return stringify(this.token);
|
||||
}
|
||||
get displayName() { return stringify(this.token); }
|
||||
|
||||
/**
|
||||
* Retrieves a `Key` for a token.
|
||||
*/
|
||||
static get(token):Key {
|
||||
return _globalKeyRegistry.get(token);
|
||||
}
|
||||
static get(token): Key { return _globalKeyRegistry.get(token); }
|
||||
|
||||
/**
|
||||
* @returns the number of keys registered in the system.
|
||||
*/
|
||||
static get numberOfKeys()/* :int */ {
|
||||
return _globalKeyRegistry.numberOfKeys;
|
||||
}
|
||||
static get numberOfKeys(): number { return _globalKeyRegistry.numberOfKeys; }
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export class KeyRegistry {
|
||||
_allKeys:Map;
|
||||
constructor() {
|
||||
this._allKeys = MapWrapper.create();
|
||||
}
|
||||
_allKeys: Map<Object, Key>;
|
||||
constructor() { this._allKeys = MapWrapper.create(); }
|
||||
|
||||
get(token):Key {
|
||||
get(token: Object): Key {
|
||||
if (token instanceof Key) return token;
|
||||
|
||||
if (MapWrapper.contains(this._allKeys, token)) {
|
||||
|
@ -63,9 +55,7 @@ export class KeyRegistry {
|
|||
return newKey;
|
||||
}
|
||||
|
||||
get numberOfKeys()/* :int */ {
|
||||
return MapWrapper.size(this._allKeys);
|
||||
}
|
||||
get numberOfKeys() /* :int */ { return MapWrapper.size(this._allKeys); }
|
||||
}
|
||||
|
||||
var _globalKeyRegistry = new KeyRegistry();
|
|
@ -1,16 +0,0 @@
|
|||
/**
|
||||
*
|
||||
*
|
||||
* @exportedAs angular2/di
|
||||
*/
|
||||
export class OpaqueToken {
|
||||
_desc:string;
|
||||
|
||||
constructor(desc:string){
|
||||
this._desc = `Token(${desc})`;
|
||||
}
|
||||
|
||||
toString():string {
|
||||
return this._desc;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
*
|
||||
*
|
||||
* @exportedAs angular2/di
|
||||
*/
|
||||
export class OpaqueToken {
|
||||
_desc: string;
|
||||
|
||||
constructor(desc: string) { this._desc = `Token(${desc})`; }
|
||||
|
||||
toString(): string { return this._desc; }
|
||||
}
|
|
@ -10,6 +10,8 @@ import {int, global, isPresent} from 'angular2/src/facade/lang';
|
|||
import {List} from 'angular2/src/facade/collection';
|
||||
import * as Rx from 'rx';
|
||||
|
||||
export var Promise = (<any>global).Promise;
|
||||
|
||||
export class PromiseWrapper {
|
||||
static resolve(obj): Promise<any> { return Promise.resolve(obj); }
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ class FunctionWrapper {
|
|||
class BaseException extends Error {
|
||||
final String message;
|
||||
|
||||
BaseException(this.message);
|
||||
BaseException([this.message]);
|
||||
|
||||
String toString() {
|
||||
return this.message;
|
||||
|
|
|
@ -9,6 +9,18 @@ export var __esModule = true;
|
|||
export var Type = Function;
|
||||
export type Type = typeof Function;
|
||||
|
||||
export class BaseException extends Error {
|
||||
message;
|
||||
stack;
|
||||
constructor(message?: string) {
|
||||
super(message);
|
||||
this.message = message;
|
||||
this.stack = (<any>new Error()).stack;
|
||||
}
|
||||
|
||||
toString(): string { return this.message; }
|
||||
}
|
||||
|
||||
export var Math = _global.Math;
|
||||
export var Date = _global.Date;
|
||||
|
||||
|
@ -28,7 +40,9 @@ if (assertionsEnabled_) {
|
|||
}
|
||||
export {int};
|
||||
|
||||
export class CONST {}
|
||||
export function CONST() {
|
||||
return (target) => target;
|
||||
};
|
||||
export class ABSTRACT {}
|
||||
export class IMPLEMENTS {}
|
||||
|
||||
|
@ -111,10 +125,10 @@ export class StringJoiner {
|
|||
toString(): string { return this.parts.join(""); }
|
||||
}
|
||||
|
||||
export class NumberParseError implements Error {
|
||||
export class NumberParseError extends BaseException {
|
||||
name: string;
|
||||
|
||||
constructor(public message: string) {}
|
||||
constructor(public message: string) { super(); }
|
||||
|
||||
toString() { return this.message; }
|
||||
}
|
||||
|
@ -191,9 +205,6 @@ export class FunctionWrapper {
|
|||
static apply(fn: Function, posArgs) { return fn.apply(null, posArgs); }
|
||||
}
|
||||
|
||||
// No subclass so that we preserve error stack.
|
||||
export var BaseException = Error;
|
||||
|
||||
// JS has NaN !== NaN
|
||||
export function looseIdentical(a, b): boolean {
|
||||
return a === b || typeof a === "number" && typeof b === "number" && isNaN(a) && isNaN(b);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
library util_decorators;
|
|
@ -1,12 +1,16 @@
|
|||
export var __esModule = true;
|
||||
|
||||
import {global} from 'angular2/src/facade/lang';
|
||||
|
||||
export function makeDecorator(annotationCls) {
|
||||
return function(...args) {
|
||||
return function() {
|
||||
var args = arguments;
|
||||
var Reflect = global.Reflect;
|
||||
if (!(Reflect && Reflect.getMetadata)) {
|
||||
throw 'reflect-metadata shim is required when using class decorators';
|
||||
}
|
||||
var annotationInstance = new annotationCls(...args);
|
||||
var annotationInstance = Object.create(annotationCls);
|
||||
annotationInstance.call(annotationInstance, args);
|
||||
return function(cls) {
|
||||
var annotations = Reflect.getMetadata('annotations', cls);
|
||||
annotations = annotations || [];
|
||||
|
@ -18,12 +22,14 @@ export function makeDecorator(annotationCls) {
|
|||
}
|
||||
|
||||
export function makeParamDecorator(annotationCls) {
|
||||
return function(...args) {
|
||||
return function() {
|
||||
var args = arguments;
|
||||
var Reflect = global.Reflect;
|
||||
if (!(Reflect && Reflect.getMetadata)) {
|
||||
throw 'reflect-metadata shim is required when using parameter decorators';
|
||||
}
|
||||
var annotationInstance = new annotationCls(...args);
|
||||
var annotationInstance = Object.create(annotationCls);
|
||||
annotationInstance.call(annotationInstance, args);
|
||||
return function(cls, unusedKey, index) {
|
||||
var parameters = Reflect.getMetadata('parameters', cls);
|
||||
parameters = parameters || [];
|
|
@ -77,6 +77,7 @@ class NoAnnotations {
|
|||
|
||||
export function main() {
|
||||
describe('injector', function () {
|
||||
|
||||
it('should instantiate a class without dependencies', function () {
|
||||
var injector = Injector.resolveAndCreate([Engine]);
|
||||
var engine = injector.get(Engine);
|
||||
|
@ -211,7 +212,7 @@ export function main() {
|
|||
.toThrowError('Invalid binding - only instances of Binding and Type are allowed, got: blah');
|
||||
expect(() => Injector.resolveAndCreate([bind("blah")]))
|
||||
.toThrowError('Invalid binding - only instances of Binding and Type are allowed, ' +
|
||||
'got: BindingBuilder with blah token');
|
||||
'got: blah');
|
||||
});
|
||||
|
||||
it('should provide itself', function () {
|
||||
|
|
|
@ -22,6 +22,7 @@ class SpyTestObj extends SpyObject {
|
|||
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||
}
|
||||
|
||||
|
||||
export function main() {
|
||||
describe('test_lib', () => {
|
||||
describe('equality', () => {
|
||||
|
|
|
@ -9509,7 +9509,7 @@
|
|||
},
|
||||
"typescript": {
|
||||
"version": "1.5.0-beta",
|
||||
"resolved": "git://github.com/alexeagle/TypeScript#cddc1867c44b6bed9095dc30f0b0f552cbc003a9"
|
||||
"resolved": "git://github.com/alexeagle/TypeScript#be9a7edff73ac2592e508732c771c85357041385"
|
||||
},
|
||||
"vinyl": {
|
||||
"version": "0.4.6",
|
||||
|
|
|
@ -14695,7 +14695,7 @@
|
|||
"typescript": {
|
||||
"version": "1.5.0-beta",
|
||||
"from": "git://github.com/alexeagle/TypeScript#error_is_class",
|
||||
"resolved": "git://github.com/alexeagle/TypeScript#cddc1867c44b6bed9095dc30f0b0f552cbc003a9"
|
||||
"resolved": "git://github.com/alexeagle/TypeScript#be9a7edff73ac2592e508732c771c85357041385"
|
||||
},
|
||||
"vinyl": {
|
||||
"version": "0.4.6",
|
||||
|
|
Loading…
Reference in New Issue