awilix-manager
Version:
Wrapper over awilix to support more complex use-cases, such as async init and eager injection
157 lines (156 loc) • 6.09 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwilixManager = void 0;
exports.asMockClass = asMockClass;
exports.asMockValue = asMockValue;
exports.asMockFunction = asMockFunction;
exports.asyncInit = asyncInit;
exports.eagerInject = eagerInject;
exports.getWithTags = getWithTags;
exports.getByPredicate = getByPredicate;
exports.asyncDispose = asyncDispose;
const awilix_1 = require("awilix");
function asMockClass(Type, opts) {
return (0, awilix_1.asClass)(Type, opts);
}
function asMockValue(value) {
return (0, awilix_1.asValue)(value);
}
function asMockFunction(fn, opts) {
return (0, awilix_1.asFunction)(fn, opts);
}
class AwilixManager {
config;
constructor(config) {
this.config = config;
if (config.strictBooleanEnforced) {
for (const entry of Object.entries(config.diContainer.registrations)) {
const [dependencyName, config] = entry;
if ('enabled' in config && config.enabled !== true && config.enabled !== false) {
throw new Error(`Invalid config for ${dependencyName}. "enabled" field can only be set to true or false, or omitted`);
}
}
}
}
async executeInit() {
if (this.config.eagerInject) {
eagerInject(this.config.diContainer);
}
if (this.config.asyncInit) {
await asyncInit(this.config.diContainer);
}
}
async executeDispose() {
await asyncDispose(this.config.diContainer);
}
getWithTags(tags) {
return getWithTags(this.config.diContainer, tags);
}
getByPredicate(predicate) {
return getByPredicate(this.config.diContainer, predicate);
}
}
exports.AwilixManager = AwilixManager;
async function asyncInit(diContainer) {
const dependenciesWithAsyncInit = Object.entries(diContainer.registrations)
.filter((entry) => {
return entry[1].asyncInit && entry[1].enabled !== false;
})
.sort((entry1, entry2) => {
const [key1, resolver1] = entry1;
const [key2, resolver2] = entry2;
const asyncInitPriority1 = resolver1.asyncInitPriority ?? 1;
const asyncInitPriority2 = resolver2.asyncInitPriority ?? 1;
if (asyncInitPriority1 !== asyncInitPriority2) {
return asyncInitPriority1 - asyncInitPriority2;
}
return key1.localeCompare(key2);
});
for (const [key, description] of dependenciesWithAsyncInit) {
const resolvedValue = diContainer.resolve(key);
// use default asyncInit method
if (description.asyncInit === true) {
if (!('asyncInit' in resolvedValue)) {
throw new Error(`Method asyncInit does not exist on dependency ${key}`);
}
await resolvedValue.asyncInit(diContainer.cradle);
continue;
}
// use function asyncInit
if (typeof description.asyncInit === 'function') {
await description.asyncInit(resolvedValue, diContainer);
continue;
}
// @ts-expect-error
if (!(description.asyncInit in resolvedValue)) {
throw new Error(`Method ${description.asyncInit} for asyncInit does not exist on dependency ${key}`);
}
// @ts-expect-error
await resolvedValue[description.asyncInit](diContainer.cradle);
}
}
function eagerInject(diContainer) {
const dependenciesWithEagerInject = Object.entries(diContainer.registrations).filter(([_key, description]) => {
return description.eagerInject && description.enabled !== false;
});
for (const [key, description] of dependenciesWithEagerInject) {
const resolvedComponent = diContainer.resolve(key);
if (typeof description.eagerInject === 'string') {
resolvedComponent[description.eagerInject]();
}
}
}
function getWithTags(diContainer, tags) {
const dependenciesWithTags = Object.entries(diContainer.registrations).filter(([_key, description]) => {
return (description.enabled !== false &&
tags.every((v) => description.tags && description.tags.includes(v)));
});
const resolvedComponents = {};
for (const [key] of dependenciesWithTags) {
resolvedComponents[key] = diContainer.resolve(key);
}
return resolvedComponents;
}
function getByPredicate(diContainer, predicate) {
const enabledDependencies = Object.entries(diContainer.registrations).filter(([_key, description]) => {
return description.enabled !== false;
});
const resolvedComponents = {};
for (const [key] of enabledDependencies) {
const resolvedElement = diContainer.resolve(key);
if (predicate(resolvedElement)) {
resolvedComponents[key] = resolvedElement;
}
}
return resolvedComponents;
}
async function asyncDispose(diContainer) {
const dependenciesWithAsyncDispose = Object.entries(diContainer.registrations)
.filter(([_key, description]) => {
return description.asyncDispose && description.enabled !== false;
})
.sort((entry1, entry2) => {
const [key1, resolver1] = entry1;
const [key2, resolver2] = entry2;
const asyncDisposePriority1 = resolver1.asyncDisposePriority ?? 1;
const asyncDisposePriority2 = resolver2.asyncDisposePriority ?? 1;
if (asyncDisposePriority1 !== asyncDisposePriority2) {
return asyncDisposePriority1 - asyncDisposePriority2;
}
return key1.localeCompare(key2);
});
for (const [key, description] of dependenciesWithAsyncDispose) {
const resolvedValue = diContainer.resolve(key);
const asyncDispose = description.asyncDispose;
if (typeof asyncDispose === 'function') {
await asyncDispose(resolvedValue);
continue;
}
if (asyncDispose === true) {
await resolvedValue.asyncDispose();
continue;
}
// @ts-ignore
await resolvedValue[asyncDispose]();
}
}
;