ts-ioc-container 72.0.0 → 72.2.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.
Files changed (235) hide show
  1. package/AGENTS.md +179 -0
  2. package/README.md +94 -0
  3. package/cjm/container/Container.js +2 -2
  4. package/cjm/container/EmptyContainer.js +17 -15
  5. package/cjm/errors/ArgumentNotFoundError.js +1 -0
  6. package/cjm/errors/CannonSingletonApplyTwiceError.js +2 -14
  7. package/cjm/errors/CannotApplySingletonTwiceError.js +18 -0
  8. package/cjm/errors/ContainerDisposedError.js +1 -0
  9. package/cjm/errors/ContainerError.js +1 -0
  10. package/cjm/errors/ContainerNotFoundError.js +1 -0
  11. package/cjm/errors/DependencyMissingKeyError.js +1 -0
  12. package/cjm/errors/DependencyNotFoundError.js +1 -0
  13. package/cjm/errors/MethodNotImplementedError.js +1 -0
  14. package/cjm/errors/ProviderDisposedError.js +1 -0
  15. package/cjm/errors/TypedEventDisposedError.js +1 -0
  16. package/cjm/errors/UnsupportedTokenTypeError.js +1 -0
  17. package/cjm/index.js +8 -3
  18. package/cjm/metadata/class.js +3 -1
  19. package/cjm/metadata/method.js +3 -1
  20. package/cjm/metadata/parameter.js +7 -1
  21. package/cjm/provider/Provider.js +6 -6
  22. package/cjm/registration/Registration.js +2 -2
  23. package/cjm/token/ConstantToken.js +4 -4
  24. package/cjm/token/FunctionToken.js +1 -1
  25. package/cjm/token/GroupInstanceToken.js +4 -4
  26. package/cjm/token/toToken.js +1 -1
  27. package/cjm/utils/TypedEvent.js +1 -1
  28. package/cjm/utils/array.js +1 -1
  29. package/esm/container/Container.js +2 -2
  30. package/esm/container/EmptyContainer.js +17 -15
  31. package/esm/errors/ArgumentNotFoundError.js +1 -0
  32. package/esm/errors/CannonSingletonApplyTwiceError.js +2 -13
  33. package/esm/errors/CannotApplySingletonTwiceError.js +14 -0
  34. package/esm/errors/ContainerDisposedError.js +1 -0
  35. package/esm/errors/ContainerError.js +1 -0
  36. package/esm/errors/ContainerNotFoundError.js +1 -0
  37. package/esm/errors/DependencyMissingKeyError.js +1 -0
  38. package/esm/errors/DependencyNotFoundError.js +1 -0
  39. package/esm/errors/MethodNotImplementedError.js +1 -0
  40. package/esm/errors/ProviderDisposedError.js +1 -0
  41. package/esm/errors/TypedEventDisposedError.js +1 -0
  42. package/esm/errors/UnsupportedTokenTypeError.js +1 -0
  43. package/esm/index.js +4 -3
  44. package/esm/metadata/class.js +1 -0
  45. package/esm/metadata/method.js +1 -0
  46. package/esm/metadata/parameter.js +5 -0
  47. package/esm/provider/Provider.js +6 -6
  48. package/esm/registration/Registration.js +2 -2
  49. package/esm/token/ConstantToken.js +4 -4
  50. package/esm/token/FunctionToken.js +1 -1
  51. package/esm/token/GroupInstanceToken.js +4 -4
  52. package/esm/token/toToken.js +1 -1
  53. package/esm/utils/TypedEvent.js +1 -1
  54. package/esm/utils/array.js +1 -1
  55. package/lib/ExecutionContext.ts +6 -0
  56. package/lib/container/AliasMap.ts +30 -0
  57. package/lib/container/AutoResolveModule.ts +24 -0
  58. package/lib/container/Container.ts +311 -0
  59. package/lib/container/EmptyContainer.ts +166 -0
  60. package/lib/container/IContainer.ts +156 -0
  61. package/lib/errors/ArgumentNotFoundError.ts +13 -0
  62. package/lib/errors/CannonSingletonApplyTwiceError.ts +6 -0
  63. package/lib/errors/CannotApplySingletonTwiceError.ts +22 -0
  64. package/lib/errors/ContainerDisposedError.ts +13 -0
  65. package/lib/errors/ContainerError.ts +15 -0
  66. package/lib/errors/ContainerNotFoundError.ts +13 -0
  67. package/lib/errors/DependencyMissingKeyError.ts +13 -0
  68. package/lib/errors/DependencyNotFoundError.ts +13 -0
  69. package/lib/errors/MethodNotImplementedError.ts +13 -0
  70. package/lib/errors/ProviderDisposedError.ts +22 -0
  71. package/lib/errors/TypedEventDisposedError.ts +22 -0
  72. package/lib/errors/UnsupportedTokenTypeError.ts +13 -0
  73. package/lib/hooks/HookCollector.ts +109 -0
  74. package/lib/hooks/HookContext.ts +85 -0
  75. package/lib/hooks/combinators.ts +51 -0
  76. package/lib/hooks/hook.ts +89 -0
  77. package/lib/hooks/injectProp.ts +14 -0
  78. package/lib/index.ts +181 -0
  79. package/lib/injector/IInjector.ts +88 -0
  80. package/lib/injector/MetadataInjector.ts +100 -0
  81. package/lib/injector/ProxyInjector.ts +31 -0
  82. package/lib/injector/SimpleInjector.ts +20 -0
  83. package/lib/metadata/class.ts +50 -0
  84. package/lib/metadata/method.ts +47 -0
  85. package/lib/metadata/parameter.ts +60 -0
  86. package/lib/metadata/target.ts +25 -0
  87. package/lib/provider/IProvider.ts +65 -0
  88. package/lib/provider/Provider.ts +174 -0
  89. package/lib/registration/IRegistration.ts +235 -0
  90. package/lib/registration/Registration.ts +122 -0
  91. package/lib/select.ts +33 -0
  92. package/lib/token/BindToken.ts +13 -0
  93. package/lib/token/ClassToken.ts +72 -0
  94. package/lib/token/ConstantToken.ts +50 -0
  95. package/lib/token/FunctionToken.ts +79 -0
  96. package/lib/token/GroupAliasToken.ts +92 -0
  97. package/lib/token/GroupInstanceToken.ts +70 -0
  98. package/lib/token/InjectionToken.ts +46 -0
  99. package/lib/token/SingleAliasToken.ts +84 -0
  100. package/lib/token/SingleToken.ts +93 -0
  101. package/lib/token/toToken.ts +46 -0
  102. package/lib/utils/ProxyRegistry.ts +149 -0
  103. package/lib/utils/TypedEvent.ts +96 -0
  104. package/lib/utils/array.ts +28 -0
  105. package/lib/utils/basic.ts +34 -0
  106. package/lib/utils/debounce.ts +18 -0
  107. package/lib/utils/errorHandler.ts +34 -0
  108. package/lib/utils/fp.ts +86 -0
  109. package/lib/utils/getConstructorChain.ts +17 -0
  110. package/lib/utils/memoize.ts +24 -0
  111. package/lib/utils/once.ts +24 -0
  112. package/lib/utils/shallowCache.ts +22 -0
  113. package/lib/utils/task.ts +33 -0
  114. package/lib/utils/throttle.ts +17 -0
  115. package/package.json +5 -3
  116. package/typings/ExecutionContext.d.ts +2 -0
  117. package/typings/ExecutionContext.d.ts.map +1 -0
  118. package/typings/container/AliasMap.d.ts +1 -0
  119. package/typings/container/AliasMap.d.ts.map +1 -0
  120. package/typings/container/AutoResolveModule.d.ts +16 -0
  121. package/typings/container/AutoResolveModule.d.ts.map +1 -0
  122. package/typings/container/Container.d.ts +60 -0
  123. package/typings/container/Container.d.ts.map +1 -0
  124. package/typings/container/EmptyContainer.d.ts +51 -0
  125. package/typings/container/EmptyContainer.d.ts.map +1 -0
  126. package/typings/container/IContainer.d.ts +75 -0
  127. package/typings/container/IContainer.d.ts.map +1 -0
  128. package/typings/errors/ArgumentNotFoundError.d.ts +3 -0
  129. package/typings/errors/ArgumentNotFoundError.d.ts.map +1 -0
  130. package/typings/errors/CannonSingletonApplyTwiceError.d.ts +6 -6
  131. package/typings/errors/CannonSingletonApplyTwiceError.d.ts.map +1 -0
  132. package/typings/errors/CannotApplySingletonTwiceError.d.ts +12 -0
  133. package/typings/errors/CannotApplySingletonTwiceError.d.ts.map +1 -0
  134. package/typings/errors/ContainerDisposedError.d.ts +3 -0
  135. package/typings/errors/ContainerDisposedError.d.ts.map +1 -0
  136. package/typings/errors/ContainerError.d.ts +7 -0
  137. package/typings/errors/ContainerError.d.ts.map +1 -0
  138. package/typings/errors/ContainerNotFoundError.d.ts +3 -0
  139. package/typings/errors/ContainerNotFoundError.d.ts.map +1 -0
  140. package/typings/errors/DependencyMissingKeyError.d.ts +3 -0
  141. package/typings/errors/DependencyMissingKeyError.d.ts.map +1 -0
  142. package/typings/errors/DependencyNotFoundError.d.ts +3 -0
  143. package/typings/errors/DependencyNotFoundError.d.ts.map +1 -0
  144. package/typings/errors/MethodNotImplementedError.d.ts +3 -0
  145. package/typings/errors/MethodNotImplementedError.d.ts.map +1 -0
  146. package/typings/errors/ProviderDisposedError.d.ts +6 -0
  147. package/typings/errors/ProviderDisposedError.d.ts.map +1 -0
  148. package/typings/errors/TypedEventDisposedError.d.ts +6 -0
  149. package/typings/errors/TypedEventDisposedError.d.ts.map +1 -0
  150. package/typings/errors/UnsupportedTokenTypeError.d.ts +3 -0
  151. package/typings/errors/UnsupportedTokenTypeError.d.ts.map +1 -0
  152. package/typings/hooks/HookCollector.d.ts +36 -0
  153. package/typings/hooks/HookCollector.d.ts.map +1 -0
  154. package/typings/hooks/HookContext.d.ts +10 -0
  155. package/typings/hooks/HookContext.d.ts.map +1 -0
  156. package/typings/hooks/combinators.d.ts +23 -0
  157. package/typings/hooks/combinators.d.ts.map +1 -0
  158. package/typings/hooks/hook.d.ts +39 -0
  159. package/typings/hooks/hook.d.ts.map +1 -0
  160. package/typings/hooks/injectProp.d.ts +9 -0
  161. package/typings/hooks/injectProp.d.ts.map +1 -0
  162. package/typings/index.d.ts +5 -3
  163. package/typings/index.d.ts.map +1 -0
  164. package/typings/injector/IInjector.d.ts +32 -0
  165. package/typings/injector/IInjector.d.ts.map +1 -0
  166. package/typings/injector/MetadataInjector.d.ts +58 -0
  167. package/typings/injector/MetadataInjector.d.ts.map +1 -0
  168. package/typings/injector/ProxyInjector.d.ts +13 -0
  169. package/typings/injector/ProxyInjector.d.ts.map +1 -0
  170. package/typings/injector/SimpleInjector.d.ts +13 -0
  171. package/typings/injector/SimpleInjector.d.ts.map +1 -0
  172. package/typings/metadata/class.d.ts +28 -0
  173. package/typings/metadata/class.d.ts.map +1 -0
  174. package/typings/metadata/method.d.ts +25 -0
  175. package/typings/metadata/method.d.ts.map +1 -0
  176. package/typings/metadata/parameter.d.ts +22 -0
  177. package/typings/metadata/parameter.d.ts.map +1 -0
  178. package/typings/metadata/target.d.ts +19 -0
  179. package/typings/metadata/target.d.ts.map +1 -0
  180. package/typings/provider/IProvider.d.ts +25 -0
  181. package/typings/provider/IProvider.d.ts.map +1 -0
  182. package/typings/provider/Provider.d.ts +30 -0
  183. package/typings/provider/Provider.d.ts.map +1 -0
  184. package/typings/registration/IRegistration.d.ts +137 -0
  185. package/typings/registration/IRegistration.d.ts.map +1 -0
  186. package/typings/registration/Registration.d.ts +23 -0
  187. package/typings/registration/Registration.d.ts.map +1 -0
  188. package/typings/select.d.ts +15 -0
  189. package/typings/select.d.ts.map +1 -0
  190. package/typings/token/BindToken.d.ts +3 -0
  191. package/typings/token/BindToken.d.ts.map +1 -0
  192. package/typings/token/ClassToken.d.ts +2 -0
  193. package/typings/token/ClassToken.d.ts.map +1 -0
  194. package/typings/token/ConstantToken.d.ts +14 -0
  195. package/typings/token/ConstantToken.d.ts.map +1 -0
  196. package/typings/token/FunctionToken.d.ts +10 -0
  197. package/typings/token/FunctionToken.d.ts.map +1 -0
  198. package/typings/token/GroupAliasToken.d.ts +14 -0
  199. package/typings/token/GroupAliasToken.d.ts.map +1 -0
  200. package/typings/token/GroupInstanceToken.d.ts +19 -0
  201. package/typings/token/GroupInstanceToken.d.ts.map +1 -0
  202. package/typings/token/InjectionToken.d.ts +8 -0
  203. package/typings/token/InjectionToken.d.ts.map +1 -0
  204. package/typings/token/SingleAliasToken.d.ts +6 -0
  205. package/typings/token/SingleAliasToken.d.ts.map +1 -0
  206. package/typings/token/SingleToken.d.ts +18 -0
  207. package/typings/token/SingleToken.d.ts.map +1 -0
  208. package/typings/token/toToken.d.ts +12 -0
  209. package/typings/token/toToken.d.ts.map +1 -0
  210. package/typings/utils/ProxyRegistry.d.ts +63 -0
  211. package/typings/utils/ProxyRegistry.d.ts.map +1 -0
  212. package/typings/utils/TypedEvent.d.ts +42 -0
  213. package/typings/utils/TypedEvent.d.ts.map +1 -0
  214. package/typings/utils/array.d.ts +7 -0
  215. package/typings/utils/array.d.ts.map +1 -0
  216. package/typings/utils/basic.d.ts +12 -0
  217. package/typings/utils/basic.d.ts.map +1 -0
  218. package/typings/utils/debounce.d.ts +2 -0
  219. package/typings/utils/debounce.d.ts.map +1 -0
  220. package/typings/utils/errorHandler.d.ts +4 -0
  221. package/typings/utils/errorHandler.d.ts.map +1 -0
  222. package/typings/utils/fp.d.ts +8 -0
  223. package/typings/utils/fp.d.ts.map +1 -0
  224. package/typings/utils/getConstructorChain.d.ts +9 -0
  225. package/typings/utils/getConstructorChain.d.ts.map +1 -0
  226. package/typings/utils/memoize.d.ts +10 -0
  227. package/typings/utils/memoize.d.ts.map +1 -0
  228. package/typings/utils/once.d.ts +2 -0
  229. package/typings/utils/once.d.ts.map +1 -0
  230. package/typings/utils/shallowCache.d.ts +2 -0
  231. package/typings/utils/shallowCache.d.ts.map +1 -0
  232. package/typings/utils/task.d.ts +13 -0
  233. package/typings/utils/task.d.ts.map +1 -0
  234. package/typings/utils/throttle.d.ts +2 -0
  235. 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
@@ -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
+ - [Composing decorators](#composing-decorators) `createComposeClassDecorator`
55
56
  - [Module](#module)
56
57
  - [Hook](#hook) `@hook`
57
58
  - [Hook domains](#hook-domains) `ScopeHook` `InjectorHook` `ProviderHook`
@@ -164,6 +165,7 @@ describe('Quickstart', function () {
164
165
  - Custom inject function: `@inject(({ scope, args }) => ...)`
165
166
  - Map an injected value: `@inject(pipe(by('Key'), sanitize(), validate()))`
166
167
  - Property inject: `@hook('onInit', injectProp(by('Key')))`
168
+ - Name a decorator stack: `const repository = (token) => createComposeClassDecorator(register(token, singleton()), addClassMeta('injection-token', () => token))`
167
169
 
168
170
  > [!TIP]
169
171
  > For classes, prefer the `@register(bindTo('Key'))` decorator over the fluent
@@ -2793,6 +2795,98 @@ describe('Scopes', function () {
2793
2795
 
2794
2796
  ```
2795
2797
 
2798
+ ### Composing decorators
2799
+
2800
+ A decorator stack repeated on every class of a layer is worth a name.
2801
+ `createComposeClassDecorator(...decorators)` gives it one: it returns a single
2802
+ `ClassDecorator` which applies the stack **bottom-up, exactly as stacking would**,
2803
+ so `@createComposeClassDecorator(a, b)` behaves like `@a @b`. A decorator which
2804
+ returns a replacement class hands it to the next one, the way the runtime threads
2805
+ a stack.
2806
+
2807
+ `createComposeMethodDecorator` and `createComposeParameterDecorator` do the same
2808
+ for methods and constructor parameters. The method form threads the property
2809
+ descriptor, so wrapping decorators (`@once`, `@throttle`, ...) compose too.
2810
+
2811
+ ```typescript
2812
+ import {
2813
+ addClassMeta,
2814
+ Container,
2815
+ createComposeClassDecorator,
2816
+ createComposeParameterDecorator,
2817
+ getClassMeta,
2818
+ inject,
2819
+ by,
2820
+ addParamLabel,
2821
+ getParamLabels,
2822
+ register,
2823
+ Registration as R,
2824
+ scope,
2825
+ singleton,
2826
+ SingleToken,
2827
+ } from 'ts-ioc-container';
2828
+
2829
+ /**
2830
+ * A decorator stack repeated on every class of a layer is worth a name.
2831
+ * `createComposeClassDecorator` (and its `createComposeMethodDecorator` /
2832
+ * `createComposeParameterDecorator` siblings) turns one into a single decorator,
2833
+ * applied bottom-up exactly as stacking would.
2834
+ */
2835
+ describe('composing decorators', () => {
2836
+ const INJECTION_TOKEN = 'injection-token';
2837
+
2838
+ // Every repository binds to its own token, is an application-scoped singleton,
2839
+ // and remembers the token it was registered under.
2840
+ const repository = <T>(token: SingleToken<T>) =>
2841
+ createComposeClassDecorator(
2842
+ register(
2843
+ token,
2844
+ scope((s) => s.hasTag('application')),
2845
+ singleton(),
2846
+ ),
2847
+ addClassMeta(INJECTION_TOKEN, () => token),
2848
+ );
2849
+
2850
+ it('should apply the whole stack the composed decorator stands for', () => {
2851
+ const UserRepositoryToken = new SingleToken<UserRepository>('IUserRepository');
2852
+
2853
+ @repository(UserRepositoryToken)
2854
+ class UserRepository {
2855
+ findById(id: string) {
2856
+ return { id };
2857
+ }
2858
+ }
2859
+
2860
+ const app = new Container({ tags: ['application'] }).addRegistration(R.fromClass(UserRepository));
2861
+
2862
+ expect(UserRepositoryToken.resolve(app)).toBeInstanceOf(UserRepository);
2863
+ // singleton() applied, so the same instance comes back
2864
+ expect(UserRepositoryToken.resolve(app)).toBe(UserRepositoryToken.resolve(app));
2865
+ // and the class still carries the metadata written beside the registration
2866
+ expect(getClassMeta(UserRepository, INJECTION_TOKEN)).toBe(UserRepositoryToken);
2867
+ });
2868
+
2869
+ it('should compose parameter decorators the same way', () => {
2870
+ const ConfigToken = new SingleToken<{ apiUrl: string }>('IConfig');
2871
+
2872
+ // @inject plus a label describing where the value came from
2873
+ const fromConfig = createComposeParameterDecorator(inject(by(ConfigToken)), addParamLabel('source', 'config'));
2874
+
2875
+ class ApiClient {
2876
+ constructor(@fromConfig public config: { apiUrl: string }) {}
2877
+ }
2878
+
2879
+ const app = new Container({ tags: ['application'] }).addRegistration(
2880
+ R.fromValue({ apiUrl: 'https://api.example.com' }).bindTo(ConfigToken),
2881
+ );
2882
+
2883
+ expect(app.resolve(ApiClient).config.apiUrl).toBe('https://api.example.com');
2884
+ expect(getParamLabels(ApiClient, 0).get('source')).toBe('config');
2885
+ });
2886
+ });
2887
+
2888
+ ```
2889
+
2796
2890
  ## Module
2797
2891
 
2798
2892
  Sometimes you want to encapsulate registration logic in separate module. This is what `IContainerModule` is for.
@@ -164,12 +164,12 @@ class Container {
164
164
  }
165
165
  validateContainer() {
166
166
  if (this.isDisposed) {
167
- throw new ContainerDisposedError_1.ContainerDisposedError('Container is already disposed');
167
+ throw new ContainerDisposedError_1.ContainerDisposedError('Container is already disposed: a scope cannot be used after dispose(). Create a new scope.');
168
168
  }
169
169
  }
170
170
  findProviderByKeyOrFail(key) {
171
171
  if (!this.providers.has(key)) {
172
- throw new DependencyNotFoundError_1.DependencyNotFoundError(`Provider ${key.toString()} does not exist`);
172
+ throw new DependencyNotFoundError_1.DependencyNotFoundError(`Provider ${key.toString()} does not exist: an alias points at a key with no provider in this scope.`);
173
173
  }
174
174
  return this.providers.get(key);
175
175
  }
@@ -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 [];
@@ -49,28 +49,30 @@ class EmptyContainer {
49
49
  }
50
50
  removeScope() { }
51
51
  useModule(module) {
52
- throw new MethodNotImplementedError_1.MethodNotImplementedError();
52
+ throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.useModule is not implemented');
53
53
  }
54
54
  addRegistration(registration) {
55
- throw new MethodNotImplementedError_1.MethodNotImplementedError();
55
+ throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.addRegistration is not implemented');
56
56
  }
57
57
  resolve(key, options) {
58
- throw new DependencyNotFoundError_1.DependencyNotFoundError(`Cannot find ${key.toString()}`);
58
+ throw new DependencyNotFoundError_1.DependencyNotFoundError(`Cannot find ${key.toString()}: no provider for this key in the resolving scope or any parent. ` +
59
+ 'Check that it is registered, that its scope(...) rule matches this scope, that its scopeAccess(...) rule allows it, ' +
60
+ 'and that it was registered before createScope() (existing child scopes are not updated).');
59
61
  }
60
62
  resolveByAlias(alias, options) {
61
63
  return [];
62
64
  }
63
65
  resolveOneByAlias(alias, options) {
64
- throw new DependencyNotFoundError_1.DependencyNotFoundError(`Cannot find alias ${alias.toString()}`);
66
+ throw new DependencyNotFoundError_1.DependencyNotFoundError(`Cannot find alias ${alias.toString()}: no accessible registration carries this alias in the resolving scope or any parent.`);
65
67
  }
66
68
  get scopeCreated() {
67
- throw new MethodNotImplementedError_1.MethodNotImplementedError();
69
+ throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.scopeCreated is not implemented');
68
70
  }
69
71
  get scopeDisposed() {
70
- throw new MethodNotImplementedError_1.MethodNotImplementedError();
72
+ throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.scopeDisposed is not implemented');
71
73
  }
72
74
  get registered() {
73
- throw new MethodNotImplementedError_1.MethodNotImplementedError();
75
+ throw new MethodNotImplementedError_1.MethodNotImplementedError('EmptyContainer.registered is not implemented');
74
76
  }
75
77
  }
76
78
  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 ContainerError_1 = require("./ContainerError");
5
- class CannonSingletonApplyTwiceError extends ContainerError_1.ContainerError {
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);
package/cjm/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createHookExecutionContext = exports.createHookContextFactory = exports.HookContext = exports.toHookFn = exports.hasHooks = exports.hook = exports.getHooks = exports.ArgumentNotFoundError = exports.TypedEventDisposedError = exports.UnsupportedTokenTypeError = exports.CannonSingletonApplyTwiceError = exports.ProviderDisposedError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.ContainerNotFoundError = exports.DependencyNotFoundError = exports.ContainerError = exports.Registration = exports.onResolve = exports.appendArgsFn = exports.appendArgs = exports.decorate = exports.singleton = exports.autoResolve = exports.lazy = exports.scopeAccess = exports.scope = exports.bindTo = exports.register = exports.toRegistrationFn = exports.toProviderFn = exports.toBindToken = exports.registerPipe = exports.isProviderPipe = exports.Provider = exports.ProxyInjector = exports.SimpleInjector = exports.resolveArgs = exports.by = exports.argsFn = exports.args = exports.arg = exports.inject = exports.MetadataInjector = exports.Injector = exports.EmptyContainer = exports.AutoResolveModule = exports.Container = exports.isDependencyKey = void 0;
4
- exports.TypedEvent = exports.getConstructorChain = exports.memoize = exports.once = exports.shallowCache = exports.debounce = exports.throttle = exports.runAtOnce = exports.runInOrder = exports.handleAsyncError = exports.handleError = exports.getMethodTags = exports.addMethodTag = exports.getMethodLabels = exports.addMethodLabel = exports.getMethodMeta = exports.addMethodMeta = exports.getParamTags = exports.addParamTag = exports.getParamLabels = exports.addParamLabel = exports.getParamMeta = exports.addParamMeta = exports.getClassTags = exports.addClassTag = exports.getClassLabels = exports.addClassLabel = exports.getClassMeta = exports.addClassMeta = exports.resolveConstructor = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = exports.GroupAliasToken = exports.argToToken = exports.toToken = exports.forwardArgs = exports.isInjectionToken = exports.InjectionToken = exports.toTask = exports.HookCollector = exports.oncePerInstance = exports.parallel = exports.sequential = exports.injectProp = void 0;
5
- exports.isSerializable = exports.Is = exports.unwrapProxy = exports.ProxyRegistry = exports.findOrFail = exports.pipe = exports.select = void 0;
3
+ exports.createHookContextFactory = exports.HookContext = exports.toHookFn = exports.hasHooks = exports.hook = exports.getHooks = exports.ArgumentNotFoundError = exports.TypedEventDisposedError = exports.UnsupportedTokenTypeError = exports.CannonSingletonApplyTwiceError = exports.CannotApplySingletonTwiceError = exports.ProviderDisposedError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.ContainerNotFoundError = exports.DependencyNotFoundError = exports.ContainerError = exports.Registration = exports.onResolve = exports.appendArgsFn = exports.appendArgs = exports.decorate = exports.singleton = exports.autoResolve = exports.lazy = exports.scopeAccess = exports.scope = exports.bindTo = exports.register = exports.toRegistrationFn = exports.toProviderFn = exports.toBindToken = exports.registerPipe = exports.isProviderPipe = exports.Provider = exports.ProxyInjector = exports.SimpleInjector = exports.resolveArgs = exports.by = exports.argsFn = exports.args = exports.arg = exports.inject = exports.MetadataInjector = exports.Injector = exports.EmptyContainer = exports.AutoResolveModule = exports.Container = exports.isDependencyKey = void 0;
4
+ exports.shallowCache = exports.debounce = exports.throttle = exports.runAtOnce = exports.runInOrder = exports.handleAsyncError = exports.handleError = exports.createComposeMethodDecorator = exports.getMethodTags = exports.addMethodTag = exports.getMethodLabels = exports.addMethodLabel = exports.getMethodMeta = exports.addMethodMeta = exports.createComposeParameterDecorator = exports.getParamTags = exports.addParamTag = exports.getParamLabels = exports.addParamLabel = exports.getParamMeta = exports.addParamMeta = exports.createComposeClassDecorator = exports.getClassTags = exports.addClassTag = exports.getClassLabels = exports.addClassLabel = exports.getClassMeta = exports.addClassMeta = exports.resolveConstructor = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = exports.GroupAliasToken = exports.argToToken = exports.toToken = exports.forwardArgs = exports.isInjectionToken = exports.InjectionToken = exports.toTask = exports.HookCollector = exports.oncePerInstance = exports.parallel = exports.sequential = exports.injectProp = exports.createHookExecutionContext = void 0;
5
+ exports.isSerializable = exports.Is = exports.unwrapProxy = exports.ProxyRegistry = exports.findOrFail = exports.pipe = exports.select = exports.TypedEvent = exports.getConstructorChain = exports.memoize = exports.once = void 0;
6
6
  var IContainer_1 = require("./container/IContainer");
7
7
  Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
8
8
  var Container_1 = require("./container/Container");
@@ -60,6 +60,8 @@ var ContainerDisposedError_1 = require("./errors/ContainerDisposedError");
60
60
  Object.defineProperty(exports, "ContainerDisposedError", { enumerable: true, get: function () { return ContainerDisposedError_1.ContainerDisposedError; } });
61
61
  var ProviderDisposedError_1 = require("./errors/ProviderDisposedError");
62
62
  Object.defineProperty(exports, "ProviderDisposedError", { enumerable: true, get: function () { return ProviderDisposedError_1.ProviderDisposedError; } });
63
+ var CannotApplySingletonTwiceError_1 = require("./errors/CannotApplySingletonTwiceError");
64
+ Object.defineProperty(exports, "CannotApplySingletonTwiceError", { enumerable: true, get: function () { return CannotApplySingletonTwiceError_1.CannotApplySingletonTwiceError; } });
63
65
  var CannonSingletonApplyTwiceError_1 = require("./errors/CannonSingletonApplyTwiceError");
64
66
  Object.defineProperty(exports, "CannonSingletonApplyTwiceError", { enumerable: true, get: function () { return CannonSingletonApplyTwiceError_1.CannonSingletonApplyTwiceError; } });
65
67
  var UnsupportedTokenTypeError_1 = require("./errors/UnsupportedTokenTypeError");
@@ -118,6 +120,7 @@ Object.defineProperty(exports, "addClassLabel", { enumerable: true, get: functio
118
120
  Object.defineProperty(exports, "getClassLabels", { enumerable: true, get: function () { return class_1.getClassLabels; } });
119
121
  Object.defineProperty(exports, "addClassTag", { enumerable: true, get: function () { return class_1.addClassTag; } });
120
122
  Object.defineProperty(exports, "getClassTags", { enumerable: true, get: function () { return class_1.getClassTags; } });
123
+ Object.defineProperty(exports, "createComposeClassDecorator", { enumerable: true, get: function () { return class_1.createComposeClassDecorator; } });
121
124
  var parameter_1 = require("./metadata/parameter");
122
125
  Object.defineProperty(exports, "addParamMeta", { enumerable: true, get: function () { return parameter_1.addParamMeta; } });
123
126
  Object.defineProperty(exports, "getParamMeta", { enumerable: true, get: function () { return parameter_1.getParamMeta; } });
@@ -125,6 +128,7 @@ Object.defineProperty(exports, "addParamLabel", { enumerable: true, get: functio
125
128
  Object.defineProperty(exports, "getParamLabels", { enumerable: true, get: function () { return parameter_1.getParamLabels; } });
126
129
  Object.defineProperty(exports, "addParamTag", { enumerable: true, get: function () { return parameter_1.addParamTag; } });
127
130
  Object.defineProperty(exports, "getParamTags", { enumerable: true, get: function () { return parameter_1.getParamTags; } });
131
+ Object.defineProperty(exports, "createComposeParameterDecorator", { enumerable: true, get: function () { return parameter_1.createComposeParameterDecorator; } });
128
132
  var method_1 = require("./metadata/method");
129
133
  Object.defineProperty(exports, "addMethodMeta", { enumerable: true, get: function () { return method_1.addMethodMeta; } });
130
134
  Object.defineProperty(exports, "getMethodMeta", { enumerable: true, get: function () { return method_1.getMethodMeta; } });
@@ -132,6 +136,7 @@ Object.defineProperty(exports, "addMethodLabel", { enumerable: true, get: functi
132
136
  Object.defineProperty(exports, "getMethodLabels", { enumerable: true, get: function () { return method_1.getMethodLabels; } });
133
137
  Object.defineProperty(exports, "addMethodTag", { enumerable: true, get: function () { return method_1.addMethodTag; } });
134
138
  Object.defineProperty(exports, "getMethodTags", { enumerable: true, get: function () { return method_1.getMethodTags; } });
139
+ Object.defineProperty(exports, "createComposeMethodDecorator", { enumerable: true, get: function () { return method_1.createComposeMethodDecorator; } });
135
140
  var errorHandler_1 = require("./utils/errorHandler");
136
141
  Object.defineProperty(exports, "handleError", { enumerable: true, get: function () { return errorHandler_1.handleError; } });
137
142
  Object.defineProperty(exports, "handleAsyncError", { enumerable: true, get: function () { return errorHandler_1.handleAsyncError; } });
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getClassTags = exports.addClassTag = exports.getClassLabels = exports.addClassLabel = exports.addClassMeta = void 0;
3
+ exports.createComposeClassDecorator = exports.getClassTags = exports.addClassTag = exports.getClassLabels = exports.addClassLabel = exports.addClassMeta = void 0;
4
4
  exports.getClassMeta = getClassMeta;
5
5
  const target_1 = require("./target");
6
6
  const addClassMeta = (key, mapFn) => (target) => {
@@ -19,3 +19,5 @@ const addClassTag = (tag) => (0, exports.addClassMeta)('tag', (prev = new Set())
19
19
  exports.addClassTag = addClassTag;
20
20
  const getClassTags = (target) => getClassMeta(target, 'tag') ?? new Set();
21
21
  exports.getClassTags = getClassTags;
22
+ const createComposeClassDecorator = (...decorators) => (target) => decorators.reduceRight((acc, decorate) => decorate(acc) ?? acc, target);
23
+ exports.createComposeClassDecorator = createComposeClassDecorator;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getMethodTags = exports.addMethodTag = exports.getMethodLabels = exports.addMethodLabel = exports.getMethodMeta = exports.addMethodMeta = void 0;
3
+ exports.createComposeMethodDecorator = exports.getMethodTags = exports.addMethodTag = exports.getMethodLabels = exports.addMethodLabel = exports.getMethodMeta = exports.addMethodMeta = void 0;
4
4
  const target_1 = require("./target");
5
5
  const addMethodMeta = (key, mapFn) => (target, propertyKey) => {
6
6
  const metadata = Reflect.getMetadata(key, target.constructor, propertyKey);
@@ -17,3 +17,5 @@ const addMethodTag = (tag) => (0, exports.addMethodMeta)('tag', (prev = new Set(
17
17
  exports.addMethodTag = addMethodTag;
18
18
  const getMethodTags = (target, propertyKey) => (0, exports.getMethodMeta)('tag', target, propertyKey) ?? new Set();
19
19
  exports.getMethodTags = getMethodTags;
20
+ const createComposeMethodDecorator = (...decorators) => (target, propertyKey, descriptor) => decorators.reduceRight((acc, decorate) => decorate(target, propertyKey, acc) ?? acc, descriptor);
21
+ exports.createComposeMethodDecorator = createComposeMethodDecorator;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getParamTags = exports.addParamTag = exports.getParamLabels = exports.addParamLabel = exports.getParamMeta = exports.addParamMeta = void 0;
3
+ exports.createComposeParameterDecorator = exports.getParamTags = exports.addParamTag = exports.getParamLabels = exports.addParamLabel = exports.getParamMeta = exports.addParamMeta = void 0;
4
4
  const target_1 = require("./target");
5
5
  const addParamMeta = (key, mapFn) => (target, _, parameterIndex) => {
6
6
  const metadata = Reflect.getOwnMetadata(key, target) ?? [];
@@ -32,3 +32,9 @@ const getParamTags = (target, parameterIndex) => {
32
32
  return all[parameterIndex] ?? new Set();
33
33
  };
34
34
  exports.getParamTags = getParamTags;
35
+ const createComposeParameterDecorator = (...decorators) => (target, propertyKey, parameterIndex) => {
36
+ for (let i = decorators.length - 1; i >= 0; i--) {
37
+ decorators[i](target, propertyKey, parameterIndex);
38
+ }
39
+ };
40
+ exports.createComposeParameterDecorator = createComposeParameterDecorator;