@lppedd/di-wise-neo 0.5.3 → 0.6.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 +16 -12
- package/dist/cjs/index.d.ts +8 -8
- package/dist/cjs/index.js +40 -18
- package/dist/cjs/index.js.map +1 -1
- package/dist/es/index.d.mts +8 -8
- package/dist/es/index.mjs +40 -18
- package/dist/es/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
<p align="center">Lightweight, type-safe, flexible dependency injection library for TypeScript and JavaScript</p>
|
4
4
|
<div align="center">
|
5
5
|
|
6
|
-
[](https://github.com/lppedd/di-wise-neo/actions/workflows/test.yml)
|
7
|
+
[](https://app.codecov.io/gh/lppedd/di-wise-neo/tree/main/src)
|
7
8
|
[](https://www.npmjs.com/package/@lppedd/di-wise-neo)
|
8
9
|
[](https://bundlejs.com/?q=@lppedd/di-wise-neo)
|
9
10
|
[](https://github.com/lppedd/di-wise-neo/blob/main/LICENSE)
|
@@ -19,7 +20,6 @@
|
|
19
20
|
|
20
21
|
## Table of Contents
|
21
22
|
|
22
|
-
- [Why yet another library](#why-yet-another-library)
|
23
23
|
- [Installation](#installation)
|
24
24
|
- [API reference](#api-reference)
|
25
25
|
- [Ergonomics & Requirements](#ergonomics)
|
@@ -79,7 +79,7 @@ the use of ECMAScript Stage 3 decorators, which do not support decorating method
|
|
79
79
|
So what's the right move? Forking the best pick and refactoring it to suite my
|
80
80
|
production needs.
|
81
81
|
|
82
|
-
|
82
|
+
### Installation
|
83
83
|
|
84
84
|
```sh
|
85
85
|
npm i @lppedd/di-wise-neo
|
@@ -93,11 +93,11 @@ pnpm add @lppedd/di-wise-neo
|
|
93
93
|
yarn add @lppedd/di-wise-neo
|
94
94
|
```
|
95
95
|
|
96
|
-
|
96
|
+
### API reference
|
97
97
|
|
98
98
|
You can find the complete API reference at [lppedd.github.io/di-wise-neo](https://lppedd.github.io/di-wise-neo)
|
99
99
|
|
100
|
-
|
100
|
+
### Ergonomics
|
101
101
|
|
102
102
|
- Does **not** depend on other libraries
|
103
103
|
- Does **not** use [reflect-metadata](https://www.npmjs.com/package/reflect-metadata) to drive decorators
|
@@ -281,7 +281,9 @@ The container will translate `TaskID` to `PID` before resolving the value.
|
|
281
281
|
|
282
282
|
The primary way to perform dependency injection in **di-wise-neo** is through
|
283
283
|
functions like `inject(T)`, `injectAll(T)`, `optional(T)`, and `optionalAll(T)`.
|
284
|
-
|
284
|
+
|
285
|
+
> [!TIP]
|
286
|
+
> Using injection functions is recommended because it preserves type safety.
|
285
287
|
|
286
288
|
### Injection context
|
287
289
|
|
@@ -473,10 +475,11 @@ In this example, `ExtensionContext` will be registered with **Resolution** scope
|
|
473
475
|
|
474
476
|
### `@AutoRegister`
|
475
477
|
|
476
|
-
Enables automatic registration of the decorated class
|
478
|
+
Enables automatic registration of the decorated class when it is resolved,
|
479
|
+
if it has not been registered beforehand.
|
477
480
|
|
478
481
|
```ts
|
479
|
-
@AutoRegister
|
482
|
+
@AutoRegister()
|
480
483
|
export class ExtensionContext {
|
481
484
|
/* ... */
|
482
485
|
}
|
@@ -487,19 +490,20 @@ container.resolve(ExtensionContext);
|
|
487
490
|
|
488
491
|
### `@EagerInstantiate`
|
489
492
|
|
490
|
-
|
493
|
+
Sets the default class scope to **Container** and marks the class for eager instantiation
|
494
|
+
upon registration.
|
491
495
|
|
492
496
|
This causes the container to immediately create and cache the instance of the class
|
493
497
|
at registration time, instead of deferring instantiation until the first resolution.
|
494
498
|
|
495
499
|
```ts
|
496
|
-
@EagerInstantiate
|
497
|
-
@Scoped(Scope.Container)
|
500
|
+
@EagerInstantiate()
|
498
501
|
export class ExtensionContext {
|
499
502
|
/* ... */
|
500
503
|
}
|
501
504
|
|
502
|
-
//
|
505
|
+
// ExtensionContext is registered with Container scope,
|
506
|
+
// and an instance is immediately created and cached by the container
|
503
507
|
container.register(ExtensionContext);
|
504
508
|
```
|
505
509
|
|
package/dist/cjs/index.d.ts
CHANGED
@@ -422,7 +422,7 @@ declare function createContainer(options?: Partial<ContainerOptions>): Container
|
|
422
422
|
*
|
423
423
|
* @example
|
424
424
|
* ```ts
|
425
|
-
* @AutoRegister
|
425
|
+
* @AutoRegister()
|
426
426
|
* class Wizard {}
|
427
427
|
*
|
428
428
|
* const wizard = container.resolve(Wizard);
|
@@ -431,28 +431,28 @@ declare function createContainer(options?: Partial<ContainerOptions>): Container
|
|
431
431
|
*
|
432
432
|
* @__NO_SIDE_EFFECTS__
|
433
433
|
*/
|
434
|
-
declare function AutoRegister
|
434
|
+
declare function AutoRegister(): ClassDecorator;
|
435
435
|
|
436
436
|
/**
|
437
|
-
* Class decorator that
|
438
|
-
* in the container
|
437
|
+
* Class decorator that sets the class scope to **Container** and enables
|
438
|
+
* eager instantiation when the class is registered in the container.
|
439
439
|
*
|
440
440
|
* This causes the container to immediately create and cache the instance of the class,
|
441
441
|
* instead of deferring instantiation until the first resolution.
|
442
442
|
*
|
443
443
|
* @example
|
444
444
|
* ```ts
|
445
|
-
* @EagerInstantiate
|
446
|
-
* @Scoped(Scope.Container)
|
445
|
+
* @EagerInstantiate()
|
447
446
|
* class Wizard {}
|
448
447
|
*
|
449
|
-
* //
|
448
|
+
* // Wizard is registered with Container scope, and an instance
|
449
|
+
* // is immediately created and cached by the container
|
450
450
|
* const wizard = container.register(Wizard);
|
451
451
|
* ```
|
452
452
|
*
|
453
453
|
* @__NO_SIDE_EFFECTS__
|
454
454
|
*/
|
455
|
-
declare function EagerInstantiate
|
455
|
+
declare function EagerInstantiate(): ClassDecorator;
|
456
456
|
|
457
457
|
interface TokensRef<Value = any> {
|
458
458
|
readonly getRefTokens: () => Set<Token<Value>>;
|
package/dist/cjs/index.js
CHANGED
@@ -536,7 +536,7 @@ function isDisposable(value) {
|
|
536
536
|
// The provider is of type ClassProvider, initialized by getMetadata
|
537
537
|
provider: metadata.provider,
|
538
538
|
options: {
|
539
|
-
scope: metadata.scope ?? this.myOptions.defaultScope
|
539
|
+
scope: metadata.scope?.value ?? this.myOptions.defaultScope
|
540
540
|
},
|
541
541
|
dependencies: metadata.dependencies
|
542
542
|
};
|
@@ -553,7 +553,7 @@ function isDisposable(value) {
|
|
553
553
|
}
|
554
554
|
// Eager-instantiate only if the class is container-scoped
|
555
555
|
if (metadata.eagerInstantiate && registration.options?.scope === Scope.Container) {
|
556
|
-
this.
|
556
|
+
this.resolveProviderValue(registration, registration.provider);
|
557
557
|
}
|
558
558
|
} else {
|
559
559
|
const [token, provider, options] = args;
|
@@ -564,7 +564,7 @@ function isDisposable(value) {
|
|
564
564
|
options: {
|
565
565
|
// The explicit registration options override what is specified
|
566
566
|
// via class decorators (e.g., @Scoped)
|
567
|
-
scope: metadata.scope ?? this.myOptions.defaultScope,
|
567
|
+
scope: metadata.scope?.value ?? this.myOptions.defaultScope,
|
568
568
|
...options
|
569
569
|
},
|
570
570
|
dependencies: metadata.dependencies
|
@@ -572,7 +572,7 @@ function isDisposable(value) {
|
|
572
572
|
this.myTokenRegistry.set(token, registration);
|
573
573
|
// Eager-instantiate only if the provided class is container-scoped
|
574
574
|
if (metadata.eagerInstantiate && registration.options?.scope === Scope.Container) {
|
575
|
-
this.
|
575
|
+
this.resolveProviderValue(registration, registration.provider);
|
576
576
|
}
|
577
577
|
} else {
|
578
578
|
if (isExistingProvider(provider)) {
|
@@ -688,7 +688,7 @@ function isDisposable(value) {
|
|
688
688
|
metadata.eagerInstantiate = eagerInstantiate;
|
689
689
|
}
|
690
690
|
}
|
691
|
-
const scope = this.resolveScope(metadata.scope);
|
691
|
+
const scope = this.resolveScope(metadata.scope?.value);
|
692
692
|
if (optional && scope === Scope.Container) {
|
693
693
|
// It would not be possible to resolve the class in container scope,
|
694
694
|
// as that would require prior registration.
|
@@ -878,7 +878,7 @@ function isDisposable(value) {
|
|
878
878
|
*
|
879
879
|
* @example
|
880
880
|
* ```ts
|
881
|
-
* @AutoRegister
|
881
|
+
* @AutoRegister()
|
882
882
|
* class Wizard {}
|
883
883
|
*
|
884
884
|
* const wizard = container.resolve(Wizard);
|
@@ -886,32 +886,45 @@ function isDisposable(value) {
|
|
886
886
|
* ```
|
887
887
|
*
|
888
888
|
* @__NO_SIDE_EFFECTS__
|
889
|
-
*/ function AutoRegister(
|
890
|
-
|
891
|
-
|
889
|
+
*/ function AutoRegister() {
|
890
|
+
return function(Class) {
|
891
|
+
const metadata = getMetadata(Class);
|
892
|
+
metadata.autoRegister = true;
|
893
|
+
};
|
892
894
|
}
|
893
895
|
|
894
896
|
/**
|
895
|
-
* Class decorator that
|
896
|
-
* in the container
|
897
|
+
* Class decorator that sets the class scope to **Container** and enables
|
898
|
+
* eager instantiation when the class is registered in the container.
|
897
899
|
*
|
898
900
|
* This causes the container to immediately create and cache the instance of the class,
|
899
901
|
* instead of deferring instantiation until the first resolution.
|
900
902
|
*
|
901
903
|
* @example
|
902
904
|
* ```ts
|
903
|
-
* @EagerInstantiate
|
904
|
-
* @Scoped(Scope.Container)
|
905
|
+
* @EagerInstantiate()
|
905
906
|
* class Wizard {}
|
906
907
|
*
|
907
|
-
* //
|
908
|
+
* // Wizard is registered with Container scope, and an instance
|
909
|
+
* // is immediately created and cached by the container
|
908
910
|
* const wizard = container.register(Wizard);
|
909
911
|
* ```
|
910
912
|
*
|
911
913
|
* @__NO_SIDE_EFFECTS__
|
912
|
-
*/ function EagerInstantiate(
|
913
|
-
|
914
|
-
|
914
|
+
*/ function EagerInstantiate() {
|
915
|
+
return function(Class) {
|
916
|
+
const metadata = getMetadata(Class);
|
917
|
+
const currentScope = metadata.scope;
|
918
|
+
assert(!currentScope || currentScope.value === Scope.Container, ()=>{
|
919
|
+
const { value, appliedBy } = currentScope;
|
920
|
+
return `class ${Class.name}: Scope.${value} was already set by @${appliedBy},\n ` + `but @EagerInstantiate is trying to set a conflicting Scope.Container.\n ` + `Only one decorator should set the class scope, or all must agree on the same value.`;
|
921
|
+
});
|
922
|
+
metadata.eagerInstantiate = true;
|
923
|
+
metadata.scope = {
|
924
|
+
value: Scope.Container,
|
925
|
+
appliedBy: "EagerInstantiate"
|
926
|
+
};
|
927
|
+
};
|
915
928
|
}
|
916
929
|
|
917
930
|
function forwardRef(token) {
|
@@ -1043,7 +1056,16 @@ function OptionalAll(token) {
|
|
1043
1056
|
*/ function Scoped(scope) {
|
1044
1057
|
return function(Class) {
|
1045
1058
|
const metadata = getMetadata(Class);
|
1046
|
-
|
1059
|
+
const currentScope = metadata.scope;
|
1060
|
+
assert(!currentScope || currentScope.value === scope, ()=>{
|
1061
|
+
const { value, appliedBy } = currentScope;
|
1062
|
+
const by = appliedBy === "Scoped" ? `another @${appliedBy} decorator` : `@${appliedBy}`;
|
1063
|
+
return `class ${Class.name}: Scope.${value} was already set by ${by},\n ` + `but @Scoped is trying to set a conflicting Scope.${scope}.\n ` + `Only one decorator should set the class scope, or all must agree on the same value.`;
|
1064
|
+
});
|
1065
|
+
metadata.scope = {
|
1066
|
+
value: scope,
|
1067
|
+
appliedBy: "Scoped"
|
1068
|
+
};
|
1047
1069
|
};
|
1048
1070
|
}
|
1049
1071
|
|