proxydi 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -3
- package/README.md +71 -0
- package/dist/ProxyDiContainer.d.ts +32 -24
- package/dist/index.cjs +509 -214
- package/dist/index.d.ts +1 -1
- package/dist/index.js +509 -214
- package/dist/index.umd.js +509 -214
- package/dist/inject.decorator.d.ts +3 -2
- package/dist/injectable.decorator.d.ts +3 -2
- package/dist/types.d.ts +25 -8
- package/documentation/README-proposal.md +49 -1
- package/documentation/proxydi.md +8 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,9 +4,19 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [[0.3.0](https://www.npmjs.com/package/proxydi/v/0.3.0)] - 2026-01-02
|
|
8
|
+
|
|
7
9
|
### Added
|
|
8
10
|
|
|
9
|
-
-
|
|
11
|
+
- `@injectable` accepts multiple dependency identifiers and always registers under the class name as a default ID
|
|
12
|
+
- `register()` can directly bind a single dependency to multiple dependency IDs
|
|
13
|
+
- `@inject` accepts `ResolveScope` to resolve dependencies from children/parent/current containers
|
|
14
|
+
- `resolve()` and `resolveAll()` accept optional `ResolveScope` to define where dependencies are searched
|
|
15
|
+
- Robust removal logic for multi-ID registrations; removing by ID leaves other IDs intact, removing by instance clears all IDs
|
|
16
|
+
|
|
17
|
+
### Breaking
|
|
18
|
+
|
|
19
|
+
- One dependency ID can now have multiple registrations; `resolve()` returns the first registered instance, while `resolveAll()`/`@injectAll` return all matching instances.
|
|
10
20
|
|
|
11
21
|
## [[0.2.0](https://www.npmjs.com/package/proxydi/v/0.2.0)] - 2026-01-01
|
|
12
22
|
|
|
@@ -20,9 +30,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
20
30
|
|
|
21
31
|
- Fixed bug where passing class constructor as `dependencyId` in `register()` would store dependency under function reference instead of class name, making it impossible to resolve with `resolve(Class)`
|
|
22
32
|
|
|
23
|
-
###
|
|
33
|
+
### Breaking
|
|
24
34
|
|
|
25
|
-
-
|
|
35
|
+
- Constructor injection support removed from `@injectable` decorator. This experimental feature caused issues with circular dependencies and added unnecessary complexity. Use field injection with `@inject` decorator instead.
|
|
26
36
|
|
|
27
37
|
## [[0.1.3](https://www.npmjs.com/package/proxydi/v/0.1.3)] - 2025-03-26
|
|
28
38
|
|
package/README.md
CHANGED
|
@@ -345,6 +345,77 @@ Therefore, after the container has been baked, the performance impact becomes ze
|
|
|
345
345
|
|
|
346
346
|
To be continued...
|
|
347
347
|
|
|
348
|
+
## Multiple Dependencies (v0.3.0+)
|
|
349
|
+
|
|
350
|
+
Sometimes you need to register multiple instances for the same dependency ID (e.g., plugins, event handlers).
|
|
351
|
+
|
|
352
|
+
### Registering multiple instances
|
|
353
|
+
|
|
354
|
+
You can register multiple dependencies with the same ID using `DuplicateStrategy.AlwaysAdd`. By default, `register()` uses `DuplicateStrategy.ReplaceIfSingleElseAdd` which maintains backward compatibility (single instance replaces existing).
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
import { DuplicateStrategy } from 'proxydi';
|
|
358
|
+
|
|
359
|
+
const container = new ProxyDiContainer();
|
|
360
|
+
|
|
361
|
+
// Register multiple handlers
|
|
362
|
+
container.register(new Handler1(), {
|
|
363
|
+
dependencyId: 'EventHandler',
|
|
364
|
+
duplicateStrategy: DuplicateStrategy.AlwaysAdd,
|
|
365
|
+
});
|
|
366
|
+
container.register(new Handler2(), {
|
|
367
|
+
dependencyId: 'EventHandler',
|
|
368
|
+
duplicateStrategy: DuplicateStrategy.AlwaysAdd,
|
|
369
|
+
});
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Resolving multiple instances
|
|
373
|
+
|
|
374
|
+
Use `@injectAll` or `resolveAll` to retrieve all registered instances:
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
class EventService {
|
|
378
|
+
@injectAll('EventHandler') private handlers: EventHandler[];
|
|
379
|
+
|
|
380
|
+
emit(event) {
|
|
381
|
+
this.handlers.forEach((h) => h.handle(event));
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
> **Note:** `resolve('EventHandler')` or `@inject('EventHandler')` will return the **first** registered instance and log a warning if multiple instances exist.
|
|
387
|
+
|
|
388
|
+
### Auto-injectable arrays
|
|
389
|
+
|
|
390
|
+
You can also use `@injectable` with an array of IDs. These classes will be automatically discovered and registered when using `resolveAll`.
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
@injectable(['EventHandler'])
|
|
394
|
+
class Handler1 {}
|
|
395
|
+
|
|
396
|
+
@injectable(['EventHandler'])
|
|
397
|
+
class Handler2 {}
|
|
398
|
+
|
|
399
|
+
// ... later ...
|
|
400
|
+
const handlers = container.resolveAll('EventHandler'); // [Handler1, Handler2]
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## Resolve Scope
|
|
404
|
+
|
|
405
|
+
You can control where dependencies are searched using `ResolveScope` in both `@inject` and `@injectAll`.
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
import { ResolveScope } from 'proxydi';
|
|
409
|
+
|
|
410
|
+
// Search only in children containers
|
|
411
|
+
@injectAll('Plugin', ResolveScope.Children)
|
|
412
|
+
private plugins: Plugin[];
|
|
413
|
+
|
|
414
|
+
// Search only in the current container (ignore parent)
|
|
415
|
+
@inject('Config', ResolveScope.Current)
|
|
416
|
+
private localConfig: Config;
|
|
417
|
+
```
|
|
418
|
+
|
|
348
419
|
## Motivation
|
|
349
420
|
|
|
350
421
|
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.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { IProxyDiContainer as IProxyDiContainer, ContainerizedDependency as ContainerizedDependency, DependencyClass } from './types';
|
|
2
|
-
import { ContainerSettings as ContainerSettings
|
|
1
|
+
import { IProxyDiContainer as IProxyDiContainer, ContainerizedDependency as ContainerizedDependency, DependencyClass, ResolveScope, DependencyId, RegisterOptions } from './types';
|
|
2
|
+
import { ContainerSettings as ContainerSettings } from './types';
|
|
3
3
|
import { MiddlewareRegistrator, MiddlewareRemover, MiddlewareResolver } from './middleware/middleware.api';
|
|
4
4
|
/**
|
|
5
5
|
* A dependency injection container
|
|
@@ -26,6 +26,10 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
|
|
|
26
26
|
* Holds proxies for dependencies registered in parent containers to provide for it dependencies from this container
|
|
27
27
|
*/
|
|
28
28
|
private inContextProxies;
|
|
29
|
+
/**
|
|
30
|
+
* Mapping from dependency instance to all IDs under which it was registered
|
|
31
|
+
*/
|
|
32
|
+
private dependencyIds;
|
|
29
33
|
/**
|
|
30
34
|
* Settings that control the behavior of the container and it's children
|
|
31
35
|
*/
|
|
@@ -44,18 +48,18 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
|
|
|
44
48
|
* In case of class, it will be instantiated without any parameters.
|
|
45
49
|
*
|
|
46
50
|
* @param dependency The dependency instance or dependency class.
|
|
47
|
-
* @param dependencyId The unique identifier for the dependency in this container. Can be a string, symbol, or class constructor (which will be normalized to class name).
|
|
48
|
-
* @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.
|
|
51
|
+
* @param dependencyId The unique identifier(s) for the dependency in this container. Can be a string, symbol, array or class constructor (which will be normalized to class name or @injectable IDs).
|
|
49
52
|
* @returns Dependency instance, registered in container
|
|
50
53
|
*/
|
|
51
|
-
register<T>(DependencyClass: DependencyClass<T>,
|
|
52
|
-
register<T>(dependency: T extends new (...args: any[]) => any ? never : T,
|
|
54
|
+
register<T>(DependencyClass: DependencyClass<T>, options?: RegisterOptions | DependencyId | DependencyId[] | DependencyClass<any>): T & ContainerizedDependency;
|
|
55
|
+
register<T>(dependency: T extends new (...args: any[]) => any ? never : T, options?: RegisterOptions | DependencyId | DependencyId[] | DependencyClass<any>): T & ContainerizedDependency;
|
|
53
56
|
/**
|
|
54
57
|
* 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
|
|
55
58
|
* @param dependencyId The identifier of the dependency. Can be a string, symbol, or class constructor (which will be normalized to class name).
|
|
56
59
|
* @returns True if the dependency is known, false otherwise.
|
|
57
60
|
*/
|
|
58
|
-
isKnown(dependencyId: DependencyId | DependencyClass<any
|
|
61
|
+
isKnown(dependencyId: DependencyId | DependencyClass<any>, scope?: ResolveScope): boolean;
|
|
62
|
+
private isKnownById;
|
|
59
63
|
/**
|
|
60
64
|
* Checks if a dependency with the given ID exists in this container only (does not check parents)
|
|
61
65
|
* @param dependencyId The identifier of the dependency. Can be a string, symbol, or class constructor (which will be normalized to class name).
|
|
@@ -68,9 +72,17 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
|
|
|
68
72
|
* @returns The resolved dependency instance with container metadata.
|
|
69
73
|
* @throws Error if the dependency cannot be found or is not auto injectable.
|
|
70
74
|
*/
|
|
71
|
-
resolve<T>(
|
|
72
|
-
resolve<T extends DependencyClass<any>>(
|
|
73
|
-
|
|
75
|
+
resolve<T>(dependency: DependencyId, scope?: ResolveScope): T & ContainerizedDependency;
|
|
76
|
+
resolve<T extends DependencyClass<any>>(dependency: T, scope?: ResolveScope): InstanceType<T> & ContainerizedDependency;
|
|
77
|
+
resolveAll<T>(dependencyId: DependencyId, scope?: ResolveScope): (T & ContainerizedDependency)[];
|
|
78
|
+
resolveAll<T extends DependencyClass<any>>(dependencyId: T, scope?: ResolveScope): (InstanceType<T> & ContainerizedDependency)[];
|
|
79
|
+
private resolveById;
|
|
80
|
+
private autoRegisterInjectable;
|
|
81
|
+
private autoRegisterAllInjectables;
|
|
82
|
+
private getContextProxy;
|
|
83
|
+
private recursiveResolveAll;
|
|
84
|
+
private findFirstInScope;
|
|
85
|
+
private dedupe;
|
|
74
86
|
/**
|
|
75
87
|
* Injects dependencies to the given object based on its defined injections metadata. Does not affect the container.
|
|
76
88
|
* @param injectionsOwner The object to inject dependencies into.
|
|
@@ -82,8 +94,7 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
|
|
|
82
94
|
*/
|
|
83
95
|
registerInjectables(): this;
|
|
84
96
|
/**
|
|
85
|
-
* Finalizes dependency injections
|
|
86
|
-
* and recursively bakes injections for child containers.
|
|
97
|
+
* Finalizes dependency injections and recursively bakes injections for child containers.
|
|
87
98
|
*/
|
|
88
99
|
bakeInjections(): void;
|
|
89
100
|
/**
|
|
@@ -101,18 +112,6 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
|
|
|
101
112
|
* recursively destroying child containers and removing itself from its parent.
|
|
102
113
|
*/
|
|
103
114
|
destroy(): void;
|
|
104
|
-
/**
|
|
105
|
-
* Recursively finds a dependency by its ID from this container or its parent.
|
|
106
|
-
* @param dependencyId The identifier of the dependency to find.
|
|
107
|
-
* @returns The dependency if found, otherwise undefined.
|
|
108
|
-
*/
|
|
109
|
-
private findDependency;
|
|
110
|
-
/**
|
|
111
|
-
* Normalizes dependency identifier by converting class constructors to their names.
|
|
112
|
-
* @param id The dependency identifier (string, symbol, or class constructor).
|
|
113
|
-
* @returns Normalized dependency identifier (string or symbol).
|
|
114
|
-
*/
|
|
115
|
-
private normalizeDependencyId;
|
|
116
115
|
/**
|
|
117
116
|
* All direct descendants of this container
|
|
118
117
|
*/
|
|
@@ -134,4 +133,13 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
|
|
|
134
133
|
* @param id The identifier of the child container to remove.
|
|
135
134
|
*/
|
|
136
135
|
private removeChild;
|
|
136
|
+
private normalizeDependencyIds;
|
|
137
|
+
private normalizeRegisterOptions;
|
|
138
|
+
private normalizeToIds;
|
|
139
|
+
private addDependencyInstance;
|
|
140
|
+
private notifyOnRegister;
|
|
141
|
+
private getAllOwnDependencies;
|
|
142
|
+
private removeById;
|
|
143
|
+
private removeByInstance;
|
|
144
|
+
private removeDependencyBinding;
|
|
137
145
|
}
|