UNPKG

injectx

Version:

A dependency injection package for javascript/typescript functional programming

147 lines (146 loc) 5.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SetDefaultContainer = exports.InjectIn = exports.GetContainer = exports.Container = exports.SupportedInjectableService = void 0; require("reflect-metadata"); var SupportedInjectableService; (function (SupportedInjectableService) { SupportedInjectableService["function"] = "function"; SupportedInjectableService["class"] = "class"; SupportedInjectableService["object"] = "object"; SupportedInjectableService["other"] = "other"; })(SupportedInjectableService = exports.SupportedInjectableService || (exports.SupportedInjectableService = {})); function isClass(v) { const result = typeof v === 'function' && /^\s*class\s+/.test(v.toString()); return result; } function getInjectableType(param) { if (typeof param === 'function' && !isClass(param)) { return SupportedInjectableService.function; } else if (typeof param === 'function' && param !== null && param.constructor && param.constructor.name === 'Function' && isClass(param)) { return SupportedInjectableService.class; } else if (typeof param === 'object' && param !== null) { return SupportedInjectableService.object; } else { return SupportedInjectableService.other; } } var Scope; (function (Scope) { Scope["singleton"] = "singleton"; Scope["scoped"] = "scoped"; })(Scope || (Scope = {})); class Container { constructor(name) { this.dependencies = new Map(); this.name = name.toString(); } Bind(service, options = {}) { if (service === undefined) { return this; } const key = options.name || service?.name; const injectableType = getInjectableType(service); const settings = { name: key, service, scope: options.scope || Scope.singleton, type: injectableType, }; this.dependencies.set(key, settings); return this; } resolve(name) { const service = this.dependencies.get(name); if (!service) { return null; } let instance; if (service.type === SupportedInjectableService.class && service.scope === Scope.singleton && !service.instance) { const dependencies = (service.service.constructor.prototype.constructorDependencies || []).map((name) => this.resolve(name)); if (dependencies?.length > 0) { instance = new service.service(...dependencies); } else { instance = new service.service(); } const propDependencies = service.service.constructor.prototype.propDependencies || new Map(); propDependencies.forEach((value, key) => { instance[key] = this.resolve(value); }); service.instance = instance; } else { instance = service.service; } return instance; } resolveAll() { const dependencies = {}; this.dependencies.forEach((value, key) => { dependencies[key.toString()] = this.resolve(key); }); return dependencies; } } exports.Container = Container; function resolveDependencies(containerNames, args) { const diContainers = containerNames.map((containerName) => GetContainer(containerName)); const dependencies = diContainers.length === 1 ? diContainers[0].resolveAll() : diContainers.reduce((acc, container) => { acc[container.name] = container.resolveAll(); return acc; }, {}); const mergedArgs = [{ ...dependencies }, ...args]; return mergedArgs; } class InjectX { } InjectX.containers = new Map(); InjectX.defaultContainerName = 'default'; function GetContainer(container = InjectX.defaultContainerName) { if (!InjectX.containers.has(container.toString())) { InjectX.containers.set(container, new Container(container.toString())); } return InjectX.containers.get(container); } exports.GetContainer = GetContainer; function InjectIn(callback, options) { const serializedCallbackName = callback.name ?.replace?.('_', '') ?.split('') .map?.((char, i) => (i === 0 ? char.toLowerCase() : char)) ?.join('') || callback.name; const callbackName = options?.callbackName || serializedCallbackName; const containerNames = options?.containers || []; if (containerNames.length < 1) { containerNames.push(InjectX.defaultContainerName); } const wrappedCallback = (...args) => { const mergedArgs = resolveDependencies(containerNames, args); const result = callback(...mergedArgs); if (typeof result === 'function') { return result(...args); } return result; }; Object.defineProperty(wrappedCallback, 'name', { value: callbackName, writable: false, }); return wrappedCallback; } exports.InjectIn = InjectIn; function SetDefaultContainer(name) { InjectX.defaultContainerName = name.toString(); } exports.SetDefaultContainer = SetDefaultContainer;