phosphor-di
Advanced tools
Comparing version 0.0.2 to 0.9.0
@@ -35,5 +35,5 @@ /** | ||
/** | ||
* A class which declares its dependencies. | ||
* A factory which declares its dependencies. | ||
*/ | ||
export interface IInjectable<T> { | ||
export interface IFactory<T> { | ||
/** | ||
@@ -46,3 +46,3 @@ * The lifetime policy for the registration. | ||
/** | ||
* The dependencies required to instantiate the class. | ||
* The dependencies required to create the instance. | ||
*/ | ||
@@ -55,62 +55,41 @@ requires: Token<any>[]; | ||
* | ||
* @returns A new instance of the type. | ||
* @returns A new instance of the type, or a Promise to an instance. | ||
*/ | ||
new (...args: any[]): T; | ||
create(...args: any[]): T | Promise<T>; | ||
} | ||
/** | ||
* A factory object which declares its dependencies. | ||
* A lightweight dependency injection container. | ||
*/ | ||
export interface IFactory<T> { | ||
export declare class Container { | ||
/** | ||
* The lifetime policy for the registration. | ||
* Test whether a token is registered with the container. | ||
* | ||
* The default value is `Lifetime.Singleton`. | ||
* @param token - The run-time type token of interest. | ||
* | ||
* @returns `true` if the token is registered, `false` otherwise. | ||
*/ | ||
lifetime?: Lifetime; | ||
isRegistered(token: Token<any>): boolean; | ||
/** | ||
* The dependencies required to create the instance. | ||
* Register a type mapping for the specified token. | ||
* | ||
* @param token - The run-time type token of interest. | ||
* | ||
* @param factory - The factory which will create the instance. | ||
* | ||
* #### Notes | ||
* If the token is already registered, or if registering the factory | ||
* would cause a circular dependency, an error will be logged to the | ||
* console and the registration will be ignored. | ||
*/ | ||
requires: Token<any>[]; | ||
register<T>(token: Token<T>, factory: IFactory<T>): void; | ||
/** | ||
* Create a new instance of the type. | ||
* Resolve an instance for the given token or factory. | ||
* | ||
* @param args - The resolved dependencies specified by `requires`. | ||
* @param value - The token or factory object to resolve. | ||
* | ||
* @returns A new instance of the type, or a Promise to an instance. | ||
* @returns A promise which resolves to an instance of the requested | ||
* type, or rejects with an error if an instance fails to resolve. | ||
*/ | ||
create(...args: any[]): T | Promise<T>; | ||
resolve<T>(value: Token<T> | IFactory<T>): Promise<T>; | ||
private _registry; | ||
} | ||
/** | ||
* A type alias for a provider object. | ||
*/ | ||
export declare type Provider<T> = IInjectable<T> | IFactory<T>; | ||
/** | ||
* Test whether a token is registered. | ||
* | ||
* @param token - The run-time type token of interest. | ||
* | ||
* @returns `true` if the token is registered, `false` otherwise. | ||
*/ | ||
export declare function isRegistered<T>(token: Token<T>): boolean; | ||
/** | ||
* Register a type mapping for the specified token. | ||
* | ||
* @param token - The run-time type token of interest. | ||
* | ||
* @param provider - The object which will create the instance. | ||
* | ||
* #### Notes | ||
* If the token is already registered, or if registering the provider | ||
* would cause a circular dependency, an error will be logged to the | ||
* console and the registration will be ignored. | ||
*/ | ||
export declare function register<T>(token: Token<T>, provider: Provider<T>): void; | ||
/** | ||
* Resolve an instance for the given token or provider. | ||
* | ||
* @param value - The token or provider object to resolve. | ||
* | ||
* @returns A promise which resolves to an instance of the requested | ||
* type, or rejects if the instance fails to resolve for any reason. | ||
*/ | ||
export declare function resolve<T>(value: Token<T> | Provider<T>): Promise<T>; |
230
lib/index.js
@@ -52,76 +52,89 @@ /*----------------------------------------------------------------------------- | ||
/** | ||
* Test whether a token is registered. | ||
* | ||
* @param token - The run-time type token of interest. | ||
* | ||
* @returns `true` if the token is registered, `false` otherwise. | ||
* A lightweight dependency injection container. | ||
*/ | ||
function isRegistered(token) { | ||
return registry.has(token); | ||
} | ||
exports.isRegistered = isRegistered; | ||
var Container = (function () { | ||
function Container() { | ||
this._registry = createRegistry(); | ||
} | ||
/** | ||
* Test whether a token is registered with the container. | ||
* | ||
* @param token - The run-time type token of interest. | ||
* | ||
* @returns `true` if the token is registered, `false` otherwise. | ||
*/ | ||
Container.prototype.isRegistered = function (token) { | ||
return this._registry.has(token); | ||
}; | ||
/** | ||
* Register a type mapping for the specified token. | ||
* | ||
* @param token - The run-time type token of interest. | ||
* | ||
* @param factory - The factory which will create the instance. | ||
* | ||
* #### Notes | ||
* If the token is already registered, or if registering the factory | ||
* would cause a circular dependency, an error will be logged to the | ||
* console and the registration will be ignored. | ||
*/ | ||
Container.prototype.register = function (token, factory) { | ||
if (this._registry.has(token)) { | ||
logRegisterError(token); | ||
return; | ||
} | ||
var cycle = findCycle(this._registry, token, factory); | ||
if (cycle.length > 0) { | ||
logCycleError(token, cycle); | ||
return; | ||
} | ||
this._registry.set(token, createResolver(factory)); | ||
}; | ||
/** | ||
* Resolve an instance for the given token or factory. | ||
* | ||
* @param value - The token or factory object to resolve. | ||
* | ||
* @returns A promise which resolves to an instance of the requested | ||
* type, or rejects with an error if an instance fails to resolve. | ||
*/ | ||
Container.prototype.resolve = function (value) { | ||
var result; | ||
if (value instanceof Token) { | ||
result = resolveToken(this._registry, value); | ||
} | ||
else { | ||
result = resolveFactory(this._registry, value); | ||
} | ||
return Promise.resolve(result); | ||
}; | ||
return Container; | ||
})(); | ||
exports.Container = Container; | ||
/** | ||
* Register a type mapping for the specified token. | ||
* | ||
* @param token - The run-time type token of interest. | ||
* | ||
* @param provider - The object which will create the instance. | ||
* | ||
* #### Notes | ||
* If the token is already registered, or if registering the provider | ||
* would cause a circular dependency, an error will be logged to the | ||
* console and the registration will be ignored. | ||
* Create a new registry instance. | ||
*/ | ||
function register(token, provider) { | ||
if (checkRegistered(token)) | ||
return; | ||
if (checkCyclic(token, provider)) | ||
return; | ||
registry.set(token, createResolver(provider)); | ||
function createRegistry() { | ||
return new Map(); | ||
} | ||
exports.register = register; | ||
/** | ||
* Resolve an instance for the given token or provider. | ||
* | ||
* @param value - The token or provider object to resolve. | ||
* | ||
* @returns A promise which resolves to an instance of the requested | ||
* type, or rejects if the instance fails to resolve for any reason. | ||
* Log an error which indicates a token is already registered. | ||
*/ | ||
function resolve(value) { | ||
var result; | ||
if (value instanceof Token) { | ||
result = resolveToken(value); | ||
} | ||
else { | ||
result = resolveProvider(value); | ||
} | ||
return Promise.resolve(result); | ||
} | ||
exports.resolve = resolve; | ||
/** | ||
* The internal registry mapping tokens to resolvers. | ||
*/ | ||
var registry = new Map(); | ||
/** | ||
* Check and log an error if the token is registered. | ||
*/ | ||
function checkRegistered(token) { | ||
if (!registry.has(token)) | ||
return false; | ||
function logRegisterError(token) { | ||
console.error("Token '" + token.name + "' is already registered."); | ||
return true; | ||
} | ||
/** | ||
* Check and log an error if the provider causes a cycle. | ||
* Log an error which indicates a cycle was detected. | ||
*/ | ||
function checkCyclic(token, provider) { | ||
var cycle = findCycle(token, provider); | ||
if (cycle.length === 0) | ||
return false; | ||
function logCycleError(token, cycle) { | ||
var path = cycle.map(function (token) { return ("'" + token.name + "'"); }).join(' -> '); | ||
console.error("Cycle detected: '" + token.name + "' -> " + path + "."); | ||
return true; | ||
} | ||
/** | ||
* Create a rejected promise which indicates the token is unregistered. | ||
*/ | ||
function rejectUnregistered(token) { | ||
return Promise.reject(new Error("Unregistered token: '" + token.name + "'.")); | ||
} | ||
/** | ||
* Find a potential cycle in the registry from the given token. | ||
@@ -133,8 +146,8 @@ * | ||
*/ | ||
function findCycle(token, provider) { | ||
function findCycle(registry, token, factory) { | ||
var trace = []; | ||
visit(provider); | ||
visit(factory); | ||
return trace; | ||
function visit(value) { | ||
for (var _i = 0, _a = value.requires; _i < _a.length; _i++) { | ||
function visit(factory) { | ||
for (var _i = 0, _a = factory.requires; _i < _a.length; _i++) { | ||
var other = _a[_i]; | ||
@@ -146,3 +159,3 @@ trace.push(other); | ||
var resolver = registry.get(other); | ||
if (resolver && visit(resolver.provider)) { | ||
if (resolver && visit(resolver.factory)) { | ||
return true; | ||
@@ -156,18 +169,12 @@ } | ||
/** | ||
* Create a rejected promise which indicates the token is unregistered. | ||
* Resolve a token using the specified registry. | ||
*/ | ||
function rejectToken(token) { | ||
return Promise.reject(new Error("Unregistered token: '" + token.name + "'.")); | ||
} | ||
/** | ||
* Resolve the given token. | ||
*/ | ||
function resolveToken(token) { | ||
function resolveToken(registry, token) { | ||
var result; | ||
var resolver = registry.get(token); | ||
if (resolver) { | ||
result = resolver.resolve(); | ||
result = resolver.resolve(registry); | ||
} | ||
else { | ||
result = rejectToken(token); | ||
result = rejectUnregistered(token); | ||
} | ||
@@ -177,30 +184,7 @@ return result; | ||
/** | ||
* Resolve the given provider. | ||
* Resolve a factory using the specified registry. | ||
*/ | ||
function resolveProvider(provider) { | ||
var result; | ||
if (typeof provider === 'function') { | ||
result = resolveInjectable(provider); | ||
} | ||
else { | ||
result = resolveFactory(provider); | ||
} | ||
return result; | ||
} | ||
/** | ||
* Resolve the given injectable. | ||
*/ | ||
function resolveInjectable(injectable) { | ||
var promises = injectable.requires.map(resolveToken); | ||
function resolveFactory(registry, factory) { | ||
var promises = factory.requires.map(function (token) { return resolveToken(registry, token); }); | ||
return Promise.all(promises).then(function (dependencies) { | ||
var instance = Object.create(injectable.prototype); | ||
return injectable.apply(instance, dependencies) || instance; | ||
}); | ||
} | ||
/** | ||
* Resolve the given factory. | ||
*/ | ||
function resolveFactory(factory) { | ||
var promises = factory.requires.map(resolveToken); | ||
return Promise.all(promises).then(function (dependencies) { | ||
return factory.create.apply(factory, dependencies); | ||
@@ -210,11 +194,11 @@ }); | ||
/** | ||
* Create a resolver for the given provider and options. | ||
* Create a resolver for the given factory. | ||
*/ | ||
function createResolver(provider) { | ||
function createResolver(factory) { | ||
var result; | ||
if (provider.lifetime === Lifetime.Transient) { | ||
result = new TransientResolver(provider); | ||
if (factory.lifetime === Lifetime.Transient) { | ||
result = new TransientResolver(factory); | ||
} | ||
else { | ||
result = new SingletonResolver(provider); | ||
result = new SingletonResolver(factory); | ||
} | ||
@@ -230,11 +214,11 @@ return result; | ||
*/ | ||
function TransientResolver(provider) { | ||
this._provider = provider; | ||
function TransientResolver(factory) { | ||
this._factory = factory; | ||
} | ||
Object.defineProperty(TransientResolver.prototype, "provider", { | ||
Object.defineProperty(TransientResolver.prototype, "factory", { | ||
/** | ||
* The provider managed by the resolver. | ||
* The factory managed by the resolver. | ||
*/ | ||
get: function () { | ||
return this._provider; | ||
return this._factory; | ||
}, | ||
@@ -245,6 +229,6 @@ enumerable: true, | ||
/** | ||
* Resolve an instance of the type from the provider. | ||
* Resolve an instance of the type from the factory. | ||
*/ | ||
TransientResolver.prototype.resolve = function () { | ||
return resolveProvider(this._provider); | ||
TransientResolver.prototype.resolve = function (registry) { | ||
return resolveFactory(registry, this._factory); | ||
}; | ||
@@ -260,14 +244,14 @@ return TransientResolver; | ||
*/ | ||
function SingletonResolver(provider) { | ||
function SingletonResolver(factory) { | ||
this._value = null; | ||
this._resolved = false; | ||
this._promise = null; | ||
this._provider = provider; | ||
this._factory = factory; | ||
} | ||
Object.defineProperty(SingletonResolver.prototype, "provider", { | ||
Object.defineProperty(SingletonResolver.prototype, "factory", { | ||
/** | ||
* The provider managed by the resolver. | ||
* The factory managed by the resolver. | ||
*/ | ||
get: function () { | ||
return this._provider; | ||
return this._factory; | ||
}, | ||
@@ -278,5 +262,5 @@ enumerable: true, | ||
/** | ||
* Resolve an instance of the type from the provider. | ||
* Resolve an instance of the type from the factory. | ||
*/ | ||
SingletonResolver.prototype.resolve = function () { | ||
SingletonResolver.prototype.resolve = function (registry) { | ||
var _this = this; | ||
@@ -289,3 +273,3 @@ if (this._resolved) { | ||
} | ||
var promise = resolveProvider(this._provider).then(function (value) { | ||
this._promise = resolveFactory(registry, this._factory).then(function (value) { | ||
_this._value = value; | ||
@@ -299,3 +283,3 @@ _this._promise = null; | ||
}); | ||
return this._promise = promise; | ||
return this._promise; | ||
}; | ||
@@ -302,0 +286,0 @@ return SingletonResolver; |
{ | ||
"name": "phosphor-di", | ||
"version": "0.0.2", | ||
"version": "0.9.0", | ||
"description": "A lightweight module for asynchronous dependency injection.", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -66,2 +66,3 @@ phosphor-di | ||
- Node 0.12.7+ | ||
- IE 11+ | ||
@@ -68,0 +69,0 @@ - Firefox 32+ |
86
15652
367