408 lines
12 KiB
TypeScript
Raw Normal View History

2016-05-31 15:22:59 -07:00
import {normalizeBool, Type, isType, isBlank, isFunction, stringify} from '../facade/lang';
import {BaseException} from '../facade/exceptions';
/**
2015-09-17 13:12:50 -07:00
* Describes how the {@link Injector} should instantiate a given token.
2015-04-15 22:35:38 +00:00
*
* See {@link provide}.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ### Example ([live demo](http://plnkr.co/edit/GNAyj6K6PfYg2NBzgwZ5?p%3Dpreview&p=preview))
2015-04-15 22:35:38 +00:00
*
* ```javascript
* var injector = Injector.resolveAndCreate([
* new Provider("message", { useValue: 'Hello' })
2015-04-15 22:35:38 +00:00
* ]);
*
2015-09-17 13:12:50 -07:00
* expect(injector.get("message")).toEqual('Hello');
2015-04-15 22:35:38 +00:00
* ```
* @ts2dart_const
* @deprecated
*/
export class Provider {
2015-04-15 22:35:38 +00:00
/**
2015-10-11 14:42:15 -07:00
* Token used when retrieving this provider. Usually, it is a type {@link Type}.
2015-04-15 22:35:38 +00:00
*/
token: any /** TODO #9100 */;
2015-04-15 22:35:38 +00:00
/**
2015-09-17 13:12:50 -07:00
* Binds a DI token to an implementation class.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ### Example ([live demo](http://plnkr.co/edit/RSTG86qgmoxCyj9SWPwY?p=preview))
2015-04-15 22:35:38 +00:00
*
* Because `useExisting` and `useClass` are often confused, the example contains
* both use cases for easy comparison.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ```typescript
2015-04-15 22:35:38 +00:00
* class Vehicle {}
*
* class Car extends Vehicle {}
*
* var injectorClass = Injector.resolveAndCreate([
* Car,
* {provide: Vehicle, useClass: Car }
2015-04-15 22:35:38 +00:00
* ]);
* var injectorAlias = Injector.resolveAndCreate([
* Car,
* {provide: Vehicle, useExisting: Car }
2015-04-15 22:35:38 +00:00
* ]);
*
* 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);
* ```
*/
useClass: Type;
2015-04-15 22:35:38 +00:00
/**
2015-09-17 13:12:50 -07:00
* Binds a DI token to a value.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ### Example ([live demo](http://plnkr.co/edit/UFVsMVQIDe7l4waWziES?p=preview))
2015-04-15 22:35:38 +00:00
*
* ```javascript
* var injector = Injector.resolveAndCreate([
* new Provider("message", { useValue: 'Hello' })
2015-04-15 22:35:38 +00:00
* ]);
*
2015-09-17 13:12:50 -07:00
* expect(injector.get("message")).toEqual('Hello');
2015-04-15 22:35:38 +00:00
* ```
*/
useValue: any /** TODO #9100 */;
2015-04-15 22:35:38 +00:00
/**
* Binds a DI token to an existing token.
2015-04-15 22:35:38 +00:00
*
* {@link Injector} returns the same instance as if the provided token was used.
* This is in contrast to `useClass` where a separate instance of `useClass` is returned.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ### Example ([live demo](http://plnkr.co/edit/QsatsOJJ6P8T2fMe9gr8?p=preview))
2015-04-15 22:35:38 +00:00
*
* Because `useExisting` and `useClass` are often confused the example contains
* both use cases for easy comparison.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ```typescript
2015-04-15 22:35:38 +00:00
* class Vehicle {}
*
* class Car extends Vehicle {}
*
* var injectorAlias = Injector.resolveAndCreate([
* Car,
* {provide: Vehicle, useExisting: Car }
2015-04-15 22:35:38 +00:00
* ]);
* var injectorClass = Injector.resolveAndCreate([
* Car,
* {provide: Vehicle, useClass: Car }
2015-04-15 22:35:38 +00:00
* ]);
*
* expect(injectorAlias.get(Vehicle)).toBe(injectorAlias.get(Car));
* expect(injectorAlias.get(Vehicle) instanceof Car).toBe(true);
2015-04-17 03:29:05 -07:00
*
2015-04-15 22:35:38 +00:00
* expect(injectorClass.get(Vehicle)).not.toBe(injectorClass.get(Car));
* expect(injectorClass.get(Vehicle) instanceof Car).toBe(true);
* ```
*/
useExisting: any /** TODO #9100 */;
2015-04-15 22:35:38 +00:00
/**
2015-09-17 13:12:50 -07:00
* Binds a DI token to a function which computes the value.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ### Example ([live demo](http://plnkr.co/edit/Scoxy0pJNqKGAPZY1VVC?p=preview))
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ```typescript
2015-04-15 22:35:38 +00:00
* var injector = Injector.resolveAndCreate([
* {provide: Number, useFactory: () => { return 1+2; }},
* new Provider(String, { useFactory: (value) => { return "Value: " + value; },
2015-09-17 13:12:50 -07:00
* deps: [Number] })
2015-04-15 22:35:38 +00:00
* ]);
*
* expect(injector.get(Number)).toEqual(3);
* expect(injector.get(String)).toEqual('Value: 3');
* ```
2015-09-17 13:12:50 -07:00
*
* Used in conjunction with dependencies.
2015-04-15 22:35:38 +00:00
*/
useFactory: Function;
2015-04-15 22:35:38 +00:00
/**
2015-09-17 13:12:50 -07:00
* Specifies a set of dependencies
* (as `token`s) which should be injected into the factory function.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ### Example ([live demo](http://plnkr.co/edit/Scoxy0pJNqKGAPZY1VVC?p=preview))
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ```typescript
2015-04-15 22:35:38 +00:00
* var injector = Injector.resolveAndCreate([
* {provide: Number, useFactory: () => { return 1+2; }},
* new Provider(String, { useFactory: (value) => { return "Value: " + value; },
2015-09-17 13:12:50 -07:00
* deps: [Number] })
2015-04-15 22:35:38 +00:00
* ]);
*
* expect(injector.get(Number)).toEqual(3);
* expect(injector.get(String)).toEqual('Value: 3');
* ```
2015-09-17 13:12:50 -07:00
*
* Used in conjunction with `useFactory`.
2015-04-15 22:35:38 +00:00
*/
dependencies: Object[];
/** @internal */
_multi: boolean;
constructor(token: any /** TODO #9100 */, {useClass, useValue, useExisting, useFactory, deps, multi}: {
useClass?: Type,
useValue?: any,
useExisting?: any,
useFactory?: Function,
deps?: Object[],
multi?: boolean
}) {
this.token = token;
this.useClass = useClass;
this.useValue = useValue;
this.useExisting = useExisting;
this.useFactory = useFactory;
this.dependencies = deps;
this._multi = multi;
}
2015-09-17 13:12:50 -07:00
// TODO: Provide a full working example after alpha38 is released.
2015-04-15 22:35:38 +00:00
/**
* Creates multiple providers matching the same token (a multi-provider).
*
* Multi-providers are used for creating pluggable service, where the system comes
* with some default providers, and the user can register additional providers.
* The combination of the default providers and the additional providers will be
* used to drive the behavior of the system.
*
2015-09-17 13:12:50 -07:00
* ### Example
*
2015-09-17 13:12:50 -07:00
* ```typescript
* var injector = Injector.resolveAndCreate([
* new Provider("Strings", { useValue: "String1", multi: true}),
* new Provider("Strings", { useValue: "String2", multi: true})
* ]);
*
* expect(injector.get("Strings")).toEqual(["String1", "String2"]);
* ```
*
* Multi-providers and regular providers cannot be mixed. The following
* will throw an exception:
2015-04-17 03:29:05 -07:00
*
2015-09-17 13:12:50 -07:00
* ```typescript
* var injector = Injector.resolveAndCreate([
* new Provider("Strings", { useValue: "String1", multi: true }),
* new Provider("Strings", { useValue: "String2"})
* ]);
* ```
2015-04-15 22:35:38 +00:00
*/
get multi(): boolean { return normalizeBool(this._multi); }
}
/**
* See {@link Provider} instead.
*
* @deprecated
* @ts2dart_const
*/
export class Binding extends Provider {
constructor(token: any /** TODO #9100 */, {toClass, toValue, toAlias, toFactory, deps, multi}: {
toClass?: Type,
toValue?: any,
toAlias?: any,
toFactory: Function, deps?: Object[], multi?: boolean
}) {
super(token, {
useClass: toClass,
useValue: toValue,
useExisting: toAlias,
useFactory: toFactory,
deps: deps,
multi: multi
});
}
/**
* @deprecated
*/
get toClass() { return this.useClass; }
/**
* @deprecated
*/
get toAlias() { return this.useExisting; }
/**
* @deprecated
*/
get toFactory() { return this.useFactory; }
/**
* @deprecated
*/
get toValue() { return this.useValue; }
}
2015-09-17 13:12:50 -07:00
/**
* Creates a {@link Provider}.
2015-04-17 03:29:05 -07:00
*
* To construct a {@link Provider}, bind a `token` to either a class, a value, a factory function,
* or
* to an existing `token`.
* See {@link ProviderBuilder} for more details.
2015-09-03 16:17:23 -07:00
*
2016-04-12 19:58:42 +02:00
* The `token` is most commonly a class or {@link OpaqueToken-class.html}.
*
* @deprecated
*/
export function bind(token: any /** TODO #9100 */): ProviderBuilder {
return new ProviderBuilder(token);
}
/**
* Helper class for the {@link bind} function.
* @deprecated
*/
export class ProviderBuilder {
constructor(public token: any /** TODO #9100 */) {}
2015-04-15 22:35:38 +00:00
/**
2015-09-17 13:12:50 -07:00
* Binds a DI token to a class.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ### Example ([live demo](http://plnkr.co/edit/ZpBCSYqv6e2ud5KXLdxQ?p=preview))
2015-04-15 22:35:38 +00:00
*
* Because `toAlias` and `toClass` are often confused, the example contains
* both use cases for easy comparison.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ```typescript
2015-04-15 22:35:38 +00:00
* class Vehicle {}
*
* class Car extends Vehicle {}
*
* var injectorClass = Injector.resolveAndCreate([
* Car,
* {provide: Vehicle, useClass: Car}
2015-04-15 22:35:38 +00:00
* ]);
* var injectorAlias = Injector.resolveAndCreate([
* Car,
* {provide: Vehicle, useExisting: Car}
2015-04-15 22:35:38 +00:00
* ]);
*
* 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): Provider {
if (!isType(type)) {
throw new BaseException(
`Trying to create a class provider but "${stringify(type)}" is not a class!`);
}
return new Provider(this.token, {useClass: type});
}
2015-04-15 22:35:38 +00:00
/**
2015-09-17 13:12:50 -07:00
* Binds a DI token to a value.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ### Example ([live demo](http://plnkr.co/edit/G024PFHmDL0cJFgfZK8O?p=preview))
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ```typescript
2015-04-15 22:35:38 +00:00
* var injector = Injector.resolveAndCreate([
* {provide: 'message', useValue: 'Hello'}
2015-04-15 22:35:38 +00:00
* ]);
*
2015-09-17 13:12:50 -07:00
* expect(injector.get('message')).toEqual('Hello');
2015-04-15 22:35:38 +00:00
* ```
*/
toValue(value: any): Provider { return new Provider(this.token, {useValue: value}); }
2015-04-15 22:35:38 +00:00
/**
* Binds a DI token to an existing token.
2015-04-15 22:35:38 +00:00
*
* Angular will return the same instance as if the provided token was used. (This is
* in contrast to `useClass` where a separate instance of `useClass` will be returned.)
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ### Example ([live demo](http://plnkr.co/edit/uBaoF2pN5cfc5AfZapNw?p=preview))
2015-04-15 22:35:38 +00:00
*
* Because `toAlias` and `toClass` are often confused, the example contains
* both use cases for easy comparison.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ```typescript
2015-04-15 22:35:38 +00:00
* class Vehicle {}
*
* class Car extends Vehicle {}
*
* var injectorAlias = Injector.resolveAndCreate([
* Car,
* {provide: Vehicle, useExisting: Car}
2015-04-15 22:35:38 +00:00
* ]);
* var injectorClass = Injector.resolveAndCreate([
* Car,
* {provide: Vehicle, useClass: Car})
2015-04-15 22:35:38 +00:00
* ]);
*
* expect(injectorAlias.get(Vehicle)).toBe(injectorAlias.get(Car));
* expect(injectorAlias.get(Vehicle) instanceof Car).toBe(true);
2015-04-17 03:29:05 -07:00
*
2015-04-15 22:35:38 +00:00
* expect(injectorClass.get(Vehicle)).not.toBe(injectorClass.get(Car));
* expect(injectorClass.get(Vehicle) instanceof Car).toBe(true);
* ```
*/
toAlias(aliasToken: /*Type*/ any): Provider {
if (isBlank(aliasToken)) {
throw new BaseException(`Can not alias ${stringify(this.token)} to a blank value!`);
}
return new Provider(this.token, {useExisting: aliasToken});
}
2015-04-15 22:35:38 +00:00
/**
2015-09-17 13:12:50 -07:00
* Binds a DI token to a function which computes the value.
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ### Example ([live demo](http://plnkr.co/edit/OejNIfTT3zb1iBxaIYOb?p=preview))
2015-04-15 22:35:38 +00:00
*
2015-09-17 13:12:50 -07:00
* ```typescript
2015-04-15 22:35:38 +00:00
* var injector = Injector.resolveAndCreate([
* {provide: Number, useFactory: () => { return 1+2; }},
* {provide: String, useFactory: (v) => { return "Value: " + v; }, deps: [Number]}
2015-04-15 22:35:38 +00:00
* ]);
*
* expect(injector.get(Number)).toEqual(3);
* expect(injector.get(String)).toEqual('Value: 3');
* ```
*/
toFactory(factory: Function, dependencies?: any[]): Provider {
if (!isFunction(factory)) {
throw new BaseException(
`Trying to create a factory provider but "${stringify(factory)}" is not a function!`);
}
return new Provider(this.token, {useFactory: factory, deps: dependencies});
}
}
/**
* Creates a {@link Provider}.
*
* See {@link Provider} for more details.
*
* <!-- TODO: improve the docs -->
* @deprecated
*/
export function provide(token: any /** TODO #9100 */, {useClass, useValue, useExisting, useFactory, deps, multi}: {
useClass?: Type,
useValue?: any,
useExisting?: any,
useFactory?: Function,
deps?: Object[],
multi?: boolean
}): Provider {
return new Provider(token, {
useClass: useClass,
useValue: useValue,
useExisting: useExisting,
useFactory: useFactory,
deps: deps,
multi: multi
});
}