78 lines
1.7 KiB
JavaScript
78 lines
1.7 KiB
JavaScript
class Container {
|
|
constructor() {
|
|
this._services = new Map();
|
|
this._singletons = new Map();
|
|
this._resolving = new Set();
|
|
}
|
|
|
|
register(name, factory, isSingleton = true) {
|
|
if (typeof name !== 'string' || name.trim() === '') {
|
|
throw new Error('Service name must be a non-empty string');
|
|
}
|
|
if (typeof factory !== 'function') {
|
|
throw new Error('Factory must be a function');
|
|
}
|
|
if (this._services.has(name)) {
|
|
throw new Error(`Service "${name}" is already registered`);
|
|
}
|
|
|
|
this._services.set(name, { factory, isSingleton });
|
|
return this;
|
|
}
|
|
|
|
resolve(name) {
|
|
if (!this._services.has(name)) {
|
|
throw new Error(`Service "${name}" is not registered`);
|
|
}
|
|
|
|
if (this._resolving.has(name)) {
|
|
const chain = Array.from(this._resolving).join(' -> ');
|
|
throw new Error(
|
|
`Circular dependency detected: ${chain} -> ${name}. ` +
|
|
`This creates a circular reference that cannot be resolved.`
|
|
);
|
|
}
|
|
|
|
const service = this._services.get(name);
|
|
|
|
if (service.isSingleton && this._singletons.has(name)) {
|
|
return this._singletons.get(name);
|
|
}
|
|
|
|
this._resolving.add(name);
|
|
|
|
try {
|
|
const instance = service.factory(this);
|
|
|
|
if (service.isSingleton) {
|
|
this._singletons.set(name, instance);
|
|
}
|
|
|
|
return instance;
|
|
} finally {
|
|
this._resolving.delete(name);
|
|
}
|
|
}
|
|
|
|
has(name) {
|
|
return this._services.has(name);
|
|
}
|
|
|
|
unregister(name) {
|
|
if (!this._services.has(name)) {
|
|
return false;
|
|
}
|
|
this._services.delete(name);
|
|
this._singletons.delete(name);
|
|
return true;
|
|
}
|
|
|
|
clear() {
|
|
this._services.clear();
|
|
this._singletons.clear();
|
|
this._resolving.clear();
|
|
}
|
|
}
|
|
|
|
module.exports = Container;
|