@fluojs/di 1.0.0-beta.2 → 1.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/container.d.ts +11 -3
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +77 -26
- package/package.json +2 -2
package/dist/container.d.ts
CHANGED
|
@@ -9,15 +9,17 @@ export declare class Container {
|
|
|
9
9
|
private readonly registrations;
|
|
10
10
|
private readonly multiRegistrations;
|
|
11
11
|
private readonly multiOverriddenTokens;
|
|
12
|
-
private
|
|
13
|
-
private
|
|
12
|
+
private requestCache;
|
|
13
|
+
private multiRequestCache;
|
|
14
14
|
private readonly multiSingletonCache;
|
|
15
15
|
private readonly staleDisposalTasks;
|
|
16
16
|
private readonly staleDisposalErrors;
|
|
17
17
|
private readonly singletonCache;
|
|
18
|
-
private readonly
|
|
18
|
+
private readonly forwardRefTokenCache;
|
|
19
|
+
private childScopes;
|
|
19
20
|
private disposePromise;
|
|
20
21
|
private disposed;
|
|
22
|
+
private trackedByRoot;
|
|
21
23
|
constructor(parent?: Container | undefined, requestScopeEnabled?: boolean, singletonCache?: Map<Token, Promise<unknown>>);
|
|
22
24
|
/**
|
|
23
25
|
* Registers providers in the current container scope.
|
|
@@ -78,6 +80,7 @@ export declare class Container {
|
|
|
78
80
|
*/
|
|
79
81
|
dispose(): Promise<void>;
|
|
80
82
|
private disposeAll;
|
|
83
|
+
private isDisposedInHierarchy;
|
|
81
84
|
private hasMulti;
|
|
82
85
|
private assertNoRegistrationConflict;
|
|
83
86
|
private hasAncestorSingleRegistration;
|
|
@@ -94,11 +97,15 @@ export declare class Container {
|
|
|
94
97
|
private resolveMultiProviderInstance;
|
|
95
98
|
private resolveExistingProviderTarget;
|
|
96
99
|
private resolveScopedOrSingletonInstance;
|
|
100
|
+
private getCachedScopedOrSingletonInstance;
|
|
97
101
|
private shouldResolveFromRoot;
|
|
98
102
|
private shouldResolveMultiProviderFromRoot;
|
|
99
103
|
private resolveDepToken;
|
|
100
104
|
private withTokenInChain;
|
|
101
105
|
private root;
|
|
106
|
+
private ensureTrackedRequestScope;
|
|
107
|
+
private requestCacheForWrite;
|
|
108
|
+
private multiRequestCacheForWrite;
|
|
102
109
|
private lookupProvider;
|
|
103
110
|
/**
|
|
104
111
|
* Resolve the cache map that should hold the instance for `provider`.
|
|
@@ -127,6 +134,7 @@ export declare class Container {
|
|
|
127
134
|
private assertSingletonDependencyScopes;
|
|
128
135
|
private resolveEffectiveProvider;
|
|
129
136
|
private resolveProviderDependencyToken;
|
|
137
|
+
private resolveForwardRefToken;
|
|
130
138
|
private resolveProviderDeps;
|
|
131
139
|
private invalidateCachedEntry;
|
|
132
140
|
}
|
package/dist/container.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAW3E,OAAO,KAAK,EASV,QAAQ,EAET,MAAM,YAAY,CAAC;AAuIpB;;GAEG;AACH,qBAAa,SAAS;
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAW3E,OAAO,KAAK,EASV,QAAQ,EAET,MAAM,YAAY,CAAC;AAuIpB;;GAEG;AACH,qBAAa,SAAS;IAiBlB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IAjBtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAwC;IACtE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA0C;IAC7E,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAoB;IAC1D,OAAO,CAAC,YAAY,CAA2C;IAC/D,OAAO,CAAC,iBAAiB,CAAwD;IACjF,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAmD;IACvF,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA4B;IAC/D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAiB;IACrD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA+B;IAC9D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAsC;IAC3E,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAAS;gBAGX,MAAM,CAAC,EAAE,SAAS,YAAA,EAClB,mBAAmB,UAAQ,EAC5C,cAAc,CAAC,EAAE,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAK/C;;;;;;;;;OASG;IACH,QAAQ,CAAC,GAAG,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI;IAyCxC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,GAAG,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI;IA6BxC;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAI1B;;;;;OAKG;IACH,kBAAkB,IAAI,SAAS;IAW/B;;;;;;;;;OASG;IACG,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAW7C;;;;;OAKG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAiBhB,UAAU;IAiBxB,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,4BAA4B;IAsBpC,OAAO,CAAC,6BAA6B;IAIrC,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,4BAA4B;IAIpC,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,qBAAqB;YAgBf,gBAAgB;YAehB,8BAA8B;IAqC5C,OAAO,CAAC,eAAe;YAgBT,kBAAkB;IAMhC,OAAO,CAAC,mCAAmC;YAoB7B,6BAA6B;YAc7B,4BAA4B;IA4B1C,OAAO,CAAC,6BAA6B;YAQvB,gCAAgC;IAuB9C,OAAO,CAAC,kCAAkC;IAY1C,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,kCAAkC;YAI5B,eAAe;YAwBf,gBAAgB;IAiB9B,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,yBAAyB;IAWjC,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,yBAAyB;IAMjC,OAAO,CAAC,cAAc;IAUtB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,QAAQ;IAuBhB,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,oBAAoB;YAkBd,YAAY;YAaZ,0BAA0B;YA0B1B,8BAA8B;IAc5C,OAAO,CAAC,mBAAmB;YAWb,yBAAyB;IAMvC,OAAO,CAAC,qBAAqB;IAoB7B,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,YAAY;YAIN,WAAW;IA+BzB,OAAO,CAAC,+BAA+B;IAsBvC,OAAO,CAAC,wBAAwB;IA6BhC,OAAO,CAAC,8BAA8B;IAYtC,OAAO,CAAC,sBAAsB;YAUhB,mBAAmB;IAUjC,OAAO,CAAC,qBAAqB;CAmD9B"}
|
package/dist/container.js
CHANGED
|
@@ -119,15 +119,17 @@ export class Container {
|
|
|
119
119
|
registrations = new Map();
|
|
120
120
|
multiRegistrations = new Map();
|
|
121
121
|
multiOverriddenTokens = new Set();
|
|
122
|
-
requestCache
|
|
123
|
-
multiRequestCache
|
|
122
|
+
requestCache;
|
|
123
|
+
multiRequestCache;
|
|
124
124
|
multiSingletonCache = new Map();
|
|
125
125
|
staleDisposalTasks = new Set();
|
|
126
126
|
staleDisposalErrors = [];
|
|
127
127
|
singletonCache;
|
|
128
|
-
|
|
128
|
+
forwardRefTokenCache = new WeakMap();
|
|
129
|
+
childScopes;
|
|
129
130
|
disposePromise;
|
|
130
131
|
disposed = false;
|
|
132
|
+
trackedByRoot = false;
|
|
131
133
|
constructor(parent, requestScopeEnabled = false, singletonCache) {
|
|
132
134
|
this.parent = parent;
|
|
133
135
|
this.requestScopeEnabled = requestScopeEnabled;
|
|
@@ -145,7 +147,7 @@ export class Container {
|
|
|
145
147
|
* @throws {InvalidProviderError} When a provider definition is structurally invalid.
|
|
146
148
|
*/
|
|
147
149
|
register(...providers) {
|
|
148
|
-
if (this.
|
|
150
|
+
if (this.isDisposedInHierarchy()) {
|
|
149
151
|
throw new ContainerResolutionError('Container has been disposed and can no longer register providers.', {
|
|
150
152
|
hint: 'Ensure providers are registered before calling container.dispose().'
|
|
151
153
|
});
|
|
@@ -189,7 +191,7 @@ export class Container {
|
|
|
189
191
|
* @throws {InvalidProviderError} When a provider definition is structurally invalid.
|
|
190
192
|
*/
|
|
191
193
|
override(...providers) {
|
|
192
|
-
if (this.
|
|
194
|
+
if (this.isDisposedInHierarchy()) {
|
|
193
195
|
throw new ContainerResolutionError('Container has been disposed and can no longer override providers.', {
|
|
194
196
|
hint: 'Ensure overrides are applied before calling container.dispose().'
|
|
195
197
|
});
|
|
@@ -228,14 +230,12 @@ export class Container {
|
|
|
228
230
|
* @throws {ContainerResolutionError} When called after the container was disposed.
|
|
229
231
|
*/
|
|
230
232
|
createRequestScope() {
|
|
231
|
-
if (this.
|
|
233
|
+
if (this.isDisposedInHierarchy()) {
|
|
232
234
|
throw new ContainerResolutionError('Container has been disposed and can no longer create request scopes.', {
|
|
233
235
|
hint: 'Create request scopes before calling container.dispose().'
|
|
234
236
|
});
|
|
235
237
|
}
|
|
236
|
-
|
|
237
|
-
this.root().childScopes.add(child);
|
|
238
|
-
return child;
|
|
238
|
+
return new Container(this, true, this.root().singletonCache);
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
/**
|
|
@@ -249,7 +249,7 @@ export class Container {
|
|
|
249
249
|
* @throws {CircularDependencyError} When provider dependency resolution detects a cycle.
|
|
250
250
|
*/
|
|
251
251
|
async resolve(token) {
|
|
252
|
-
if (this.
|
|
252
|
+
if (this.isDisposedInHierarchy()) {
|
|
253
253
|
throw new ContainerResolutionError('Container has been disposed and can no longer resolve providers.', {
|
|
254
254
|
token,
|
|
255
255
|
hint: 'Ensure all resolves complete before calling container.dispose().'
|
|
@@ -281,17 +281,24 @@ export class Container {
|
|
|
281
281
|
async disposeAll() {
|
|
282
282
|
try {
|
|
283
283
|
// Dispose all live request-scope children first (root only)
|
|
284
|
-
if (!this.parent && this.childScopes.size > 0) {
|
|
284
|
+
if (!this.parent && this.childScopes && this.childScopes.size > 0) {
|
|
285
285
|
await Promise.all(Array.from(this.childScopes).map(child => child.dispose()));
|
|
286
286
|
this.childScopes.clear();
|
|
287
287
|
}
|
|
288
288
|
await this.disposeCache(this.disposalCacheEntries());
|
|
289
289
|
} finally {
|
|
290
|
-
if (this.parent) {
|
|
291
|
-
this.root().childScopes
|
|
290
|
+
if (this.parent && this.trackedByRoot) {
|
|
291
|
+
this.root().childScopes?.delete(this);
|
|
292
|
+
this.trackedByRoot = false;
|
|
292
293
|
}
|
|
293
294
|
}
|
|
294
295
|
}
|
|
296
|
+
isDisposedInHierarchy() {
|
|
297
|
+
if (this.disposed) {
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
return this.parent?.isDisposedInHierarchy() ?? false;
|
|
301
|
+
}
|
|
295
302
|
hasMulti(token) {
|
|
296
303
|
if (this.multiRegistrations.has(token)) return true;
|
|
297
304
|
return this.parent?.hasMulti(token) ?? false;
|
|
@@ -362,6 +369,10 @@ export class Container {
|
|
|
362
369
|
if (provider.scope === 'transient') {
|
|
363
370
|
return await this.withTokenInChain(token, chain, activeTokens, async (c, at) => this.instantiate(provider, c, at));
|
|
364
371
|
}
|
|
372
|
+
const cachedInstance = this.getCachedScopedOrSingletonInstance(provider);
|
|
373
|
+
if (cachedInstance) {
|
|
374
|
+
return await cachedInstance;
|
|
375
|
+
}
|
|
365
376
|
return await this.withTokenInChain(token, chain, activeTokens, async (c, at) => this.resolveScopedOrSingletonInstance(provider, c, at));
|
|
366
377
|
}
|
|
367
378
|
requireProvider(token) {
|
|
@@ -431,6 +442,15 @@ export class Container {
|
|
|
431
442
|
}
|
|
432
443
|
return cache.get(provider.provide);
|
|
433
444
|
}
|
|
445
|
+
getCachedScopedOrSingletonInstance(provider) {
|
|
446
|
+
if (provider.scope !== Scope.DEFAULT) {
|
|
447
|
+
return undefined;
|
|
448
|
+
}
|
|
449
|
+
if (this.shouldResolveFromRoot(provider)) {
|
|
450
|
+
return this.root().getCachedScopedOrSingletonInstance(provider);
|
|
451
|
+
}
|
|
452
|
+
return this.cacheFor(provider).get(provider.provide);
|
|
453
|
+
}
|
|
434
454
|
shouldResolveFromRoot(provider) {
|
|
435
455
|
return provider.scope === Scope.DEFAULT && this.requestScopeEnabled && !this.registrations.has(provider.provide);
|
|
436
456
|
}
|
|
@@ -446,7 +466,7 @@ export class Container {
|
|
|
446
466
|
return this.resolveWithChain(innerToken, chain, activeTokens);
|
|
447
467
|
}
|
|
448
468
|
if (isForwardRef(depEntry)) {
|
|
449
|
-
const resolvedToken =
|
|
469
|
+
const resolvedToken = this.resolveForwardRefToken(depEntry);
|
|
450
470
|
return this.resolveWithChain(resolvedToken, chain, activeTokens, /* allowForwardRef */true);
|
|
451
471
|
}
|
|
452
472
|
return this.resolveWithChain(depEntry, chain, activeTokens);
|
|
@@ -464,6 +484,25 @@ export class Container {
|
|
|
464
484
|
root() {
|
|
465
485
|
return this.parent ? this.parent.root() : this;
|
|
466
486
|
}
|
|
487
|
+
ensureTrackedRequestScope() {
|
|
488
|
+
if (!this.requestScopeEnabled || !this.parent || this.trackedByRoot) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
const root = this.root();
|
|
492
|
+
root.childScopes ??= new Set();
|
|
493
|
+
root.childScopes.add(this);
|
|
494
|
+
this.trackedByRoot = true;
|
|
495
|
+
}
|
|
496
|
+
requestCacheForWrite() {
|
|
497
|
+
this.ensureTrackedRequestScope();
|
|
498
|
+
this.requestCache ??= new Map();
|
|
499
|
+
return this.requestCache;
|
|
500
|
+
}
|
|
501
|
+
multiRequestCacheForWrite() {
|
|
502
|
+
this.ensureTrackedRequestScope();
|
|
503
|
+
this.multiRequestCache ??= new Map();
|
|
504
|
+
return this.multiRequestCache;
|
|
505
|
+
}
|
|
467
506
|
lookupProvider(token) {
|
|
468
507
|
const local = this.registrations.get(token);
|
|
469
508
|
if (local) {
|
|
@@ -486,7 +525,7 @@ export class Container {
|
|
|
486
525
|
cacheFor(provider) {
|
|
487
526
|
if (provider.scope === Scope.DEFAULT) {
|
|
488
527
|
if (this.requestScopeEnabled && this.registrations.has(provider.provide)) {
|
|
489
|
-
return this.
|
|
528
|
+
return this.requestCacheForWrite();
|
|
490
529
|
}
|
|
491
530
|
return this.root().singletonCache;
|
|
492
531
|
}
|
|
@@ -497,12 +536,12 @@ export class Container {
|
|
|
497
536
|
hint: 'Wrap the resolve call inside a request-scoped child container created via container.createRequestScope().'
|
|
498
537
|
});
|
|
499
538
|
}
|
|
500
|
-
return this.
|
|
539
|
+
return this.requestCacheForWrite();
|
|
501
540
|
}
|
|
502
541
|
multiCacheFor(provider) {
|
|
503
542
|
if (provider.scope === Scope.DEFAULT) {
|
|
504
543
|
if (this.requestScopeEnabled && this.hasLocalMultiProvider(provider)) {
|
|
505
|
-
return this.
|
|
544
|
+
return this.multiRequestCacheForWrite();
|
|
506
545
|
}
|
|
507
546
|
return this.root().multiSingletonCache;
|
|
508
547
|
}
|
|
@@ -513,15 +552,15 @@ export class Container {
|
|
|
513
552
|
hint: 'Wrap the resolve call inside a request-scoped child container created via container.createRequestScope().'
|
|
514
553
|
});
|
|
515
554
|
}
|
|
516
|
-
return this.
|
|
555
|
+
return this.multiRequestCacheForWrite();
|
|
517
556
|
}
|
|
518
557
|
hasLocalMultiProvider(provider) {
|
|
519
558
|
return this.multiRegistrations.get(provider.provide)?.includes(provider) ?? false;
|
|
520
559
|
}
|
|
521
560
|
disposalCacheEntries() {
|
|
522
561
|
if (this.parent) {
|
|
523
|
-
const entries = Array.from(this.requestCache
|
|
524
|
-
for (const [provider, promise] of this.multiRequestCache
|
|
562
|
+
const entries = Array.from(this.requestCache?.entries() ?? []);
|
|
563
|
+
for (const [provider, promise] of this.multiRequestCache?.entries() ?? []) {
|
|
525
564
|
entries.push([provider, promise]);
|
|
526
565
|
}
|
|
527
566
|
return entries;
|
|
@@ -577,8 +616,8 @@ export class Container {
|
|
|
577
616
|
}
|
|
578
617
|
clearDisposalCaches() {
|
|
579
618
|
if (this.parent) {
|
|
580
|
-
this.requestCache
|
|
581
|
-
this.multiRequestCache
|
|
619
|
+
this.requestCache?.clear();
|
|
620
|
+
this.multiRequestCache?.clear();
|
|
582
621
|
return;
|
|
583
622
|
}
|
|
584
623
|
this.singletonCache.clear();
|
|
@@ -679,13 +718,21 @@ export class Container {
|
|
|
679
718
|
}
|
|
680
719
|
resolveProviderDependencyToken(depEntry) {
|
|
681
720
|
if (isForwardRef(depEntry)) {
|
|
682
|
-
return
|
|
721
|
+
return this.resolveForwardRefToken(depEntry);
|
|
683
722
|
}
|
|
684
723
|
if (isOptionalToken(depEntry)) {
|
|
685
724
|
return depEntry.token;
|
|
686
725
|
}
|
|
687
726
|
return depEntry;
|
|
688
727
|
}
|
|
728
|
+
resolveForwardRefToken(forwardRefEntry) {
|
|
729
|
+
if (this.forwardRefTokenCache.has(forwardRefEntry)) {
|
|
730
|
+
return this.forwardRefTokenCache.get(forwardRefEntry);
|
|
731
|
+
}
|
|
732
|
+
const resolvedToken = forwardRefEntry.forwardRef();
|
|
733
|
+
this.forwardRefTokenCache.set(forwardRefEntry, resolvedToken);
|
|
734
|
+
return resolvedToken;
|
|
735
|
+
}
|
|
689
736
|
async resolveProviderDeps(provider, chain, activeTokens) {
|
|
690
737
|
const deps = new Array(provider.inject.length);
|
|
691
738
|
for (const [index, entry] of provider.inject.entries()) {
|
|
@@ -694,7 +741,7 @@ export class Container {
|
|
|
694
741
|
return deps;
|
|
695
742
|
}
|
|
696
743
|
invalidateCachedEntry(token, scope) {
|
|
697
|
-
if (this.requestCache
|
|
744
|
+
if (this.requestCache?.has(token)) {
|
|
698
745
|
const cached = this.requestCache.get(token);
|
|
699
746
|
if (cached) {
|
|
700
747
|
this.scheduleStaleDisposal(cached);
|
|
@@ -720,12 +767,16 @@ export class Container {
|
|
|
720
767
|
this.multiSingletonCache.delete(provider);
|
|
721
768
|
}
|
|
722
769
|
}
|
|
723
|
-
|
|
770
|
+
const multiRequestCache = this.multiRequestCache;
|
|
771
|
+
if (!multiRequestCache) {
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
for (const [provider, cached] of multiRequestCache.entries()) {
|
|
724
775
|
if (provider.provide !== token) {
|
|
725
776
|
continue;
|
|
726
777
|
}
|
|
727
778
|
this.scheduleStaleDisposal(cached);
|
|
728
|
-
|
|
779
|
+
multiRequestCache.delete(provider);
|
|
729
780
|
}
|
|
730
781
|
}
|
|
731
782
|
}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"container",
|
|
10
10
|
"provider"
|
|
11
11
|
],
|
|
12
|
-
"version": "1.0.0-beta.
|
|
12
|
+
"version": "1.0.0-beta.4",
|
|
13
13
|
"private": false,
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"dist"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@fluojs/core": "^1.0.0-beta.
|
|
39
|
+
"@fluojs/core": "^1.0.0-beta.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"vitest": "^3.2.4"
|