proxydi 0.0.10 → 0.0.12
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/CHANGELOG.md +91 -0
- package/README.md +60 -1
- package/dist/ProxyDiContainer.d.ts +6 -6
- package/dist/index.cjs +108 -28
- package/dist/index.d.ts +3 -1
- package/dist/index.js +107 -28
- package/dist/index.umd.js +108 -28
- package/dist/middleware/MiddlewareListener.d.ts +29 -0
- package/dist/middleware/middleware.d.ts +3 -0
- package/dist/types.d.ts +4 -4
- package/package.json +1 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [[0.0.12](https://www.npmjs.com/package/proxydi/v/0.0.12)] - 2025-03-04
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Experimental @middleware [#14](https://github.com/proxy-di/proxydi/pull/14)
|
|
13
|
+
|
|
14
|
+
## [[0.0.11](https://www.npmjs.com/package/proxydi/v/0.0.11)] - 2025-03-03
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- resolveInjectables() method [#13](https://github.com/proxy-di/proxydi/pull/13)
|
|
19
|
+
|
|
20
|
+
## [[0.0.10](https://www.npmjs.com/package/proxydi/v/0.0.10)] - 2025-03-02
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Renamed @autoInjectable to @injectable
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- Experimental constructor injections via @injectable decorator [#12](https://github.com/proxy-di/proxydi/pull/12)
|
|
29
|
+
|
|
30
|
+
## [[0.0.9](https://www.npmjs.com/package/proxydi/v/0.0.9)] - 2025-02-27
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- resolveAll() function to find all dependencies of a given kind [#11](https://github.com/proxy-di/proxydi/pull/11)
|
|
35
|
+
|
|
36
|
+
## [[0.0.8](https://www.npmjs.com/package/proxydi/v/0.0.8)] - 2025-02-26
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- API improvements [#10](https://github.com/proxy-di/proxydi/pull/10)
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- Added access to child containers
|
|
45
|
+
- PROXYDI_CONTAINER and DEPENDENCY_ID now public
|
|
46
|
+
- Enhanced hierarchy documentation
|
|
47
|
+
|
|
48
|
+
## [[0.0.7](https://www.npmjs.com/package/proxydi/v/0.0.7)] - 2025-02-21
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
|
|
52
|
+
- TypeDoc integration [#7](https://github.com/proxy-di/proxydi/pull/7)
|
|
53
|
+
- Action to publish documentation on GitHub Pages
|
|
54
|
+
|
|
55
|
+
## [[0.0.6](https://www.npmjs.com/package/proxydi/v/0.0.6)] - 2025-02-21
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- Improved API [#6](https://github.com/proxy-di/proxydi/pull/6)
|
|
60
|
+
|
|
61
|
+
## [[0.0.5](https://www.npmjs.com/package/proxydi/v/0.0.5)] - 2025-02-20
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- Baking dependencies [#5](https://github.com/proxy-di/proxydi/pull/5)
|
|
66
|
+
- 100% test coverage
|
|
67
|
+
- Changed API with new terminology
|
|
68
|
+
|
|
69
|
+
## [[0.0.4](https://www.npmjs.com/package/proxydi/v/0.0.4)] - 2025-02-11
|
|
70
|
+
|
|
71
|
+
### Changed
|
|
72
|
+
|
|
73
|
+
- Implemented proxy per instance instead of per container [#2](https://github.com/proxy-di/proxydi/pull/2)
|
|
74
|
+
- Ability to register anything as an instance
|
|
75
|
+
- Changed settings to object format
|
|
76
|
+
- Added settings presets
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
|
|
80
|
+
- Made injectables known
|
|
81
|
+
|
|
82
|
+
## [[0.0.3](https://www.npmjs.com/package/proxydi/v/0.0.3)] - 2025-02-07
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
|
|
86
|
+
- Draft DI-container implementation
|
|
87
|
+
- @injectable decorator
|
|
88
|
+
- Basic project setup with CI/CD
|
|
89
|
+
- Testing framework integration
|
|
90
|
+
- Basic package configuration
|
|
91
|
+
- Repository initialization
|
package/README.md
CHANGED
|
@@ -15,7 +15,9 @@ Core features:
|
|
|
15
15
|
- Currently under active development, the API may change until version 0.1.0
|
|
16
16
|
|
|
17
17
|
Eperimemntal features:
|
|
18
|
+
|
|
18
19
|
- Construtor injections (see unit tests for examples)
|
|
20
|
+
- Middleware listeners (see unit tests for examples)
|
|
19
21
|
- Matches dependencies by unique identifiers or automatically using class names and property names
|
|
20
22
|
|
|
21
23
|
## Quick start
|
|
@@ -242,10 +244,67 @@ In this example, the character activates all its perks, which are registered in
|
|
|
242
244
|
|
|
243
245
|
### Reference to the container
|
|
244
246
|
|
|
245
|
-
Here you should be wondering, how [resolveAll()](https://proxy-di.github.io/proxydi/functions/resolveAll.html
|
|
247
|
+
Here you should be wondering, how [resolveAll()](https://proxy-di.github.io/proxydi/functions/resolveAll.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.
|
|
246
248
|
|
|
247
249
|
Despite this explanation is a little bit complicated, the example is still simple, the character just activates all its perks.
|
|
248
250
|
|
|
251
|
+
## Injectable classes
|
|
252
|
+
|
|
253
|
+
Look at the following example:
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
@injectable()
|
|
257
|
+
class GameEngine {
|
|
258
|
+
start = () => console.log('Game started');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const container = new ProxyDiContainer();
|
|
262
|
+
|
|
263
|
+
const gameEngine = container.resolve(GameEngine);
|
|
264
|
+
gameEngine.start();
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
```shell
|
|
268
|
+
> Game started
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Two things happen here:
|
|
272
|
+
|
|
273
|
+
1. We use the [@injectable()](https://proxy-di.github.io/proxydi/functions/injectable.html) decorator to mark the class as injectable. This allows us to resolve the dependency without registering it in the container.
|
|
274
|
+
|
|
275
|
+
2. To resolve the dependency instance, we pass the injectable class itself as the dependency identifier. This is possible because ProxyDi automatically uses the class name as the dependency identifier when none is explicitly provided. As an additional bonus, the `gameEngine` has a type `GameEngine`.
|
|
276
|
+
|
|
277
|
+
### Implicitly resolving injectable() dependencies
|
|
278
|
+
|
|
279
|
+
There are a few important nuances about the `@injectable()` decorator to keep in mind. The first is how these dependencies are resolved. Consider this example:
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
const parent = new ProxyDiContainer();
|
|
283
|
+
const child = parent.createChildContainer();
|
|
284
|
+
|
|
285
|
+
const engine1 = child.resolve(GameEngine);
|
|
286
|
+
const engine2 = parent.resolve(GameEngine);
|
|
287
|
+
|
|
288
|
+
engine1 === engine2; // false
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Here we create a hierarchy of containers and resolve the same dependency from the child container first and then from the parent container. The result is two different instances of the GameEngine class. This happens because during the first resolution, the child container doesn't find GameEngine in either itself or its parent container, so it creates a new instance and stores it in itself. When the parent container resolves GameEngine, it creates another instance since he knowns nothing about child depenencies
|
|
292
|
+
|
|
293
|
+
There are two ways to avoid this behavior:
|
|
294
|
+
|
|
295
|
+
1. Don't use the `@injectable()` decorator and always register dependencies explicitly
|
|
296
|
+
2. Use the `registerInjectables()` method to create instances for all injectable dependencies in the container. In this case every time when you resolve injectable dependency, you will get the same instance:
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
const parent = new ProxyDiContainer().registerInjectables();
|
|
300
|
+
const child = parent.createChildContainer();
|
|
301
|
+
|
|
302
|
+
const engine1 = child.resolve(GameEngine);
|
|
303
|
+
const engine2 = parent.resolve(GameEngine);
|
|
304
|
+
|
|
305
|
+
engine1 === engine2; // true now
|
|
306
|
+
```
|
|
307
|
+
|
|
249
308
|
## Rewriting dependencies
|
|
250
309
|
|
|
251
310
|
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:
|
|
@@ -29,6 +29,7 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
|
|
|
29
29
|
* Settings that control the behavior of the container and it's children
|
|
30
30
|
*/
|
|
31
31
|
readonly settings: Required<ContainerSettings>;
|
|
32
|
+
private middlewareListener;
|
|
32
33
|
/**
|
|
33
34
|
* Creates a new instance of ProxyDiContainer.
|
|
34
35
|
* @param settings Optional container settings to override defaults.
|
|
@@ -47,12 +48,6 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
|
|
|
47
48
|
register<T>(DependencyClass: DependencyClass<T>, dependencyId: DependencyId): T & ContainerizedDependency;
|
|
48
49
|
register<T>(dependency: T extends new (...args: any[]) => any ? never : T, dependencyId: DependencyId): T & ContainerizedDependency;
|
|
49
50
|
private createInstance;
|
|
50
|
-
/**
|
|
51
|
-
* Internal method that implements registeration of dependency and prepare it for injection.
|
|
52
|
-
* @param dependencyId The unique identifier of the dependency.
|
|
53
|
-
* @param dependency The dependency instance.
|
|
54
|
-
*/
|
|
55
|
-
private registerImpl;
|
|
56
51
|
/**
|
|
57
52
|
* 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
|
|
58
53
|
* @param dependencyId The identifier of the dependency.
|
|
@@ -72,6 +67,11 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
|
|
|
72
67
|
* @param injectionsOwner The object to inject dependencies into.
|
|
73
68
|
*/
|
|
74
69
|
injectDependenciesTo(injectionsOwner: any): void;
|
|
70
|
+
/**
|
|
71
|
+
* Creates instances for all injectable classes and registers them in this container.
|
|
72
|
+
* @returns This container to allow use along with constructor.
|
|
73
|
+
*/
|
|
74
|
+
registerInjectables(): this;
|
|
75
75
|
/**
|
|
76
76
|
* Finalizes dependency injections, prevents further rewriting of dependencies,
|
|
77
77
|
* and recursively bakes injections for child containers.
|
package/dist/index.cjs
CHANGED
|
@@ -12,7 +12,7 @@ const DEPENDENCY_ID = Symbol('DependencyId');
|
|
|
12
12
|
* This property is present in each dependency instance that was registered in ProxyDiContainer.
|
|
13
13
|
* The property stores a reference to the ProxyDiContainer in which the dependency was registered.
|
|
14
14
|
*/
|
|
15
|
-
const
|
|
15
|
+
const PROXYDI_CONTAINER = Symbol('proxyDiContainer');
|
|
16
16
|
const IS_INJECTION_PROXY = Symbol('isInjectionProxy');
|
|
17
17
|
const INJECTION_OWNER = Symbol('injectionOwner');
|
|
18
18
|
const IS_INSTANCE_PROXY = Symbol('isInstanceProxy');
|
|
@@ -93,7 +93,7 @@ class InjectionProxy {
|
|
|
93
93
|
constructor(onwer, container) {
|
|
94
94
|
this[_a] = true;
|
|
95
95
|
this[INJECTION_OWNER] = onwer;
|
|
96
|
-
this[
|
|
96
|
+
this[PROXYDI_CONTAINER] = container;
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
_a = IS_INJECTION_PROXY;
|
|
@@ -190,6 +190,72 @@ function makeConstructorDependencyProxy(container, dependencyId) {
|
|
|
190
190
|
});
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
const middlewaresClasses = {};
|
|
194
|
+
function middleware() {
|
|
195
|
+
return function (value, context) {
|
|
196
|
+
if ((context === null || context === undefined ? undefined : context.kind) !== 'class') {
|
|
197
|
+
throw new Error('@middleware decorator should decorate classes');
|
|
198
|
+
}
|
|
199
|
+
const name = context.name;
|
|
200
|
+
if (middlewaresClasses[name]) {
|
|
201
|
+
throw new Error(`ProxyDi has already regisered middleware ${String(name)} by @middleware`);
|
|
202
|
+
}
|
|
203
|
+
middlewaresClasses[name] = value;
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
class MiddlewareListener {
|
|
208
|
+
constructor(parent) {
|
|
209
|
+
this.parent = parent;
|
|
210
|
+
this.listeners = {
|
|
211
|
+
register: [],
|
|
212
|
+
remove: [],
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
add(middleware) {
|
|
216
|
+
if (isRegistingMiddleware(middleware)) {
|
|
217
|
+
middleware.onRegister && this.on('register', middleware.onRegister);
|
|
218
|
+
}
|
|
219
|
+
if (isRemovingMiddleware(middleware)) {
|
|
220
|
+
middleware.onRemove && this.on('remove', middleware.onRemove);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
remove(middleware) {
|
|
224
|
+
if (isRegistingMiddleware(middleware)) {
|
|
225
|
+
middleware.onRegister &&
|
|
226
|
+
this.off('register', middleware.onRegister);
|
|
227
|
+
}
|
|
228
|
+
if (isRemovingMiddleware(middleware)) {
|
|
229
|
+
middleware.onRemove && this.off('remove', middleware.onRemove);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
on(event, listener) {
|
|
233
|
+
this.listeners[event].push(listener);
|
|
234
|
+
}
|
|
235
|
+
onRegister(container, dependencyId, dependency) {
|
|
236
|
+
var _a;
|
|
237
|
+
this.listeners.register.forEach((listener) => listener(container, dependencyId, dependency));
|
|
238
|
+
(_a = this.parent) === null || _a === undefined ? undefined : _a.onRegister(container, dependencyId, dependency);
|
|
239
|
+
}
|
|
240
|
+
onRemove(container, dependencyId) {
|
|
241
|
+
var _a;
|
|
242
|
+
this.listeners.remove.forEach((listener) => listener(container, dependencyId));
|
|
243
|
+
(_a = this.parent) === null || _a === undefined ? undefined : _a.onRemove(container, dependencyId);
|
|
244
|
+
}
|
|
245
|
+
off(event, listener) {
|
|
246
|
+
const index = this.listeners[event].indexOf(listener);
|
|
247
|
+
if (index !== -1) {
|
|
248
|
+
this.listeners[event].splice(index, 1);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function isRegistingMiddleware(middleware) {
|
|
253
|
+
return middleware.onRegister;
|
|
254
|
+
}
|
|
255
|
+
function isRemovingMiddleware(middleware) {
|
|
256
|
+
return middleware.onRemove;
|
|
257
|
+
}
|
|
258
|
+
|
|
193
259
|
/**
|
|
194
260
|
* A dependency injection container
|
|
195
261
|
*/
|
|
@@ -210,6 +276,7 @@ class ProxyDiContainer {
|
|
|
210
276
|
*/
|
|
211
277
|
this.parentDependencyProxies = {};
|
|
212
278
|
this.id = ProxyDiContainer.idCounter++;
|
|
279
|
+
this.middlewareListener = new MiddlewareListener(parent === null || parent === undefined ? undefined : parent.middlewareListener);
|
|
213
280
|
if (parent) {
|
|
214
281
|
this.parent = parent;
|
|
215
282
|
this.parent.addChild(this);
|
|
@@ -217,28 +284,36 @@ class ProxyDiContainer {
|
|
|
217
284
|
this.settings = Object.assign(Object.assign({}, DEFAULT_SETTINGS), settings);
|
|
218
285
|
}
|
|
219
286
|
register(dependency, dependencyId) {
|
|
287
|
+
var _a;
|
|
220
288
|
if (this.dependencies[dependencyId]) {
|
|
221
289
|
if (!this.settings.allowRewriteDependencies) {
|
|
222
290
|
throw new Error(`ProxyDi already has dependency for ${String(dependencyId)}`);
|
|
223
291
|
}
|
|
224
292
|
}
|
|
225
|
-
let
|
|
293
|
+
let instance;
|
|
226
294
|
const isClass = typeof dependency === 'function';
|
|
227
295
|
if (isClass) {
|
|
228
|
-
|
|
296
|
+
instance = this.createInstance(dependency, dependencyId);
|
|
229
297
|
}
|
|
230
298
|
else {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
299
|
+
instance = dependency;
|
|
300
|
+
}
|
|
301
|
+
const isObject = typeof instance === 'object';
|
|
302
|
+
if (!isObject && !this.settings.allowRegisterAnything) {
|
|
303
|
+
throw new Error(`Can't register as dependency (allowRegisterAnything is off for this contatiner): ${instance}`);
|
|
236
304
|
}
|
|
237
|
-
if (
|
|
238
|
-
|
|
305
|
+
if (isObject) {
|
|
306
|
+
instance[PROXYDI_CONTAINER] = this;
|
|
307
|
+
instance[DEPENDENCY_ID] = dependencyId;
|
|
239
308
|
}
|
|
240
|
-
this.
|
|
241
|
-
|
|
309
|
+
this.injectDependenciesTo(instance);
|
|
310
|
+
this.dependencies[dependencyId] = instance;
|
|
311
|
+
const constructorName = (_a = instance.constructor) === null || _a === undefined ? undefined : _a.name;
|
|
312
|
+
if (constructorName && middlewaresClasses[constructorName]) {
|
|
313
|
+
this.middlewareListener.add(instance);
|
|
314
|
+
}
|
|
315
|
+
this.middlewareListener.onRegister(this, dependencyId, instance);
|
|
316
|
+
return instance;
|
|
242
317
|
}
|
|
243
318
|
createInstance(Dependency, dependencyId) {
|
|
244
319
|
const paramIds = constructorInjections[dependencyId] || [];
|
|
@@ -249,18 +324,6 @@ class ProxyDiContainer {
|
|
|
249
324
|
}
|
|
250
325
|
return new Dependency(...params);
|
|
251
326
|
}
|
|
252
|
-
/**
|
|
253
|
-
* Internal method that implements registeration of dependency and prepare it for injection.
|
|
254
|
-
* @param dependencyId The unique identifier of the dependency.
|
|
255
|
-
* @param dependency The dependency instance.
|
|
256
|
-
*/
|
|
257
|
-
registerImpl(dependency, dependencyId) {
|
|
258
|
-
this.injectDependenciesTo(dependency);
|
|
259
|
-
if (typeof dependency === 'object') {
|
|
260
|
-
dependency[DEPENDENCY_ID] = dependencyId;
|
|
261
|
-
}
|
|
262
|
-
this.dependencies[dependencyId] = dependency;
|
|
263
|
-
}
|
|
264
327
|
/**
|
|
265
328
|
* 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
|
|
266
329
|
* @param dependencyId The identifier of the dependency.
|
|
@@ -286,7 +349,7 @@ class ProxyDiContainer {
|
|
|
286
349
|
}
|
|
287
350
|
const instance = this.findDependency(dependency);
|
|
288
351
|
if (instance) {
|
|
289
|
-
if (instance[
|
|
352
|
+
if (instance[PROXYDI_CONTAINER] !== this &&
|
|
290
353
|
typeof instance === 'object' &&
|
|
291
354
|
this.settings.resolveInContainerContext) {
|
|
292
355
|
const proxy = makeDependencyProxy(instance);
|
|
@@ -310,6 +373,16 @@ class ProxyDiContainer {
|
|
|
310
373
|
injection.set(injectionsOwner, dependencyProxy);
|
|
311
374
|
});
|
|
312
375
|
}
|
|
376
|
+
/**
|
|
377
|
+
* Creates instances for all injectable classes and registers them in this container.
|
|
378
|
+
* @returns This container to allow use along with constructor.
|
|
379
|
+
*/
|
|
380
|
+
registerInjectables() {
|
|
381
|
+
for (const [dependencyId, InjectableClass] of Object.entries(injectableClasses)) {
|
|
382
|
+
this.register(InjectableClass, dependencyId);
|
|
383
|
+
}
|
|
384
|
+
return this;
|
|
385
|
+
}
|
|
313
386
|
/**
|
|
314
387
|
* Finalizes dependency injections, prevents further rewriting of dependencies,
|
|
315
388
|
* and recursively bakes injections for child containers.
|
|
@@ -339,11 +412,16 @@ class ProxyDiContainer {
|
|
|
339
412
|
* @param dependencyOrId The dependency instance or dependency identifier to remove.
|
|
340
413
|
*/
|
|
341
414
|
remove(dependencyOrId) {
|
|
415
|
+
var _a;
|
|
342
416
|
const id = isDependency(dependencyOrId)
|
|
343
417
|
? dependencyOrId[DEPENDENCY_ID]
|
|
344
418
|
: dependencyOrId;
|
|
345
419
|
const dependency = this.dependencies[id];
|
|
346
420
|
if (dependency) {
|
|
421
|
+
const constructorName = (_a = dependency.constructor) === null || _a === undefined ? undefined : _a.name;
|
|
422
|
+
if (constructorName && middlewaresClasses[constructorName]) {
|
|
423
|
+
this.middlewareListener.remove(dependency);
|
|
424
|
+
}
|
|
347
425
|
const dependencyInjects = dependency[INJECTIONS]
|
|
348
426
|
? dependency[INJECTIONS]
|
|
349
427
|
: {};
|
|
@@ -352,6 +430,7 @@ class ProxyDiContainer {
|
|
|
352
430
|
});
|
|
353
431
|
delete dependency[DEPENDENCY_ID];
|
|
354
432
|
delete this.dependencies[id];
|
|
433
|
+
this.middlewareListener.onRemove(this, id);
|
|
355
434
|
}
|
|
356
435
|
}
|
|
357
436
|
/**
|
|
@@ -445,7 +524,7 @@ function resolveAll(instance, dependencyId) {
|
|
|
445
524
|
const id = findInjectableId(dependencyId);
|
|
446
525
|
return resolveAll(instance, id);
|
|
447
526
|
}
|
|
448
|
-
const container = instance[
|
|
527
|
+
const container = instance[PROXYDI_CONTAINER];
|
|
449
528
|
if (!container) {
|
|
450
529
|
throw new Error('Instance is not registered in any container');
|
|
451
530
|
}
|
|
@@ -463,8 +542,9 @@ function recursiveResolveAll(container, dependencyId) {
|
|
|
463
542
|
}
|
|
464
543
|
|
|
465
544
|
exports.DEPENDENCY_ID = DEPENDENCY_ID;
|
|
466
|
-
exports.
|
|
545
|
+
exports.PROXYDI_CONTAINER = PROXYDI_CONTAINER;
|
|
467
546
|
exports.ProxyDiContainer = ProxyDiContainer;
|
|
468
547
|
exports.inject = inject;
|
|
469
548
|
exports.injectable = injectable;
|
|
549
|
+
exports.middleware = middleware;
|
|
470
550
|
exports.resolveAll = resolveAll;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { inject } from './inject';
|
|
2
2
|
export { ProxyDiContainer } from './ProxyDiContainer';
|
|
3
3
|
export { injectable } from './injectable';
|
|
4
|
-
export {
|
|
4
|
+
export { middleware } from './middleware/middleware';
|
|
5
|
+
export { MiddlewareRegisteringListener, MiddlewareRemovingListener, } from './middleware/MiddlewareListener';
|
|
6
|
+
export { Injection, DependencyId, DependencyClass, ContainerSettings, PROXYDI_CONTAINER, DEPENDENCY_ID, } from './types';
|
|
5
7
|
export { resolveAll } from './resolveAll';
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ const DEPENDENCY_ID = Symbol('DependencyId');
|
|
|
10
10
|
* This property is present in each dependency instance that was registered in ProxyDiContainer.
|
|
11
11
|
* The property stores a reference to the ProxyDiContainer in which the dependency was registered.
|
|
12
12
|
*/
|
|
13
|
-
const
|
|
13
|
+
const PROXYDI_CONTAINER = Symbol('proxyDiContainer');
|
|
14
14
|
const IS_INJECTION_PROXY = Symbol('isInjectionProxy');
|
|
15
15
|
const INJECTION_OWNER = Symbol('injectionOwner');
|
|
16
16
|
const IS_INSTANCE_PROXY = Symbol('isInstanceProxy');
|
|
@@ -91,7 +91,7 @@ class InjectionProxy {
|
|
|
91
91
|
constructor(onwer, container) {
|
|
92
92
|
this[_a] = true;
|
|
93
93
|
this[INJECTION_OWNER] = onwer;
|
|
94
|
-
this[
|
|
94
|
+
this[PROXYDI_CONTAINER] = container;
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
_a = IS_INJECTION_PROXY;
|
|
@@ -188,6 +188,72 @@ function makeConstructorDependencyProxy(container, dependencyId) {
|
|
|
188
188
|
});
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
const middlewaresClasses = {};
|
|
192
|
+
function middleware() {
|
|
193
|
+
return function (value, context) {
|
|
194
|
+
if ((context === null || context === undefined ? undefined : context.kind) !== 'class') {
|
|
195
|
+
throw new Error('@middleware decorator should decorate classes');
|
|
196
|
+
}
|
|
197
|
+
const name = context.name;
|
|
198
|
+
if (middlewaresClasses[name]) {
|
|
199
|
+
throw new Error(`ProxyDi has already regisered middleware ${String(name)} by @middleware`);
|
|
200
|
+
}
|
|
201
|
+
middlewaresClasses[name] = value;
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
class MiddlewareListener {
|
|
206
|
+
constructor(parent) {
|
|
207
|
+
this.parent = parent;
|
|
208
|
+
this.listeners = {
|
|
209
|
+
register: [],
|
|
210
|
+
remove: [],
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
add(middleware) {
|
|
214
|
+
if (isRegistingMiddleware(middleware)) {
|
|
215
|
+
middleware.onRegister && this.on('register', middleware.onRegister);
|
|
216
|
+
}
|
|
217
|
+
if (isRemovingMiddleware(middleware)) {
|
|
218
|
+
middleware.onRemove && this.on('remove', middleware.onRemove);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
remove(middleware) {
|
|
222
|
+
if (isRegistingMiddleware(middleware)) {
|
|
223
|
+
middleware.onRegister &&
|
|
224
|
+
this.off('register', middleware.onRegister);
|
|
225
|
+
}
|
|
226
|
+
if (isRemovingMiddleware(middleware)) {
|
|
227
|
+
middleware.onRemove && this.off('remove', middleware.onRemove);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
on(event, listener) {
|
|
231
|
+
this.listeners[event].push(listener);
|
|
232
|
+
}
|
|
233
|
+
onRegister(container, dependencyId, dependency) {
|
|
234
|
+
var _a;
|
|
235
|
+
this.listeners.register.forEach((listener) => listener(container, dependencyId, dependency));
|
|
236
|
+
(_a = this.parent) === null || _a === undefined ? undefined : _a.onRegister(container, dependencyId, dependency);
|
|
237
|
+
}
|
|
238
|
+
onRemove(container, dependencyId) {
|
|
239
|
+
var _a;
|
|
240
|
+
this.listeners.remove.forEach((listener) => listener(container, dependencyId));
|
|
241
|
+
(_a = this.parent) === null || _a === undefined ? undefined : _a.onRemove(container, dependencyId);
|
|
242
|
+
}
|
|
243
|
+
off(event, listener) {
|
|
244
|
+
const index = this.listeners[event].indexOf(listener);
|
|
245
|
+
if (index !== -1) {
|
|
246
|
+
this.listeners[event].splice(index, 1);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function isRegistingMiddleware(middleware) {
|
|
251
|
+
return middleware.onRegister;
|
|
252
|
+
}
|
|
253
|
+
function isRemovingMiddleware(middleware) {
|
|
254
|
+
return middleware.onRemove;
|
|
255
|
+
}
|
|
256
|
+
|
|
191
257
|
/**
|
|
192
258
|
* A dependency injection container
|
|
193
259
|
*/
|
|
@@ -208,6 +274,7 @@ class ProxyDiContainer {
|
|
|
208
274
|
*/
|
|
209
275
|
this.parentDependencyProxies = {};
|
|
210
276
|
this.id = ProxyDiContainer.idCounter++;
|
|
277
|
+
this.middlewareListener = new MiddlewareListener(parent === null || parent === undefined ? undefined : parent.middlewareListener);
|
|
211
278
|
if (parent) {
|
|
212
279
|
this.parent = parent;
|
|
213
280
|
this.parent.addChild(this);
|
|
@@ -215,28 +282,36 @@ class ProxyDiContainer {
|
|
|
215
282
|
this.settings = Object.assign(Object.assign({}, DEFAULT_SETTINGS), settings);
|
|
216
283
|
}
|
|
217
284
|
register(dependency, dependencyId) {
|
|
285
|
+
var _a;
|
|
218
286
|
if (this.dependencies[dependencyId]) {
|
|
219
287
|
if (!this.settings.allowRewriteDependencies) {
|
|
220
288
|
throw new Error(`ProxyDi already has dependency for ${String(dependencyId)}`);
|
|
221
289
|
}
|
|
222
290
|
}
|
|
223
|
-
let
|
|
291
|
+
let instance;
|
|
224
292
|
const isClass = typeof dependency === 'function';
|
|
225
293
|
if (isClass) {
|
|
226
|
-
|
|
294
|
+
instance = this.createInstance(dependency, dependencyId);
|
|
227
295
|
}
|
|
228
296
|
else {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
297
|
+
instance = dependency;
|
|
298
|
+
}
|
|
299
|
+
const isObject = typeof instance === 'object';
|
|
300
|
+
if (!isObject && !this.settings.allowRegisterAnything) {
|
|
301
|
+
throw new Error(`Can't register as dependency (allowRegisterAnything is off for this contatiner): ${instance}`);
|
|
234
302
|
}
|
|
235
|
-
if (
|
|
236
|
-
|
|
303
|
+
if (isObject) {
|
|
304
|
+
instance[PROXYDI_CONTAINER] = this;
|
|
305
|
+
instance[DEPENDENCY_ID] = dependencyId;
|
|
237
306
|
}
|
|
238
|
-
this.
|
|
239
|
-
|
|
307
|
+
this.injectDependenciesTo(instance);
|
|
308
|
+
this.dependencies[dependencyId] = instance;
|
|
309
|
+
const constructorName = (_a = instance.constructor) === null || _a === undefined ? undefined : _a.name;
|
|
310
|
+
if (constructorName && middlewaresClasses[constructorName]) {
|
|
311
|
+
this.middlewareListener.add(instance);
|
|
312
|
+
}
|
|
313
|
+
this.middlewareListener.onRegister(this, dependencyId, instance);
|
|
314
|
+
return instance;
|
|
240
315
|
}
|
|
241
316
|
createInstance(Dependency, dependencyId) {
|
|
242
317
|
const paramIds = constructorInjections[dependencyId] || [];
|
|
@@ -247,18 +322,6 @@ class ProxyDiContainer {
|
|
|
247
322
|
}
|
|
248
323
|
return new Dependency(...params);
|
|
249
324
|
}
|
|
250
|
-
/**
|
|
251
|
-
* Internal method that implements registeration of dependency and prepare it for injection.
|
|
252
|
-
* @param dependencyId The unique identifier of the dependency.
|
|
253
|
-
* @param dependency The dependency instance.
|
|
254
|
-
*/
|
|
255
|
-
registerImpl(dependency, dependencyId) {
|
|
256
|
-
this.injectDependenciesTo(dependency);
|
|
257
|
-
if (typeof dependency === 'object') {
|
|
258
|
-
dependency[DEPENDENCY_ID] = dependencyId;
|
|
259
|
-
}
|
|
260
|
-
this.dependencies[dependencyId] = dependency;
|
|
261
|
-
}
|
|
262
325
|
/**
|
|
263
326
|
* 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
|
|
264
327
|
* @param dependencyId The identifier of the dependency.
|
|
@@ -284,7 +347,7 @@ class ProxyDiContainer {
|
|
|
284
347
|
}
|
|
285
348
|
const instance = this.findDependency(dependency);
|
|
286
349
|
if (instance) {
|
|
287
|
-
if (instance[
|
|
350
|
+
if (instance[PROXYDI_CONTAINER] !== this &&
|
|
288
351
|
typeof instance === 'object' &&
|
|
289
352
|
this.settings.resolveInContainerContext) {
|
|
290
353
|
const proxy = makeDependencyProxy(instance);
|
|
@@ -308,6 +371,16 @@ class ProxyDiContainer {
|
|
|
308
371
|
injection.set(injectionsOwner, dependencyProxy);
|
|
309
372
|
});
|
|
310
373
|
}
|
|
374
|
+
/**
|
|
375
|
+
* Creates instances for all injectable classes and registers them in this container.
|
|
376
|
+
* @returns This container to allow use along with constructor.
|
|
377
|
+
*/
|
|
378
|
+
registerInjectables() {
|
|
379
|
+
for (const [dependencyId, InjectableClass] of Object.entries(injectableClasses)) {
|
|
380
|
+
this.register(InjectableClass, dependencyId);
|
|
381
|
+
}
|
|
382
|
+
return this;
|
|
383
|
+
}
|
|
311
384
|
/**
|
|
312
385
|
* Finalizes dependency injections, prevents further rewriting of dependencies,
|
|
313
386
|
* and recursively bakes injections for child containers.
|
|
@@ -337,11 +410,16 @@ class ProxyDiContainer {
|
|
|
337
410
|
* @param dependencyOrId The dependency instance or dependency identifier to remove.
|
|
338
411
|
*/
|
|
339
412
|
remove(dependencyOrId) {
|
|
413
|
+
var _a;
|
|
340
414
|
const id = isDependency(dependencyOrId)
|
|
341
415
|
? dependencyOrId[DEPENDENCY_ID]
|
|
342
416
|
: dependencyOrId;
|
|
343
417
|
const dependency = this.dependencies[id];
|
|
344
418
|
if (dependency) {
|
|
419
|
+
const constructorName = (_a = dependency.constructor) === null || _a === undefined ? undefined : _a.name;
|
|
420
|
+
if (constructorName && middlewaresClasses[constructorName]) {
|
|
421
|
+
this.middlewareListener.remove(dependency);
|
|
422
|
+
}
|
|
345
423
|
const dependencyInjects = dependency[INJECTIONS]
|
|
346
424
|
? dependency[INJECTIONS]
|
|
347
425
|
: {};
|
|
@@ -350,6 +428,7 @@ class ProxyDiContainer {
|
|
|
350
428
|
});
|
|
351
429
|
delete dependency[DEPENDENCY_ID];
|
|
352
430
|
delete this.dependencies[id];
|
|
431
|
+
this.middlewareListener.onRemove(this, id);
|
|
353
432
|
}
|
|
354
433
|
}
|
|
355
434
|
/**
|
|
@@ -443,7 +522,7 @@ function resolveAll(instance, dependencyId) {
|
|
|
443
522
|
const id = findInjectableId(dependencyId);
|
|
444
523
|
return resolveAll(instance, id);
|
|
445
524
|
}
|
|
446
|
-
const container = instance[
|
|
525
|
+
const container = instance[PROXYDI_CONTAINER];
|
|
447
526
|
if (!container) {
|
|
448
527
|
throw new Error('Instance is not registered in any container');
|
|
449
528
|
}
|
|
@@ -460,4 +539,4 @@ function recursiveResolveAll(container, dependencyId) {
|
|
|
460
539
|
return all;
|
|
461
540
|
}
|
|
462
541
|
|
|
463
|
-
export { DEPENDENCY_ID,
|
|
542
|
+
export { DEPENDENCY_ID, PROXYDI_CONTAINER, ProxyDiContainer, inject, injectable, middleware, resolveAll };
|
package/dist/index.umd.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* This property is present in each dependency instance that was registered in ProxyDiContainer.
|
|
17
17
|
* The property stores a reference to the ProxyDiContainer in which the dependency was registered.
|
|
18
18
|
*/
|
|
19
|
-
const
|
|
19
|
+
const PROXYDI_CONTAINER = Symbol('proxyDiContainer');
|
|
20
20
|
const IS_INJECTION_PROXY = Symbol('isInjectionProxy');
|
|
21
21
|
const INJECTION_OWNER = Symbol('injectionOwner');
|
|
22
22
|
const IS_INSTANCE_PROXY = Symbol('isInstanceProxy');
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
constructor(onwer, container) {
|
|
98
98
|
this[_a] = true;
|
|
99
99
|
this[INJECTION_OWNER] = onwer;
|
|
100
|
-
this[
|
|
100
|
+
this[PROXYDI_CONTAINER] = container;
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
_a = IS_INJECTION_PROXY;
|
|
@@ -194,6 +194,72 @@
|
|
|
194
194
|
});
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
const middlewaresClasses = {};
|
|
198
|
+
function middleware() {
|
|
199
|
+
return function (value, context) {
|
|
200
|
+
if ((context === null || context === undefined ? undefined : context.kind) !== 'class') {
|
|
201
|
+
throw new Error('@middleware decorator should decorate classes');
|
|
202
|
+
}
|
|
203
|
+
const name = context.name;
|
|
204
|
+
if (middlewaresClasses[name]) {
|
|
205
|
+
throw new Error(`ProxyDi has already regisered middleware ${String(name)} by @middleware`);
|
|
206
|
+
}
|
|
207
|
+
middlewaresClasses[name] = value;
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
class MiddlewareListener {
|
|
212
|
+
constructor(parent) {
|
|
213
|
+
this.parent = parent;
|
|
214
|
+
this.listeners = {
|
|
215
|
+
register: [],
|
|
216
|
+
remove: [],
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
add(middleware) {
|
|
220
|
+
if (isRegistingMiddleware(middleware)) {
|
|
221
|
+
middleware.onRegister && this.on('register', middleware.onRegister);
|
|
222
|
+
}
|
|
223
|
+
if (isRemovingMiddleware(middleware)) {
|
|
224
|
+
middleware.onRemove && this.on('remove', middleware.onRemove);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
remove(middleware) {
|
|
228
|
+
if (isRegistingMiddleware(middleware)) {
|
|
229
|
+
middleware.onRegister &&
|
|
230
|
+
this.off('register', middleware.onRegister);
|
|
231
|
+
}
|
|
232
|
+
if (isRemovingMiddleware(middleware)) {
|
|
233
|
+
middleware.onRemove && this.off('remove', middleware.onRemove);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
on(event, listener) {
|
|
237
|
+
this.listeners[event].push(listener);
|
|
238
|
+
}
|
|
239
|
+
onRegister(container, dependencyId, dependency) {
|
|
240
|
+
var _a;
|
|
241
|
+
this.listeners.register.forEach((listener) => listener(container, dependencyId, dependency));
|
|
242
|
+
(_a = this.parent) === null || _a === undefined ? undefined : _a.onRegister(container, dependencyId, dependency);
|
|
243
|
+
}
|
|
244
|
+
onRemove(container, dependencyId) {
|
|
245
|
+
var _a;
|
|
246
|
+
this.listeners.remove.forEach((listener) => listener(container, dependencyId));
|
|
247
|
+
(_a = this.parent) === null || _a === undefined ? undefined : _a.onRemove(container, dependencyId);
|
|
248
|
+
}
|
|
249
|
+
off(event, listener) {
|
|
250
|
+
const index = this.listeners[event].indexOf(listener);
|
|
251
|
+
if (index !== -1) {
|
|
252
|
+
this.listeners[event].splice(index, 1);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function isRegistingMiddleware(middleware) {
|
|
257
|
+
return middleware.onRegister;
|
|
258
|
+
}
|
|
259
|
+
function isRemovingMiddleware(middleware) {
|
|
260
|
+
return middleware.onRemove;
|
|
261
|
+
}
|
|
262
|
+
|
|
197
263
|
/**
|
|
198
264
|
* A dependency injection container
|
|
199
265
|
*/
|
|
@@ -214,6 +280,7 @@
|
|
|
214
280
|
*/
|
|
215
281
|
this.parentDependencyProxies = {};
|
|
216
282
|
this.id = ProxyDiContainer.idCounter++;
|
|
283
|
+
this.middlewareListener = new MiddlewareListener(parent === null || parent === undefined ? undefined : parent.middlewareListener);
|
|
217
284
|
if (parent) {
|
|
218
285
|
this.parent = parent;
|
|
219
286
|
this.parent.addChild(this);
|
|
@@ -221,28 +288,36 @@
|
|
|
221
288
|
this.settings = Object.assign(Object.assign({}, DEFAULT_SETTINGS), settings);
|
|
222
289
|
}
|
|
223
290
|
register(dependency, dependencyId) {
|
|
291
|
+
var _a;
|
|
224
292
|
if (this.dependencies[dependencyId]) {
|
|
225
293
|
if (!this.settings.allowRewriteDependencies) {
|
|
226
294
|
throw new Error(`ProxyDi already has dependency for ${String(dependencyId)}`);
|
|
227
295
|
}
|
|
228
296
|
}
|
|
229
|
-
let
|
|
297
|
+
let instance;
|
|
230
298
|
const isClass = typeof dependency === 'function';
|
|
231
299
|
if (isClass) {
|
|
232
|
-
|
|
300
|
+
instance = this.createInstance(dependency, dependencyId);
|
|
233
301
|
}
|
|
234
302
|
else {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
303
|
+
instance = dependency;
|
|
304
|
+
}
|
|
305
|
+
const isObject = typeof instance === 'object';
|
|
306
|
+
if (!isObject && !this.settings.allowRegisterAnything) {
|
|
307
|
+
throw new Error(`Can't register as dependency (allowRegisterAnything is off for this contatiner): ${instance}`);
|
|
240
308
|
}
|
|
241
|
-
if (
|
|
242
|
-
|
|
309
|
+
if (isObject) {
|
|
310
|
+
instance[PROXYDI_CONTAINER] = this;
|
|
311
|
+
instance[DEPENDENCY_ID] = dependencyId;
|
|
243
312
|
}
|
|
244
|
-
this.
|
|
245
|
-
|
|
313
|
+
this.injectDependenciesTo(instance);
|
|
314
|
+
this.dependencies[dependencyId] = instance;
|
|
315
|
+
const constructorName = (_a = instance.constructor) === null || _a === undefined ? undefined : _a.name;
|
|
316
|
+
if (constructorName && middlewaresClasses[constructorName]) {
|
|
317
|
+
this.middlewareListener.add(instance);
|
|
318
|
+
}
|
|
319
|
+
this.middlewareListener.onRegister(this, dependencyId, instance);
|
|
320
|
+
return instance;
|
|
246
321
|
}
|
|
247
322
|
createInstance(Dependency, dependencyId) {
|
|
248
323
|
const paramIds = constructorInjections[dependencyId] || [];
|
|
@@ -253,18 +328,6 @@
|
|
|
253
328
|
}
|
|
254
329
|
return new Dependency(...params);
|
|
255
330
|
}
|
|
256
|
-
/**
|
|
257
|
-
* Internal method that implements registeration of dependency and prepare it for injection.
|
|
258
|
-
* @param dependencyId The unique identifier of the dependency.
|
|
259
|
-
* @param dependency The dependency instance.
|
|
260
|
-
*/
|
|
261
|
-
registerImpl(dependency, dependencyId) {
|
|
262
|
-
this.injectDependenciesTo(dependency);
|
|
263
|
-
if (typeof dependency === 'object') {
|
|
264
|
-
dependency[DEPENDENCY_ID] = dependencyId;
|
|
265
|
-
}
|
|
266
|
-
this.dependencies[dependencyId] = dependency;
|
|
267
|
-
}
|
|
268
331
|
/**
|
|
269
332
|
* 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
|
|
270
333
|
* @param dependencyId The identifier of the dependency.
|
|
@@ -290,7 +353,7 @@
|
|
|
290
353
|
}
|
|
291
354
|
const instance = this.findDependency(dependency);
|
|
292
355
|
if (instance) {
|
|
293
|
-
if (instance[
|
|
356
|
+
if (instance[PROXYDI_CONTAINER] !== this &&
|
|
294
357
|
typeof instance === 'object' &&
|
|
295
358
|
this.settings.resolveInContainerContext) {
|
|
296
359
|
const proxy = makeDependencyProxy(instance);
|
|
@@ -314,6 +377,16 @@
|
|
|
314
377
|
injection.set(injectionsOwner, dependencyProxy);
|
|
315
378
|
});
|
|
316
379
|
}
|
|
380
|
+
/**
|
|
381
|
+
* Creates instances for all injectable classes and registers them in this container.
|
|
382
|
+
* @returns This container to allow use along with constructor.
|
|
383
|
+
*/
|
|
384
|
+
registerInjectables() {
|
|
385
|
+
for (const [dependencyId, InjectableClass] of Object.entries(injectableClasses)) {
|
|
386
|
+
this.register(InjectableClass, dependencyId);
|
|
387
|
+
}
|
|
388
|
+
return this;
|
|
389
|
+
}
|
|
317
390
|
/**
|
|
318
391
|
* Finalizes dependency injections, prevents further rewriting of dependencies,
|
|
319
392
|
* and recursively bakes injections for child containers.
|
|
@@ -343,11 +416,16 @@
|
|
|
343
416
|
* @param dependencyOrId The dependency instance or dependency identifier to remove.
|
|
344
417
|
*/
|
|
345
418
|
remove(dependencyOrId) {
|
|
419
|
+
var _a;
|
|
346
420
|
const id = isDependency(dependencyOrId)
|
|
347
421
|
? dependencyOrId[DEPENDENCY_ID]
|
|
348
422
|
: dependencyOrId;
|
|
349
423
|
const dependency = this.dependencies[id];
|
|
350
424
|
if (dependency) {
|
|
425
|
+
const constructorName = (_a = dependency.constructor) === null || _a === undefined ? undefined : _a.name;
|
|
426
|
+
if (constructorName && middlewaresClasses[constructorName]) {
|
|
427
|
+
this.middlewareListener.remove(dependency);
|
|
428
|
+
}
|
|
351
429
|
const dependencyInjects = dependency[INJECTIONS]
|
|
352
430
|
? dependency[INJECTIONS]
|
|
353
431
|
: {};
|
|
@@ -356,6 +434,7 @@
|
|
|
356
434
|
});
|
|
357
435
|
delete dependency[DEPENDENCY_ID];
|
|
358
436
|
delete this.dependencies[id];
|
|
437
|
+
this.middlewareListener.onRemove(this, id);
|
|
359
438
|
}
|
|
360
439
|
}
|
|
361
440
|
/**
|
|
@@ -449,7 +528,7 @@
|
|
|
449
528
|
const id = findInjectableId(dependencyId);
|
|
450
529
|
return resolveAll(instance, id);
|
|
451
530
|
}
|
|
452
|
-
const container = instance[
|
|
531
|
+
const container = instance[PROXYDI_CONTAINER];
|
|
453
532
|
if (!container) {
|
|
454
533
|
throw new Error('Instance is not registered in any container');
|
|
455
534
|
}
|
|
@@ -467,10 +546,11 @@
|
|
|
467
546
|
}
|
|
468
547
|
|
|
469
548
|
exports.DEPENDENCY_ID = DEPENDENCY_ID;
|
|
470
|
-
exports.
|
|
549
|
+
exports.PROXYDI_CONTAINER = PROXYDI_CONTAINER;
|
|
471
550
|
exports.ProxyDiContainer = ProxyDiContainer;
|
|
472
551
|
exports.inject = inject;
|
|
473
552
|
exports.injectable = injectable;
|
|
553
|
+
exports.middleware = middleware;
|
|
474
554
|
exports.resolveAll = resolveAll;
|
|
475
555
|
|
|
476
556
|
}));
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ProxyDiContainer } from '../ProxyDiContainer';
|
|
2
|
+
import { DependencyId } from '../types';
|
|
3
|
+
export interface MiddlewareListenerEvent {
|
|
4
|
+
register: (container: ProxyDiContainer, dependencyId: DependencyId, dependency: any) => void;
|
|
5
|
+
remove: (container: ProxyDiContainer, dependencyId: DependencyId) => void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Describe the middleware that able to listen to the registering of a dependency in containers hierarchy
|
|
9
|
+
*/
|
|
10
|
+
export interface MiddlewareRegisteringListener {
|
|
11
|
+
onRegister(container: ProxyDiContainer, dependencyId: DependencyId, dependency: any): void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Describe the middleware that able to listen to the removing of a dependency in containers hierarchy
|
|
15
|
+
*/
|
|
16
|
+
export interface MiddlewareRemovingListener {
|
|
17
|
+
onRemove(container: ProxyDiContainer, dependencyId: DependencyId): void;
|
|
18
|
+
}
|
|
19
|
+
export declare class MiddlewareListener {
|
|
20
|
+
private parent?;
|
|
21
|
+
private listeners;
|
|
22
|
+
constructor(parent?: MiddlewareListener | undefined);
|
|
23
|
+
add(middleware: any): void;
|
|
24
|
+
remove(middleware: any): void;
|
|
25
|
+
private on;
|
|
26
|
+
onRegister(container: ProxyDiContainer, dependencyId: DependencyId, dependency: any): void;
|
|
27
|
+
onRemove(container: ProxyDiContainer, dependencyId: DependencyId): void;
|
|
28
|
+
private off;
|
|
29
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export type IProxyDiContainer = {
|
|
|
12
12
|
isKnown: (dependencyId: DependencyId) => boolean;
|
|
13
13
|
injectDependenciesTo: (dependency: any) => void;
|
|
14
14
|
register: (dependency: any, dependencyId: DependencyId) => any;
|
|
15
|
-
resolve: <T>(dependencyId: DependencyId) => T & ContainerizedDependency;
|
|
15
|
+
resolve: <T>(dependencyId: DependencyId | DependencyClass<any>) => T & ContainerizedDependency;
|
|
16
16
|
createChildContainer: () => IProxyDiContainer;
|
|
17
17
|
children: IProxyDiContainer[];
|
|
18
18
|
getChild(id: number): IProxyDiContainer;
|
|
@@ -32,7 +32,7 @@ export declare const DEPENDENCY_ID: unique symbol;
|
|
|
32
32
|
* This property is present in each dependency instance that was registered in ProxyDiContainer.
|
|
33
33
|
* The property stores a reference to the ProxyDiContainer in which the dependency was registered.
|
|
34
34
|
*/
|
|
35
|
-
export declare const
|
|
35
|
+
export declare const PROXYDI_CONTAINER: unique symbol;
|
|
36
36
|
export type Injections = Record<string | symbol, Injection>;
|
|
37
37
|
export type Dependency = {
|
|
38
38
|
[INJECTIONS]: Injections;
|
|
@@ -48,7 +48,7 @@ export type ContainerizedDependency = Dependency & {
|
|
|
48
48
|
/**
|
|
49
49
|
* ProxyDi container in which this instance was registered
|
|
50
50
|
*/
|
|
51
|
-
[
|
|
51
|
+
[PROXYDI_CONTAINER]: IProxyDiContainer;
|
|
52
52
|
};
|
|
53
53
|
export type ContainerSettings = {
|
|
54
54
|
allowRegisterAnything?: boolean;
|
|
@@ -61,5 +61,5 @@ export declare const IS_INSTANCE_PROXY: unique symbol;
|
|
|
61
61
|
export type InjectionProxy = {
|
|
62
62
|
[IS_INJECTION_PROXY]: true;
|
|
63
63
|
[INJECTION_OWNER]: ContainerizedDependency;
|
|
64
|
-
[
|
|
64
|
+
[PROXYDI_CONTAINER]: IProxyDiContainer;
|
|
65
65
|
};
|