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