sipp
Version:
An Opinionated, High-Productivity MVC Web Framework in TypeScript
99 lines • 4.15 kB
JavaScript
;
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