UNPKG

sipp

Version:

An Opinionated, High-Productivity MVC Web Framework in TypeScript

99 lines 4.15 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.registry = exports.ServiceRegistry = void 0; const utils_1 = require("../../utils"); const ParamNotResolveable_1 = require("../../exceptions/ParamNotResolveable"); class ServiceRegistry { constructor() { this.serviceMap = new Map(); this.resolutionCache = new Map(); this.globalProviders = []; } async resolve(obj, Type) { const Constructor = obj.constructor; const providers = this.getProvidersFor(Constructor); if (!providers.length) { throw new ParamNotResolveable_1.ParamNotResolveable(`Class ${Constructor.name} has no registered providers.`); } const resolve = async (Type) => { const typeFactories = this.filterProvidersForType(providers, Type); if (!typeFactories.length) { throw new ParamNotResolveable_1.ParamNotResolveable(`Class ${Type.name} has no registered resolution factories.`); } for (let i = 0, n = providers.length; i < n; i++) { const typeFactory = typeFactories[i]; if (!typeFactory) { continue; } const resolution = await typeFactories[i](resolve, Type); if (resolution !== undefined) { return resolution; } } throw new ParamNotResolveable_1.ParamNotResolveable(`Class ${Type.name} has registered service providers, but they did not return a defined value for ${Type.name}.`); }; return resolve(Type); } filterProvidersForType(providers, Type) { return (providers .filter(([ResolverType]) => { return utils_1.compareClasses(Type, ResolverType); }) .sort(([AResolverType], [BResolverType]) => { const isADirectMatch = AResolverType === Type; const isBDirectMatch = BResolverType === Type; if ((isADirectMatch && isBDirectMatch) || (!isADirectMatch && !isBDirectMatch)) { return 0; } return isADirectMatch ? -1 : 1; }) .map(([_, resolveFunction]) => resolveFunction)); } registerProviders(providers) { providers.forEach((provider) => { provider.register((ConstructorScope, Type, factoryFn) => { this.registerFor(ConstructorScope, Type, factoryFn); }); }); } getProvidersFor(ObjectClass) { if (!this.resolutionCache.has(ObjectClass)) { const directServiceProvidersForClass = this.serviceMap.get(ObjectClass) || []; const indirectServiceProvidersForClass = this.getIndirectProviders(ObjectClass); this.resolutionCache.set(ObjectClass, [ ...directServiceProvidersForClass, ...indirectServiceProvidersForClass, ...this.globalProviders, ]); } return this.resolutionCache.get(ObjectClass); } registerFor(ProvidedClasses, Type, fn) { if (ProvidedClasses === '*') { this.globalProviders.push([Type, fn]); return; } Array.isArray(ProvidedClasses) ? ProvidedClasses.map((ProvidedClass) => this.addToRegistry(ProvidedClass, [Type, fn])) : this.addToRegistry(ProvidedClasses, [Type, fn]); } getIndirectProviders(ObjectClass) { const indirect = []; this.serviceMap.forEach((fns, ProvidedClass) => { if (ObjectClass !== ProvidedClass && utils_1.compareClasses(ObjectClass, ProvidedClass)) { indirect.push(...fns); } }); return indirect; } addToRegistry(ProvidedClass, typeProvider) { const providers = this.serviceMap.get(ProvidedClass) || []; providers.push(typeProvider); this.serviceMap.set(ProvidedClass, providers); } } exports.ServiceRegistry = ServiceRegistry; exports.registry = new ServiceRegistry(); //# sourceMappingURL=ServiceRegistry.js.map