@lppedd/di-wise-neo 0.6.0 → 0.7.0
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 +107 -67
- package/dist/cjs/index.js +233 -158
- package/dist/cjs/index.js.map +1 -1
- package/dist/es/index.d.mts +107 -67
- package/dist/es/index.mjs +233 -159
- package/dist/es/index.mjs.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
> in part thanks to TypeScript's experimental decorators. Shout out to [@exuanbo](https://github.com/exuanbo)
|
19
19
|
> for the strong foundations!
|
20
20
|
|
21
|
-
|
21
|
+
### Table of Contents
|
22
22
|
|
23
23
|
- [Installation](#installation)
|
24
24
|
- [API reference](#api-reference)
|
@@ -31,7 +31,7 @@
|
|
31
31
|
- [Behavioral decorators](#behavioral-decorators)
|
32
32
|
- [Testing support](#testing-support)
|
33
33
|
|
34
|
-
|
34
|
+
### Why yet another library
|
35
35
|
|
36
36
|
I've been developing VS Code extensions for a while as part of my daily work.
|
37
37
|
It's enjoyable work! However, extensions always reach that tipping point where
|
@@ -444,7 +444,7 @@ export class ExtensionContext {
|
|
444
444
|
|
445
445
|
## Behavioral decorators
|
446
446
|
|
447
|
-
The library includes
|
447
|
+
The library includes four behavioral decorators that influence how classes are registered in the container.
|
448
448
|
These decorators attach metadata to the class type, which is then interpreted by the container during registration.
|
449
449
|
|
450
450
|
### `@Scoped`
|
@@ -473,6 +473,32 @@ container.register(
|
|
473
473
|
|
474
474
|
In this example, `ExtensionContext` will be registered with **Resolution** scope instead.
|
475
475
|
|
476
|
+
### `@Named`
|
477
|
+
|
478
|
+
Marks a class or injected dependency with a unique name (qualifier), allowing the container
|
479
|
+
to distinguish between multiple implementations of the same type.
|
480
|
+
|
481
|
+
```ts
|
482
|
+
@Named("persistent")
|
483
|
+
@Scoped(Scope.Container)
|
484
|
+
export class PersistentSecretStorage implements SecretStorage {
|
485
|
+
/* ... */
|
486
|
+
}
|
487
|
+
|
488
|
+
// Register the class with Type<SecretStorage>.
|
489
|
+
// The container will automatically qualify the registration with 'persistent'.
|
490
|
+
container.register(ISecretStorage, { useClass: PersistentSecretStorage });
|
491
|
+
|
492
|
+
// Inject the SecretStorage dependency by name
|
493
|
+
export class ExtensionContext {
|
494
|
+
constructor(@Inject(ISecretStorage) @Named("persistent") readonly secretStorage: SecretStorage) {}
|
495
|
+
|
496
|
+
/* ... */
|
497
|
+
}
|
498
|
+
```
|
499
|
+
|
500
|
+
The container will throw an error at registration time if the name is already taken by another registration.
|
501
|
+
|
476
502
|
### `@AutoRegister`
|
477
503
|
|
478
504
|
Enables automatic registration of the decorated class when it is resolved,
|
package/dist/cjs/index.d.ts
CHANGED
@@ -62,22 +62,81 @@ declare function createType<T>(typeName: string): Type<T>;
|
|
62
62
|
* Provides a class instance for a token via a class constructor.
|
63
63
|
*/
|
64
64
|
interface ClassProvider<Instance extends object> {
|
65
|
+
/**
|
66
|
+
* The class to instantiate for the token.
|
67
|
+
*/
|
65
68
|
readonly useClass: Constructor<Instance>;
|
69
|
+
/**
|
70
|
+
* An optional name to qualify this provider.
|
71
|
+
* If specified, the token must be resolved using the same name.
|
72
|
+
*
|
73
|
+
* Equivalent to decorating the class with `@Named(...)`.
|
74
|
+
*
|
75
|
+
* @example
|
76
|
+
* ```ts
|
77
|
+
* export class ExtensionContext {
|
78
|
+
* // Decorator-based injection
|
79
|
+
* constructor(@Inject(ISecretStorage) @Named("persistent") secretStorage: SecretStorage) {}
|
80
|
+
*
|
81
|
+
* // Function-based injection
|
82
|
+
* constructor(secretStorage = inject(ISecretStorage, "persistent")) {}
|
83
|
+
* }
|
84
|
+
* ```
|
85
|
+
*/
|
86
|
+
readonly name?: string;
|
66
87
|
}
|
67
88
|
/**
|
68
89
|
* Provides a value for a token via a factory function.
|
69
|
-
*
|
70
|
-
* The factory function runs inside the injection context and can
|
71
|
-
* thus access dependencies via {@link inject}-like functions.
|
72
90
|
*/
|
73
91
|
interface FactoryProvider<Value> {
|
92
|
+
/**
|
93
|
+
* A function that produces the value at resolution time.
|
94
|
+
*
|
95
|
+
* The function runs inside the injection context and can
|
96
|
+
* access dependencies via {@link inject}-like helpers.
|
97
|
+
*/
|
74
98
|
readonly useFactory: (...args: []) => Value;
|
99
|
+
/**
|
100
|
+
* An optional name to qualify this provider.
|
101
|
+
* If specified, the token must be resolved using the same name.
|
102
|
+
*
|
103
|
+
* @example
|
104
|
+
* ```ts
|
105
|
+
* export class ExtensionContext {
|
106
|
+
* // Decorator-based injection
|
107
|
+
* constructor(@Inject(ISecretStorage) @Named("persistent") secretStorage: SecretStorage) {}
|
108
|
+
*
|
109
|
+
* // Function-based injection
|
110
|
+
* constructor(secretStorage = inject(ISecretStorage, "persistent")) {}
|
111
|
+
* }
|
112
|
+
* ```
|
113
|
+
*/
|
114
|
+
readonly name?: string;
|
75
115
|
}
|
76
116
|
/**
|
77
117
|
* Provides a static - already constructed - value for a token.
|
78
118
|
*/
|
79
119
|
interface ValueProvider<T> {
|
120
|
+
/**
|
121
|
+
* The static value to associate with the token.
|
122
|
+
*/
|
80
123
|
readonly useValue: T;
|
124
|
+
/**
|
125
|
+
* An optional name to qualify this provider.
|
126
|
+
* If specified, the token must be resolved using the same name.
|
127
|
+
*
|
128
|
+
* @example
|
129
|
+
* ```ts
|
130
|
+
* export class ExtensionContext {
|
131
|
+
* // Decorator-based injection
|
132
|
+
* constructor(@Inject(ISecretStorage) @Named("persistent") secretStorage: SecretStorage) {}
|
133
|
+
*
|
134
|
+
* // Function-based injection
|
135
|
+
* constructor(secretStorage = inject(ISecretStorage, "persistent")) {}
|
136
|
+
* }
|
137
|
+
* ```
|
138
|
+
*/
|
139
|
+
readonly name?: string;
|
81
140
|
}
|
82
141
|
/**
|
83
142
|
* Aliases another registered token.
|
@@ -85,6 +144,9 @@ interface ValueProvider<T> {
|
|
85
144
|
* Resolving this token will return the value of the aliased one.
|
86
145
|
*/
|
87
146
|
interface ExistingProvider<Value> {
|
147
|
+
/**
|
148
|
+
* The existing token to alias.
|
149
|
+
*/
|
88
150
|
readonly useExisting: Token<Value>;
|
89
151
|
}
|
90
152
|
/**
|
@@ -212,77 +274,33 @@ interface Container {
|
|
212
274
|
/**
|
213
275
|
* Returns whether the token is registered in this container or in parent containers, if any.
|
214
276
|
*/
|
215
|
-
isRegistered(token: Token): boolean;
|
216
|
-
/**
|
217
|
-
* Registers a concrete class, where the class acts as its own token.
|
218
|
-
*
|
219
|
-
* Tokens provided via the {@link Injectable} decorator applied to the class
|
220
|
-
* are also registered as aliases.
|
221
|
-
*
|
222
|
-
* The default registration scope is determined by the {@link Scoped} decorator,
|
223
|
-
* if present.
|
224
|
-
*/
|
225
|
-
registerClass<Instance extends object>(Class: Constructor<Instance>): void;
|
226
|
-
/**
|
227
|
-
* Registers a concrete class with a token.
|
228
|
-
*
|
229
|
-
* The default registration scope is determined by the {@link Scoped} decorator
|
230
|
-
* applied to the class, if present, but it can be overridden by passing explicit
|
231
|
-
* registration options.
|
232
|
-
*/
|
233
|
-
registerClass<Instance extends object, ProvidedInstance extends Instance>(token: Token<Instance>, Class: Constructor<ProvidedInstance>, options?: RegistrationOptions): void;
|
234
|
-
/**
|
235
|
-
* Registers a token whose value is produced by a factory function.
|
236
|
-
*
|
237
|
-
* The factory function runs inside the injection context and can
|
238
|
-
* thus access dependencies via {@link inject}-like functions.
|
239
|
-
*/
|
240
|
-
registerFactory<Value, ProvidedValue extends Value>(token: Token<Value>, factory: (...args: []) => ProvidedValue, options?: RegistrationOptions): void;
|
241
|
-
/**
|
242
|
-
* Registers a token with a fixed value.
|
243
|
-
*
|
244
|
-
* The provided value is returned as-is when the token is resolved (scopes do not apply).
|
245
|
-
*/
|
246
|
-
registerValue<Value, ProvidedValue extends Value>(token: Token<Value>, value: ProvidedValue): void;
|
247
|
-
/**
|
248
|
-
* Registers one or more tokens as aliases for a target token.
|
249
|
-
*
|
250
|
-
* When an alias is resolved, the target token is resolved instead.
|
251
|
-
*/
|
252
|
-
registerAlias<Value, ProvidedValue extends Value>(targetToken: Token<ProvidedValue>, aliasTokens: Tokens<Value>): void;
|
277
|
+
isRegistered(token: Token, name?: string): boolean;
|
253
278
|
/**
|
254
279
|
* Registers a {@link ClassProvider}, using the class itself as its token.
|
255
280
|
*
|
256
281
|
* Tokens provided via the {@link Injectable} decorator applied to the class
|
257
282
|
* are also registered as aliases.
|
258
283
|
*
|
259
|
-
* The scope is determined by the {@link Scoped} decorator
|
260
|
-
*
|
261
|
-
* @see registerClass
|
284
|
+
* The scope is determined by the {@link Scoped} decorator - if present -
|
285
|
+
* or by the {@link ContainerOptions.defaultScope} value.
|
262
286
|
*/
|
263
287
|
register<Instance extends object>(Class: Constructor<Instance>): Container;
|
264
288
|
/**
|
265
289
|
* Registers a {@link ClassProvider} with a token.
|
266
290
|
*
|
267
291
|
* The default registration scope is determined by the {@link Scoped} decorator
|
268
|
-
* applied to the provided class
|
269
|
-
* passing explicit registration options.
|
270
|
-
*
|
271
|
-
* @see registerClass
|
292
|
+
* applied to the provided class - if present - or by the {@link ContainerOptions.defaultScope}
|
293
|
+
* value, but it can be overridden by passing explicit registration options.
|
272
294
|
*/
|
273
295
|
register<Instance extends object, ProviderInstance extends Instance>(token: Token<Instance>, provider: ClassProvider<ProviderInstance>, options?: RegistrationOptions): Container;
|
274
296
|
/**
|
275
297
|
* Registers a {@link FactoryProvider} with a token.
|
276
|
-
*
|
277
|
-
* @see registerFactory
|
278
298
|
*/
|
279
299
|
register<Value, ProviderValue extends Value>(token: Token<Value>, provider: FactoryProvider<ProviderValue>, options?: RegistrationOptions): Container;
|
280
300
|
/**
|
281
301
|
* Registers an {@link ExistingProvider} with a token.
|
282
302
|
*
|
283
303
|
* The token will alias the one set in `useExisting`.
|
284
|
-
*
|
285
|
-
* @see registerAlias
|
286
304
|
*/
|
287
305
|
register<Value, ProviderValue extends Value>(token: Token<Value>, provider: ExistingProvider<ProviderValue>): Container;
|
288
306
|
/**
|
@@ -290,8 +308,6 @@ interface Container {
|
|
290
308
|
*
|
291
309
|
* Values provided via `useValue` are never cached (scopes do not apply)
|
292
310
|
* and are simply returned as-is.
|
293
|
-
*
|
294
|
-
* @see registerValue
|
295
311
|
*/
|
296
312
|
register<Value, ProviderValue extends Value>(token: Token<Value>, provider: ValueProvider<ProviderValue>): Container;
|
297
313
|
/**
|
@@ -302,7 +318,7 @@ interface Container {
|
|
302
318
|
*
|
303
319
|
* Note that only this container is affected. Parent containers, if any, remain unchanged.
|
304
320
|
*/
|
305
|
-
unregister<Value>(token: Token<Value
|
321
|
+
unregister<Value>(token: Token<Value>, name?: string): Value[];
|
306
322
|
/**
|
307
323
|
* Resolves the given class to the instance associated with it.
|
308
324
|
*
|
@@ -328,9 +344,10 @@ interface Container {
|
|
328
344
|
* If the class is registered with _container_ scope, the resolved instance is cached
|
329
345
|
* in the container's internal registry.
|
330
346
|
*/
|
331
|
-
resolve<Instance extends object>(Class: Constructor<Instance>,
|
332
|
-
resolve<Instance extends object>(Class: Constructor<Instance>, optional
|
333
|
-
resolve<Instance extends object>(Class: Constructor<Instance>, optional?:
|
347
|
+
resolve<Instance extends object>(Class: Constructor<Instance>, name?: string): Instance;
|
348
|
+
resolve<Instance extends object>(Class: Constructor<Instance>, optional?: false, name?: string): Instance;
|
349
|
+
resolve<Instance extends object>(Class: Constructor<Instance>, optional: true, name?: string): Instance | undefined;
|
350
|
+
resolve<Instance extends object>(Class: Constructor<Instance>, optional?: boolean, name?: string): Instance | undefined;
|
334
351
|
/**
|
335
352
|
* Resolves the given token to the value associated with it.
|
336
353
|
*
|
@@ -349,9 +366,10 @@ interface Container {
|
|
349
366
|
* If the token is registered with _container_ scope, the resolved value is cached
|
350
367
|
* in the container's internal registry.
|
351
368
|
*/
|
352
|
-
resolve<Value>(token: Token<Value>,
|
353
|
-
resolve<Value>(token: Token<Value>, optional
|
354
|
-
resolve<Value>(token: Token<Value>, optional?:
|
369
|
+
resolve<Value>(token: Token<Value>, name?: string): Value;
|
370
|
+
resolve<Value>(token: Token<Value>, optional?: false, name?: string): Value;
|
371
|
+
resolve<Value>(token: Token<Value>, optional: true, name?: string): Value | undefined;
|
372
|
+
resolve<Value>(token: Token<Value>, optional?: boolean, name?: string): Value | undefined;
|
355
373
|
/**
|
356
374
|
* Resolves the given class to all instances provided by the registrations associated with it.
|
357
375
|
*
|
@@ -447,7 +465,7 @@ declare function AutoRegister(): ClassDecorator;
|
|
447
465
|
*
|
448
466
|
* // Wizard is registered with Container scope, and an instance
|
449
467
|
* // is immediately created and cached by the container
|
450
|
-
*
|
468
|
+
* container.register(Wizard);
|
451
469
|
* ```
|
452
470
|
*
|
453
471
|
* @__NO_SIDE_EFFECTS__
|
@@ -568,6 +586,26 @@ declare function InjectAll<Value>(token: Token<Value>): ParameterDecorator;
|
|
568
586
|
*/
|
569
587
|
declare function InjectAll<Value>(tokens: TokenRef<Value>): ParameterDecorator;
|
570
588
|
|
589
|
+
/**
|
590
|
+
* Qualifies a class or an injected parameter with a unique name.
|
591
|
+
*
|
592
|
+
* This allows the container to distinguish between multiple implementations
|
593
|
+
* of the same interface or type during registration and injection.
|
594
|
+
*
|
595
|
+
* @example
|
596
|
+
* ```ts
|
597
|
+
* @Named("dumbledore")
|
598
|
+
* class Dumbledore implements Wizard {}
|
599
|
+
*
|
600
|
+
* // Register Dumbledore with Type<Wizard>
|
601
|
+
* container.register(IWizard, { useClass: Dumbledore });
|
602
|
+
* const dumbledore = container.resolve(IWizard, "dumbledore");
|
603
|
+
* ```
|
604
|
+
*
|
605
|
+
* @__NO_SIDE_EFFECTS__
|
606
|
+
*/
|
607
|
+
declare function Named(name: string): ClassDecorator & ParameterDecorator;
|
608
|
+
|
571
609
|
/**
|
572
610
|
* Parameter decorator that injects the instance associated with the given class,
|
573
611
|
* or `undefined` if the class is not registered in the container.
|
@@ -656,13 +694,13 @@ declare function Scoped(scope: Scope): ClassDecorator;
|
|
656
694
|
*
|
657
695
|
* Throws an error if the class is not registered in the container.
|
658
696
|
*/
|
659
|
-
declare function inject<Instance extends object>(Class: Constructor<Instance
|
697
|
+
declare function inject<Instance extends object>(Class: Constructor<Instance>, name?: string): Instance;
|
660
698
|
/**
|
661
699
|
* Injects the value associated with the given token.
|
662
700
|
*
|
663
701
|
* Throws an error if the token is not registered in the container.
|
664
702
|
*/
|
665
|
-
declare function inject<Value>(token: Token<Value
|
703
|
+
declare function inject<Value>(token: Token<Value>, name?: string): Value;
|
666
704
|
/**
|
667
705
|
* Injects the instance associated with the given class.
|
668
706
|
*
|
@@ -684,8 +722,9 @@ declare function inject<Value>(token: Token<Value>): Value;
|
|
684
722
|
*
|
685
723
|
* @param thisArg - The containing instance, used to help resolve circular dependencies.
|
686
724
|
* @param Class - The class to resolve.
|
725
|
+
* @param name - The name qualifier of the class to resolve.
|
687
726
|
*/
|
688
|
-
declare function injectBy<Instance extends object>(thisArg: any, Class: Constructor<Instance
|
727
|
+
declare function injectBy<Instance extends object>(thisArg: any, Class: Constructor<Instance>, name?: string): Instance;
|
689
728
|
/**
|
690
729
|
* Injects the value associated with the given token.
|
691
730
|
*
|
@@ -707,8 +746,9 @@ declare function injectBy<Instance extends object>(thisArg: any, Class: Construc
|
|
707
746
|
*
|
708
747
|
* @param thisArg - The containing instance, used to help resolve circular dependencies.
|
709
748
|
* @param token - The token to resolve.
|
749
|
+
* @param name - The name qualifier of the token to resolve.
|
710
750
|
*/
|
711
|
-
declare function injectBy<Value>(thisArg: any, token: Token<Value
|
751
|
+
declare function injectBy<Value>(thisArg: any, token: Token<Value>, name?: string): Value;
|
712
752
|
|
713
753
|
/**
|
714
754
|
* Injects all instances provided by the registrations associated with the given class.
|
@@ -865,5 +905,5 @@ interface Middleware {
|
|
865
905
|
*/
|
866
906
|
declare function applyMiddleware(container: Container, middlewares: Middleware[]): Container;
|
867
907
|
|
868
|
-
export { AutoRegister, EagerInstantiate, Inject, InjectAll, Injectable, Injector, Optional, OptionalAll, Scope, Scoped, applyMiddleware, build, createContainer, createType, forwardRef, inject, injectAll, injectBy, setClassIdentityMapping };
|
908
|
+
export { AutoRegister, EagerInstantiate, Inject, InjectAll, Injectable, Injector, Named, Optional, OptionalAll, Scope, Scoped, applyMiddleware, build, createContainer, createType, forwardRef, inject, injectAll, injectBy, setClassIdentityMapping };
|
869
909
|
export type { ClassProvider, Constructor, Container, ContainerOptions, ExistingProvider, FactoryProvider, Middleware, MiddlewareComposer, Provider, RegistrationOptions, Token, TokenRef, Tokens, TokensRef, Type, ValueProvider };
|