ts-ioc-container 72.1.0 → 72.3.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/AGENTS.md +179 -0
- package/README.md +169 -0
- package/cjm/container/Container.js +5 -2
- package/cjm/container/EmptyContainer.js +20 -15
- package/cjm/errors/ArgumentNotFoundError.js +1 -0
- package/cjm/errors/CannonSingletonApplyTwiceError.js +2 -14
- package/cjm/errors/CannotApplySingletonTwiceError.js +18 -0
- package/cjm/errors/ContainerDisposedError.js +1 -0
- package/cjm/errors/ContainerError.js +1 -0
- package/cjm/errors/ContainerNotFoundError.js +1 -0
- package/cjm/errors/DependencyMissingKeyError.js +1 -0
- package/cjm/errors/DependencyNotFoundError.js +1 -0
- package/cjm/errors/MethodNotImplementedError.js +1 -0
- package/cjm/errors/ProviderDisposedError.js +1 -0
- package/cjm/errors/TypedEventDisposedError.js +1 -0
- package/cjm/errors/UnsupportedTokenTypeError.js +1 -0
- package/cjm/feature/IFeatureFlags.js +6 -0
- package/cjm/index.js +14 -3
- package/cjm/provider/Provider.js +6 -6
- package/cjm/registration/Registration.js +2 -2
- package/cjm/token/BindableToken.js +63 -0
- package/cjm/token/ConstantToken.js +4 -4
- package/cjm/token/FunctionToken.js +1 -1
- package/cjm/token/GroupAliasToken.js +5 -50
- package/cjm/token/GroupInstanceToken.js +4 -4
- package/cjm/token/MultiVariantFeatureToken.js +84 -0
- package/cjm/token/SingleAliasToken.js +5 -50
- package/cjm/token/SingleToken.js +5 -50
- package/cjm/token/ToggleFeatureToken.js +10 -0
- package/cjm/token/toToken.js +1 -1
- package/cjm/utils/TypedEvent.js +1 -1
- package/cjm/utils/array.js +1 -1
- package/esm/container/Container.js +5 -2
- package/esm/container/EmptyContainer.js +20 -15
- package/esm/errors/ArgumentNotFoundError.js +1 -0
- package/esm/errors/CannonSingletonApplyTwiceError.js +2 -13
- package/esm/errors/CannotApplySingletonTwiceError.js +14 -0
- package/esm/errors/ContainerDisposedError.js +1 -0
- package/esm/errors/ContainerError.js +1 -0
- package/esm/errors/ContainerNotFoundError.js +1 -0
- package/esm/errors/DependencyMissingKeyError.js +1 -0
- package/esm/errors/DependencyNotFoundError.js +1 -0
- package/esm/errors/MethodNotImplementedError.js +1 -0
- package/esm/errors/ProviderDisposedError.js +1 -0
- package/esm/errors/TypedEventDisposedError.js +1 -0
- package/esm/errors/UnsupportedTokenTypeError.js +1 -0
- package/esm/feature/IFeatureFlags.js +3 -0
- package/esm/index.js +5 -0
- package/esm/provider/Provider.js +6 -6
- package/esm/registration/Registration.js +2 -2
- package/esm/token/BindableToken.js +59 -0
- package/esm/token/ConstantToken.js +4 -4
- package/esm/token/FunctionToken.js +1 -1
- package/esm/token/GroupAliasToken.js +5 -50
- package/esm/token/GroupInstanceToken.js +4 -4
- package/esm/token/MultiVariantFeatureToken.js +80 -0
- package/esm/token/SingleAliasToken.js +5 -50
- package/esm/token/SingleToken.js +5 -50
- package/esm/token/ToggleFeatureToken.js +6 -0
- package/esm/token/toToken.js +1 -1
- package/esm/utils/TypedEvent.js +1 -1
- package/esm/utils/array.js +1 -1
- package/lib/ExecutionContext.ts +6 -0
- package/lib/container/AliasMap.ts +30 -0
- package/lib/container/AutoResolveModule.ts +24 -0
- package/lib/container/Container.ts +315 -0
- package/lib/container/EmptyContainer.ts +170 -0
- package/lib/container/IContainer.ts +159 -0
- package/lib/errors/ArgumentNotFoundError.ts +13 -0
- package/lib/errors/CannonSingletonApplyTwiceError.ts +6 -0
- package/lib/errors/CannotApplySingletonTwiceError.ts +22 -0
- package/lib/errors/ContainerDisposedError.ts +13 -0
- package/lib/errors/ContainerError.ts +15 -0
- package/lib/errors/ContainerNotFoundError.ts +13 -0
- package/lib/errors/DependencyMissingKeyError.ts +13 -0
- package/lib/errors/DependencyNotFoundError.ts +13 -0
- package/lib/errors/MethodNotImplementedError.ts +13 -0
- package/lib/errors/ProviderDisposedError.ts +22 -0
- package/lib/errors/TypedEventDisposedError.ts +22 -0
- package/lib/errors/UnsupportedTokenTypeError.ts +13 -0
- package/lib/feature/IFeatureFlags.ts +44 -0
- package/lib/hooks/HookCollector.ts +109 -0
- package/lib/hooks/HookContext.ts +85 -0
- package/lib/hooks/combinators.ts +51 -0
- package/lib/hooks/hook.ts +89 -0
- package/lib/hooks/injectProp.ts +14 -0
- package/lib/index.ts +197 -0
- package/lib/injector/IInjector.ts +88 -0
- package/lib/injector/MetadataInjector.ts +100 -0
- package/lib/injector/ProxyInjector.ts +31 -0
- package/lib/injector/SimpleInjector.ts +20 -0
- package/lib/metadata/class.ts +50 -0
- package/lib/metadata/method.ts +47 -0
- package/lib/metadata/parameter.ts +60 -0
- package/lib/metadata/target.ts +25 -0
- package/lib/provider/IProvider.ts +65 -0
- package/lib/provider/Provider.ts +174 -0
- package/lib/registration/IRegistration.ts +242 -0
- package/lib/registration/Registration.ts +122 -0
- package/lib/select.ts +33 -0
- package/lib/token/BindToken.ts +13 -0
- package/lib/token/BindableToken.ts +137 -0
- package/lib/token/ClassToken.ts +72 -0
- package/lib/token/ConstantToken.ts +50 -0
- package/lib/token/FunctionToken.ts +79 -0
- package/lib/token/GroupAliasToken.ts +33 -0
- package/lib/token/GroupInstanceToken.ts +70 -0
- package/lib/token/InjectionToken.ts +46 -0
- package/lib/token/MultiVariantFeatureToken.ts +160 -0
- package/lib/token/SingleAliasToken.ts +28 -0
- package/lib/token/SingleToken.ts +35 -0
- package/lib/token/ToggleFeatureToken.ts +27 -0
- package/lib/token/toToken.ts +46 -0
- package/lib/utils/ProxyRegistry.ts +149 -0
- package/lib/utils/TypedEvent.ts +96 -0
- package/lib/utils/array.ts +28 -0
- package/lib/utils/basic.ts +34 -0
- package/lib/utils/debounce.ts +18 -0
- package/lib/utils/errorHandler.ts +34 -0
- package/lib/utils/fp.ts +86 -0
- package/lib/utils/getConstructorChain.ts +17 -0
- package/lib/utils/memoize.ts +24 -0
- package/lib/utils/once.ts +24 -0
- package/lib/utils/shallowCache.ts +22 -0
- package/lib/utils/task.ts +33 -0
- package/lib/utils/throttle.ts +17 -0
- package/package.json +6 -4
- package/typings/ExecutionContext.d.ts +2 -0
- package/typings/ExecutionContext.d.ts.map +1 -0
- package/typings/container/AliasMap.d.ts +1 -0
- package/typings/container/AliasMap.d.ts.map +1 -0
- package/typings/container/AutoResolveModule.d.ts +16 -0
- package/typings/container/AutoResolveModule.d.ts.map +1 -0
- package/typings/container/Container.d.ts +61 -0
- package/typings/container/Container.d.ts.map +1 -0
- package/typings/container/EmptyContainer.d.ts +52 -0
- package/typings/container/EmptyContainer.d.ts.map +1 -0
- package/typings/container/IContainer.d.ts +77 -0
- package/typings/container/IContainer.d.ts.map +1 -0
- package/typings/errors/ArgumentNotFoundError.d.ts +3 -0
- package/typings/errors/ArgumentNotFoundError.d.ts.map +1 -0
- package/typings/errors/CannonSingletonApplyTwiceError.d.ts +6 -6
- package/typings/errors/CannonSingletonApplyTwiceError.d.ts.map +1 -0
- package/typings/errors/CannotApplySingletonTwiceError.d.ts +12 -0
- package/typings/errors/CannotApplySingletonTwiceError.d.ts.map +1 -0
- package/typings/errors/ContainerDisposedError.d.ts +3 -0
- package/typings/errors/ContainerDisposedError.d.ts.map +1 -0
- package/typings/errors/ContainerError.d.ts +7 -0
- package/typings/errors/ContainerError.d.ts.map +1 -0
- package/typings/errors/ContainerNotFoundError.d.ts +3 -0
- package/typings/errors/ContainerNotFoundError.d.ts.map +1 -0
- package/typings/errors/DependencyMissingKeyError.d.ts +3 -0
- package/typings/errors/DependencyMissingKeyError.d.ts.map +1 -0
- package/typings/errors/DependencyNotFoundError.d.ts +3 -0
- package/typings/errors/DependencyNotFoundError.d.ts.map +1 -0
- package/typings/errors/MethodNotImplementedError.d.ts +3 -0
- package/typings/errors/MethodNotImplementedError.d.ts.map +1 -0
- package/typings/errors/ProviderDisposedError.d.ts +6 -0
- package/typings/errors/ProviderDisposedError.d.ts.map +1 -0
- package/typings/errors/TypedEventDisposedError.d.ts +6 -0
- package/typings/errors/TypedEventDisposedError.d.ts.map +1 -0
- package/typings/errors/UnsupportedTokenTypeError.d.ts +3 -0
- package/typings/errors/UnsupportedTokenTypeError.d.ts.map +1 -0
- package/typings/feature/IFeatureFlags.d.ts +42 -0
- package/typings/feature/IFeatureFlags.d.ts.map +1 -0
- package/typings/hooks/HookCollector.d.ts +36 -0
- package/typings/hooks/HookCollector.d.ts.map +1 -0
- package/typings/hooks/HookContext.d.ts +10 -0
- package/typings/hooks/HookContext.d.ts.map +1 -0
- package/typings/hooks/combinators.d.ts +23 -0
- package/typings/hooks/combinators.d.ts.map +1 -0
- package/typings/hooks/hook.d.ts +39 -0
- package/typings/hooks/hook.d.ts.map +1 -0
- package/typings/hooks/injectProp.d.ts +9 -0
- package/typings/hooks/injectProp.d.ts.map +1 -0
- package/typings/index.d.ts +6 -0
- package/typings/index.d.ts.map +1 -0
- package/typings/injector/IInjector.d.ts +32 -0
- package/typings/injector/IInjector.d.ts.map +1 -0
- package/typings/injector/MetadataInjector.d.ts +58 -0
- package/typings/injector/MetadataInjector.d.ts.map +1 -0
- package/typings/injector/ProxyInjector.d.ts +13 -0
- package/typings/injector/ProxyInjector.d.ts.map +1 -0
- package/typings/injector/SimpleInjector.d.ts +13 -0
- package/typings/injector/SimpleInjector.d.ts.map +1 -0
- package/typings/metadata/class.d.ts +27 -0
- package/typings/metadata/class.d.ts.map +1 -0
- package/typings/metadata/method.d.ts +24 -0
- package/typings/metadata/method.d.ts.map +1 -0
- package/typings/metadata/parameter.d.ts +21 -0
- package/typings/metadata/parameter.d.ts.map +1 -0
- package/typings/metadata/target.d.ts +19 -0
- package/typings/metadata/target.d.ts.map +1 -0
- package/typings/provider/IProvider.d.ts +25 -0
- package/typings/provider/IProvider.d.ts.map +1 -0
- package/typings/provider/Provider.d.ts +30 -0
- package/typings/provider/Provider.d.ts.map +1 -0
- package/typings/registration/IRegistration.d.ts +144 -0
- package/typings/registration/IRegistration.d.ts.map +1 -0
- package/typings/registration/Registration.d.ts +23 -0
- package/typings/registration/Registration.d.ts.map +1 -0
- package/typings/select.d.ts +15 -0
- package/typings/select.d.ts.map +1 -0
- package/typings/token/BindToken.d.ts +3 -0
- package/typings/token/BindToken.d.ts.map +1 -0
- package/typings/token/BindableToken.d.ts +80 -0
- package/typings/token/BindableToken.d.ts.map +1 -0
- package/typings/token/ClassToken.d.ts +2 -0
- package/typings/token/ClassToken.d.ts.map +1 -0
- package/typings/token/ConstantToken.d.ts +14 -0
- package/typings/token/ConstantToken.d.ts.map +1 -0
- package/typings/token/FunctionToken.d.ts +10 -0
- package/typings/token/FunctionToken.d.ts.map +1 -0
- package/typings/token/GroupAliasToken.d.ts +21 -22
- package/typings/token/GroupAliasToken.d.ts.map +1 -0
- package/typings/token/GroupInstanceToken.d.ts +19 -0
- package/typings/token/GroupInstanceToken.d.ts.map +1 -0
- package/typings/token/InjectionToken.d.ts +8 -0
- package/typings/token/InjectionToken.d.ts.map +1 -0
- package/typings/token/MultiVariantFeatureToken.d.ts +79 -0
- package/typings/token/MultiVariantFeatureToken.d.ts.map +1 -0
- package/typings/token/SingleAliasToken.d.ts +16 -22
- package/typings/token/SingleAliasToken.d.ts.map +1 -0
- package/typings/token/SingleToken.d.ts +25 -21
- package/typings/token/SingleToken.d.ts.map +1 -0
- package/typings/token/ToggleFeatureToken.d.ts +25 -0
- package/typings/token/ToggleFeatureToken.d.ts.map +1 -0
- package/typings/token/toToken.d.ts +12 -0
- package/typings/token/toToken.d.ts.map +1 -0
- package/typings/utils/ProxyRegistry.d.ts +63 -0
- package/typings/utils/ProxyRegistry.d.ts.map +1 -0
- package/typings/utils/TypedEvent.d.ts +42 -0
- package/typings/utils/TypedEvent.d.ts.map +1 -0
- package/typings/utils/array.d.ts +7 -0
- package/typings/utils/array.d.ts.map +1 -0
- package/typings/utils/basic.d.ts +12 -0
- package/typings/utils/basic.d.ts.map +1 -0
- package/typings/utils/debounce.d.ts +2 -0
- package/typings/utils/debounce.d.ts.map +1 -0
- package/typings/utils/errorHandler.d.ts +4 -0
- package/typings/utils/errorHandler.d.ts.map +1 -0
- package/typings/utils/fp.d.ts +8 -0
- package/typings/utils/fp.d.ts.map +1 -0
- package/typings/utils/getConstructorChain.d.ts +9 -0
- package/typings/utils/getConstructorChain.d.ts.map +1 -0
- package/typings/utils/memoize.d.ts +10 -0
- package/typings/utils/memoize.d.ts.map +1 -0
- package/typings/utils/once.d.ts +2 -0
- package/typings/utils/once.d.ts.map +1 -0
- package/typings/utils/shallowCache.d.ts +2 -0
- package/typings/utils/shallowCache.d.ts.map +1 -0
- package/typings/utils/task.d.ts +13 -0
- package/typings/utils/task.d.ts.map +1 -0
- package/typings/utils/throttle.d.ts +2 -0
- package/typings/utils/throttle.d.ts.map +1 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# ts-ioc-container — guide for AI coding agents
|
|
2
|
+
|
|
3
|
+
This file ships inside the npm package, so it matches the version installed in
|
|
4
|
+
`node_modules`. **Trust it over what you remember**: the API changed a lot
|
|
5
|
+
between major versions, and code written for an older version usually compiles
|
|
6
|
+
badly or not at all. Every recipe below is executed by the package's test suite
|
|
7
|
+
(`__tests__/readme/agentRecipes.spec.ts`).
|
|
8
|
+
|
|
9
|
+
More detail: `README.md` next to this file. Types with JSDoc: `typings/`.
|
|
10
|
+
Source: `lib/`.
|
|
11
|
+
|
|
12
|
+
## Setup
|
|
13
|
+
|
|
14
|
+
```shell
|
|
15
|
+
npm install ts-ioc-container reflect-metadata
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import 'reflect-metadata'; // first line of the entrypoint
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{ "compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true } }
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Recipes
|
|
27
|
+
|
|
28
|
+
### Register a class and inject it by token
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { bindTo, by, Container, inject, register, Registration as R, scope, singleton, SingleToken } from 'ts-ioc-container';
|
|
32
|
+
|
|
33
|
+
interface ILogger {
|
|
34
|
+
log(message: string): void;
|
|
35
|
+
}
|
|
36
|
+
const ILoggerToken = new SingleToken<ILogger>('ILogger');
|
|
37
|
+
|
|
38
|
+
@register(bindTo(ILoggerToken), scope((s) => s.hasTag('application')), singleton())
|
|
39
|
+
class Logger implements ILogger {
|
|
40
|
+
log(message: string) {}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class App {
|
|
44
|
+
constructor(@inject(by(ILoggerToken)) private logger: ILogger) {}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const container = new Container({ tags: ['application'] }).addRegistration(R.fromClass(Logger));
|
|
48
|
+
const app = container.resolve(App); // an unregistered class is constructed by the injector
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Request-scoped service depending on an application singleton
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
const IRepositoryToken = new SingleToken<Repository>('IRepository');
|
|
55
|
+
|
|
56
|
+
@register(bindTo(IRepositoryToken), scope((s) => s.hasTag('request')), singleton())
|
|
57
|
+
class Repository {
|
|
58
|
+
constructor(@inject(by(ILoggerToken)) readonly logger: ILogger) {}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const app = new Container({ tags: ['application'] })
|
|
62
|
+
.addRegistration(R.fromClass(Logger))
|
|
63
|
+
.addRegistration(R.fromClass(Repository));
|
|
64
|
+
|
|
65
|
+
const request = app.createScope({ tags: ['request'] }); // one per request
|
|
66
|
+
const repo = IRepositoryToken.resolve(request);
|
|
67
|
+
request.dispose(); // when the request ends; child scopes are not disposed automatically
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Use tags `application` / `request` / `transaction` on a backend and
|
|
71
|
+
`application` / `page` / `widget` on a frontend.
|
|
72
|
+
|
|
73
|
+
### Values and factories
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
container
|
|
77
|
+
.addRegistration(R.fromValue('https://api.example.com').bindTo('API_URL'))
|
|
78
|
+
.addRegistration(R.fromFn(({ scope }) => `${scope.resolve<string>('API_URL')}/v1`).bindTo('API_V1'));
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Use the fluent `.bindTo(...)` only for `fromValue` / `fromFn` and for classes
|
|
82
|
+
you don't own. For your own classes, use `@register(bindTo(...))`.
|
|
83
|
+
|
|
84
|
+
### Runtime arguments
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
@register(bindTo(IClientToken))
|
|
88
|
+
class Client {
|
|
89
|
+
constructor(@inject(arg(0)) readonly baseUrl: string) {}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
IClientToken.args('https://a.example.com').resolve(container);
|
|
93
|
+
IClientToken.resolve(container, { args: ['https://b.example.com'] });
|
|
94
|
+
container.resolve<Client>('IClient', { args: ['https://c.example.com'] });
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`token.args(...)`, `token.argsFn(...)` and `token.lazy()` return a **new**
|
|
98
|
+
token; the original is never changed.
|
|
99
|
+
|
|
100
|
+
### Lifecycle hooks (you run them)
|
|
101
|
+
|
|
102
|
+
The library only **collects** hooks. It ships no hook names, no hook modules and
|
|
103
|
+
no runner. Define the hook name, collect on an event, and run the actions:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { hook, HookCollector, type HookType, runInOrder, toTask } from 'ts-ioc-container';
|
|
107
|
+
|
|
108
|
+
const onInit = (fn: HookType) => hook('onInit', fn);
|
|
109
|
+
const onInitHooks = new HookCollector({ key: 'onInit' });
|
|
110
|
+
|
|
111
|
+
class Service {
|
|
112
|
+
@onInit((ctx) => {
|
|
113
|
+
ctx.invokeMethod({ args: ctx.resolveArgs() }); // hook functions return void
|
|
114
|
+
})
|
|
115
|
+
init() {}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
container.getInjector().onConstructed((instance, scope) => {
|
|
119
|
+
void runInOrder(onInitHooks.getActions(instance, { scope }).map(toTask));
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Other events to collect on: `container.scopeDisposed.subscribe(...)`,
|
|
124
|
+
`container.registered.subscribe((provider) => provider.onResolved(...))`, or the
|
|
125
|
+
`onResolve(...)` registration pipe for a single registration. Combine several
|
|
126
|
+
hooks on one member with `sequential(...)`, `parallel(...)` or
|
|
127
|
+
`oncePerInstance(...)`. Decorating one member twice with the same key replaces
|
|
128
|
+
the first hook.
|
|
129
|
+
|
|
130
|
+
## Pitfalls
|
|
131
|
+
|
|
132
|
+
| Symptom | Cause | Fix |
|
|
133
|
+
| --- | --- | --- |
|
|
134
|
+
| Constructor param is `undefined` | Params without `@inject` are never injected | Annotate every param: `@inject(by(Token))` |
|
|
135
|
+
| TS error on `@inject(Token)` | `inject` takes one `InjectFn` | `@inject(by(Token))`, `@inject(by('Key'))`, `@inject(by(Class))` |
|
|
136
|
+
| TS error on `container.resolve(Token)` | `container.resolve` takes a key or a class | `Token.resolve(container)` |
|
|
137
|
+
| A "singleton" differs per request | A registration without `scope(...)` is copied into every child scope | Add `scope((s) => s.hasTag('application'))` |
|
|
138
|
+
| `DependencyNotFoundError` from an outer scope | Outer scopes cannot resolve inner-scope-only dependencies | Register the dependency in the outer scope too, or move the consumer inward |
|
|
139
|
+
| Registration missing in an existing child scope | Scopes copy registrations when `createScope()` runs | Register before creating the scope, or add it to the child |
|
|
140
|
+
| Constructor receives a token object instead of an instance | Args are passed as-is, never resolved | `Token.argsFn((scope) => [Other.resolve(scope)])` |
|
|
141
|
+
| Hook method never runs | Nothing runs hooks for you | Collect with `HookCollector` and run the actions (see above) |
|
|
142
|
+
| TS error on a hook arrow function | `HookFn` must return `void` or `Promise<void>` | Use a block body: `(ctx) => { ... }` |
|
|
143
|
+
| `@inject` metadata missing at runtime | `reflect-metadata` not imported first | `import 'reflect-metadata'` at the top of the entrypoint |
|
|
144
|
+
|
|
145
|
+
## Removed APIs (do not use)
|
|
146
|
+
|
|
147
|
+
| Removed | Use instead |
|
|
148
|
+
| --- | --- |
|
|
149
|
+
| `@inject(Token)`, `@inject('Key')`, `@inject(Token, ...mappers)` | `@inject(by(Token))`, `@inject(pipe(by(Token), mapFn))` |
|
|
150
|
+
| `toMappedToken` | `pipe(by(Token), ...mappers)` |
|
|
151
|
+
| `InjectFn` as `(scope, options)` | `({ scope, args }) => ...` — the scope is inside the options object |
|
|
152
|
+
| `onConstruct`, `onDispose`, `onResolved` decorators from the library | Define your own: `const onConstruct = (fn: HookType) => hook('onConstruct', fn)` |
|
|
153
|
+
| `OnConstructModule`, `OnDisposeModule`, `OnResolvedModule`, `resolved(...)` | Subscribe to `getInjector().onConstructed`, `scopeDisposed`, `registered` yourself |
|
|
154
|
+
| Hook execution strategies, `onError` options | Run the collected actions yourself (`runInOrder`, `runAtOnce`, `toTask`) |
|
|
155
|
+
| `Async`-suffixed hooks and modules | Hooks are async-capable by default |
|
|
156
|
+
| `onceResolved`, `onceResolvedAsync` | `oncePerInstance(hook)` |
|
|
157
|
+
| Several hooks passed to one `@hook(...)` | `@hook(key, sequential(a, b))` or `parallel(a, b)` |
|
|
158
|
+
| `container.onScopeCreated(...)` and similar methods | `container.scopeCreated.subscribe(...)` (events return an unsubscribe fn) |
|
|
159
|
+
| `args(index)` injector helper | `arg(index)`; `args` now injects the whole args array |
|
|
160
|
+
| `InjectionToken.getKey()` | Tokens are `Serializable` |
|
|
161
|
+
| Args that are tokens being auto-resolved | `token.argsFn((scope) => [Other.resolve(scope)])` |
|
|
162
|
+
| `isProxy`, `getProxyTarget` | `unwrapProxy` |
|
|
163
|
+
|
|
164
|
+
## Errors
|
|
165
|
+
|
|
166
|
+
All errors extend `ContainerError` and carry a stable `code`:
|
|
167
|
+
|
|
168
|
+
| Code | Error | Usually means |
|
|
169
|
+
| --- | --- | --- |
|
|
170
|
+
| `IOC_DEPENDENCY_NOT_FOUND` | `DependencyNotFoundError` | Key not registered in this scope chain, or excluded by `scope(...)` / `scopeAccess(...)` |
|
|
171
|
+
| `IOC_DEPENDENCY_MISSING_KEY` | `DependencyMissingKeyError` | A registration has no key: add `bindTo(...)` |
|
|
172
|
+
| `IOC_CONTAINER_DISPOSED` | `ContainerDisposedError` | Using a scope after `dispose()` |
|
|
173
|
+
| `IOC_PROVIDER_DISPOSED` | `ProviderDisposedError` | Using a provider after its scope was disposed |
|
|
174
|
+
| `IOC_EVENT_DISPOSED` | `TypedEventDisposedError` | Subscribing to an event of a disposed scope |
|
|
175
|
+
| `IOC_SINGLETON_APPLIED_TWICE` | `CannotApplySingletonTwiceError` | `singleton()` appears twice in one registration |
|
|
176
|
+
| `IOC_UNSUPPORTED_TOKEN_TYPE` | `UnsupportedTokenTypeError` | `toToken(...)` got a value that is not a key, class or token |
|
|
177
|
+
| `IOC_ARGUMENT_NOT_FOUND` | `ArgumentNotFoundError` | `findOrFail` / `argsFn` predicate matched nothing |
|
|
178
|
+
| `IOC_CONTAINER_NOT_FOUND` | `ContainerNotFoundError` | No container is associated with the target |
|
|
179
|
+
| `IOC_METHOD_NOT_IMPLEMENTED` | `MethodNotImplementedError` | Called a method the object does not support (e.g. on `EmptyContainer`) |
|
package/README.md
CHANGED
|
@@ -53,6 +53,7 @@ provider pipelines, aliases, and custom injector strategies.
|
|
|
53
53
|
- [Token](#token) `bindTo`
|
|
54
54
|
- [Scope](#scope) `scope`
|
|
55
55
|
- [Composing decorators](#composing-decorators) `createComposeClassDecorator`
|
|
56
|
+
- [Feature flags](#feature-flags) `MultiVariantFeatureToken` `ToggleFeatureToken`
|
|
56
57
|
- [Module](#module)
|
|
57
58
|
- [Hook](#hook) `@hook`
|
|
58
59
|
- [Hook domains](#hook-domains) `ScopeHook` `InjectorHook` `ProviderHook`
|
|
@@ -2887,6 +2888,174 @@ describe('composing decorators', () => {
|
|
|
2887
2888
|
|
|
2888
2889
|
```
|
|
2889
2890
|
|
|
2891
|
+
### Feature flags
|
|
2892
|
+
|
|
2893
|
+
Feature tokens let a feature flag choose which implementation is injected, so
|
|
2894
|
+
consumers depend on one type and never see the flag. The implementations
|
|
2895
|
+
decide where they belong - each one's own token declares its role:
|
|
2896
|
+
|
|
2897
|
+
- `token.variantOf(Feature, 'blue')` - used while the flag serves the variant `blue` (`getVariant`)
|
|
2898
|
+
- `token.primaryVariantOf(Feature)` - used while the flag is on and no named variant implementation matches
|
|
2899
|
+
- `token.fallbackOf(Feature)` - used otherwise: the flag is off, serves nothing implemented, or its client throws
|
|
2900
|
+
|
|
2901
|
+
**Every flag has a fallback**: resolving a feature without one registered is a
|
|
2902
|
+
`DependencyNotFoundError`, whatever the flag serves. `MultiVariantFeatureToken<T, V>`
|
|
2903
|
+
is the general case; `ToggleFeatureToken<T>` is its on/off case - no named
|
|
2904
|
+
variants, only a primary one (`isEnabled`). Each implementation stays
|
|
2905
|
+
injectable through its own token.
|
|
2906
|
+
|
|
2907
|
+
The flag client comes from `IFeatureFlagsToken` and the context it evaluates
|
|
2908
|
+
for from `IFeatureContextToken`, both resolved from the resolving scope on every
|
|
2909
|
+
resolution - register the context in your `request` scope. A missing client or
|
|
2910
|
+
context is a `DependencyNotFoundError`, never a silent fallback.
|
|
2911
|
+
|
|
2912
|
+
`IFeatureFlags` is shaped after Unleash (`isEnabled(name, context)`,
|
|
2913
|
+
`getVariant(name, context)`), so an Unleash client is registered as is:
|
|
2914
|
+
`R.fromValue(unleash).bindTo(IFeatureFlagsToken)`. Resolution is synchronous;
|
|
2915
|
+
wrap an asynchronous client (e.g. the OpenFeature server SDK) in an adapter
|
|
2916
|
+
that evaluates ahead of time. `Feature.lazy()` defers the evaluation to first use.
|
|
2917
|
+
|
|
2918
|
+
```typescript
|
|
2919
|
+
import 'reflect-metadata';
|
|
2920
|
+
import {
|
|
2921
|
+
by,
|
|
2922
|
+
Container,
|
|
2923
|
+
type FeatureContext,
|
|
2924
|
+
type FeatureVariant,
|
|
2925
|
+
type IFeatureFlags,
|
|
2926
|
+
IFeatureContextToken,
|
|
2927
|
+
IFeatureFlagsToken,
|
|
2928
|
+
inject,
|
|
2929
|
+
MultiVariantFeatureToken,
|
|
2930
|
+
register,
|
|
2931
|
+
Registration as R,
|
|
2932
|
+
SingleToken,
|
|
2933
|
+
ToggleFeatureToken,
|
|
2934
|
+
} from 'ts-ioc-container';
|
|
2935
|
+
|
|
2936
|
+
/**
|
|
2937
|
+
* Checkout Domain - Feature Flags
|
|
2938
|
+
*
|
|
2939
|
+
* A flag chooses which implementation is injected; the consumer depends on one
|
|
2940
|
+
* type and never sees the flag. The implementations decide where they belong:
|
|
2941
|
+
* each one's own token declares it
|
|
2942
|
+
*
|
|
2943
|
+
* - `.variantOf(feature, name)` - used while the flag serves the variant `name`;
|
|
2944
|
+
* - `.primaryVariantOf(feature)` - used while the flag is on and no named
|
|
2945
|
+
* variant implementation matches (the "on" side of a toggle);
|
|
2946
|
+
* - `.fallbackOf(feature)` - used otherwise. Every flag has one.
|
|
2947
|
+
*
|
|
2948
|
+
* `ToggleFeatureToken` is the on/off case of `MultiVariantFeatureToken`: no
|
|
2949
|
+
* named variants, only a primary one.
|
|
2950
|
+
*
|
|
2951
|
+
* The flag client is any object with `isEnabled(name, context)` and
|
|
2952
|
+
* `getVariant(name, context)` - an Unleash client works as is:
|
|
2953
|
+
* container.addRegistration(R.fromValue(unleash).bindTo(IFeatureFlagsToken));
|
|
2954
|
+
*/
|
|
2955
|
+
|
|
2956
|
+
// Toggle: new checkout on / off
|
|
2957
|
+
interface IPaymentGateway {
|
|
2958
|
+
pay(amount: number): string;
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2961
|
+
const PaymentGatewayToken = new ToggleFeatureToken<IPaymentGateway>('new-checkout');
|
|
2962
|
+
|
|
2963
|
+
// Each implementation's own token declares where it belongs
|
|
2964
|
+
@register(new SingleToken<IPaymentGateway>('LegacyGateway').fallbackOf(PaymentGatewayToken))
|
|
2965
|
+
class LegacyGateway implements IPaymentGateway {
|
|
2966
|
+
pay(amount: number) {
|
|
2967
|
+
return `legacy charged ${amount}`;
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
|
|
2971
|
+
@register(new SingleToken<IPaymentGateway>('StripeGateway').primaryVariantOf(PaymentGatewayToken))
|
|
2972
|
+
class StripeGateway implements IPaymentGateway {
|
|
2973
|
+
pay(amount: number) {
|
|
2974
|
+
return `stripe charged ${amount}`;
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
|
|
2978
|
+
// Multi-variant: A/B/n experiment on the checkout button
|
|
2979
|
+
interface ICheckoutButton {
|
|
2980
|
+
render(): string;
|
|
2981
|
+
}
|
|
2982
|
+
|
|
2983
|
+
const CheckoutButtonToken = new MultiVariantFeatureToken<ICheckoutButton, 'blue' | 'green'>('checkout-button');
|
|
2984
|
+
|
|
2985
|
+
@register(new SingleToken<ICheckoutButton>('GreyButton').fallbackOf(CheckoutButtonToken))
|
|
2986
|
+
class GreyButton implements ICheckoutButton {
|
|
2987
|
+
render() {
|
|
2988
|
+
return 'grey button';
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
|
|
2992
|
+
@register(new SingleToken<ICheckoutButton>('BlueButton').variantOf(CheckoutButtonToken, 'blue'))
|
|
2993
|
+
class BlueButton implements ICheckoutButton {
|
|
2994
|
+
render() {
|
|
2995
|
+
return 'blue button';
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
@register(new SingleToken<ICheckoutButton>('GreenButton').variantOf(CheckoutButtonToken, 'green'))
|
|
3000
|
+
class GreenButton implements ICheckoutButton {
|
|
3001
|
+
render() {
|
|
3002
|
+
return 'green button';
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
|
|
3006
|
+
class CheckoutPage {
|
|
3007
|
+
constructor(
|
|
3008
|
+
@inject(by(PaymentGatewayToken)) private readonly gateway: IPaymentGateway,
|
|
3009
|
+
@inject(by(CheckoutButtonToken)) private readonly button: ICheckoutButton,
|
|
3010
|
+
) {}
|
|
3011
|
+
|
|
3012
|
+
render(amount: number) {
|
|
3013
|
+
return `${this.button.render()}, ${this.gateway.pay(amount)}`;
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
|
|
3017
|
+
// Stands in for an Unleash client
|
|
3018
|
+
class InMemoryFlags implements IFeatureFlags {
|
|
3019
|
+
isEnabled(name: string, context?: FeatureContext) {
|
|
3020
|
+
return name === 'new-checkout' && context?.userId === 'beta-tester';
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
getVariant(name: string, context?: FeatureContext): FeatureVariant {
|
|
3024
|
+
const bucket = { 'beta-tester': 'green', 'user-1': 'blue' }[context?.userId ?? ''];
|
|
3025
|
+
return name === 'checkout-button' && bucket
|
|
3026
|
+
? { name: bucket, enabled: true }
|
|
3027
|
+
: { name: 'disabled', enabled: false };
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
|
|
3031
|
+
describe('Feature flags', () => {
|
|
3032
|
+
const app = new Container({ tags: ['application'] })
|
|
3033
|
+
.addRegistration(R.fromValue(new InMemoryFlags()).bindTo(IFeatureFlagsToken))
|
|
3034
|
+
.addRegistration(R.fromClass(LegacyGateway))
|
|
3035
|
+
.addRegistration(R.fromClass(GreyButton))
|
|
3036
|
+
.addRegistration(R.fromClass(StripeGateway))
|
|
3037
|
+
.addRegistration(R.fromClass(BlueButton))
|
|
3038
|
+
.addRegistration(R.fromClass(GreenButton));
|
|
3039
|
+
|
|
3040
|
+
// The context is per request: each request evaluates the flags for its own user
|
|
3041
|
+
const handleRequest = (userId: string) => {
|
|
3042
|
+
const request = app.createScope({ tags: ['request'] });
|
|
3043
|
+
request.addRegistration(R.fromValue({ userId }).bindTo(IFeatureContextToken));
|
|
3044
|
+
return request.resolve(CheckoutPage).render(42);
|
|
3045
|
+
};
|
|
3046
|
+
|
|
3047
|
+
it('serves each user the implementations their flags select', () => {
|
|
3048
|
+
expect(handleRequest('beta-tester')).toBe('green button, stripe charged 42');
|
|
3049
|
+
expect(handleRequest('user-1')).toBe('blue button, legacy charged 42');
|
|
3050
|
+
});
|
|
3051
|
+
|
|
3052
|
+
it('serves the fallbacks to everyone else', () => {
|
|
3053
|
+
expect(handleRequest('regular-user')).toBe('grey button, legacy charged 42');
|
|
3054
|
+
});
|
|
3055
|
+
});
|
|
3056
|
+
|
|
3057
|
+
```
|
|
3058
|
+
|
|
2890
3059
|
## Module
|
|
2891
3060
|
|
|
2892
3061
|
Sometimes you want to encapsulate registration logic in separate module. This is what `IContainerModule` is for.
|
|
@@ -129,6 +129,9 @@ class Container {
|
|
|
129
129
|
hasRegistration(key) {
|
|
130
130
|
return this.registrations.some((r) => r.getKeyOrFail() === key) || this.parent.hasRegistration(key);
|
|
131
131
|
}
|
|
132
|
+
hasAlias(alias) {
|
|
133
|
+
return this.aliases.getKeysByAlias(alias).length > 0 || this.parent.hasAlias(alias);
|
|
134
|
+
}
|
|
132
135
|
addInstance(instance) {
|
|
133
136
|
this.instances.add(instance);
|
|
134
137
|
}
|
|
@@ -164,12 +167,12 @@ class Container {
|
|
|
164
167
|
}
|
|
165
168
|
validateContainer() {
|
|
166
169
|
if (this.isDisposed) {
|
|
167
|
-
throw new ContainerDisposedError_1.ContainerDisposedError('Container is already disposed');
|
|
170
|
+
throw new ContainerDisposedError_1.ContainerDisposedError('Container is already disposed: a scope cannot be used after dispose(). Create a new scope.');
|
|
168
171
|
}
|
|
169
172
|
}
|
|
170
173
|
findProviderByKeyOrFail(key) {
|
|
171
174
|
if (!this.providers.has(key)) {
|
|
172
|
-
throw new DependencyNotFoundError_1.DependencyNotFoundError(`Provider ${key.toString()} does not exist
|
|
175
|
+
throw new DependencyNotFoundError_1.DependencyNotFoundError(`Provider ${key.toString()} does not exist: an alias points at a key with no provider in this scope.`);
|
|
173
176
|
}
|
|
174
177
|
return this.providers.get(key);
|
|
175
178
|
}
|
|
@@ -5,7 +5,7 @@ const MethodNotImplementedError_1 = require("../errors/MethodNotImplementedError
|
|
|
5
5
|
const DependencyNotFoundError_1 = require("../errors/DependencyNotFoundError");
|
|
6
6
|
class EmptyContainer {
|
|
7
7
|
get isDisposed() {
|
|
8
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
8
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.isDisposed is not implemented');
|
|
9
9
|
}
|
|
10
10
|
addInstance(instance) { }
|
|
11
11
|
getParent() {
|
|
@@ -21,25 +21,25 @@ class EmptyContainer {
|
|
|
21
21
|
return false;
|
|
22
22
|
}
|
|
23
23
|
createScope() {
|
|
24
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
24
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.createScope is not implemented');
|
|
25
25
|
}
|
|
26
26
|
getInjector() {
|
|
27
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
27
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.getInjector is not implemented');
|
|
28
28
|
}
|
|
29
29
|
autoResolve(options) {
|
|
30
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
30
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.autoResolve is not implemented');
|
|
31
31
|
}
|
|
32
32
|
dispose() {
|
|
33
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
33
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.dispose is not implemented');
|
|
34
34
|
}
|
|
35
35
|
register(key, value) {
|
|
36
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
36
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.register is not implemented');
|
|
37
37
|
}
|
|
38
38
|
hasTag(tag) {
|
|
39
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
39
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.hasTag is not implemented');
|
|
40
40
|
}
|
|
41
41
|
addTags(...tags) {
|
|
42
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
42
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.addTags is not implemented');
|
|
43
43
|
}
|
|
44
44
|
getRegistrations() {
|
|
45
45
|
return [];
|
|
@@ -47,30 +47,35 @@ class EmptyContainer {
|
|
|
47
47
|
hasRegistration(key) {
|
|
48
48
|
return false;
|
|
49
49
|
}
|
|
50
|
+
hasAlias(alias) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
50
53
|
removeScope() { }
|
|
51
54
|
useModule(module) {
|
|
52
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
55
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.useModule is not implemented');
|
|
53
56
|
}
|
|
54
57
|
addRegistration(registration) {
|
|
55
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
58
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.addRegistration is not implemented');
|
|
56
59
|
}
|
|
57
60
|
resolve(key, options) {
|
|
58
|
-
throw new DependencyNotFoundError_1.DependencyNotFoundError(`Cannot find ${key.toString()}`
|
|
61
|
+
throw new DependencyNotFoundError_1.DependencyNotFoundError(`Cannot find ${key.toString()}: no provider for this key in the resolving scope or any parent. ` +
|
|
62
|
+
'Check that it is registered, that its scope(...) rule matches this scope, that its scopeAccess(...) rule allows it, ' +
|
|
63
|
+
'and that it was registered before createScope() (existing child scopes are not updated).');
|
|
59
64
|
}
|
|
60
65
|
resolveByAlias(alias, options) {
|
|
61
66
|
return [];
|
|
62
67
|
}
|
|
63
68
|
resolveOneByAlias(alias, options) {
|
|
64
|
-
throw new DependencyNotFoundError_1.DependencyNotFoundError(`Cannot find alias ${alias.toString()}
|
|
69
|
+
throw new DependencyNotFoundError_1.DependencyNotFoundError(`Cannot find alias ${alias.toString()}: no accessible registration carries this alias in the resolving scope or any parent.`);
|
|
65
70
|
}
|
|
66
71
|
get scopeCreated() {
|
|
67
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
72
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.scopeCreated is not implemented');
|
|
68
73
|
}
|
|
69
74
|
get scopeDisposed() {
|
|
70
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
75
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.scopeDisposed is not implemented');
|
|
71
76
|
}
|
|
72
77
|
get registered() {
|
|
73
|
-
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
78
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.registered is not implemented');
|
|
74
79
|
}
|
|
75
80
|
}
|
|
76
81
|
exports.EmptyContainer = EmptyContainer;
|
|
@@ -4,6 +4,7 @@ exports.ArgumentNotFoundError = void 0;
|
|
|
4
4
|
const ContainerError_1 = require("./ContainerError");
|
|
5
5
|
class ArgumentNotFoundError extends ContainerError_1.ContainerError {
|
|
6
6
|
name = 'ArgumentNotFoundError';
|
|
7
|
+
code = 'IOC_ARGUMENT_NOT_FOUND';
|
|
7
8
|
constructor(message = 'Argument not found') {
|
|
8
9
|
super(message);
|
|
9
10
|
Object.setPrototypeOf(this, ArgumentNotFoundError.prototype);
|
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CannonSingletonApplyTwiceError = void 0;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
name = 'CannonSingletonApplyTwiceError';
|
|
7
|
-
constructor(message) {
|
|
8
|
-
super(message);
|
|
9
|
-
Object.setPrototypeOf(this, CannonSingletonApplyTwiceError.prototype);
|
|
10
|
-
}
|
|
11
|
-
static assert(isTrue, failMessage) {
|
|
12
|
-
if (!isTrue) {
|
|
13
|
-
throw new CannonSingletonApplyTwiceError(failMessage);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
exports.CannonSingletonApplyTwiceError = CannonSingletonApplyTwiceError;
|
|
4
|
+
const CannotApplySingletonTwiceError_1 = require("./CannotApplySingletonTwiceError");
|
|
5
|
+
exports.CannonSingletonApplyTwiceError = CannotApplySingletonTwiceError_1.CannotApplySingletonTwiceError;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CannotApplySingletonTwiceError = void 0;
|
|
4
|
+
const ContainerError_1 = require("./ContainerError");
|
|
5
|
+
class CannotApplySingletonTwiceError extends ContainerError_1.ContainerError {
|
|
6
|
+
name = 'CannotApplySingletonTwiceError';
|
|
7
|
+
code = 'IOC_SINGLETON_APPLIED_TWICE';
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
Object.setPrototypeOf(this, CannotApplySingletonTwiceError.prototype);
|
|
11
|
+
}
|
|
12
|
+
static assert(isTrue, failMessage) {
|
|
13
|
+
if (!isTrue) {
|
|
14
|
+
throw new CannotApplySingletonTwiceError(failMessage);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.CannotApplySingletonTwiceError = CannotApplySingletonTwiceError;
|
|
@@ -4,6 +4,7 @@ exports.ContainerDisposedError = void 0;
|
|
|
4
4
|
const ContainerError_1 = require("./ContainerError");
|
|
5
5
|
class ContainerDisposedError extends ContainerError_1.ContainerError {
|
|
6
6
|
name = 'ContainerDisposedError';
|
|
7
|
+
code = 'IOC_CONTAINER_DISPOSED';
|
|
7
8
|
constructor(message) {
|
|
8
9
|
super(message);
|
|
9
10
|
Object.setPrototypeOf(this, ContainerDisposedError.prototype);
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ContainerError = void 0;
|
|
4
4
|
class ContainerError extends Error {
|
|
5
5
|
name = 'ContainerError';
|
|
6
|
+
code = 'IOC_CONTAINER_ERROR';
|
|
6
7
|
constructor(message) {
|
|
7
8
|
super(message);
|
|
8
9
|
Object.setPrototypeOf(this, ContainerError.prototype);
|
|
@@ -4,6 +4,7 @@ exports.ContainerNotFoundError = void 0;
|
|
|
4
4
|
const ContainerError_1 = require("./ContainerError");
|
|
5
5
|
class ContainerNotFoundError extends ContainerError_1.ContainerError {
|
|
6
6
|
name = 'ContainerNotFoundError';
|
|
7
|
+
code = 'IOC_CONTAINER_NOT_FOUND';
|
|
7
8
|
constructor(message) {
|
|
8
9
|
super(message);
|
|
9
10
|
Object.setPrototypeOf(this, ContainerNotFoundError.prototype);
|
|
@@ -4,6 +4,7 @@ exports.DependencyMissingKeyError = void 0;
|
|
|
4
4
|
const ContainerError_1 = require("./ContainerError");
|
|
5
5
|
class DependencyMissingKeyError extends ContainerError_1.ContainerError {
|
|
6
6
|
name = 'DependencyMissingKeyError';
|
|
7
|
+
code = 'IOC_DEPENDENCY_MISSING_KEY';
|
|
7
8
|
constructor(message) {
|
|
8
9
|
super(message);
|
|
9
10
|
Object.setPrototypeOf(this, DependencyMissingKeyError.prototype);
|
|
@@ -4,6 +4,7 @@ exports.DependencyNotFoundError = void 0;
|
|
|
4
4
|
const ContainerError_1 = require("./ContainerError");
|
|
5
5
|
class DependencyNotFoundError extends ContainerError_1.ContainerError {
|
|
6
6
|
name = 'DependencyNotFoundError';
|
|
7
|
+
code = 'IOC_DEPENDENCY_NOT_FOUND';
|
|
7
8
|
constructor(message) {
|
|
8
9
|
super(message);
|
|
9
10
|
Object.setPrototypeOf(this, DependencyNotFoundError.prototype);
|
|
@@ -4,6 +4,7 @@ exports.MethodNotImplementedError = void 0;
|
|
|
4
4
|
const ContainerError_1 = require("./ContainerError");
|
|
5
5
|
class MethodNotImplementedError extends ContainerError_1.ContainerError {
|
|
6
6
|
name = 'MethodNotImplementedError';
|
|
7
|
+
code = 'IOC_METHOD_NOT_IMPLEMENTED';
|
|
7
8
|
constructor(message) {
|
|
8
9
|
super(message);
|
|
9
10
|
Object.setPrototypeOf(this, MethodNotImplementedError.prototype);
|
|
@@ -4,6 +4,7 @@ exports.ProviderDisposedError = void 0;
|
|
|
4
4
|
const ContainerError_1 = require("./ContainerError");
|
|
5
5
|
class ProviderDisposedError extends ContainerError_1.ContainerError {
|
|
6
6
|
name = 'ProviderDisposedError';
|
|
7
|
+
code = 'IOC_PROVIDER_DISPOSED';
|
|
7
8
|
static assert(isTrue, failMessage) {
|
|
8
9
|
if (!isTrue) {
|
|
9
10
|
throw new ProviderDisposedError(failMessage);
|
|
@@ -4,6 +4,7 @@ exports.TypedEventDisposedError = void 0;
|
|
|
4
4
|
const ContainerError_1 = require("./ContainerError");
|
|
5
5
|
class TypedEventDisposedError extends ContainerError_1.ContainerError {
|
|
6
6
|
name = 'TypedEventDisposedError';
|
|
7
|
+
code = 'IOC_EVENT_DISPOSED';
|
|
7
8
|
static assert(isTrue, failMessage) {
|
|
8
9
|
if (!isTrue) {
|
|
9
10
|
throw new TypedEventDisposedError(failMessage);
|
|
@@ -4,6 +4,7 @@ exports.UnsupportedTokenTypeError = void 0;
|
|
|
4
4
|
const ContainerError_1 = require("./ContainerError");
|
|
5
5
|
class UnsupportedTokenTypeError extends ContainerError_1.ContainerError {
|
|
6
6
|
name = 'UnsupportedTokenTypeError';
|
|
7
|
+
code = 'IOC_UNSUPPORTED_TOKEN_TYPE';
|
|
7
8
|
constructor(message) {
|
|
8
9
|
super(message);
|
|
9
10
|
Object.setPrototypeOf(this, UnsupportedTokenTypeError.prototype);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IFeatureContextToken = exports.IFeatureFlagsToken = void 0;
|
|
4
|
+
const SingleToken_1 = require("../token/SingleToken");
|
|
5
|
+
exports.IFeatureFlagsToken = new SingleToken_1.SingleToken('IFeatureFlags');
|
|
6
|
+
exports.IFeatureContextToken = new SingleToken_1.SingleToken('IFeatureContext');
|