@lppedd/di-wise-neo 0.6.0 → 0.7.1
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/README.md +29 -3
- package/dist/cjs/index.d.ts +157 -71
- package/dist/cjs/index.js +241 -169
- package/dist/cjs/index.js.map +1 -1
- package/dist/es/index.d.mts +157 -71
- package/dist/es/index.mjs +238 -170
- package/dist/es/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/es/index.mjs
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
// @internal
|
2
2
|
function assert(condition, message) {
|
3
3
|
if (!condition) {
|
4
|
-
|
5
|
-
throw new Error(tag(resolvedMessage));
|
4
|
+
throw new Error(tag(typeof message === "string" ? message : message()));
|
6
5
|
}
|
7
6
|
}
|
8
7
|
// @internal
|
@@ -16,11 +15,7 @@ function throwUnregisteredError(token) {
|
|
16
15
|
// @internal
|
17
16
|
function throwExistingUnregisteredError(sourceToken, targetTokenOrError) {
|
18
17
|
let message = tag(`token resolution error encountered while resolving ${sourceToken.name}`);
|
19
|
-
|
20
|
-
message += `\n [cause] ${untag(targetTokenOrError.message)}`;
|
21
|
-
} else {
|
22
|
-
message += `\n [cause] the aliased token ${targetTokenOrError.name} is not registered`;
|
23
|
-
}
|
18
|
+
message += isError(targetTokenOrError) ? `\n [cause] ${untag(targetTokenOrError.message)}` : `\n [cause] the aliased token ${targetTokenOrError.name} is not registered`;
|
24
19
|
throw new Error(message);
|
25
20
|
}
|
26
21
|
function isError(value) {
|
@@ -31,8 +26,7 @@ function tag(message) {
|
|
31
26
|
return `[di-wise-neo] ${message}`;
|
32
27
|
}
|
33
28
|
function untag(message) {
|
34
|
-
return message.startsWith("[di-wise-neo]")
|
35
|
-
? message.substring(13).trimStart() : message;
|
29
|
+
return message.startsWith("[di-wise-neo]") ? message.substring(13).trimStart() : message;
|
36
30
|
}
|
37
31
|
|
38
32
|
// @internal
|
@@ -127,23 +121,23 @@ function ensureInjectionContext(fn) {
|
|
127
121
|
return context;
|
128
122
|
}
|
129
123
|
|
130
|
-
function inject(token) {
|
124
|
+
function inject(token, name) {
|
131
125
|
const context = ensureInjectionContext(inject);
|
132
|
-
return context.container.resolve(token);
|
126
|
+
return context.container.resolve(token, name);
|
133
127
|
}
|
134
|
-
function injectBy(thisArg, token) {
|
128
|
+
function injectBy(thisArg, token, name) {
|
135
129
|
const context = ensureInjectionContext(injectBy);
|
136
130
|
const resolution = context.resolution;
|
137
131
|
const currentFrame = resolution.stack.peek();
|
138
132
|
if (!currentFrame) {
|
139
|
-
return inject(token);
|
133
|
+
return inject(token, name);
|
140
134
|
}
|
141
135
|
const currentRef = {
|
142
136
|
current: thisArg
|
143
137
|
};
|
144
138
|
const cleanup = resolution.dependents.set(currentFrame.provider, currentRef);
|
145
139
|
try {
|
146
|
-
return inject(token);
|
140
|
+
return inject(token, name);
|
147
141
|
} finally{
|
148
142
|
cleanup();
|
149
143
|
}
|
@@ -154,41 +148,59 @@ function injectAll(token) {
|
|
154
148
|
return context.container.resolveAll(token);
|
155
149
|
}
|
156
150
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
151
|
+
// @internal
|
152
|
+
class Metadata {
|
153
|
+
constructor(Class){
|
154
|
+
this.dependencies = {
|
155
|
+
constructor: [],
|
156
|
+
methods: new Map()
|
157
|
+
};
|
158
|
+
this.tokensRef = {
|
159
|
+
getRefTokens: ()=>new Set()
|
160
|
+
};
|
161
|
+
this.provider = {
|
162
|
+
useClass: Class
|
163
|
+
};
|
164
|
+
}
|
165
|
+
get name() {
|
166
|
+
return this.provider.name;
|
167
|
+
}
|
168
|
+
set name(name) {
|
169
|
+
this.provider.name = name;
|
170
|
+
}
|
171
|
+
getConstructorDependency(index) {
|
172
|
+
const i = this.dependencies.constructor.findIndex((d)=>d.index === index);
|
173
|
+
if (i > -1) {
|
174
|
+
return this.dependencies.constructor[i];
|
175
|
+
}
|
176
|
+
const dependency = {
|
177
|
+
index: index
|
178
|
+
};
|
179
|
+
this.dependencies.constructor.push(dependency);
|
180
|
+
return dependency;
|
181
|
+
}
|
182
|
+
getMethodDependency(method, index) {
|
183
|
+
let methodDeps = this.dependencies.methods.get(method);
|
184
|
+
if (!methodDeps) {
|
185
|
+
this.dependencies.methods.set(method, methodDeps = []);
|
186
|
+
}
|
187
|
+
const i = methodDeps.findIndex((d)=>d.index === index);
|
188
|
+
if (i > -1) {
|
189
|
+
return methodDeps[i];
|
190
|
+
}
|
191
|
+
const dependency = {
|
192
|
+
index: index
|
193
|
+
};
|
194
|
+
methodDeps.push(dependency);
|
195
|
+
return dependency;
|
196
|
+
}
|
174
197
|
}
|
175
198
|
// @internal
|
176
199
|
function getMetadata(Class) {
|
177
200
|
const originalClass = classIdentityMap.get(Class) ?? Class;
|
178
201
|
let metadata = metadataMap.get(originalClass);
|
179
202
|
if (!metadata) {
|
180
|
-
metadataMap.set(originalClass, metadata =
|
181
|
-
tokensRef: {
|
182
|
-
getRefTokens: ()=>new Set()
|
183
|
-
},
|
184
|
-
provider: {
|
185
|
-
useClass: originalClass
|
186
|
-
},
|
187
|
-
dependencies: {
|
188
|
-
constructor: [],
|
189
|
-
methods: new Map()
|
190
|
-
}
|
191
|
-
});
|
203
|
+
metadataMap.set(originalClass, metadata = new Metadata(originalClass));
|
192
204
|
}
|
193
205
|
if (metadata.provider.useClass !== Class) {
|
194
206
|
// This is part of the class identity mapping API (see setClassIdentityMapping).
|
@@ -202,32 +214,48 @@ function getMetadata(Class) {
|
|
202
214
|
// We must update useClass to be the extender class B so that instances created by the
|
203
215
|
// DI container match the consumer's registered class. Without this update, the DI
|
204
216
|
// system would instantiate the original class A, causing behavior inconsistencies.
|
205
|
-
//
|
206
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
207
217
|
metadata.provider.useClass = Class;
|
208
218
|
}
|
209
219
|
return metadata;
|
210
220
|
}
|
221
|
+
/**
|
222
|
+
* Registers a mapping between a generated (e.g., decorated or proxied) constructor
|
223
|
+
* and its original, underlying constructor.
|
224
|
+
*
|
225
|
+
* This allows libraries or consumers that manipulate constructors, such as through
|
226
|
+
* class decorators, to inform the DI system about the real "identity" of a class.
|
227
|
+
*
|
228
|
+
* @param transformedClass The constructor function returned by a class decorator or factory.
|
229
|
+
* @param originalClass The original constructor function.
|
230
|
+
*
|
231
|
+
* @remarks
|
232
|
+
* This API affects the core class identity resolution mechanism of the DI system.
|
233
|
+
* Incorrect usage may cause metadata to be misassociated, leading to subtle errors.
|
234
|
+
* Use only when manipulating constructors (e.g., via decorators or proxies),
|
235
|
+
* and ensure the mapping is correct.
|
236
|
+
*/ function setClassIdentityMapping(transformedClass, originalClass) {
|
237
|
+
classIdentityMap.set(transformedClass, originalClass);
|
238
|
+
}
|
211
239
|
const classIdentityMap = new WeakMap();
|
212
240
|
const metadataMap = new WeakMap();
|
213
241
|
|
214
|
-
function optional(token) {
|
242
|
+
function optional(token, name) {
|
215
243
|
const context = ensureInjectionContext(optional);
|
216
|
-
return context.container.resolve(token, true);
|
244
|
+
return context.container.resolve(token, true, name);
|
217
245
|
}
|
218
|
-
function optionalBy(thisArg, token) {
|
246
|
+
function optionalBy(thisArg, token, name) {
|
219
247
|
const context = ensureInjectionContext(optionalBy);
|
220
248
|
const resolution = context.resolution;
|
221
249
|
const currentFrame = resolution.stack.peek();
|
222
250
|
if (!currentFrame) {
|
223
|
-
return optional(token);
|
251
|
+
return optional(token, name);
|
224
252
|
}
|
225
253
|
const currentRef = {
|
226
254
|
current: thisArg
|
227
255
|
};
|
228
256
|
const cleanup = resolution.dependents.set(currentFrame.provider, currentRef);
|
229
257
|
try {
|
230
|
-
return optional(token);
|
258
|
+
return optional(token, name);
|
231
259
|
} finally{
|
232
260
|
cleanup();
|
233
261
|
}
|
@@ -286,28 +314,29 @@ const Scope = {
|
|
286
314
|
}
|
287
315
|
// @internal
|
288
316
|
function isConstructor(token) {
|
289
|
-
return typeof token
|
317
|
+
return typeof token === "function";
|
290
318
|
}
|
291
319
|
|
292
320
|
// @internal
|
293
321
|
function getTypeName(value) {
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
322
|
+
switch(typeof value){
|
323
|
+
case "string":
|
324
|
+
return `"${value}"`;
|
325
|
+
case "function":
|
326
|
+
return value.name && `typeof ${value.name}` || "Function";
|
327
|
+
case "object":
|
328
|
+
{
|
329
|
+
if (value === null) {
|
330
|
+
return "null";
|
331
|
+
}
|
332
|
+
const proto = Object.getPrototypeOf(value);
|
333
|
+
if (proto && proto !== Object.prototype) {
|
334
|
+
const constructor = proto.constructor;
|
335
|
+
if (typeof constructor === "function" && constructor.name) {
|
336
|
+
return constructor.name;
|
337
|
+
}
|
338
|
+
}
|
309
339
|
}
|
310
|
-
}
|
311
340
|
}
|
312
341
|
return typeof value;
|
313
342
|
}
|
@@ -318,28 +347,46 @@ class TokenRegistry {
|
|
318
347
|
this.myMap = new Map();
|
319
348
|
this.myParent = parent;
|
320
349
|
}
|
321
|
-
get(token) {
|
350
|
+
get(token, name) {
|
322
351
|
// To clarify, at(-1) means we take the last added registration for this token
|
323
|
-
return this.getAll(token)
|
352
|
+
return this.getAll(token, name).at(-1);
|
324
353
|
}
|
325
|
-
getAll(token) {
|
326
|
-
|
354
|
+
getAll(token, name) {
|
355
|
+
// Internal registrations cannot have a name
|
356
|
+
const internal = name !== undefined ? undefined : internals.get(token);
|
327
357
|
return internal && [
|
328
358
|
internal
|
329
|
-
] || this.getAllFromParent(token);
|
359
|
+
] || this.getAllFromParent(token, name);
|
330
360
|
}
|
331
361
|
set(token, registration) {
|
332
362
|
assert(!internals.has(token), `cannot register reserved token ${token.name}`);
|
333
363
|
let registrations = this.myMap.get(token);
|
334
364
|
if (!registrations) {
|
335
365
|
this.myMap.set(token, registrations = []);
|
366
|
+
} else if (registration.name !== undefined) {
|
367
|
+
const existing = registrations.filter((r)=>r.name === registration.name);
|
368
|
+
assert(existing.length === 0, `a ${token.name} token named '${registration.name}' is already registered`);
|
336
369
|
}
|
337
370
|
registrations.push(registration);
|
338
371
|
}
|
339
|
-
delete(token) {
|
372
|
+
delete(token, name) {
|
340
373
|
const registrations = this.myMap.get(token);
|
341
|
-
|
342
|
-
|
374
|
+
if (registrations) {
|
375
|
+
if (name !== undefined) {
|
376
|
+
const removedRegistrations = [];
|
377
|
+
const newRegistrations = [];
|
378
|
+
for (const registration of registrations){
|
379
|
+
const array = registration.name === name ? removedRegistrations : newRegistrations;
|
380
|
+
array.push(registration);
|
381
|
+
}
|
382
|
+
if (removedRegistrations.length > 0) {
|
383
|
+
this.myMap.set(token, newRegistrations);
|
384
|
+
return removedRegistrations;
|
385
|
+
}
|
386
|
+
}
|
387
|
+
this.myMap.delete(token);
|
388
|
+
}
|
389
|
+
return registrations ?? [];
|
343
390
|
}
|
344
391
|
deleteAll() {
|
345
392
|
const tokens = Array.from(this.myMap.keys());
|
@@ -367,9 +414,14 @@ class TokenRegistry {
|
|
367
414
|
}
|
368
415
|
return Array.from(values);
|
369
416
|
}
|
370
|
-
getAllFromParent(token) {
|
371
|
-
const
|
372
|
-
|
417
|
+
getAllFromParent(token, name) {
|
418
|
+
const thisRegistrations = this.myMap.get(token);
|
419
|
+
let registrations = thisRegistrations || this.myParent?.getAllFromParent(token, name);
|
420
|
+
if (registrations && name !== undefined) {
|
421
|
+
registrations = registrations.filter((r)=>r.name === name);
|
422
|
+
assert(registrations.length < 2, `internal error: more than one registration named '${name}'`);
|
423
|
+
}
|
424
|
+
return registrations ?? [];
|
373
425
|
}
|
374
426
|
}
|
375
427
|
// @internal
|
@@ -467,9 +519,6 @@ function isDisposable(value) {
|
|
467
519
|
getAllCached(token) {
|
468
520
|
this.checkDisposed();
|
469
521
|
const registrations = this.myTokenRegistry.getAll(token);
|
470
|
-
if (!registrations) {
|
471
|
-
return [];
|
472
|
-
}
|
473
522
|
const values = new Set();
|
474
523
|
for (const registration of registrations){
|
475
524
|
const value = registration.value;
|
@@ -491,46 +540,17 @@ function isDisposable(value) {
|
|
491
540
|
}
|
492
541
|
return Array.from(values);
|
493
542
|
}
|
494
|
-
isRegistered(token) {
|
543
|
+
isRegistered(token, name) {
|
495
544
|
this.checkDisposed();
|
496
|
-
return this.myTokenRegistry.get(token) !== undefined;
|
497
|
-
}
|
498
|
-
registerClass(token, Class, options) {
|
499
|
-
// This mess will go away once/if we remove the register method
|
500
|
-
// in favor of the multiple specialized ones
|
501
|
-
if (Class) {
|
502
|
-
const ctor = Class ?? token;
|
503
|
-
this.register(token, {
|
504
|
-
useClass: ctor
|
505
|
-
}, options);
|
506
|
-
} else {
|
507
|
-
this.register(token);
|
508
|
-
}
|
509
|
-
}
|
510
|
-
registerFactory(token, factory, options) {
|
511
|
-
this.register(token, {
|
512
|
-
useFactory: factory
|
513
|
-
}, options);
|
514
|
-
}
|
515
|
-
registerValue(token, value) {
|
516
|
-
this.register(token, {
|
517
|
-
useValue: value
|
518
|
-
});
|
519
|
-
}
|
520
|
-
registerAlias(targetToken, aliasTokens) {
|
521
|
-
// De-duplicate tokens
|
522
|
-
for (const alias of new Set(aliasTokens)){
|
523
|
-
this.register(alias, {
|
524
|
-
useExisting: targetToken
|
525
|
-
});
|
526
|
-
}
|
545
|
+
return this.myTokenRegistry.get(token, name) !== undefined;
|
527
546
|
}
|
528
547
|
register(...args) {
|
529
548
|
this.checkDisposed();
|
530
|
-
if (args.length
|
549
|
+
if (args.length === 1) {
|
531
550
|
const Class = args[0];
|
532
551
|
const metadata = getMetadata(Class);
|
533
552
|
const registration = {
|
553
|
+
name: metadata.name,
|
534
554
|
// The provider is of type ClassProvider, initialized by getMetadata
|
535
555
|
provider: metadata.provider,
|
536
556
|
options: {
|
@@ -558,10 +578,11 @@ function isDisposable(value) {
|
|
558
578
|
if (isClassProvider(provider)) {
|
559
579
|
const metadata = getMetadata(provider.useClass);
|
560
580
|
const registration = {
|
581
|
+
// An explicit provider name overrides what is specified via @Named
|
582
|
+
name: metadata.name ?? provider.name,
|
561
583
|
provider: metadata.provider,
|
562
584
|
options: {
|
563
|
-
//
|
564
|
-
// via class decorators (e.g., @Scoped)
|
585
|
+
// Explicit registration options override what is specified via class decorators (e.g., @Scoped)
|
565
586
|
scope: metadata.scope?.value ?? this.myOptions.defaultScope,
|
566
587
|
...options
|
567
588
|
},
|
@@ -573,10 +594,12 @@ function isDisposable(value) {
|
|
573
594
|
this.resolveProviderValue(registration, registration.provider);
|
574
595
|
}
|
575
596
|
} else {
|
576
|
-
|
597
|
+
const existingProvider = isExistingProvider(provider);
|
598
|
+
if (existingProvider) {
|
577
599
|
assert(token !== provider.useExisting, `the useExisting token ${token.name} cannot be the same as the token being registered`);
|
578
600
|
}
|
579
601
|
this.myTokenRegistry.set(token, {
|
602
|
+
name: existingProvider ? undefined : provider.name,
|
580
603
|
provider: provider,
|
581
604
|
options: options
|
582
605
|
});
|
@@ -584,12 +607,9 @@ function isDisposable(value) {
|
|
584
607
|
}
|
585
608
|
return this;
|
586
609
|
}
|
587
|
-
unregister(token) {
|
610
|
+
unregister(token, name) {
|
588
611
|
this.checkDisposed();
|
589
|
-
const registrations = this.myTokenRegistry.delete(token);
|
590
|
-
if (!registrations) {
|
591
|
-
return [];
|
592
|
-
}
|
612
|
+
const registrations = this.myTokenRegistry.delete(token, name);
|
593
613
|
const values = new Set();
|
594
614
|
for (const registration of registrations){
|
595
615
|
const value = registration.value;
|
@@ -599,22 +619,31 @@ function isDisposable(value) {
|
|
599
619
|
}
|
600
620
|
return Array.from(values);
|
601
621
|
}
|
602
|
-
resolve(token,
|
622
|
+
resolve(token, optionalOrName, name) {
|
603
623
|
this.checkDisposed();
|
604
|
-
|
624
|
+
let localOptional;
|
625
|
+
let localName;
|
626
|
+
if (typeof optionalOrName === "string") {
|
627
|
+
localName = optionalOrName;
|
628
|
+
} else {
|
629
|
+
localOptional = optionalOrName;
|
630
|
+
localName = name;
|
631
|
+
}
|
632
|
+
const registration = this.myTokenRegistry.get(token, localName);
|
605
633
|
if (registration) {
|
606
|
-
return this.resolveRegistration(token, registration);
|
634
|
+
return this.resolveRegistration(token, registration, localName);
|
607
635
|
}
|
608
636
|
if (isConstructor(token)) {
|
609
|
-
return this.instantiateClass(token,
|
637
|
+
return this.instantiateClass(token, localOptional);
|
610
638
|
}
|
611
|
-
return
|
639
|
+
return optionalOrName ? undefined : throwUnregisteredError(token);
|
612
640
|
}
|
613
641
|
resolveAll(token, optional) {
|
614
642
|
this.checkDisposed();
|
615
643
|
const registrations = this.myTokenRegistry.getAll(token);
|
616
|
-
if (registrations) {
|
617
|
-
return registrations
|
644
|
+
if (registrations.length > 0) {
|
645
|
+
return registrations //
|
646
|
+
.map((registration)=>this.resolveRegistration(token, registration)).filter((value)=>value != null);
|
618
647
|
}
|
619
648
|
if (isConstructor(token)) {
|
620
649
|
const instance = this.instantiateClass(token, optional);
|
@@ -650,12 +679,12 @@ function isDisposable(value) {
|
|
650
679
|
// Allow values to be GCed
|
651
680
|
disposedRefs.clear();
|
652
681
|
}
|
653
|
-
resolveRegistration(token, registration) {
|
682
|
+
resolveRegistration(token, registration, name) {
|
654
683
|
let currRegistration = registration;
|
655
684
|
let currProvider = currRegistration.provider;
|
656
685
|
while(isExistingProvider(currProvider)){
|
657
686
|
const targetToken = currProvider.useExisting;
|
658
|
-
currRegistration = this.myTokenRegistry.get(targetToken);
|
687
|
+
currRegistration = this.myTokenRegistry.get(targetToken, name);
|
659
688
|
if (!currRegistration) {
|
660
689
|
throwExistingUnregisteredError(token, targetToken);
|
661
690
|
}
|
@@ -786,7 +815,7 @@ function isDisposable(value) {
|
|
786
815
|
}
|
787
816
|
}
|
788
817
|
resolveScope(scope = this.myOptions.defaultScope, context = useInjectionContext()) {
|
789
|
-
if (scope
|
818
|
+
if (scope === Scope.Inherited) {
|
790
819
|
const dependentFrame = context?.resolution.stack.peek();
|
791
820
|
return dependentFrame?.scope || Scope.Transient;
|
792
821
|
}
|
@@ -796,7 +825,7 @@ function isDisposable(value) {
|
|
796
825
|
const dependencies = registration.dependencies;
|
797
826
|
if (dependencies) {
|
798
827
|
assert(isClassProvider(registration.provider), `internal error: not a ClassProvider`);
|
799
|
-
const ctorDeps = dependencies.constructor;
|
828
|
+
const ctorDeps = dependencies.constructor.filter((d)=>d.appliedBy);
|
800
829
|
if (ctorDeps.length > 0) {
|
801
830
|
// Let's check if all necessary constructor parameters are decorated.
|
802
831
|
// If not, we cannot safely create an instance.
|
@@ -807,13 +836,13 @@ function isDisposable(value) {
|
|
807
836
|
});
|
808
837
|
return ctorDeps.sort((a, b)=>a.index - b.index).map((dep)=>{
|
809
838
|
const token = dep.tokenRef.getRefToken();
|
810
|
-
switch(dep.
|
839
|
+
switch(dep.appliedBy){
|
811
840
|
case "Inject":
|
812
|
-
return this.resolve(token);
|
841
|
+
return this.resolve(token, dep.name);
|
813
842
|
case "InjectAll":
|
814
843
|
return this.resolveAll(token);
|
815
844
|
case "Optional":
|
816
|
-
return this.resolve(token, true);
|
845
|
+
return this.resolve(token, true, dep.name);
|
817
846
|
case "OptionalAll":
|
818
847
|
return this.resolveAll(token, true);
|
819
848
|
}
|
@@ -828,7 +857,9 @@ function isDisposable(value) {
|
|
828
857
|
assert(isClassProvider(registration.provider), `internal error: not a ClassProvider`);
|
829
858
|
const ctor = registration.provider.useClass;
|
830
859
|
// Perform method injection
|
831
|
-
for (const
|
860
|
+
for (const entry of dependencies.methods){
|
861
|
+
const key = entry[0];
|
862
|
+
const methodDeps = entry[1].filter((d)=>d.appliedBy);
|
832
863
|
// Let's check if all necessary method parameters are decorated.
|
833
864
|
// If not, we cannot safely invoke the method.
|
834
865
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
@@ -839,13 +870,13 @@ function isDisposable(value) {
|
|
839
870
|
});
|
840
871
|
const args = methodDeps.sort((a, b)=>a.index - b.index).map((dep)=>{
|
841
872
|
const token = dep.tokenRef.getRefToken();
|
842
|
-
switch(dep.
|
873
|
+
switch(dep.appliedBy){
|
843
874
|
case "Inject":
|
844
|
-
return injectBy(instance, token);
|
875
|
+
return injectBy(instance, token, dep.name);
|
845
876
|
case "InjectAll":
|
846
877
|
return injectAll(token);
|
847
878
|
case "Optional":
|
848
|
-
return optionalBy(instance, token);
|
879
|
+
return optionalBy(instance, token, dep.name);
|
849
880
|
case "OptionalAll":
|
850
881
|
return optionalAll(token);
|
851
882
|
}
|
@@ -905,7 +936,7 @@ function isDisposable(value) {
|
|
905
936
|
*
|
906
937
|
* // Wizard is registered with Container scope, and an instance
|
907
938
|
* // is immediately created and cached by the container
|
908
|
-
*
|
939
|
+
* container.register(Wizard);
|
909
940
|
* ```
|
910
941
|
*
|
911
942
|
* @__NO_SIDE_EFFECTS__
|
@@ -954,41 +985,31 @@ function isTokenRef(value) {
|
|
954
985
|
return value && typeof value === "object" && typeof value.getRefToken === "function";
|
955
986
|
}
|
956
987
|
|
957
|
-
|
958
|
-
|
959
|
-
//
|
988
|
+
// @internal
|
989
|
+
function updateParameterMetadata(decorator, target, propertyKey, parameterIndex, updateFn) {
|
990
|
+
// Error out immediately if the decorator has been applied to a static method
|
960
991
|
if (propertyKey !== undefined && typeof target === "function") {
|
961
|
-
assert(false, `@${decorator} cannot be used on static
|
992
|
+
assert(false, `@${decorator} cannot be used on static method ${target.name}.${String(propertyKey)}`);
|
962
993
|
}
|
963
|
-
const tokenRef = isTokenRef(token) ? token : forwardRef(()=>token);
|
964
994
|
if (propertyKey === undefined) {
|
965
995
|
// Constructor
|
966
996
|
const metadata = getMetadata(target);
|
967
|
-
metadata.
|
968
|
-
|
969
|
-
tokenRef: tokenRef,
|
970
|
-
index: parameterIndex
|
971
|
-
});
|
997
|
+
const dependency = metadata.getConstructorDependency(parameterIndex);
|
998
|
+
updateFn(dependency);
|
972
999
|
} else {
|
973
|
-
//
|
1000
|
+
// Instance method
|
974
1001
|
const metadata = getMetadata(target.constructor);
|
975
|
-
const
|
976
|
-
|
977
|
-
if (dep === undefined) {
|
978
|
-
dep = [];
|
979
|
-
methods.set(propertyKey, dep);
|
980
|
-
}
|
981
|
-
dep.push({
|
982
|
-
decorator: decorator,
|
983
|
-
tokenRef: tokenRef,
|
984
|
-
index: parameterIndex
|
985
|
-
});
|
1002
|
+
const dependency = metadata.getMethodDependency(propertyKey, parameterIndex);
|
1003
|
+
updateFn(dependency);
|
986
1004
|
}
|
987
1005
|
}
|
988
1006
|
|
989
1007
|
function Inject(token) {
|
990
1008
|
return function(target, propertyKey, parameterIndex) {
|
991
|
-
|
1009
|
+
updateParameterMetadata("Inject", target, propertyKey, parameterIndex, (dependency)=>{
|
1010
|
+
dependency.appliedBy = "Inject";
|
1011
|
+
dependency.tokenRef = isTokenRef(token) ? token : forwardRef(()=>token);
|
1012
|
+
});
|
992
1013
|
};
|
993
1014
|
}
|
994
1015
|
|
@@ -1014,19 +1035,66 @@ function Inject(token) {
|
|
1014
1035
|
|
1015
1036
|
function InjectAll(token) {
|
1016
1037
|
return function(target, propertyKey, parameterIndex) {
|
1017
|
-
|
1038
|
+
updateParameterMetadata("InjectAll", target, propertyKey, parameterIndex, (dependency)=>{
|
1039
|
+
dependency.appliedBy = "InjectAll";
|
1040
|
+
dependency.tokenRef = isTokenRef(token) ? token : forwardRef(()=>token);
|
1041
|
+
});
|
1042
|
+
};
|
1043
|
+
}
|
1044
|
+
|
1045
|
+
/**
|
1046
|
+
* Qualifies a class or an injected parameter with a unique name.
|
1047
|
+
*
|
1048
|
+
* This allows the container to distinguish between multiple implementations
|
1049
|
+
* of the same interface or type during registration and injection.
|
1050
|
+
*
|
1051
|
+
* @example
|
1052
|
+
* ```ts
|
1053
|
+
* @Named("dumbledore")
|
1054
|
+
* class Dumbledore implements Wizard {}
|
1055
|
+
*
|
1056
|
+
* // Register Dumbledore with Type<Wizard>
|
1057
|
+
* container.register(IWizard, { useClass: Dumbledore });
|
1058
|
+
* const dumbledore = container.resolve(IWizard, "dumbledore");
|
1059
|
+
* ```
|
1060
|
+
*
|
1061
|
+
* @__NO_SIDE_EFFECTS__
|
1062
|
+
*/ function Named(name) {
|
1063
|
+
if (!name.trim()) {
|
1064
|
+
assert(false, "the @Named qualifier cannot be empty or blank");
|
1065
|
+
}
|
1066
|
+
return function(target, propertyKey, parameterIndex) {
|
1067
|
+
if (parameterIndex === undefined) {
|
1068
|
+
// The decorator has been applied to the class
|
1069
|
+
const ctor = target;
|
1070
|
+
const metadata = getMetadata(ctor);
|
1071
|
+
assert(!metadata.name, `a @Named('${metadata.name}') qualifier has already been applied to ${ctor.name}`);
|
1072
|
+
metadata.name = name;
|
1073
|
+
} else {
|
1074
|
+
// The decorator has been applied to a method parameter
|
1075
|
+
updateParameterMetadata("Named", target, propertyKey, parameterIndex, (dependency)=>{
|
1076
|
+
assert(!dependency.name, `a @Named('${dependency.name}') qualifier has already been applied to the parameter`);
|
1077
|
+
dependency.name = name;
|
1078
|
+
});
|
1079
|
+
}
|
1018
1080
|
};
|
1019
1081
|
}
|
1020
1082
|
|
1021
1083
|
function Optional(token) {
|
1022
1084
|
return function(target, propertyKey, parameterIndex) {
|
1023
|
-
|
1085
|
+
updateParameterMetadata("Optional", target, propertyKey, parameterIndex, (dependency)=>{
|
1086
|
+
dependency.appliedBy = "Optional";
|
1087
|
+
dependency.tokenRef = isTokenRef(token) ? token : forwardRef(()=>token);
|
1088
|
+
});
|
1024
1089
|
};
|
1025
1090
|
}
|
1026
1091
|
|
1027
1092
|
function OptionalAll(token) {
|
1028
1093
|
return function(target, propertyKey, parameterIndex) {
|
1029
|
-
|
1094
|
+
updateParameterMetadata("OptionalAll", target, propertyKey, parameterIndex, (dependency)=>{
|
1095
|
+
dependency.appliedBy = "OptionalAll";
|
1096
|
+
dependency.tokenRef = isTokenRef(token) ? token : forwardRef(()=>token);
|
1097
|
+
});
|
1030
1098
|
};
|
1031
1099
|
}
|
1032
1100
|
|
@@ -1107,9 +1175,9 @@ function OptionalAll(token) {
|
|
1107
1175
|
}
|
1108
1176
|
}
|
1109
1177
|
return {
|
1110
|
-
inject: (token)=>withCurrentContext(()=>inject(token)),
|
1178
|
+
inject: (token, name)=>withCurrentContext(()=>inject(token, name)),
|
1111
1179
|
injectAll: (token)=>withCurrentContext(()=>injectAll(token)),
|
1112
|
-
optional: (token)=>withCurrentContext(()=>optional(token)),
|
1180
|
+
optional: (token, name)=>withCurrentContext(()=>optional(token, name)),
|
1113
1181
|
optionalAll: (token)=>withCurrentContext(()=>optionalAll(token))
|
1114
1182
|
};
|
1115
1183
|
});
|
@@ -1158,5 +1226,5 @@ function OptionalAll(token) {
|
|
1158
1226
|
return container;
|
1159
1227
|
}
|
1160
1228
|
|
1161
|
-
export { AutoRegister, EagerInstantiate, Inject, InjectAll, Injectable, Injector, Optional, OptionalAll, Scope, Scoped, applyMiddleware, build, createContainer, createType, forwardRef, inject, injectAll, injectBy, setClassIdentityMapping };
|
1229
|
+
export { AutoRegister, EagerInstantiate, Inject, InjectAll, Injectable, Injector, Named, Optional, OptionalAll, Scope, Scoped, applyMiddleware, build, createContainer, createType, forwardRef, inject, injectAll, injectBy, optional, optionalAll, optionalBy, setClassIdentityMapping };
|
1162
1230
|
//# sourceMappingURL=index.mjs.map
|