@@ -28,6 +28,7 @@ import Lifecycle from "./types/lifecycle";
28
28
import ResolutionContext from "./resolution-context" ;
29
29
import { formatErrorCtor } from "./error-helpers" ;
30
30
import { DelayedConstructor } from "./lazy-helpers" ;
31
+ import Disposable , { isDisposable } from "./types/disposable" ;
31
32
import InterceptorOptions from "./types/interceptor-options" ;
32
33
import Interceptors from "./interceptors" ;
33
34
@@ -45,6 +46,8 @@ export const typeInfo = new Map<constructor<any>, ParamInfo[]>();
45
46
class InternalDependencyContainer implements DependencyContainer {
46
47
private _registry = new Registry ( ) ;
47
48
private interceptors = new Interceptors ( ) ;
49
+ private disposed = false ;
50
+ private disposables = new Set < Disposable > ( ) ;
48
51
49
52
public constructor ( private parent ?: InternalDependencyContainer ) { }
50
53
@@ -81,6 +84,8 @@ class InternalDependencyContainer implements DependencyContainer {
81
84
providerOrConstructor : Provider < T > | constructor < T > ,
82
85
options : RegistrationOptions = { lifecycle : Lifecycle . Transient }
83
86
) : InternalDependencyContainer {
87
+ this . ensureNotDisposed ( ) ;
88
+
84
89
let provider : Provider < T > ;
85
90
86
91
if ( ! isProvider ( providerOrConstructor ) ) {
@@ -139,6 +144,8 @@ class InternalDependencyContainer implements DependencyContainer {
139
144
from : InjectionToken < T > ,
140
145
to : InjectionToken < T >
141
146
) : InternalDependencyContainer {
147
+ this . ensureNotDisposed ( ) ;
148
+
142
149
if ( isNormalToken ( to ) ) {
143
150
return this . register ( from , {
144
151
useToken : to
@@ -154,6 +161,8 @@ class InternalDependencyContainer implements DependencyContainer {
154
161
token : InjectionToken < T > ,
155
162
instance : T
156
163
) : InternalDependencyContainer {
164
+ this . ensureNotDisposed ( ) ;
165
+
157
166
return this . register ( token , {
158
167
useValue : instance
159
168
} ) ;
@@ -171,6 +180,8 @@ class InternalDependencyContainer implements DependencyContainer {
171
180
from : InjectionToken < T > ,
172
181
to ?: InjectionToken < T >
173
182
) : InternalDependencyContainer {
183
+ this . ensureNotDisposed ( ) ;
184
+
174
185
if ( isNormalToken ( from ) ) {
175
186
if ( isNormalToken ( to ) ) {
176
187
return this . register (
@@ -213,6 +224,8 @@ class InternalDependencyContainer implements DependencyContainer {
213
224
token : InjectionToken < T > ,
214
225
context : ResolutionContext = new ResolutionContext ( )
215
226
) : T {
227
+ this . ensureNotDisposed ( ) ;
228
+
216
229
const registration = this . getRegistration ( token ) ;
217
230
218
231
if ( ! registration && isNormalToken ( token ) ) {
@@ -282,6 +295,8 @@ class InternalDependencyContainer implements DependencyContainer {
282
295
registration : Registration ,
283
296
context : ResolutionContext
284
297
) : T {
298
+ this . ensureNotDisposed ( ) ;
299
+
285
300
// If we have already resolved this scoped dependency, return it
286
301
if (
287
302
registration . options . lifecycle === Lifecycle . ResolutionScoped &&
@@ -334,6 +349,8 @@ class InternalDependencyContainer implements DependencyContainer {
334
349
token : InjectionToken < T > ,
335
350
context : ResolutionContext = new ResolutionContext ( )
336
351
) : T [ ] {
352
+ this . ensureNotDisposed ( ) ;
353
+
337
354
const registrations = this . getAllRegistrations ( token ) ;
338
355
339
356
if ( ! registrations && isNormalToken ( token ) ) {
@@ -360,6 +377,8 @@ class InternalDependencyContainer implements DependencyContainer {
360
377
}
361
378
362
379
public isRegistered < T > ( token : InjectionToken < T > , recursive = false ) : boolean {
380
+ this . ensureNotDisposed ( ) ;
381
+
363
382
return (
364
383
this . _registry . has ( token ) ||
365
384
( recursive &&
@@ -369,12 +388,15 @@ class InternalDependencyContainer implements DependencyContainer {
369
388
}
370
389
371
390
public reset ( ) : void {
391
+ this . ensureNotDisposed ( ) ;
372
392
this . _registry . clear ( ) ;
373
393
this . interceptors . preResolution . clear ( ) ;
374
394
this . interceptors . postResolution . clear ( ) ;
375
395
}
376
396
377
397
public clearInstances ( ) : void {
398
+ this . ensureNotDisposed ( ) ;
399
+
378
400
for ( const [ token , registrations ] of this . _registry . entries ( ) ) {
379
401
this . _registry . setAll (
380
402
token ,
@@ -391,6 +413,8 @@ class InternalDependencyContainer implements DependencyContainer {
391
413
}
392
414
393
415
public createChildContainer ( ) : DependencyContainer {
416
+ this . ensureNotDisposed ( ) ;
417
+
394
418
const childContainer = new InternalDependencyContainer ( this ) ;
395
419
396
420
for ( const [ token , registrations ] of this . _registry . entries ( ) ) {
@@ -443,6 +467,21 @@ class InternalDependencyContainer implements DependencyContainer {
443
467
} ) ;
444
468
}
445
469
470
+ public async dispose ( ) : Promise < void > {
471
+ this . disposed = true ;
472
+
473
+ const promises : Promise < unknown > [ ] = [ ] ;
474
+ this . disposables . forEach ( disposable => {
475
+ const maybePromise = disposable . dispose ( ) ;
476
+
477
+ if ( maybePromise ) {
478
+ promises . push ( maybePromise ) ;
479
+ }
480
+ } ) ;
481
+
482
+ await Promise . all ( promises ) ;
483
+ }
484
+
446
485
private getRegistration < T > ( token : InjectionToken < T > ) : Registration | null {
447
486
if ( this . isRegistered ( token ) ) {
448
487
return this . _registry . get ( token ) ! ;
@@ -478,18 +517,27 @@ class InternalDependencyContainer implements DependencyContainer {
478
517
this . resolve ( target , context )
479
518
) ;
480
519
}
481
- const paramInfo = typeInfo . get ( ctor ) ;
482
- if ( ! paramInfo || paramInfo . length === 0 ) {
483
- if ( ctor . length === 0 ) {
484
- return new ctor ( ) ;
485
- } else {
486
- throw new Error ( `TypeInfo not known for "${ ctor . name } "` ) ;
520
+
521
+ const instance : T = ( ( ) => {
522
+ const paramInfo = typeInfo . get ( ctor ) ;
523
+ if ( ! paramInfo || paramInfo . length === 0 ) {
524
+ if ( ctor . length === 0 ) {
525
+ return new ctor ( ) ;
526
+ } else {
527
+ throw new Error ( `TypeInfo not known for "${ ctor . name } "` ) ;
528
+ }
487
529
}
488
- }
489
530
490
- const params = paramInfo . map ( this . resolveParams ( context , ctor ) ) ;
531
+ const params = paramInfo . map ( this . resolveParams ( context , ctor ) ) ;
532
+
533
+ return new ctor ( ...params ) ;
534
+ } ) ( ) ;
491
535
492
- return new ctor ( ...params ) ;
536
+ if ( isDisposable ( instance ) ) {
537
+ this . disposables . add ( instance ) ;
538
+ }
539
+
540
+ return instance ;
493
541
}
494
542
495
543
private resolveParams < T > ( context : ResolutionContext , ctor : constructor < T > ) {
@@ -523,6 +571,14 @@ class InternalDependencyContainer implements DependencyContainer {
523
571
}
524
572
} ;
525
573
}
574
+
575
+ private ensureNotDisposed ( ) : void {
576
+ if ( this . disposed ) {
577
+ throw new Error (
578
+ "This container has been disposed, you cannot interact with a disposed container"
579
+ ) ;
580
+ }
581
+ }
526
582
}
527
583
528
584
export const instance : DependencyContainer = new InternalDependencyContainer ( ) ;
0 commit comments