di-tory
Version:
Compose applications with dependency injection
141 lines (140 loc) • 5.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Module = exports.scope = void 0;
const Stack_js_1 = require("../stack/Stack.js");
const DependencyResolutionError_js_1 = require("../DependencyResolutionError.js");
exports.scope = {
module: 'module',
singleton: 'singleton',
};
const createModule = (singletons, privateResolvers, publicResolvers, initializers, params) => {
const resolvers = Object.assign(Object.assign({}, privateResolvers), publicResolvers);
const resolutionStack = new Stack_js_1.Stack();
const moduleInstances = new Map();
const self = {};
const module = {};
for (const name of Object.keys(privateResolvers)) {
Object.defineProperty(self, name, {
get: () => resolve(name),
});
Object.defineProperty(module, name, {
get: () => {
throw new DependencyResolutionError_js_1.DependencyResolutionError(DependencyResolutionError_js_1.DependencyResolutionErrorCode.PrivateMemberAccessFailure, resolutionStack.toStringArray(), String(name));
},
});
}
for (const name of Object.keys(publicResolvers)) {
Object.defineProperty(self, name, {
get: () => resolve(name),
});
Object.defineProperty(module, name, {
get: () => resolve(name),
});
}
const resolve = (name) => {
var _a;
const resolver = resolvers[name];
const instances = resolver.scope === 'singleton' ? singletons : moduleInstances;
if (instances.has(name))
return instances.get(name);
const currentStack = resolutionStack.toStringArray();
try {
resolutionStack.push(name);
}
catch (_b) {
throw new DependencyResolutionError_js_1.DependencyResolutionError(DependencyResolutionError_js_1.DependencyResolutionErrorCode.CircularDependencyFailure, resolutionStack.toStringArray(), String(name));
}
let instance;
try {
instance = resolver(self, params);
}
catch (err) {
if (err instanceof DependencyResolutionError_js_1.DependencyResolutionError)
throw err;
throw new DependencyResolutionError_js_1.DependencyResolutionError(DependencyResolutionError_js_1.DependencyResolutionErrorCode.InstantiationFailure, currentStack, String(name), err);
}
resolutionStack.pop();
instances.set(name, instance);
if (resolutionStack.length === 0) {
(_a = initializers[name]) === null || _a === void 0 ? void 0 : _a.call(instance, self, params);
}
return instance;
};
return module;
};
const Module = () => {
const privateResolvers = {};
const publicResolvers = {};
let initializers = null;
let sealed = false;
const singletons = new Map();
const self = {
private(resolvers, scope) {
var _a;
if (sealed) {
throw new Error('Cannot extend initialized module');
}
for (const name of Object.keys(resolvers)) {
const resolver = resolvers[name];
if (typeof resolver !== 'function') {
throw new Error(`Expected ${String(name)} to be a function, but got ${typeof resolver}`);
}
(_a = resolver.scope) !== null && _a !== void 0 ? _a : (resolver.scope = scope);
privateResolvers[name] = resolver;
}
return self;
},
privateImpl(implementation) {
if (sealed) {
throw new Error('Cannot extend initialized module');
}
for (const name of Object.keys(implementation)) {
const method = implementation[name];
const resolver = (moduleInstance) => (...args) => method(moduleInstance, ...args);
resolver.scope = 'module';
privateResolvers[name] = resolver;
}
return self;
},
public(resolvers, scope) {
var _a;
if (sealed) {
throw new Error('Cannot extend initialized module');
}
for (const name of Object.keys(resolvers)) {
const resolver = resolvers[name];
if (typeof resolver !== 'function') {
throw new Error(`Expected ${String(name)} to be a function, but got ${typeof resolver}`);
}
(_a = resolver.scope) !== null && _a !== void 0 ? _a : (resolver.scope = scope);
publicResolvers[name] = resolver;
}
return self;
},
publicImpl(implementation) {
if (sealed) {
throw new Error('Cannot extend initialized module');
}
for (const name of Object.keys(implementation)) {
const method = implementation[name];
const resolver = (moduleInstance) => (...args) => method(moduleInstance, ...args);
resolver.scope = 'module';
publicResolvers[name] = resolver;
}
return self;
},
init(initializer) {
initializers = initializer;
sealed = true;
return self;
},
create(params = {}) {
sealed = true;
return createModule(singletons, privateResolvers, publicResolvers, initializers !== null && initializers !== void 0 ? initializers : {}, params);
},
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return self;
};
exports.Module = Module;
exports.default = exports.Module;