ts-ioc-container 72.3.0 → 72.3.2
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 +73 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -52,6 +52,7 @@ provider pipelines, aliases, and custom injector strategies.
|
|
|
52
52
|
- [Registration](#registration) `@register`
|
|
53
53
|
- [Token](#token) `bindTo`
|
|
54
54
|
- [Scope](#scope) `scope`
|
|
55
|
+
- [Environment-based registration](#environment-based-registration) `Env`
|
|
55
56
|
- [Composing decorators](#composing-decorators) `createComposeClassDecorator`
|
|
56
57
|
- [Feature flags](#feature-flags) `MultiVariantFeatureToken` `ToggleFeatureToken`
|
|
57
58
|
- [Module](#module)
|
|
@@ -2796,6 +2797,78 @@ describe('Scopes', function () {
|
|
|
2796
2797
|
|
|
2797
2798
|
```
|
|
2798
2799
|
|
|
2800
|
+
### Environment-based registration
|
|
2801
|
+
|
|
2802
|
+
Picking an implementation by deployment environment (`prod` / `dev` / `test`)
|
|
2803
|
+
needs no dedicated API - it is the same `scope()` mechanism as above: tag the
|
|
2804
|
+
container with its env and scope each implementation to the env it belongs to.
|
|
2805
|
+
Multiple registrations share the same key; only the one whose scope rule
|
|
2806
|
+
matches the container's tag registers there.
|
|
2807
|
+
|
|
2808
|
+
```typescript
|
|
2809
|
+
import { bindTo, Container, register, Registration as R, scope, SingleToken } from 'ts-ioc-container';
|
|
2810
|
+
|
|
2811
|
+
/**
|
|
2812
|
+
* Environment-based Registration
|
|
2813
|
+
*
|
|
2814
|
+
* An app often needs a different implementation per deployment environment -
|
|
2815
|
+
* a real payment gateway in production, a stub in tests, a verbose one in dev.
|
|
2816
|
+
* This is a plain application of `scope()`: tag the container with its env and
|
|
2817
|
+
* scope each implementation to the env tag it belongs to. No dedicated API is
|
|
2818
|
+
* needed - the same `ScopeMatchRule` mechanism used for `request` / `transaction`
|
|
2819
|
+
* scopes applies here too.
|
|
2820
|
+
*/
|
|
2821
|
+
type Env = 'prod' | 'dev' | 'test';
|
|
2822
|
+
|
|
2823
|
+
interface IPaymentGateway {
|
|
2824
|
+
charge(amount: number): string;
|
|
2825
|
+
}
|
|
2826
|
+
|
|
2827
|
+
const PaymentGatewayToken = new SingleToken<IPaymentGateway>('IPaymentGateway');
|
|
2828
|
+
|
|
2829
|
+
@register(bindTo(PaymentGatewayToken), scope((c) => c.hasTag('prod')))
|
|
2830
|
+
class StripeGateway implements IPaymentGateway {
|
|
2831
|
+
charge(amount: number): string {
|
|
2832
|
+
return `charged $${amount} via Stripe`;
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
@register(bindTo(PaymentGatewayToken), scope((c) => c.hasTag('dev')))
|
|
2837
|
+
class LoggingGateway implements IPaymentGateway {
|
|
2838
|
+
charge(amount: number): string {
|
|
2839
|
+
return `[dev] would charge $${amount}`;
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
@register(bindTo(PaymentGatewayToken), scope((c) => c.hasTag('test')))
|
|
2844
|
+
class FakeGateway implements IPaymentGateway {
|
|
2845
|
+
charge(amount: number): string {
|
|
2846
|
+
return `faked charge of $${amount}`;
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
const createContainerForEnv = (env: Env) =>
|
|
2851
|
+
new Container({ tags: [env] })
|
|
2852
|
+
.addRegistration(R.fromClass(StripeGateway))
|
|
2853
|
+
.addRegistration(R.fromClass(LoggingGateway))
|
|
2854
|
+
.addRegistration(R.fromClass(FakeGateway));
|
|
2855
|
+
|
|
2856
|
+
describe('Environment-based registration', function () {
|
|
2857
|
+
it('should resolve the implementation whose scope tag matches the container env', function () {
|
|
2858
|
+
expect(PaymentGatewayToken.resolve(createContainerForEnv('prod'))).toBeInstanceOf(StripeGateway);
|
|
2859
|
+
expect(PaymentGatewayToken.resolve(createContainerForEnv('dev'))).toBeInstanceOf(LoggingGateway);
|
|
2860
|
+
expect(PaymentGatewayToken.resolve(createContainerForEnv('test'))).toBeInstanceOf(FakeGateway);
|
|
2861
|
+
});
|
|
2862
|
+
|
|
2863
|
+
it('should behave like the environment it was resolved for', function () {
|
|
2864
|
+
const gateway = PaymentGatewayToken.resolve(createContainerForEnv('test'));
|
|
2865
|
+
|
|
2866
|
+
expect(gateway.charge(10)).toBe('faked charge of $10');
|
|
2867
|
+
});
|
|
2868
|
+
});
|
|
2869
|
+
|
|
2870
|
+
```
|
|
2871
|
+
|
|
2799
2872
|
### Composing decorators
|
|
2800
2873
|
|
|
2801
2874
|
A decorator stack repeated on every class of a layer is worth a name.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-ioc-container",
|
|
3
|
-
"version": "72.3.
|
|
3
|
+
"version": "72.3.2",
|
|
4
4
|
"description": "Fast, lightweight TypeScript dependency injection container with a clean API, scoped lifecycles, decorators, tokens, hooks, lazy injection, customizable providers, and no global container objects.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"build:cjm": "node ../scripts/build.mjs cjm",
|
|
91
91
|
"build:esm": "node ../scripts/build.mjs esm",
|
|
92
92
|
"build:types": "node ../scripts/build.mjs types",
|
|
93
|
-
"generate:docs": "../scripts/generate-readme/generate-readme.ts
|
|
93
|
+
"generate:docs": "../scripts/generate-readme/generate-readme.ts",
|
|
94
94
|
"build": "pnpm run build:cjm && pnpm run build:esm && pnpm run build:types",
|
|
95
95
|
"test": "vitest run",
|
|
96
96
|
"test:spec": "vitest run __tests__/specs",
|