proxydi 0.0.10 → 0.0.11

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 ADDED
@@ -0,0 +1,85 @@
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.10](https://www.npmjs.com/package/proxydi/v/0.0.11)] - 2025-03-03
9
+
10
+ ### Added
11
+
12
+ - resolveInjectables() method [#12](https://github.com/proxy-di/proxydi/pull/13)
13
+
14
+ ## [[0.0.10](https://www.npmjs.com/package/proxydi/v/0.0.10)] - 2025-03-02
15
+
16
+ ### Changed
17
+
18
+ - Renamed @autoInjectable to @injectable
19
+
20
+ ### Added
21
+
22
+ - Experimental constructor injections via @injectable decorator [#12](https://github.com/proxy-di/proxydi/pull/12)
23
+
24
+ ## [[0.0.9](https://www.npmjs.com/package/proxydi/v/0.0.9)] - 2025-02-27
25
+
26
+ ### Added
27
+
28
+ - resolveAll() function to find all dependencies of a given kind [#11](https://github.com/proxy-di/proxydi/pull/11)
29
+
30
+ ## [[0.0.8](https://www.npmjs.com/package/proxydi/v/0.0.8)] - 2025-02-26
31
+
32
+ ### Changed
33
+
34
+ - API improvements [#10](https://github.com/proxy-di/proxydi/pull/10)
35
+
36
+ ### Added
37
+
38
+ - Added access to child containers
39
+ - PROXYDI_CONTAINER and DEPENDENCY_ID now public
40
+ - Enhanced hierarchy documentation
41
+
42
+ ## [[0.0.7](https://www.npmjs.com/package/proxydi/v/0.0.7)] - 2025-02-21
43
+
44
+ ### Added
45
+
46
+ - TypeDoc integration [#7](https://github.com/proxy-di/proxydi/pull/7)
47
+ - Action to publish documentation on GitHub Pages
48
+
49
+ ## [[0.0.6](https://www.npmjs.com/package/proxydi/v/0.0.6)] - 2025-02-21
50
+
51
+ ### Changed
52
+
53
+ - Improved API [#6](https://github.com/proxy-di/proxydi/pull/6)
54
+
55
+ ## [[0.0.5](https://www.npmjs.com/package/proxydi/v/0.0.5)] - 2025-02-20
56
+
57
+ ### Changed
58
+
59
+ - Baking dependencies [#5](https://github.com/proxy-di/proxydi/pull/5)
60
+ - 100% test coverage
61
+ - Changed API with new terminology
62
+
63
+ ## [[0.0.4](https://www.npmjs.com/package/proxydi/v/0.0.4)] - 2025-02-11
64
+
65
+ ### Changed
66
+
67
+ - Implemented proxy per instance instead of per container [#2](https://github.com/proxy-di/proxydi/pull/2)
68
+ - Ability to register anything as an instance
69
+ - Changed settings to object format
70
+ - Added settings presets
71
+
72
+ ### Fixed
73
+
74
+ - Made injectables known
75
+
76
+ ## [[0.0.3](https://www.npmjs.com/package/proxydi/v/0.0.3)] - 2025-02-07
77
+
78
+ ### Added
79
+
80
+ - Draft DI-container implementation
81
+ - @injectable decorator
82
+ - Basic project setup with CI/CD
83
+ - Testing framework integration
84
+ - Basic package configuration
85
+ - Repository initialization
package/README.md CHANGED
@@ -15,6 +15,7 @@ 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)
19
20
  - Matches dependencies by unique identifiers or automatically using class names and property names
20
21
 
@@ -242,10 +243,67 @@ In this example, the character activates all its perks, which are registered in
242
243
 
243
244
  ### Reference to the container
244
245
 
245
- 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.
246
+ 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
247
 
247
248
  Despite this explanation is a little bit complicated, the example is still simple, the character just activates all its perks.
248
249
 
250
+ ## Injectable classes
251
+
252
+ Look at the following example:
253
+
254
+ ```typescript
255
+ @injectable()
256
+ class GameEngine {
257
+ start = () => console.log('Game started');
258
+ }
259
+
260
+ const container = new ProxyDiContainer();
261
+
262
+ const gameEngine = container.resolve(GameEngine);
263
+ gameEngine.start();
264
+ ```
265
+
266
+ ```shell
267
+ > Game started
268
+ ```
269
+
270
+ Two things happen here:
271
+
272
+ 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.
273
+
274
+ 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`.
275
+
276
+ ### Implicitly resolving injectable() dependencies
277
+
278
+ 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:
279
+
280
+ ```typescript
281
+ const parent = new ProxyDiContainer();
282
+ const child = parent.createChildContainer();
283
+
284
+ const engine1 = child.resolve(GameEngine);
285
+ const engine2 = parent.resolve(GameEngine);
286
+
287
+ engine1 === engine2; // false
288
+ ```
289
+
290
+ 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
291
+
292
+ There are two ways to avoid this behavior:
293
+
294
+ 1. Don't use the `@injectable()` decorator and always register dependencies explicitly
295
+ 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:
296
+
297
+ ```typescript
298
+ const parent = new ProxyDiContainer().registerInjectables();
299
+ const child = parent.createChildContainer();
300
+
301
+ const engine1 = child.resolve(GameEngine);
302
+ const engine2 = parent.resolve(GameEngine);
303
+
304
+ engine1 === engine2; // true now
305
+ ```
306
+
249
307
  ## Rewriting dependencies
250
308
 
251
309
  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:
@@ -72,6 +72,11 @@ export declare class ProxyDiContainer implements IProxyDiContainer {
72
72
  * @param injectionsOwner The object to inject dependencies into.
73
73
  */
74
74
  injectDependenciesTo(injectionsOwner: any): void;
75
+ /**
76
+ * Creates instances for all injectable classes and registers them in this container.
77
+ * @returns This container to allow use along with constructor.
78
+ */
79
+ registerInjectables(): this;
75
80
  /**
76
81
  * Finalizes dependency injections, prevents further rewriting of dependencies,
77
82
  * 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 PROXYDY_CONTAINER = Symbol('proxyDiContainer');
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[PROXYDY_CONTAINER] = container;
96
+ this[PROXYDI_CONTAINER] = container;
97
97
  }
98
98
  }
99
99
  _a = IS_INJECTION_PROXY;
@@ -235,7 +235,7 @@ class ProxyDiContainer {
235
235
  }
236
236
  }
237
237
  if (typeof dependencyInstance === 'object') {
238
- dependencyInstance[PROXYDY_CONTAINER] = this;
238
+ dependencyInstance[PROXYDI_CONTAINER] = this;
239
239
  }
240
240
  this.registerImpl(dependencyInstance, dependencyId);
241
241
  return dependencyInstance;
@@ -286,7 +286,7 @@ class ProxyDiContainer {
286
286
  }
287
287
  const instance = this.findDependency(dependency);
288
288
  if (instance) {
289
- if (instance[PROXYDY_CONTAINER] !== this &&
289
+ if (instance[PROXYDI_CONTAINER] !== this &&
290
290
  typeof instance === 'object' &&
291
291
  this.settings.resolveInContainerContext) {
292
292
  const proxy = makeDependencyProxy(instance);
@@ -310,6 +310,16 @@ class ProxyDiContainer {
310
310
  injection.set(injectionsOwner, dependencyProxy);
311
311
  });
312
312
  }
313
+ /**
314
+ * Creates instances for all injectable classes and registers them in this container.
315
+ * @returns This container to allow use along with constructor.
316
+ */
317
+ registerInjectables() {
318
+ for (const [dependencyId, InjectableClass] of Object.entries(injectableClasses)) {
319
+ this.register(InjectableClass, dependencyId);
320
+ }
321
+ return this;
322
+ }
313
323
  /**
314
324
  * Finalizes dependency injections, prevents further rewriting of dependencies,
315
325
  * and recursively bakes injections for child containers.
@@ -445,7 +455,7 @@ function resolveAll(instance, dependencyId) {
445
455
  const id = findInjectableId(dependencyId);
446
456
  return resolveAll(instance, id);
447
457
  }
448
- const container = instance[PROXYDY_CONTAINER];
458
+ const container = instance[PROXYDI_CONTAINER];
449
459
  if (!container) {
450
460
  throw new Error('Instance is not registered in any container');
451
461
  }
@@ -463,7 +473,7 @@ function recursiveResolveAll(container, dependencyId) {
463
473
  }
464
474
 
465
475
  exports.DEPENDENCY_ID = DEPENDENCY_ID;
466
- exports.PROXYDY_CONTAINER = PROXYDY_CONTAINER;
476
+ exports.PROXYDI_CONTAINER = PROXYDI_CONTAINER;
467
477
  exports.ProxyDiContainer = ProxyDiContainer;
468
478
  exports.inject = inject;
469
479
  exports.injectable = injectable;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { inject } from './inject';
2
2
  export { ProxyDiContainer } from './ProxyDiContainer';
3
3
  export { injectable } from './injectable';
4
- export { Injection, DependencyId, DependencyClass, ContainerSettings, PROXYDY_CONTAINER, DEPENDENCY_ID, } from './types';
4
+ export { Injection, DependencyId, DependencyClass, ContainerSettings, PROXYDI_CONTAINER, DEPENDENCY_ID, } from './types';
5
5
  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 PROXYDY_CONTAINER = Symbol('proxyDiContainer');
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[PROXYDY_CONTAINER] = container;
94
+ this[PROXYDI_CONTAINER] = container;
95
95
  }
96
96
  }
97
97
  _a = IS_INJECTION_PROXY;
@@ -233,7 +233,7 @@ class ProxyDiContainer {
233
233
  }
234
234
  }
235
235
  if (typeof dependencyInstance === 'object') {
236
- dependencyInstance[PROXYDY_CONTAINER] = this;
236
+ dependencyInstance[PROXYDI_CONTAINER] = this;
237
237
  }
238
238
  this.registerImpl(dependencyInstance, dependencyId);
239
239
  return dependencyInstance;
@@ -284,7 +284,7 @@ class ProxyDiContainer {
284
284
  }
285
285
  const instance = this.findDependency(dependency);
286
286
  if (instance) {
287
- if (instance[PROXYDY_CONTAINER] !== this &&
287
+ if (instance[PROXYDI_CONTAINER] !== this &&
288
288
  typeof instance === 'object' &&
289
289
  this.settings.resolveInContainerContext) {
290
290
  const proxy = makeDependencyProxy(instance);
@@ -308,6 +308,16 @@ class ProxyDiContainer {
308
308
  injection.set(injectionsOwner, dependencyProxy);
309
309
  });
310
310
  }
311
+ /**
312
+ * Creates instances for all injectable classes and registers them in this container.
313
+ * @returns This container to allow use along with constructor.
314
+ */
315
+ registerInjectables() {
316
+ for (const [dependencyId, InjectableClass] of Object.entries(injectableClasses)) {
317
+ this.register(InjectableClass, dependencyId);
318
+ }
319
+ return this;
320
+ }
311
321
  /**
312
322
  * Finalizes dependency injections, prevents further rewriting of dependencies,
313
323
  * and recursively bakes injections for child containers.
@@ -443,7 +453,7 @@ function resolveAll(instance, dependencyId) {
443
453
  const id = findInjectableId(dependencyId);
444
454
  return resolveAll(instance, id);
445
455
  }
446
- const container = instance[PROXYDY_CONTAINER];
456
+ const container = instance[PROXYDI_CONTAINER];
447
457
  if (!container) {
448
458
  throw new Error('Instance is not registered in any container');
449
459
  }
@@ -460,4 +470,4 @@ function recursiveResolveAll(container, dependencyId) {
460
470
  return all;
461
471
  }
462
472
 
463
- export { DEPENDENCY_ID, PROXYDY_CONTAINER, ProxyDiContainer, inject, injectable, resolveAll };
473
+ export { DEPENDENCY_ID, PROXYDI_CONTAINER, ProxyDiContainer, inject, injectable, 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 PROXYDY_CONTAINER = Symbol('proxyDiContainer');
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[PROXYDY_CONTAINER] = container;
100
+ this[PROXYDI_CONTAINER] = container;
101
101
  }
102
102
  }
103
103
  _a = IS_INJECTION_PROXY;
@@ -239,7 +239,7 @@
239
239
  }
240
240
  }
241
241
  if (typeof dependencyInstance === 'object') {
242
- dependencyInstance[PROXYDY_CONTAINER] = this;
242
+ dependencyInstance[PROXYDI_CONTAINER] = this;
243
243
  }
244
244
  this.registerImpl(dependencyInstance, dependencyId);
245
245
  return dependencyInstance;
@@ -290,7 +290,7 @@
290
290
  }
291
291
  const instance = this.findDependency(dependency);
292
292
  if (instance) {
293
- if (instance[PROXYDY_CONTAINER] !== this &&
293
+ if (instance[PROXYDI_CONTAINER] !== this &&
294
294
  typeof instance === 'object' &&
295
295
  this.settings.resolveInContainerContext) {
296
296
  const proxy = makeDependencyProxy(instance);
@@ -314,6 +314,16 @@
314
314
  injection.set(injectionsOwner, dependencyProxy);
315
315
  });
316
316
  }
317
+ /**
318
+ * Creates instances for all injectable classes and registers them in this container.
319
+ * @returns This container to allow use along with constructor.
320
+ */
321
+ registerInjectables() {
322
+ for (const [dependencyId, InjectableClass] of Object.entries(injectableClasses)) {
323
+ this.register(InjectableClass, dependencyId);
324
+ }
325
+ return this;
326
+ }
317
327
  /**
318
328
  * Finalizes dependency injections, prevents further rewriting of dependencies,
319
329
  * and recursively bakes injections for child containers.
@@ -449,7 +459,7 @@
449
459
  const id = findInjectableId(dependencyId);
450
460
  return resolveAll(instance, id);
451
461
  }
452
- const container = instance[PROXYDY_CONTAINER];
462
+ const container = instance[PROXYDI_CONTAINER];
453
463
  if (!container) {
454
464
  throw new Error('Instance is not registered in any container');
455
465
  }
@@ -467,7 +477,7 @@
467
477
  }
468
478
 
469
479
  exports.DEPENDENCY_ID = DEPENDENCY_ID;
470
- exports.PROXYDY_CONTAINER = PROXYDY_CONTAINER;
480
+ exports.PROXYDI_CONTAINER = PROXYDI_CONTAINER;
471
481
  exports.ProxyDiContainer = ProxyDiContainer;
472
482
  exports.inject = inject;
473
483
  exports.injectable = injectable;
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 PROXYDY_CONTAINER: unique symbol;
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
- [PROXYDY_CONTAINER]: IProxyDiContainer;
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
- [PROXYDY_CONTAINER]: IProxyDiContainer;
64
+ [PROXYDI_CONTAINER]: IProxyDiContainer;
65
65
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "proxydi",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "description": "A typed hierarchical DI container that resolves circular dependencies via Proxy",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",