aurelia-dependency-injection
Version:
A lightweight, extensible dependency injection container for JavaScript.
128 lines (113 loc) • 4.37 kB
text/typescript
import './internal';
import { metadata } from 'aurelia-metadata';
import { Container } from './container';
import { DependencyCtorOrFunctor, ImplOrAny, Impl, Args, DependencyCtor, DependencyFunctor } from './types';
/**
* Decorator: Specifies a custom Invoker for the decorated item.
*/
export function invoker<TBase, TImpl extends Impl<TBase>, TArgs extends Args<TBase>>(
value: Invoker<TBase, TImpl, TArgs>
): (target: DependencyCtor<TBase, TImpl, TArgs>) => void {
return target => {
metadata.define(metadata.invoker, value, target);
};
}
/**
* Decorator: Specifies that the decorated item should be called as a factory
* function, rather than a constructor.
*/
export function invokeAsFactory<TBase, TImpl extends Impl<TBase>, TArgs extends Args<TBase>>(
potentialTarget?: DependencyCtor<TBase, TImpl, TArgs>
): void | ((target: DependencyCtor<TBase, TImpl, TArgs>) => void) {
const deco = (target: DependencyCtor<TBase, TImpl, TArgs>) => {
metadata.define(metadata.invoker, FactoryInvoker.instance, target);
};
return potentialTarget ? deco(potentialTarget) : deco;
}
/**
* A strategy for invoking a function, resulting in an object instance.
*/
export interface Invoker<TBase, TImpl extends Impl<TBase>, TArgs extends Args<TBase>> {
/**
* Invokes the function with the provided dependencies.
* @param fn The constructor or factory function.
* @param dependencies The dependencies of the function call.
* @return The result of the function invocation.
*/
invoke(
container: Container,
fn: DependencyCtorOrFunctor<TBase, TImpl, TArgs>,
dependencies: TArgs
): ImplOrAny<TImpl>;
/**
* Invokes the function with the provided dependencies.
* @param fn The constructor or factory function.
* @param staticDependencies The static dependencies of the function.
* @param dynamicDependencies Additional dependencies to use during
* invocation.
* @return The result of the function invocation.
*/
invokeWithDynamicDependencies(
container: Container,
fn: DependencyCtorOrFunctor<TBase, TImpl, TArgs>,
staticDependencies: TArgs[number][],
dynamicDependencies: TArgs[number][]
): ImplOrAny<TImpl>;
}
/**
* An Invoker that is used to invoke a factory method.
*/
export class FactoryInvoker<
TBase,
TImpl extends Impl<TBase> = Impl<TBase>,
TArgs extends Args<TBase> = Args<TBase>
> implements Invoker<TBase, TImpl, TArgs> {
/**
* The singleton instance of the FactoryInvoker.
*/
public static instance: FactoryInvoker<any>;
/**
* Invokes the function with the provided dependencies.
* @param container The calling container.
* @param fn The constructor or factory function.
* @param dependencies The dependencies of the function call.
* @return The result of the function invocation.
*/
public invoke(
container: Container,
fn: DependencyCtorOrFunctor<TBase, TImpl, TArgs>,
dependencies: TArgs
): ImplOrAny<TImpl> {
let i = dependencies.length;
const args = new Array(i);
while (i--) {
args[i] = container.get(dependencies[i]);
}
return ((fn as DependencyFunctor<TBase, TImpl, TArgs>).apply(undefined, args as TArgs)) as ImplOrAny<TImpl>;
}
/**
* Invokes the function with the provided dependencies.
* @param container The calling container.
* @param fn The constructor or factory function.
* @param staticDependencies The static dependencies of the function.
* @param dynamicDependencies Additional dependencies to use during invocation.
* @return The result of the function invocation.
*/
public invokeWithDynamicDependencies(
container: Container,
fn: DependencyCtorOrFunctor<TBase, TImpl, TArgs>,
staticDependencies: TArgs[number][],
dynamicDependencies: TArgs[number][]
): ImplOrAny<TImpl> {
let i = staticDependencies.length;
let args = new Array(i);
while (i--) {
args[i] = container.get(staticDependencies[i]);
}
if (dynamicDependencies !== undefined) {
args = args.concat(dynamicDependencies);
}
return (fn as DependencyFunctor<TBase, TImpl, TArgs>).apply(undefined, args as TArgs) as ImplOrAny<TImpl>;
}
}
FactoryInvoker.instance = new FactoryInvoker();