1- type Provider < T = any > = {
2- factory : ( ) => T ;
3- lifetime : "singleton" | "transient" ;
4- } ;
1+ import type { Factory , Lifetime } from "@/types" ;
2+
3+ interface Dependency < T = any > {
4+ lifetime : Lifetime ;
5+ factory : Factory < T > ;
6+ instance ?: T ;
7+ }
58
69export class Container {
7- private static registry = new Map < unknown , Provider > ( ) ;
8- private static instances = new WeakMap < object , unknown > ( ) ;
9- private static resolutionStack : unknown [ ] = [ ] ; // Track resolution path for circular dependencies
10+ private static dependencies = new WeakMap < object , Dependency > ( ) ;
1011
1112 static register < T > (
12- token : unknown ,
13- factory : ( ) => T ,
14- lifetime : "singleton" | "transient" = "singleton"
13+ token : object ,
14+ factory : Factory < T > ,
15+ lifetime : Lifetime = "singleton"
1516 ) {
16- this . registry . set ( token , { factory, lifetime } ) ;
17+ this . dependencies . set ( token , { factory, lifetime } ) ;
1718 }
1819
19- static resolve < T > ( token : T ) : T {
20- // Detect circular dependencies
21- if ( this . resolutionStack . includes ( token ) ) {
22- const cycleStart = this . resolutionStack . indexOf ( token ) ;
23- const cyclePath = [
24- ...this . resolutionStack . slice ( cycleStart ) ,
25- token
26- ] . map ( t => this . getTokenName ( t ) ) . join ( ' -> ' ) ;
27-
28- throw new Error ( `Circular dependency detected: ${ cyclePath } ` ) ;
29- }
30-
20+ static resolve < T extends object > ( token : T ) : T {
3121 try {
32- this . resolutionStack . push ( token ) ;
33- const provider = this . registry . get ( token ) ;
34- if ( ! provider ) { throw new Error ( `No provider for token: ${ String ( token ) } ` ) ; } ;
35-
36- // Handle singleton lifetime
37- if ( provider . lifetime === "singleton" ) {
38- if ( ! this . instances . has ( token as object ) ) {
39- this . instances . set ( token as object , provider . factory ( ) ) ;
22+ const dep = this . dependencies . get ( token ) ;
23+ if ( ! dep ) {
24+ throw new Error ( `Dependency ${ token } not registered` ) ;
25+ }
26+
27+ if ( dep . lifetime === "singleton" ) {
28+ if ( ! dep . instance ) {
29+ dep . instance = dep . factory ( ) ;
4030 }
41- return this . instances . get ( token as object ) as T ;
31+ return dep . instance ;
4232 }
4333
44- // Transient lifetime
45- return provider . factory ( ) as T ;
46- } finally {
47- // Clean up stack even if errors occur
48- this . resolutionStack . pop ( ) ;
34+ return dep . factory ( ) ;
35+ } catch ( error ) {
36+ if ( error instanceof Error ) {
37+ throw new Error ( `Error resolving ${ token } : ${ error . message } ` ) ;
38+ }
39+ throw error ;
4940 }
5041 }
5142
52- private static getTokenName ( token : unknown ) : string {
53- if ( typeof token === 'function' ) { return token . name || 'AnonymousClass' ; } ;
54- if ( typeof token === 'symbol' ) { return token . toString ( ) ; } ;
55- return String ( token ) ;
43+ static async resolveAsync < T > ( token : object ) : Promise < T > {
44+ const dep = this . dependencies . get ( token ) ;
45+ if ( ! dep ) {
46+ throw new Error ( `Dependency ${ token } not found` ) ;
47+ } ;
48+
49+ if ( dep . lifetime === "singleton" ) {
50+ if ( ! dep . instance ) {
51+ dep . instance = await dep . factory ( ) ;
52+ }
53+ return dep . instance ;
54+ }
55+
56+ return await dep . factory ( ) ;
5657 }
5758}
0 commit comments