@di-framework/di-framework 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +472 -0
- package/dist/container.d.ts +136 -0
- package/dist/container.js +402 -0
- package/dist/decorators.d.ts +93 -0
- package/dist/decorators.js +128 -0
- package/dist/types.d.ts +242 -0
- package/dist/types.js +140 -0
- package/package.json +50 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type Definitions and Utilities for the DI Framework
|
|
3
|
+
*
|
|
4
|
+
* Provides interfaces and utility types for building services
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Represents a service class constructor
|
|
8
|
+
*/
|
|
9
|
+
export type ServiceClass<T> = new (...args: any[]) => T;
|
|
10
|
+
/**
|
|
11
|
+
* Represents a factory function that creates a service
|
|
12
|
+
*/
|
|
13
|
+
export type ServiceFactory<T> = () => T;
|
|
14
|
+
/**
|
|
15
|
+
* Service registration options
|
|
16
|
+
*/
|
|
17
|
+
export interface InjectionOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Whether this service should be a singleton (default: true)
|
|
20
|
+
* Singleton: same instance returned for each resolution
|
|
21
|
+
* Transient: new instance created for each resolution
|
|
22
|
+
*/
|
|
23
|
+
singleton?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Service with lifecycle methods
|
|
27
|
+
*/
|
|
28
|
+
export interface ILifecycleService {
|
|
29
|
+
/**
|
|
30
|
+
* Called after the service is created
|
|
31
|
+
*/
|
|
32
|
+
onInit?(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Called before the service is destroyed
|
|
35
|
+
*/
|
|
36
|
+
onDestroy?(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Called to set environment variables
|
|
39
|
+
*/
|
|
40
|
+
setEnv?(env: Record<string, any>): void;
|
|
41
|
+
/**
|
|
42
|
+
* Called to set execution context
|
|
43
|
+
*/
|
|
44
|
+
setCtx?(context: any): void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Error thrown when DI resolution fails
|
|
48
|
+
*/
|
|
49
|
+
export declare class DIError extends Error {
|
|
50
|
+
constructor(message: string);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Error thrown when circular dependency is detected
|
|
54
|
+
*/
|
|
55
|
+
export declare class CircularDependencyError extends DIError {
|
|
56
|
+
constructor(message: string);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Error thrown when service is not registered
|
|
60
|
+
*/
|
|
61
|
+
export declare class ServiceNotFoundError extends DIError {
|
|
62
|
+
constructor(serviceName: string);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Type-safe service class identity
|
|
66
|
+
*
|
|
67
|
+
* Use this to ensure type safety when working with service classes
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* type UserServiceId = ServiceId<UserService>;
|
|
71
|
+
* const serviceId: UserServiceId = UserService;
|
|
72
|
+
*/
|
|
73
|
+
export type ServiceId<T> = ServiceClass<T>;
|
|
74
|
+
/**
|
|
75
|
+
* Utility type to extract the constructor parameters of a service
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* type UserServiceDeps = ConstructorParameters<typeof UserService>;
|
|
79
|
+
*/
|
|
80
|
+
export type ServiceDependencies<T> = T extends ServiceClass<infer U> ? ConstructorParameters<ServiceClass<U>> : never;
|
|
81
|
+
/**
|
|
82
|
+
* Utility type to make all properties of a service optional
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* @Container()
|
|
86
|
+
* class MyService implements PartialService<MyService> {
|
|
87
|
+
* optionalDependency?: SomeService;
|
|
88
|
+
* }
|
|
89
|
+
*/
|
|
90
|
+
export type PartialService<T> = Partial<T>;
|
|
91
|
+
/**
|
|
92
|
+
* Utility to create a service instance with mocked dependencies
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* const mockUserService = new MockService<UserService>({
|
|
96
|
+
* database: mockDb,
|
|
97
|
+
* logger: mockLogger
|
|
98
|
+
* });
|
|
99
|
+
*/
|
|
100
|
+
export type MockServiceOptions<T> = {
|
|
101
|
+
[K in keyof T]?: T[K];
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Represents a resolvable service in the container
|
|
105
|
+
*/
|
|
106
|
+
export type Resolvable = ServiceClass<any> | string;
|
|
107
|
+
/**
|
|
108
|
+
* Configuration for the DI container
|
|
109
|
+
*/
|
|
110
|
+
export interface ContainerConfig {
|
|
111
|
+
/**
|
|
112
|
+
* Whether to throw on unregistered services (default: true)
|
|
113
|
+
*/
|
|
114
|
+
throwOnUnregistered?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Whether to detect circular dependencies (default: true)
|
|
117
|
+
*/
|
|
118
|
+
detectCircularDependencies?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Maximum recursion depth for dependency resolution (default: 100)
|
|
121
|
+
*/
|
|
122
|
+
maxResolutionDepth?: number;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Service metadata stored in the container
|
|
126
|
+
*/
|
|
127
|
+
export interface ServiceMetadata<T = any> {
|
|
128
|
+
type: ServiceClass<T> | ServiceFactory<T>;
|
|
129
|
+
singleton: boolean;
|
|
130
|
+
instance?: T;
|
|
131
|
+
dependencies?: string[];
|
|
132
|
+
createdAt?: Date;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Result of resolving a service
|
|
136
|
+
*/
|
|
137
|
+
export interface ResolutionResult<T = any> {
|
|
138
|
+
service: T;
|
|
139
|
+
serviceClass: ServiceClass<T>;
|
|
140
|
+
isSingleton: boolean;
|
|
141
|
+
resolutionTimeMs: number;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Information about a registered service
|
|
145
|
+
*/
|
|
146
|
+
export interface ServiceInfo {
|
|
147
|
+
name: string;
|
|
148
|
+
isSingleton: boolean;
|
|
149
|
+
dependencies: string[];
|
|
150
|
+
hasInstance: boolean;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Generic service base class with lifecycle support
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* @Container()
|
|
157
|
+
* export class MyService extends BaseService {
|
|
158
|
+
* onInit() {
|
|
159
|
+
* console.log('Service initialized');
|
|
160
|
+
* }
|
|
161
|
+
* }
|
|
162
|
+
*/
|
|
163
|
+
export declare abstract class BaseService implements ILifecycleService {
|
|
164
|
+
protected logger: ILogger;
|
|
165
|
+
onInit?(): void;
|
|
166
|
+
onDestroy?(): void;
|
|
167
|
+
setEnv?(env: Record<string, any>): void;
|
|
168
|
+
setCtx?(context: any): void;
|
|
169
|
+
protected log(message: string): void;
|
|
170
|
+
protected error(message: string): void;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Logger interface for services
|
|
174
|
+
*/
|
|
175
|
+
export interface ILogger {
|
|
176
|
+
log(message: string): void;
|
|
177
|
+
error(message: string): void;
|
|
178
|
+
warn(message: string): void;
|
|
179
|
+
debug(message: string): void;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Console-based logger implementation
|
|
183
|
+
*/
|
|
184
|
+
export declare class ConsoleLogger implements ILogger {
|
|
185
|
+
log(message: string): void;
|
|
186
|
+
error(message: string): void;
|
|
187
|
+
warn(message: string): void;
|
|
188
|
+
debug(message: string): void;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Utility functions for working with services
|
|
192
|
+
*/
|
|
193
|
+
export declare namespace ServiceUtils {
|
|
194
|
+
/**
|
|
195
|
+
* Check if an object is a service class
|
|
196
|
+
*/
|
|
197
|
+
function isServiceClass(obj: any): obj is ServiceClass<any>;
|
|
198
|
+
/**
|
|
199
|
+
* Check if an object is a factory function
|
|
200
|
+
*/
|
|
201
|
+
function isFactory(obj: any): obj is ServiceFactory<any>;
|
|
202
|
+
/**
|
|
203
|
+
* Get the service name
|
|
204
|
+
*/
|
|
205
|
+
function getServiceName(service: Resolvable): string;
|
|
206
|
+
/**
|
|
207
|
+
* Create a mock service for testing
|
|
208
|
+
*/
|
|
209
|
+
function createMockService<T>(overrides?: Partial<T>): Partial<T>;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Decorator factory for creating custom decorators
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* export function Cached(ttl: number = 60000) {
|
|
216
|
+
* return function (
|
|
217
|
+
* target: any,
|
|
218
|
+
* propertyKey: string,
|
|
219
|
+
* descriptor: PropertyDescriptor
|
|
220
|
+
* ) {
|
|
221
|
+
* const originalMethod = descriptor.value;
|
|
222
|
+
* const cache = new Map<string, { data: any; time: number }>();
|
|
223
|
+
*
|
|
224
|
+
* descriptor.value = function (...args: any[]) {
|
|
225
|
+
* const key = JSON.stringify(args);
|
|
226
|
+
* const cached = cache.get(key);
|
|
227
|
+
* const now = Date.now();
|
|
228
|
+
*
|
|
229
|
+
* if (cached && now - cached.time < ttl) {
|
|
230
|
+
* return cached.data;
|
|
231
|
+
* }
|
|
232
|
+
*
|
|
233
|
+
* const result = originalMethod.apply(this, args);
|
|
234
|
+
* cache.set(key, { data: result, time: now });
|
|
235
|
+
* return result;
|
|
236
|
+
* };
|
|
237
|
+
*
|
|
238
|
+
* return descriptor;
|
|
239
|
+
* };
|
|
240
|
+
* }
|
|
241
|
+
*/
|
|
242
|
+
export declare function createDecorator<T extends (...args: any[]) => any>(decorator: T): T;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type Definitions and Utilities for the DI Framework
|
|
3
|
+
*
|
|
4
|
+
* Provides interfaces and utility types for building services
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Error thrown when DI resolution fails
|
|
8
|
+
*/
|
|
9
|
+
export class DIError extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'DIError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Error thrown when circular dependency is detected
|
|
17
|
+
*/
|
|
18
|
+
export class CircularDependencyError extends DIError {
|
|
19
|
+
constructor(message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = 'CircularDependencyError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Error thrown when service is not registered
|
|
26
|
+
*/
|
|
27
|
+
export class ServiceNotFoundError extends DIError {
|
|
28
|
+
constructor(serviceName) {
|
|
29
|
+
super(`Service '${serviceName}' is not registered in the DI container`);
|
|
30
|
+
this.name = 'ServiceNotFoundError';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generic service base class with lifecycle support
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* @Container()
|
|
38
|
+
* export class MyService extends BaseService {
|
|
39
|
+
* onInit() {
|
|
40
|
+
* console.log('Service initialized');
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
*/
|
|
44
|
+
export class BaseService {
|
|
45
|
+
logger = new ConsoleLogger();
|
|
46
|
+
log(message) {
|
|
47
|
+
this.logger.log(message);
|
|
48
|
+
}
|
|
49
|
+
error(message) {
|
|
50
|
+
this.logger.error(message);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Console-based logger implementation
|
|
55
|
+
*/
|
|
56
|
+
export class ConsoleLogger {
|
|
57
|
+
log(message) {
|
|
58
|
+
console.log(`[LOG] ${message}`);
|
|
59
|
+
}
|
|
60
|
+
error(message) {
|
|
61
|
+
console.error(`[ERROR] ${message}`);
|
|
62
|
+
}
|
|
63
|
+
warn(message) {
|
|
64
|
+
console.warn(`[WARN] ${message}`);
|
|
65
|
+
}
|
|
66
|
+
debug(message) {
|
|
67
|
+
console.debug(`[DEBUG] ${message}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Utility functions for working with services
|
|
72
|
+
*/
|
|
73
|
+
export var ServiceUtils;
|
|
74
|
+
(function (ServiceUtils) {
|
|
75
|
+
/**
|
|
76
|
+
* Check if an object is a service class
|
|
77
|
+
*/
|
|
78
|
+
function isServiceClass(obj) {
|
|
79
|
+
return typeof obj === 'function' && obj.prototype;
|
|
80
|
+
}
|
|
81
|
+
ServiceUtils.isServiceClass = isServiceClass;
|
|
82
|
+
/**
|
|
83
|
+
* Check if an object is a factory function
|
|
84
|
+
*/
|
|
85
|
+
function isFactory(obj) {
|
|
86
|
+
return typeof obj === 'function' && !isServiceClass(obj);
|
|
87
|
+
}
|
|
88
|
+
ServiceUtils.isFactory = isFactory;
|
|
89
|
+
/**
|
|
90
|
+
* Get the service name
|
|
91
|
+
*/
|
|
92
|
+
function getServiceName(service) {
|
|
93
|
+
if (typeof service === 'string') {
|
|
94
|
+
return service;
|
|
95
|
+
}
|
|
96
|
+
return service.name;
|
|
97
|
+
}
|
|
98
|
+
ServiceUtils.getServiceName = getServiceName;
|
|
99
|
+
/**
|
|
100
|
+
* Create a mock service for testing
|
|
101
|
+
*/
|
|
102
|
+
function createMockService(overrides = {}) {
|
|
103
|
+
return overrides;
|
|
104
|
+
}
|
|
105
|
+
ServiceUtils.createMockService = createMockService;
|
|
106
|
+
})(ServiceUtils || (ServiceUtils = {}));
|
|
107
|
+
/**
|
|
108
|
+
* Decorator factory for creating custom decorators
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* export function Cached(ttl: number = 60000) {
|
|
112
|
+
* return function (
|
|
113
|
+
* target: any,
|
|
114
|
+
* propertyKey: string,
|
|
115
|
+
* descriptor: PropertyDescriptor
|
|
116
|
+
* ) {
|
|
117
|
+
* const originalMethod = descriptor.value;
|
|
118
|
+
* const cache = new Map<string, { data: any; time: number }>();
|
|
119
|
+
*
|
|
120
|
+
* descriptor.value = function (...args: any[]) {
|
|
121
|
+
* const key = JSON.stringify(args);
|
|
122
|
+
* const cached = cache.get(key);
|
|
123
|
+
* const now = Date.now();
|
|
124
|
+
*
|
|
125
|
+
* if (cached && now - cached.time < ttl) {
|
|
126
|
+
* return cached.data;
|
|
127
|
+
* }
|
|
128
|
+
*
|
|
129
|
+
* const result = originalMethod.apply(this, args);
|
|
130
|
+
* cache.set(key, { data: result, time: now });
|
|
131
|
+
* return result;
|
|
132
|
+
* };
|
|
133
|
+
*
|
|
134
|
+
* return descriptor;
|
|
135
|
+
* };
|
|
136
|
+
* }
|
|
137
|
+
*/
|
|
138
|
+
export function createDecorator(decorator) {
|
|
139
|
+
return decorator;
|
|
140
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@di-framework/di-framework",
|
|
3
|
+
"version": "2.0.4",
|
|
4
|
+
"description": "Lightweight, zero-dependency TypeScript Dependency Injection framework using decorators. Works seamlessly with SWC and TypeScript's native decorator support.",
|
|
5
|
+
"main": "./dist/container.js",
|
|
6
|
+
"types": "./dist/container.d.ts",
|
|
7
|
+
"module": "./dist/container.js",
|
|
8
|
+
"author": "github.com/geoffsee",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"dependency-injection",
|
|
12
|
+
"di",
|
|
13
|
+
"ioc",
|
|
14
|
+
"inversion-of-control",
|
|
15
|
+
"decorators",
|
|
16
|
+
"typescript",
|
|
17
|
+
"swc",
|
|
18
|
+
"framework"
|
|
19
|
+
],
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": "./dist/container.js",
|
|
23
|
+
"types": "./dist/container.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"./container": "./dist/container.js",
|
|
26
|
+
"./decorators": "./dist/decorators.js",
|
|
27
|
+
"./types": "./dist/types.js"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/geoffsee/di-framework"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/geoffsee/di-framework/issues"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/geoffsee/di-framework#readme",
|
|
38
|
+
"scripts": {
|
|
39
|
+
"test": "bun test"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"typescript": "^5"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {},
|
|
45
|
+
"files": [
|
|
46
|
+
"dist",
|
|
47
|
+
"README.md",
|
|
48
|
+
"MIGRATION_GUIDE.md"
|
|
49
|
+
]
|
|
50
|
+
}
|