proxydi 0.0.7 → 0.0.9

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 proxy-di
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 proxy-di
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,206 +1,296 @@
1
- # ProxyDi
2
-
3
- [![Coverage Status](https://coveralls.io/repos/github/proxy-di/proxydi/badge.png)](https://coveralls.io/github/proxy-di/proxydi)
4
-
5
- A typed hierarchical DI container that resolves circular dependencies via Proxy.
6
-
7
- Core features:
8
-
9
- - Uses Stage 3 decorators, supported in TypeScript 5.x ([examples repository](https://github.com/proxy-di/node-ts-examples)) and Babel via babel-plugin-proposal-decorators ([examples repository](https://github.com/proxy-di/node-babel-examples))
10
- - Automatically resolves circular dependencies with no persormance impact
11
- - Resolves dependencies in the context of a particular container
12
- - Matches dependencies by unique identifiers or automatically using class names and property names
13
- - Currently under active development, the API may change until version 0.1.0
14
-
15
- # Quick start
16
-
17
- Install the `proxydi` package in your JavaScript or TypeScript project:
18
-
19
- ```shell
20
- npm i proxydi
21
- ```
22
-
23
- ## TypeScript set up
24
-
25
- If you are using TypeScript, ensure that `experimentalDecorators` is set to `false` in your `tsconfig.json`. This enables support for Stage 3 decorators:
26
-
27
- ```jsonc
28
- // tsconfig.json
29
- {
30
- "compilerOptions": {
31
- // ...
32
- "experimentalDecorators": false,
33
- "strictPropertyInitialization": false,
34
- },
35
- //...
36
- }
37
- ```
38
-
39
- Changing `strictPropertyInitialization` is not necessary, but if you leave it at the default value, you will need to slightly modify the examples. More about this later.
40
-
41
- ## Babel set up
42
-
43
- For Babel projects, ensure that @babel/plugin-proposal-decorators is configured exactly as follows:
44
-
45
- ```jsonc
46
- // .babelrc
47
- {
48
- // ...
49
- "plugins": [
50
- // other plugins
51
- ["@babel/plugin-proposal-decorators", { "version": "2023-11" }],
52
- ],
53
- }
54
- ```
55
-
56
- ## Usage
57
-
58
- > We will use TypeScript for all examples, because it is easier to remove typing than add it
59
-
60
- The process of using ProxyDi consists of 3 stages:
61
-
62
- 1. Use the @inject decorator to define the dependencies to be resolved by the ProxyDi container. In this example, we define an interface for characters and ask ProxyDi to resolve the `Role` dependency for actors.
63
-
64
- ```typescript
65
- interface Character {
66
- greet(): string;
67
- }
68
-
69
- class Actor {
70
- @inject('Role') role: Character;
71
-
72
- play = () => this.role.greet();
73
- }
74
- ```
75
-
76
- 2. Next, set up the ProxyDi container and fill it with dependencies. Let's define an agent 007 role and prepare our first container:
77
-
78
- ```typescript
79
- class Agent007 implements Character {
80
- greet = () => 'Bond... James Bond';
81
- }
82
-
83
- const container = new ProxyDiContainer();
84
- container.registerDependency(Agent007, 'Role');
85
- container.registerDependency(Actor, 'Actor');
86
- ```
87
-
88
- 3. At the last stage, take dependencies from the ProxyDi container and just use them. Let our actor play its role:
89
-
90
- ```typescript
91
- const actor = container.resolve<Actor>('Actor');
92
- console.log(actor.play());
93
- ```
94
-
95
- And the result is:
96
-
97
- ```shell
98
- > Bond... James Bond
99
- ```
100
-
101
- # The Reason
102
-
103
- To illustrate why we should use a container for this simple purpose, let's create a container for another character and ask the actor to play the new role:
104
-
105
- ```typescript
106
- class M implements Character {
107
- greet = () => '007, I have a new mission for you';
108
- }
109
-
110
- const container = new ProxyDiContainer();
111
- container.registerDependency(M, 'Role');
112
- container.registerDependency(Actor, 'Actor');
113
-
114
- const actor = container.resolve<Actor>('Actor');
115
- console.log(actor.play());
116
- ```
117
-
118
- ```shell
119
- > 007, I have a new mission for you
120
- ```
121
-
122
- In this example, we changed the behavior of the actor by changing the role dependency in the ProxyDi container. This is the goal of the [Dependency inversion principle](https://en.wikipedia.org/wiki/Dependency_inversion_principle) in SOLID. Continuing our metaphor, the actor can play any role, but he is not the one who decides which role he will play. This is a film director's decision, and here we just cosplay him by setting up our containers.
123
-
124
- So, ProxyDi is just a tool to link dependencies. And nothing more.
125
-
126
- # Circular dependencies
127
-
128
- There are several rough edges in traditional DI container implementations that ProxyDi addresses. The first of these is circular dependencies.
129
-
130
- Let's illustrate this with a movie set metaphor. During filming, the actor and director work together in a continuous feedback loop:
131
-
132
- ```typescript
133
- class Director {
134
- @inject('Actor') private actor: Actor;
135
- private passionLevel = 1;
136
-
137
- direct(line: string) {
138
- return this.actor.perform(line, this.passionLevel);
139
- }
140
- }
141
-
142
- class Actor {
143
- @inject('Role') private role: Character;
144
- @inject('Director') private director: Director;
145
-
146
- play() {
147
- const line = this.role.greet();
148
- // Here, the actor asks the director how to perform the line.
149
- return this.director.direct(line);
150
- }
151
-
152
- perform(line: string, loudness: number = 0) {
153
- return line + '!'.repeat(loudness);
154
- }
155
- }
156
-
157
- const container = new ProxyDiContainer();
158
- container.registerDependency(Actor, 'Actor');
159
- container.registerDependency(Director, 'Director');
160
- container.registerDependency(Agent007, 'Role');
161
-
162
- const actor = container.resolve<Actor>('Actor');
163
- console.log(actor.play());
164
- ```
165
-
166
- ```shell
167
- > Bond... James Bond!
168
- ```
169
-
170
- In traditional DI containers, this scene would be tricky to shoot - the Director calls Actor's methods while Actor simultaneously needs Director's guidance. But ProxyDi handles it elegantly using JavaScript Proxies, without any worries on your part.
171
-
172
- # Rewriting dependencies
173
-
174
- By default, ProxyDi doesn't allow rewriting dependencies in the container. After a dependency becomes known to the container, any attempt to register a new dependency with the same dependency ID will throw an Error:
175
-
176
- ```typescript
177
- const container = new ProxyDiContainer();
178
- container.registerDependency(Actor, 'Actor');
179
- container.registerDependency(Actor, 'Actor'); // !!! Error here
180
- ```
181
-
182
- However, there is an option that allows you to do these kinds of things:
183
-
184
- ```typescript
185
- const container = new ProxyDiContainer({ allowRewriteDependencies: true });
186
- container.registerDependency(Actor, 'Actor');
187
-
188
- const actor = container.resolve<Actor>('Actor');
189
- const wrapper = new ActorWrapper(actor);
190
-
191
- container.registerDependency(wrapper, 'Actor'); // No error is thrown here now
192
- ```
193
-
194
- ## Injection proxy performance
195
-
196
- As mentioned before, ProxyDi uses `Proxy` for each field marked by the @inject() decorator. This makes it possible to resolve circular dependencies. By default, these proxies are replaced by the actual dependency instances from the container during their first use, so the performance impact on your application is minimal.
197
-
198
- However, if you allow rewriting dependencies in the container, these proxies remain in use to keep injections updated. As a result, every time you access a dependency field, there is a significant performance impact. In our tests, property access via Proxy is up to 100 times slower. For this reason, we recommend not allowing rewriting dependencies in production and keeping the container’s default behavior.
199
-
200
- ## Baking injections
201
-
202
- There is a container method `bakeInjections()` that bakes all injections and freezes the current container’s dependencies. After calling this method, the container will deny any attempts to rewrite dependencies. It also bakes the dependencies in all its children.
203
-
204
- After the container has been baked, the performance impact becomes zero. Therefore, you should use this method even for containers with default settings, ensuring that your application don't have to wait for the first use of each injection before they are baked.
205
-
206
- To be continued...
1
+ # ProxyDi
2
+
3
+ [![Coverage Status](https://coveralls.io/repos/github/proxy-di/proxydi/badge.png)](https://coveralls.io/github/proxy-di/proxydi)
4
+
5
+ A typed hierarchical DI container that resolves circular dependencies via Proxy.
6
+
7
+ <img src="https://github.com/proxy-di/proxydi/blob/main/assets/ProxyDiLogo.png?raw=true" width="196">
8
+
9
+ Core features:
10
+
11
+ - Uses Stage 3 decorators, supported in TypeScript 5.x ([examples repository](https://github.com/proxy-di/node-ts-examples)) and Babel via babel-plugin-proposal-decorators ([examples repository](https://github.com/proxy-di/node-babel-examples))
12
+ - Automatically resolves circular dependencies with no performance impact
13
+ - Resolves dependencies in the context of a particular container
14
+ - Supports hierarchical containers with the ability to resolve dependencies in both directions
15
+ - Matches dependencies by unique identifiers or automatically using class names and property names
16
+ - Currently under active development, the API may change until version 0.1.0
17
+
18
+ ## Quick start
19
+
20
+ > If you are using React, you should use the React wrapper for ProxyDi instead of this library directly: [@proxydi/react](https://github.com/proxy-di/proxydi-react)
21
+
22
+ Install the `proxydi` package in your JavaScript or TypeScript project:
23
+
24
+ ```shell
25
+ npm i proxydi
26
+ ```
27
+
28
+ ### Configure TypeScript
29
+
30
+ If you are using TypeScript, ensure that `experimentalDecorators` is set to `false` in your `tsconfig.json`. This enables support for Stage 3 decorators:
31
+
32
+ ```jsonc
33
+ // tsconfig.json
34
+ {
35
+ "compilerOptions": {
36
+ // ...
37
+ "experimentalDecorators": false,
38
+ "strictPropertyInitialization": false,
39
+ },
40
+ //...
41
+ }
42
+ ```
43
+
44
+ Changing `strictPropertyInitialization` is not necessary, but if you leave it at the default value, you will need to slightly modify the examples. More about this later.
45
+
46
+ ### Configure Babel
47
+
48
+ For Babel projects, ensure that @babel/plugin-proposal-decorators is configured exactly as follows:
49
+
50
+ ```jsonc
51
+ // .babelrc
52
+ {
53
+ // ...
54
+ "plugins": [
55
+ // other plugins
56
+ ["@babel/plugin-proposal-decorators", { "version": "2023-11" }],
57
+ ],
58
+ }
59
+ ```
60
+
61
+ ### Usage
62
+
63
+ > We will use TypeScript for all examples, because it is easier to remove typing than add it
64
+
65
+ The process of using ProxyDi consists of 3 stages:
66
+
67
+ 1. Use the [@inject()](https://proxy-di.github.io/proxydi/functions/inject.html) decorator to define the dependencies to be resolved by the ProxyDi container. In this example, we define an interface for characters and ask ProxyDi to resolve the `Role` dependency for actors.
68
+
69
+ ```typescript
70
+ interface Character {
71
+ greet(): string;
72
+ }
73
+
74
+ class Actor {
75
+ @inject('Role') role: Character;
76
+
77
+ play = () => this.role.greet();
78
+ }
79
+ ```
80
+
81
+ 2. Next, create the [ProxyDiContainer](https://proxy-di.github.io/proxydi/classes/ProxyDiContainer.html)
82
+ and fill it with dependencies using [register()](https://proxy-di.github.io/proxydi/classes/ProxyDiContainer.html#register) method. For example, let's define an agent 007 role and prepare our first container:
83
+
84
+ ```typescript
85
+ class Agent007 implements Character {
86
+ greet = () => 'Bond... James Bond';
87
+ }
88
+
89
+ const container = new ProxyDiContainer();
90
+ container.register(Agent007, 'Role');
91
+ container.register(Actor, 'Actor');
92
+ ```
93
+
94
+ 3. At the last stage, take dependencies from the ProxyDi container by [resolve()](https://proxy-di.github.io/proxydi/classes/ProxyDiContainer.html#resolve) method and just use them. To continue our example, let our actor play its role:
95
+
96
+ ```typescript
97
+ const actor = container.resolve<Actor>('Actor');
98
+ console.log(actor.play());
99
+ ```
100
+
101
+ And the result is:
102
+
103
+ ```shell
104
+ > Bond... James Bond
105
+ ```
106
+
107
+ ## The Reason
108
+
109
+ To illustrate why we should use a container for this simple purpose, let's create a container for another character and ask the actor to play the new role:
110
+
111
+ ```typescript
112
+ class M implements Character {
113
+ greet = () => '007, I have a new mission for you';
114
+ }
115
+
116
+ const container = new ProxyDiContainer();
117
+ container.register(M, 'Role');
118
+ container.register(Actor, 'Actor');
119
+
120
+ const actor = container.resolve<Actor>('Actor');
121
+ console.log(actor.play());
122
+ ```
123
+
124
+ ```shell
125
+ > 007, I have a new mission for you
126
+ ```
127
+
128
+ In this example, we changed the behavior of the actor by changing the role dependency in the ProxyDi container. This is exactly the goal of the [Dependency inversion principle](https://en.wikipedia.org/wiki/Dependency_inversion_principle) in the SOLID approach to software design. Continuing our metaphor, the actor can play any role, but he is not the one who decides which role he will play. This is a film director's decision, and here we just cosplay him by setting up our containers.
129
+
130
+ > So, ProxyDi is just a tool to link dependencies, allowing them to freely communicate with each other without worrying about which specific dependency they're dealing with. And nothing more.
131
+
132
+ ## Circular dependencies
133
+
134
+ There are several rough edges in traditional DI container implementations that ProxyDi addresses. The first of these is circular dependencies.
135
+
136
+ Let's illustrate this with a movie set metaphor. During filming, the actor and director work together in a continuous feedback loop:
137
+
138
+ ```typescript
139
+ class Director {
140
+ @inject('Actor') private actor: Actor;
141
+ private passionLevel = 1;
142
+
143
+ direct(line: string) {
144
+ return this.actor.perform(line, this.passionLevel);
145
+ }
146
+ }
147
+
148
+ class Actor {
149
+ @inject('Role') private role: Character;
150
+ @inject('Director') private director: Director;
151
+
152
+ play() {
153
+ const line = this.role.greet();
154
+ // Here, the actor asks the director how to perform the line.
155
+ return this.director.direct(line);
156
+ }
157
+
158
+ perform(line: string, loudness: number = 0) {
159
+ return line + '!'.repeat(loudness);
160
+ }
161
+ }
162
+
163
+ const container = new ProxyDiContainer();
164
+ container.register(Actor, 'Actor');
165
+ container.register(Director, 'Director');
166
+ container.register(Agent007, 'Role');
167
+
168
+ const actor = container.resolve<Actor>('Actor');
169
+ console.log(actor.play());
170
+ ```
171
+
172
+ ```shell
173
+ > Bond... James Bond!
174
+ ```
175
+
176
+ In traditional DI containers, this scene would be tricky to shoot - the Director calls Actor's methods while Actor simultaneously needs Director's guidance.
177
+
178
+ But take a look, our approach is still the same - we just link dependencies with @inject and use them freely without any worries. ProxyDi handles this tricky issue as elegantly as possible. It does this using JavaScript Proxies, more about Proxies and their impact on performance [later](#injection-proxy-performance).
179
+
180
+ ## Hierarchy of containers
181
+
182
+ Another tricky part of DI containers is the ability to create multiple instances of the same class. ProxyDi solves this problem in the simplest way possible - it just does not allow it. When you register a class as a dependency, there is only one instance of this class in the container.
183
+
184
+ Instead, it suggests you to use a hierarchy of containers by using [createChildContainer()](https://proxy-di.github.io/proxydi/classes/ProxyDiContainer.html#createchildcontainer) method. Child container inherits all parent settings and can resolve exactly the same dependencies as their parent (but parent container does not have access to dependencies registered in its children).
185
+
186
+ For example, imagine you are working on a game level, there are many characters on this level, and each character could have many perks.
187
+
188
+ With ProxyDi we can present all these stuff in a hierarchy of containers. The most top container holds information about game level, the most bottom ones hold information about perks:
189
+
190
+ ```typescript
191
+ const tutorialContainer = new ProxyDiContainer();
192
+ tutorialContainer.register(new GameLevel({ undewater: true }), 'level');
193
+
194
+ const heroContainer = tutorialContainer.createChildContainer();
195
+ const hero = heroContainer.register<Character>(Character, 'character');
196
+
197
+ const perksContainer = heroContainer.createChildContainer();
198
+ const perk = perksContainer.register(new UnderwaterShield(10), 'perk');
199
+ ```
200
+
201
+ This is not how I propose to design games, ECS pattern does it better, but the goal was to demonstrate that with this approach instead of creating bunches of instances to represent your project entities, you can create bunches of containers each of them containing instances related to each other.
202
+
203
+ ### Resolving dependencies from parents
204
+
205
+ As a bonus, each bottom level dependency is free to use any dependency from the top just as if they were registered in its own container:
206
+
207
+ ```typescript
208
+ class UnderwaterShield {
209
+ @inject('level') private level: GameLevel;
210
+ @inject('character') private character: Character;
211
+
212
+ constructor(private amount: number) {}
213
+
214
+ activate = () =>
215
+ this.level.isUnderwater && (this.character.health += this.amount);
216
+ }
217
+ ```
218
+
219
+ In this example, the shield perk increases character health if it is underwater. The perk receives both level and character using the @inject() decorator, the same way as we have seen so far.
220
+
221
+ ## Resolving dependencies from children
222
+
223
+ Backward bonus of containers hierarchy, each top level dependency is free to use all dependency from the bottom:
224
+
225
+ ```typescript
226
+ class Character {
227
+ public health = 100;
228
+
229
+ hit(abount: number) {
230
+ this.health -= abount;
231
+
232
+ const perks = resolveAll<Perk>(this, 'perk');
233
+ perks.forEach((perk) => perk.activate());
234
+ }
235
+ }
236
+ ```
237
+
238
+ In this example, the character activates all its perks, which are registered in all children containers. The way it do this job need a little bit more explanation.
239
+
240
+ ### Reference to the container
241
+
242
+ Here you should be wondering, how [resolveAll()](https://proxy-di.github.io/proxydi/functions/resolveAll.html.html) function knows about the container, to which character belongs. The answer - each time when dependency is registered in the ProxyDiContainer, it saves a reference to itself in this dependency instance. So, when you call resolveAll() function, it just takes this reference from the instance and then recursively resolves all asked dependencies from this container and all its children and children of children and so on.
243
+
244
+ Despite this explanation is a little bit complicated, the example is still simple, the character just activates all its perks.
245
+
246
+ ## Rewriting dependencies
247
+
248
+ By default, ProxyDi doesn't allow rewriting dependencies in the container. After a dependency becomes known to the container, any attempt to register a new dependency with the same dependency ID will throw an Error:
249
+
250
+ ```typescript
251
+ const container = new ProxyDiContainer();
252
+ container.register(Actor, 'Actor');
253
+ container.register(Actor, 'Actor'); // !!! Error here
254
+ ```
255
+
256
+ However, there is an option that allows you to do these kinds of things:
257
+
258
+ ```typescript
259
+ const container = new ProxyDiContainer({ allowRewriteDependencies: true });
260
+ container.register(Actor, 'Actor');
261
+
262
+ const actor = container.resolve<Actor>('Actor');
263
+ const wrapper = new ActorWrapper(actor);
264
+
265
+ container.register(wrapper, 'Actor'); // No error is thrown here now
266
+ ```
267
+
268
+ ### Injection proxy performance
269
+
270
+ As mentioned before, ProxyDi uses `Proxy` for each field marked by the @inject() decorator. This makes it possible to resolve circular dependencies. By default, these proxies are replaced by the actual dependency instances from the container during their first use, so the performance impact on your application is minimal.
271
+
272
+ However, if you allow rewriting dependencies in the container, these proxies remain in use to keep injections updated. As a result, every time you access a dependency field, there is a significant performance impact. In our tests, property access via Proxy is up to 100 times slower. For this reason, we recommend not allowing rewriting dependencies in production and keeping the container’s default behavior.
273
+
274
+ ### Baking injections
275
+
276
+ There is a container method [bakeInjections()](https://proxy-di.github.io/proxydi/classes/ProxyDiContainer.html#bakeinjections) that bakes all injections and freezes the current container’s dependencies. After calling this method, the container restores behaviour by default and denies any attempts to rewrite dependencies. It also bakes the dependencies in all its children.
277
+
278
+ Therefore, after the container has been baked, the performance impact becomes zero. So, you could use this method even for containers with default settings, ensuring that your application doesn't have to wait for the first use of each injection before they are baked.
279
+
280
+ To be continued...
281
+
282
+ ## Motivation
283
+
284
+ The world and software changes, they become more complex over time. But the main imperative in software development stays the same - managing the complexity. Despite the tendency that software is written more often by artificial intelligence than humans, complexity stays complexity. The less complex conceptions any kind of intelligence should operate, the more efficient it will be.
285
+
286
+ The main goal of ProxyDi is to decrease complexity in the very small field of connecting different entities of software code between each other, no matter by whom this code was written. This is my attempt to make the linking of dependencies as transparent and simple as possible for developers.
287
+
288
+ Also, I'm tired of moving this-like code from one project to another. I hope that ProxyDi will be a good enough solution for this problem not only for me. To be honest, this is the 4th attempt to create an "ideal" DI container and my 1st that uses Stage 3 decorators. I hope, this one will be the last one. With your help :) For TS/JS technology stack, of course!
289
+
290
+ ## Contributing
291
+
292
+ Any reviews, comments, ideas, issues, and pull requests are welcome. Contribution documentation is not ready yet but is planned. Feel free to contribute even now though! :)
293
+
294
+ ## License
295
+
296
+ This project is licensed under the terms of the MIT License. See the [LICENSE](./LICENSE) file for details.
@@ -1,4 +1,4 @@
1
- import { IProxyDiContainer as IProxyDiContainer, ContainerizedDependency as ContainerizedDependency, Instanced, DependencyClass } from './types';
1
+ import { IProxyDiContainer as IProxyDiContainer, ContainerizedDependency as ContainerizedDependency, DependencyClass } from './types';
2
2
  import { ContainerSettings as ContainerSettings, DependencyId } from './types';
3
3
  /**
4
4
  * A dependency injection container
@@ -9,16 +9,16 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
9
9
  */
10
10
  private static idCounter;
11
11
  /**
12
- * Unique identifier for this container class instance.
12
+ * Just unique number identifier for this container, nothing more
13
13
  */
14
14
  readonly id: number;
15
15
  /**
16
16
  * Optional parent container from which this container can inherit dependencies.
17
17
  */
18
18
  readonly parent?: ProxyDiContainer;
19
- private children;
19
+ private _children;
20
20
  /**
21
- * Holds dependencies registered particular in this container.
21
+ * Holds dependency instances registered particular in this container.
22
22
  */
23
23
  private dependencies;
24
24
  /**
@@ -36,22 +36,22 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
36
36
  */
37
37
  constructor(settings?: ContainerSettings, parent?: ProxyDiContainer);
38
38
  /**
39
- * Registers a dependency in the container.
40
- * Overload signatures:
41
- * registerDependency<T>(dependency: T, dependencyId: DependencyId): void;
42
- * registerDependency<T>(DependencyClass: new (...args: any[]) => T, dependencyId: DependencyId): void;
43
- * @param param The dependency instance or dependency class.
39
+ * Registers a dependency in the container. Could register eacher class or instance.
40
+ * In case of class, it will be instantiated without any parameters.
41
+ *
42
+ * @param dependency The dependency instance or dependency class.
44
43
  * @param dependencyId The unique identifier for the dependency in this container.
45
44
  * @throws Error if dependency is already registered and rewriting is not allowed or if invalid dependency (not object) is provided and this it now allowed.
45
+ * @returns Dependency instance, registered in container
46
46
  */
47
- registerDependency<T>(dependency: Instanced<T>, dependencyId: DependencyId): void;
48
- registerDependency<T>(DependencyClass: DependencyClass<T>, dependencyId: DependencyId): void;
47
+ register<T>(DependencyClass: DependencyClass<T>, dependencyId: DependencyId): T & ContainerizedDependency;
48
+ register<T>(dependency: T extends new (...args: any[]) => any ? never : T, dependencyId: DependencyId): T & ContainerizedDependency;
49
49
  /**
50
50
  * Internal method that implements registeration of dependency and prepare it for injection.
51
51
  * @param dependencyId The unique identifier of the dependency.
52
52
  * @param dependency The dependency instance.
53
53
  */
54
- private registerDependencyImpl;
54
+ private registerImpl;
55
55
  /**
56
56
  * Checks if a dependency with the given ID is known to the container or its ancestors which means that it can be resolved by this container
57
57
  * @param dependencyId The identifier of the dependency.
@@ -65,7 +65,7 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
65
65
  * @throws Error if the dependency cannot be found or is not auto injectable.
66
66
  */
67
67
  resolve<T>(dependencyId: DependencyId): T & ContainerizedDependency;
68
- resolve<T extends new (...args: any[]) => any>(SomeClass: T): InstanceType<T>;
68
+ resolve<T extends new (...args: any[]) => any>(SomeClass: T): InstanceType<T> & ContainerizedDependency;
69
69
  /**
70
70
  * Injects dependencies to the given object based on its defined injections metadata. Does not affect the container.
71
71
  * @param injectionsOwner The object to inject dependencies into.
@@ -85,7 +85,7 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
85
85
  * Removes a given dependency from the container using either the dependency instance or its ID.
86
86
  * @param dependencyOrId The dependency instance or dependency identifier to remove.
87
87
  */
88
- removeDependency(dependencyOrId: DependencyId | ContainerizedDependency): void;
88
+ remove(dependencyOrId: DependencyId | ContainerizedDependency): void;
89
89
  /**
90
90
  * Destroys the container by removing all dependencies,
91
91
  * recursively destroying child containers and removing itself from its parent.
@@ -97,6 +97,16 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
97
97
  * @returns The dependency if found, otherwise undefined.
98
98
  */
99
99
  private findDependency;
100
+ /**
101
+ * All direct descendants of this container
102
+ */
103
+ get children(): ProxyDiContainer[];
104
+ /**
105
+ *
106
+ * @param id Unique identifier of container
107
+ * @returns
108
+ */
109
+ getChild(id: number): ProxyDiContainer;
100
110
  /**
101
111
  * Registers a child container to this container.
102
112
  * @param child The child container to add.