@wizecorp/stratusjs
Version:
Stratus React Framework
175 lines • 5.84 kB
JavaScript
/**
* Dependency injection container for services
*/
export class ServiceContainer {
constructor() {
Object.defineProperty(this, "services", {
enumerable: true,
configurable: true,
writable: true,
value: new Map()
});
Object.defineProperty(this, "factories", {
enumerable: true,
configurable: true,
writable: true,
value: new Map()
});
Object.defineProperty(this, "singletons", {
enumerable: true,
configurable: true,
writable: true,
value: new Set()
});
Object.defineProperty(this, "initializing", {
enumerable: true,
configurable: true,
writable: true,
value: new Set()
});
}
/**
* Register a service or factory in the container
*/
register(token, serviceOrFactory, options = {}) {
const { singleton = true } = options;
if (typeof serviceOrFactory === 'function' && !this.isServiceInstance(serviceOrFactory)) {
// It's a factory function
this.factories.set(token, serviceOrFactory);
}
else {
// It's a service instance
this.services.set(token, serviceOrFactory);
}
if (singleton) {
this.singletons.add(token);
}
}
/**
* Get a service synchronously
*/
get(token) {
// Check if already instantiated
if (this.services.has(token)) {
return this.services.get(token);
}
// Check if we have a factory
if (this.factories.has(token)) {
const factory = this.factories.get(token);
const service = factory();
if (service instanceof Promise) {
throw new Error(`Service "${String(token)}" is async and requires getAsync(). Use await container.getAsync("${String(token)}") instead.`);
}
// Cache if singleton
if (this.singletons.has(token)) {
this.services.set(token, service);
}
return service;
}
// Try to instantiate if it's a constructor
if (typeof token === 'function') {
const service = new token();
if (this.singletons.has(token)) {
this.services.set(token, service);
}
return service;
}
throw new Error(`Service "${String(token)}" not found. Make sure it's registered in the container.`);
}
/**
* Get a service asynchronously (supports async factories)
*/
async getAsync(token) {
// Prevent circular dependencies
if (this.initializing.has(token)) {
throw new Error(`Circular dependency detected for service "${String(token)}"`);
}
// Check if already instantiated
if (this.services.has(token)) {
return this.services.get(token);
}
this.initializing.add(token);
try {
// Check if we have a factory
if (this.factories.has(token)) {
const factory = this.factories.get(token);
const service = await factory();
// Cache if singleton
if (this.singletons.has(token)) {
this.services.set(token, service);
}
// Initialize service if it has an initialize method
if (service && typeof service.initialize === 'function') {
await service.initialize();
}
return service;
}
// Try to instantiate if it's a constructor
if (typeof token === 'function') {
const service = new token();
if (this.singletons.has(token)) {
this.services.set(token, service);
}
// Initialize service if it has an initialize method
if (service && typeof service.initialize === 'function') {
await service.initialize();
}
return service;
}
throw new Error(`Service "${String(token)}" not found. Make sure it's registered in the container.`);
}
finally {
this.initializing.delete(token);
}
}
/**
* Check if a service is registered
*/
has(token) {
return this.services.has(token) || this.factories.has(token);
}
/**
* Remove a service from the container
*/
remove(token) {
const service = this.services.get(token);
// Call destroy if the service has it
if (service && typeof service.destroy === 'function') {
service.destroy();
}
this.services.delete(token);
this.factories.delete(token);
this.singletons.delete(token);
}
/**
* Clear all services
*/
clear() {
// Destroy all services that have a destroy method
for (const service of this.services.values()) {
if (service && typeof service.destroy === 'function') {
service.destroy();
}
}
this.services.clear();
this.factories.clear();
this.singletons.clear();
this.initializing.clear();
}
/**
* Get all registered service tokens
*/
getTokens() {
return [
...Array.from(this.services.keys()),
...Array.from(this.factories.keys())
];
}
/**
* Check if value is a service instance (has name property)
*/
isServiceInstance(value) {
return value && typeof value === 'object' && 'name' in value;
}
}
//# sourceMappingURL=ServiceContainer.js.map