decorator-dependency-injection 1.0.3 → 1.0.5

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/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/decorator-dependency-injection.svg)](http://badge.fury.io/js/decorator-dependency-injection)
4
4
  [![Build Status](https://github.com/mallocator/decorator-dependency-injection/actions/workflows/release.yml/badge.svg)](https://github.com/mallocator/decorator-dependency-injection/actions/workflows/release.yml)
5
+ [![Coverage](https://img.shields.io/badge/coverage-93%25-brightgreen)](https://github.com/mallocator/decorator-dependency-injection)
5
6
 
6
7
  ## Description
7
8
 
@@ -61,9 +62,9 @@ The ```@Singleton``` decorator is used to inject a single instance of a dependen
61
62
  want to share the same instance of a class across multiple classes.
62
63
 
63
64
  ```javascript
64
- import {Singleton} from 'decorator-dependency-injection';
65
+ import {Singleton, Inject} from 'decorator-dependency-injection';
65
66
 
66
- @Singleton
67
+ @Singleton()
67
68
  class Dependency {
68
69
  }
69
70
 
@@ -78,9 +79,9 @@ The ```@Factory``` decorator is used to inject a new instance of a dependency in
78
79
  This is useful when you want to create a new instance of a class each time it is injected.
79
80
 
80
81
  ```javascript
81
- import {Factory} from 'decorator-dependency-injection';
82
+ import {Factory, Inject} from 'decorator-dependency-injection';
82
83
 
83
- @Factory
84
+ @Factory()
84
85
  class Dependency {
85
86
  }
86
87
 
@@ -89,26 +90,185 @@ class Consumer {
89
90
  }
90
91
  ```
91
92
 
92
- ### LazyInject
93
+ ### InjectLazy
93
94
 
94
95
  ```@Inject``` annotated properties are evaluated during instance initialization. That means that all properties should
95
96
  be accessible in the constructor. That also means that we're creating an instance no matter if you access the property
96
- or not. If you want to only create an instance when you access the property, you can use the ```@LazyInject```
97
+ or not. If you want to only create an instance when you access the property, you can use the ```@InjectLazy```
97
98
  decorator. This will create the instance only when the property is accessed for the first time. Note that this also
98
- works from the constructor, same as the regular ```@Inject```.
99
+ works from the constructor, same as the regular ```@Inject```.
99
100
 
100
101
  ```javascript
101
- import {LazyInject} from 'decorator-dependency-injection';
102
+ import {Singleton, InjectLazy} from 'decorator-dependency-injection';
102
103
 
103
- @Singleton
104
+ @Singleton()
104
105
  class Dependency {
105
106
  }
106
107
 
107
108
  class Consumer {
108
- @LazyInject(Dependency) dependency // creates an instance only when the property is accessed
109
+ @InjectLazy(Dependency) dependency // creates an instance only when the property is accessed
110
+ }
111
+ ```
112
+
113
+ ### Private Field Injection
114
+
115
+ Both `@Inject` and `@InjectLazy` support private fields using the `#` syntax:
116
+
117
+ ```javascript
118
+ import {Singleton, Inject} from 'decorator-dependency-injection';
119
+
120
+ @Singleton()
121
+ class Database {
122
+ query(sql) { /* ... */ }
123
+ }
124
+
125
+ class UserService {
126
+ @Inject(Database) #db // truly private - not accessible from outside
127
+
128
+ getUser(id) {
129
+ return this.#db.query(`SELECT * FROM users WHERE id = ${id}`)
130
+ }
131
+ }
132
+
133
+ const service = new UserService()
134
+ service.#db // SyntaxError: Private field '#db' must be declared
135
+ ```
136
+
137
+ ### The `accessor` Keyword
138
+
139
+ The `accessor` keyword (part of the TC39 decorators proposal) creates an auto-accessor - a private backing field with
140
+ automatic getter/setter. This is particularly useful for **lazy injection with private fields**.
141
+
142
+ ```javascript
143
+ class Example {
144
+ accessor myField = 'value'
145
+ }
146
+
147
+ // Roughly equivalent to:
148
+ class Example {
149
+ #myField = 'value'
150
+ get myField() { return this.#myField }
151
+ set myField(v) { this.#myField = v }
152
+ }
153
+ ```
154
+
155
+ #### Using `accessor` with Injection
156
+
157
+ ```javascript
158
+ import {Singleton, Inject, InjectLazy} from 'decorator-dependency-injection';
159
+
160
+ @Singleton()
161
+ class ExpensiveService {
162
+ constructor() {
163
+ console.log('ExpensiveService created')
164
+ }
165
+ }
166
+
167
+ class Consumer {
168
+ // Public accessor - works with both @Inject and @InjectLazy
169
+ @Inject(ExpensiveService) accessor service
170
+
171
+ // Private accessor - recommended for lazy private injection
172
+ @InjectLazy(ExpensiveService) accessor #privateService
173
+
174
+ doWork() {
175
+ // Instance created only when first accessed
176
+ return this.#privateService.process()
177
+ }
178
+ }
179
+ ```
180
+
181
+ ### Injection Support Matrix
182
+
183
+ | Decorator | Syntax | Lazy? | Notes |
184
+ |-----------|--------|-------|-------|
185
+ | `@Inject` | `@Inject(Dep) field` | No | Standard injection |
186
+ | `@Inject` | `@Inject(Dep) #field` | No | Private field injection |
187
+ | `@Inject` | `@Inject(Dep) accessor field` | No* | Accessor injection |
188
+ | `@Inject` | `@Inject(Dep) accessor #field` | No* | Private accessor injection |
189
+ | `@Inject` | `@Inject(Dep) static field` | No | Static field injection |
190
+ | `@Inject` | `@Inject(Dep) static #field` | No | Static private field |
191
+ | `@Inject` | `@Inject(Dep) static accessor field` | No* | Static accessor |
192
+ | `@Inject` | `@Inject(Dep) static accessor #field` | No* | Static private accessor |
193
+ | `@InjectLazy` | `@InjectLazy(Dep) field` | ✅ Yes | Lazy public field |
194
+ | `@InjectLazy` | `@InjectLazy(Dep) #field` | ⚠️ No | See caveat below |
195
+ | `@InjectLazy` | `@InjectLazy(Dep) accessor field` | ✅ Yes | Lazy accessor |
196
+ | `@InjectLazy` | `@InjectLazy(Dep) accessor #field` | ✅ Yes | **Recommended for lazy private** |
197
+ | `@InjectLazy` | `@InjectLazy(Dep) static field` | ✅ Yes | Lazy static field |
198
+ | `@InjectLazy` | `@InjectLazy(Dep) static #field` | ⚠️ No | Same caveat as instance private |
199
+ | `@InjectLazy` | `@InjectLazy(Dep) static accessor #field` | ✅ Yes | Lazy static private accessor |
200
+
201
+ *`@Inject` with accessors caches on first access, which is similar to lazy behavior.
202
+
203
+ #### Caveat: `@InjectLazy` with Private Fields
204
+
205
+ Due to JavaScript limitations, `@InjectLazy` on private fields (`#field`) **cannot be truly lazy**. The instance is
206
+ created at construction time (or class definition time for static fields), not on first access. This is because
207
+ `Object.defineProperty()` cannot create getters on private fields.
208
+
209
+ This applies to both instance and static private fields.
210
+
211
+ **Recommendation:** For true lazy injection with private members, use the `accessor` keyword:
212
+
213
+ ```javascript
214
+ // ❌ Not truly lazy (created at construction)
215
+ @InjectLazy(ExpensiveService) #service
216
+
217
+ // ✅ Truly lazy (created on first access)
218
+ @InjectLazy(ExpensiveService) accessor #service
219
+
220
+ // Static fields work the same way:
221
+ // ❌ Not truly lazy (created at class definition)
222
+ @InjectLazy(ExpensiveService) static #service
223
+
224
+ // ✅ Truly lazy
225
+ @InjectLazy(ExpensiveService) static accessor #service
226
+ ```
227
+
228
+ ### Static Field Injection
229
+
230
+ All injection decorators work with static fields. Static injections are shared across all instances of the class:
231
+
232
+ ```javascript
233
+ import {Factory, Singleton, Inject} from 'decorator-dependency-injection';
234
+
235
+ @Singleton()
236
+ class SharedConfig {
237
+ apiUrl = 'https://api.example.com'
109
238
  }
239
+
240
+ @Factory()
241
+ class RequestLogger {
242
+ static nextId = 0
243
+ id = ++RequestLogger.nextId
244
+ }
245
+
246
+ class ApiService {
247
+ @Inject(SharedConfig) static config // Shared across all instances
248
+ @Inject(RequestLogger) logger // New instance per ApiService
249
+
250
+ getUrl() {
251
+ return ApiService.config.apiUrl
252
+ }
253
+ }
254
+
255
+ const a = new ApiService()
256
+ const b = new ApiService()
257
+ console.log(a.logger.id) // 1
258
+ console.log(b.logger.id) // 2
259
+ console.log(ApiService.config === ApiService.config) // true (singleton)
110
260
  ```
111
261
 
262
+ ### Additional Supported Features
263
+
264
+ The injection decorators also support:
265
+
266
+ - **Computed property names**: `@Inject(Dep) [dynamicPropertyName]`
267
+ - **Symbol property names**: `@Inject(Dep) [Symbol('key')]`
268
+ - **Inheritance**: Subclasses inherit parent class injections
269
+ - **Multiple decorators**: Combine `@Inject` with other decorators
270
+ - **Nested injection**: Singletons/Factories can have their own injected dependencies
271
+
112
272
  ## Passing parameters to a dependency
113
273
 
114
274
  You can pass parameters to a dependency by using the ```@Inject``` decorator with a function that returns the
@@ -138,9 +298,9 @@ will only be passed to the dependency the first time it is created.
138
298
  You can mock dependencies by using the ```@Mock``` decorator with a function that returns the mock dependency.
139
299
 
140
300
  ```javascript
141
- import {Factory, Inject, Mock} from 'decorator-dependency-injection'
301
+ import {Factory, Inject, Mock, resetMock} from 'decorator-dependency-injection'
142
302
 
143
- @Factory
303
+ @Factory()
144
304
  class Dependency {
145
305
  method() {
146
306
  return 'real'
@@ -177,18 +337,91 @@ The `resetMock` utility function allows you to remove any active mock for a depe
177
337
  implementation. This is useful for cleaning up after tests or switching between real and mock dependencies.
178
338
 
179
339
  ```javascript
180
- import {resetMock} from 'decorator-dependency-injection';
340
+ import {resetMock, resetMocks} from 'decorator-dependency-injection';
181
341
 
182
342
  resetMock(Dependency); // Restores the original Dependency implementation
343
+ resetMocks(); // Restores all mocked dependencies
344
+ ```
345
+
346
+ ### Clearing the Container
347
+
348
+ For complete test isolation, you can clear all registered instances from the container:
349
+
350
+ ```javascript
351
+ import {clearContainer} from 'decorator-dependency-injection';
352
+
353
+ clearContainer(); // Removes all registered singletons, factories, and mocks
354
+ ```
355
+
356
+ ### Validation Helpers
357
+
358
+ The library provides utilities to validate registrations at runtime, which is useful for catching configuration
359
+ errors early:
360
+
361
+ #### `isRegistered(clazzOrName)`
362
+
363
+ Check if a class or name is registered:
364
+
365
+ ```javascript
366
+ import {Singleton, isRegistered} from 'decorator-dependency-injection';
367
+
368
+ @Singleton()
369
+ class MyService {}
370
+
371
+ console.log(isRegistered(MyService)); // true
372
+ console.log(isRegistered('unknownName')); // false
373
+ ```
374
+
375
+ #### `validateRegistrations(...tokens)`
376
+
377
+ Validate multiple registrations at once. Throws an error with helpful details if any are missing:
378
+
379
+ ```javascript
380
+ import {validateRegistrations} from 'decorator-dependency-injection';
381
+
382
+ // At application startup - fail fast if dependencies are missing
383
+ try {
384
+ validateRegistrations(UserService, AuthService, 'databaseConnection');
385
+ } catch (err) {
386
+ // Error: Missing registrations: [UserService, databaseConnection].
387
+ // Ensure these classes are decorated with @Singleton() or @Factory() before use.
388
+ }
389
+ ```
390
+
391
+ This is particularly useful in:
392
+ - Application bootstrap to catch missing dependencies before runtime failures
393
+ - Test setup to ensure mocks are properly configured
394
+ - Module initialization to validate external dependencies
395
+
396
+ ### Debug Mode
397
+
398
+ Enable debug logging to understand the injection lifecycle:
399
+
400
+ ```javascript
401
+ import {setDebug} from 'decorator-dependency-injection';
402
+
403
+ setDebug(true);
404
+
405
+ // Now logs will appear when:
406
+ // - Classes are registered: [DI] Registered singleton: UserService
407
+ // - Instances are created: [DI] Creating singleton: UserService
408
+ // - Cached singletons are returned: [DI] Returning cached singleton: UserService
409
+ // - Mocks are registered: [DI] Mocked UserService with MockUserService
183
410
  ```
184
411
 
412
+ This is helpful for:
413
+ - Debugging injection order issues
414
+ - Understanding when instances are created (eager vs lazy)
415
+ - Troubleshooting circular dependencies
416
+ - Verifying test mocks are applied correctly
417
+
185
418
  You can also use the ```@Mock``` decorator as a proxy instead of a full mock. Any method calls not implemented in the
186
419
  mock will be passed to the real dependency.
187
420
 
188
421
  ```javascript
189
- import {Factory, Inject, Mock} from 'decorator-dependency-injection'
422
+ import {Factory, Inject, Mock, resetMock} from 'decorator-dependency-injection'
190
423
 
191
- @Factory
424
+ @Factory()
192
425
  class Dependency {
193
426
  method() {
194
427
  return 'real'
@@ -225,6 +458,62 @@ const consumer = new Consumer() // prints 'real other'
225
458
 
226
459
  For more examples, see the tests in the ```test``` directory.
227
460
 
461
+ ## Advanced Usage
462
+
463
+ ### Using Isolated Containers
464
+
465
+ For advanced scenarios like parallel test execution or module isolation, you can create separate containers:
466
+
467
+ ```javascript
468
+ import {Container} from 'decorator-dependency-injection';
469
+
470
+ const container1 = new Container();
471
+ const container2 = new Container();
472
+
473
+ class MyService {}
474
+
475
+ // Register the same class in different containers
476
+ container1.registerSingleton(MyService);
477
+ container2.registerSingleton(MyService);
478
+
479
+ // Each container maintains its own singleton instance
480
+ const ctx1 = container1.getContext(MyService);
481
+ const ctx2 = container2.getContext(MyService);
482
+
483
+ const instance1 = container1.getInstance(ctx1, []);
484
+ const instance2 = container2.getInstance(ctx2, []);
485
+
486
+ console.log(instance1 === instance2); // false - different containers
487
+ ```
488
+
489
+ ### Accessing the Default Container
490
+
491
+ You can access the default global container for programmatic registration:
492
+
493
+ ```javascript
494
+ import {getContainer} from 'decorator-dependency-injection';
495
+
496
+ const container = getContainer();
497
+ console.log(container.has(MyService)); // Check if a class is registered
498
+ ```
499
+
500
+ ## TypeScript Support
501
+
502
+ The library includes TypeScript definitions with helpful type aliases:
503
+
504
+ ```typescript
505
+ import {Constructor, InjectionToken} from 'decorator-dependency-injection';
506
+
507
+ // Constructor<T> - a class constructor that creates instances of T
508
+ const MyClass: Constructor<MyService> = MyService;
509
+
510
+ // InjectionToken<T> - either a class or a string name
511
+ const token1: InjectionToken<MyService> = MyService;
512
+ const token2: InjectionToken = 'myServiceName';
513
+ ```
514
+
515
+ All decorator functions and utilities are fully typed with generics for better autocomplete and type safety.
516
+
228
517
  ## Running the tests
229
518
 
230
519
  To run the tests, run the following command in the project root.
@@ -238,4 +527,6 @@ npm test
238
527
  - 1.0.0 - Initial release
239
528
  - 1.0.1 - Automated release with GitHub Actions
240
529
  - 1.0.2 - Added proxy option to @Mock decorator
241
- - 1.0.3 - Added @LazyInject decorator
530
+ - 1.0.3 - Added @InjectLazy decorator
531
+ - 1.0.4 - Added Container abstraction, clearContainer(), TypeScript definitions, improved proxy support
532
+ - 1.0.5 - Added private field and accessor support for @Inject and @InjectLazy, debug mode, validation helpers
@@ -0,0 +1,77 @@
1
+ import { defineConfig } from "eslint/config";
2
+ import js from "@eslint/js";
3
+ import babelParser from "@babel/eslint-parser";
4
+
5
+ export default defineConfig([
6
+ // Recommended base config
7
+ js.configs.recommended,
8
+
9
+ // Global ignores
10
+ {
11
+ ignores: ["node_modules/**", "coverage/**", "docs/**", ".history/**"]
12
+ },
13
+
14
+ // Source files configuration
15
+ {
16
+ name: "source-files",
17
+ files: ["index.js", "src/**/*.js"],
18
+ languageOptions: {
19
+ ecmaVersion: 2022,
20
+ sourceType: "module",
21
+ parser: babelParser,
22
+ parserOptions: {
23
+ requireConfigFile: true,
24
+ babelOptions: {
25
+ configFile: "./babel.config.json"
26
+ }
27
+ },
28
+ globals: {
29
+ console: "readonly",
30
+ process: "readonly"
31
+ }
32
+ },
33
+ rules: {
34
+ "no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
35
+ "prefer-const": "error",
36
+ "no-var": "error",
37
+ "eqeqeq": ["error", "always"],
38
+ "no-throw-literal": "error"
39
+ }
40
+ },
41
+
42
+ // Test files with relaxed rules and Jest globals
43
+ {
44
+ name: "test-files",
45
+ files: ["test/**/*.js"],
46
+ languageOptions: {
47
+ ecmaVersion: 2022,
48
+ sourceType: "module",
49
+ parser: babelParser,
50
+ parserOptions: {
51
+ requireConfigFile: true,
52
+ babelOptions: {
53
+ configFile: "./babel.config.json"
54
+ }
55
+ },
56
+ globals: {
57
+ console: "readonly",
58
+ process: "readonly",
59
+ describe: "readonly",
60
+ it: "readonly",
61
+ expect: "readonly",
62
+ beforeEach: "readonly",
63
+ afterEach: "readonly",
64
+ jest: "readonly",
65
+ fail: "readonly"
66
+ }
67
+ },
68
+ rules: {
69
+ // In tests, decorated classes are often "used" by the decorator system (side effects)
70
+ // rather than being referenced directly. Also allow underscore-prefixed vars.
71
+ "no-unused-vars": ["warn", {
72
+ "argsIgnorePattern": "^_",
73
+ "varsIgnorePattern": "^_|Mock|Service|Factory|Singleton|Consumer|Injection|Lazy|^[A-Z]$|^[A-Z][0-9]$"
74
+ }]
75
+ }
76
+ }
77
+ ]);
package/index.d.ts ADDED
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Type definitions for decorator-dependency-injection
3
+ */
4
+
5
+ /**
6
+ * A class constructor type.
7
+ * @template T The instance type
8
+ */
9
+ export type Constructor<T = any> = new (...args: any[]) => T
10
+
11
+ /**
12
+ * Valid injection target: either a class constructor or a string name.
13
+ */
14
+ export type InjectionToken<T = any> = string | Constructor<T>
15
+
16
+ /**
17
+ * Context for registered instances in the container
18
+ */
19
+ export interface InstanceContext {
20
+ /** The type of registration */
21
+ type: 'singleton' | 'factory'
22
+ /** The current class constructor (may be a mock) */
23
+ clazz: new (...args: any[]) => any
24
+ /** The original class constructor if mocked */
25
+ originalClazz?: new (...args: any[]) => any
26
+ /** The cached singleton instance */
27
+ instance?: any
28
+ /** Whether to use proxy mocking */
29
+ proxy?: boolean
30
+ }
31
+
32
+ /**
33
+ * A dependency injection container that manages singleton and factory instances.
34
+ */
35
+ export declare class Container {
36
+ /**
37
+ * Enable or disable debug logging.
38
+ * When enabled, logs when instances are created.
39
+ */
40
+ setDebug(enabled: boolean): void
41
+
42
+ /**
43
+ * Register a class as a singleton.
44
+ */
45
+ registerSingleton<T>(clazz: Constructor<T>, name?: string): void
46
+
47
+ /**
48
+ * Register a class as a factory.
49
+ */
50
+ registerFactory<T>(clazz: Constructor<T>, name?: string): void
51
+
52
+ /**
53
+ * Get the context for a given class or name.
54
+ * @throws Error if the class/name is not registered
55
+ */
56
+ getContext<T>(clazzOrName: InjectionToken<T>): InstanceContext
57
+
58
+ /**
59
+ * Check if a class or name is registered.
60
+ */
61
+ has<T>(clazzOrName: InjectionToken<T>): boolean
62
+
63
+ /**
64
+ * Get or create an instance based on the context.
65
+ */
66
+ getInstance<T>(instanceContext: InstanceContext, params: any[]): T
67
+
68
+ /**
69
+ * Register a mock for an existing class.
70
+ */
71
+ registerMock<T>(
72
+ targetClazzOrName: InjectionToken<T>,
73
+ mockClazz: Constructor<T>,
74
+ useProxy?: boolean
75
+ ): void
76
+
77
+ /**
78
+ * Reset a specific mock to its original class.
79
+ */
80
+ resetMock<T>(clazzOrName: InjectionToken<T>): void
81
+
82
+ /**
83
+ * Reset all mocks to their original classes.
84
+ */
85
+ resetAllMocks(): void
86
+
87
+ /**
88
+ * Clear all registered instances and mocks.
89
+ */
90
+ clear(): void
91
+ }
92
+
93
+ /**
94
+ * Register a class as a singleton.
95
+ * @param name Optional name to register the singleton under
96
+ */
97
+ export declare function Singleton(name?: string): ClassDecorator
98
+
99
+ /**
100
+ * Register a class as a factory.
101
+ * @param name Optional name to register the factory under
102
+ */
103
+ export declare function Factory(name?: string): ClassDecorator
104
+
105
+ /**
106
+ * Decorator return type that works for both fields and accessors.
107
+ * For fields, returns a function that provides the initial value.
108
+ * For accessors, returns an object with get/set/init.
109
+ */
110
+ export type FieldOrAccessorDecorator = (
111
+ target: undefined,
112
+ context: ClassFieldDecoratorContext | ClassAccessorDecoratorContext
113
+ ) => void | ((initialValue: any) => any) | ClassAccessorDecoratorResult<any, any>
114
+
115
+ /**
116
+ * Inject a singleton or factory instance into a class field or accessor.
117
+ *
118
+ * Supports:
119
+ * - Public fields: `@Inject(MyClass) myField`
120
+ * - Private fields: `@Inject(MyClass) #myField`
121
+ * - Public accessors: `@Inject(MyClass) accessor myField`
122
+ * - Private accessors: `@Inject(MyClass) accessor #myField`
123
+ *
124
+ * @param clazzOrName The class or name to inject
125
+ * @param params Optional parameters to pass to the constructor
126
+ *
127
+ * @example
128
+ * class MyService {
129
+ * @Inject(Database) db
130
+ * @Inject(Logger) #logger // private field
131
+ * @Inject(Cache) accessor cache // accessor (recommended for lazy-like behavior)
132
+ * }
133
+ */
134
+ export declare function Inject<T>(
135
+ clazzOrName: InjectionToken<T>,
136
+ ...params: any[]
137
+ ): FieldOrAccessorDecorator
138
+
139
+ /**
140
+ * Inject a singleton or factory instance lazily into a class field or accessor.
141
+ * The instance is created on first access.
142
+ *
143
+ * Supports:
144
+ * - Public fields: `@InjectLazy(MyClass) myField` (true lazy)
145
+ * - Private fields: `@InjectLazy(MyClass) #myField` (not truly lazy - use accessor instead)
146
+ * - Public accessors: `@InjectLazy(MyClass) accessor myField` (true lazy)
147
+ * - Private accessors: `@InjectLazy(MyClass) accessor #myField` (true lazy, recommended)
148
+ *
149
+ * Note: For true lazy injection with private members, use the accessor syntax:
150
+ * `@InjectLazy(MyClass) accessor #myField`
151
+ *
152
+ * @param clazzOrName The class or name to inject
153
+ * @param params Optional parameters to pass to the constructor
154
+ *
155
+ * @example
156
+ * class MyService {
157
+ * @InjectLazy(ExpensiveService) accessor #expensiveService
158
+ * }
159
+ */
160
+ export declare function InjectLazy<T>(
161
+ clazzOrName: InjectionToken<T>,
162
+ ...params: any[]
163
+ ): FieldOrAccessorDecorator
164
+
165
+ /**
166
+ * Mark a class as a mock for another class.
167
+ * @param mockedClazzOrName The class or name to mock
168
+ * @param proxy If true, unmocked methods delegate to the original
169
+ */
170
+ export declare function Mock<T>(
171
+ mockedClazzOrName: InjectionToken<T>,
172
+ proxy?: boolean
173
+ ): ClassDecorator
174
+
175
+ /**
176
+ * Reset all mocks to their original classes.
177
+ */
178
+ export declare function resetMocks(): void
179
+
180
+ /**
181
+ * Reset a specific mock to its original class.
182
+ * @param clazzOrName The class or name to reset
183
+ */
184
+ export declare function resetMock<T>(clazzOrName: InjectionToken<T>): void
185
+
186
+ /**
187
+ * Clear all registered instances and mocks from the container.
188
+ */
189
+ export declare function clearContainer(): void
190
+
191
+ /**
192
+ * Get the default container instance.
193
+ */
194
+ export declare function getContainer(): Container
195
+
196
+ /**
197
+ * Enable or disable debug logging for dependency injection.
198
+ * When enabled, logs when instances are registered, created, and mocked.
199
+ * @param enabled Whether to enable debug mode
200
+ */
201
+ export declare function setDebug(enabled: boolean): void
202
+
203
+ /**
204
+ * Check if a class or name is registered in the default container.
205
+ * Useful for validation before injection.
206
+ * @param clazzOrName The class or name to check
207
+ * @returns true if registered, false otherwise
208
+ */
209
+ export declare function isRegistered<T>(clazzOrName: InjectionToken<T>): boolean
210
+
211
+ /**
212
+ * Validate that all provided injection tokens are registered.
213
+ * Throws an error with details about missing registrations.
214
+ * Useful for fail-fast validation at application startup.
215
+ * @param tokens Array of classes or names to validate
216
+ * @throws Error if any token is not registered
217
+ */
218
+ export declare function validateRegistrations<T extends InjectionToken[]>(...tokens: T): void
219
+
220
+ /**
221
+ * Create a proxy that delegates to the mock first, then falls back to the original.
222
+ * This is an internal utility but exported for advanced use cases.
223
+ *
224
+ * @param mock The mock instance
225
+ * @param original The original instance to fall back to
226
+ */
227
+ export declare function createProxy<T extends object>(mock: T, original: T): T