UNPKG

redux-providers

Version:

Minimalist dependency injection system for redux. Create providers to be injected and used in redux reducers.

74 lines (62 loc) 2.86 kB
import "reflect-metadata"; import { Constructable } from "../types/constructable"; import { METADATA_KEY } from "../constants/metadata.keys"; import { InstanceContainer } from "../container/instance-container"; import { ActionHandler } from "../decorators/action/action"; import { Provider } from "../decorators/provider/provider"; export namespace Resolver { /** * Resolve provided target class (either @Provider or @ReduxAction) * * @param target the target to resolve * @param container the container to keep the instance in * @param parentModuleName name of the module the target is provided in (used i.e. for error messages) */ export function resolve<T>(target: Constructable<T>, container: InstanceContainer, parentModuleName: string): T { const isProvider = Reflect.hasOwnMetadata(METADATA_KEY.PROVIDER_PARAM_TYPES, target); if (isProvider) { return resolveProvider<T>(target, container, parentModuleName); } const isReduxAction = Reflect.hasOwnMetadata(METADATA_KEY.ACTION_HANDLER_PARAM_TYPES, target); if (isReduxAction) { return resolveAction<T>(target, container, parentModuleName); } const allowedDecorators = [Provider.name, ActionHandler.name]; throw new Error("Target must be one of " + allowedDecorators + "!"); } function resolveProvider<T>(target: Constructable<T>, container: InstanceContainer, parentModuleName: string): T { if (!Reflect.hasOwnMetadata(METADATA_KEY.PROVIDER_PARAM_TYPES, target)) { throw new Error("Attempting to resolve target with name: " + target.name + ". " + target.name + " is not a provider in module: " + parentModuleName + "!"); } if (containerHasElement(container, target.name)) { return container.get(target.name); } let designParamTypes = Reflect.getMetadata(METADATA_KEY.PROVIDER_PARAM_TYPES, target) || []; let injections = designParamTypes.map((token: Constructable<T>) => { return resolveProvider<T>(token, container, parentModuleName); }); let newInstance = new target(...injections); container.add(target.name, newInstance); return newInstance; } function resolveAction<T>(target: Constructable<T>, container: InstanceContainer, parentModuleName: string): T { if (containerHasElement(container, target.name)) { return container.get(target.name); } let reducActionDesignParamTypes = Reflect.getMetadata(METADATA_KEY.ACTION_HANDLER_PARAM_TYPES, target) || []; let injections = reducActionDesignParamTypes.map((token: Constructable<T>) => { return resolve<T>(token, container, parentModuleName); }); let newInstance = new target(...injections); container.add(target.name, newInstance); return newInstance; } function containerHasElement(container: InstanceContainer, instanceIdentifier: string) { try { container.get(instanceIdentifier); return true; } catch (e) { return false; } } }