fragment-ts 1.0.25 → 1.0.26
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/dist/cli/commands/init.command.js +1 -1
- package/dist/core/container/di-container.d.ts +5 -0
- package/dist/core/container/di-container.d.ts.map +1 -1
- package/dist/core/container/di-container.js +100 -90
- package/dist/core/container/di-container.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/init.command.ts +1 -1
- package/src/core/container/di-container.ts +128 -165
|
@@ -10,6 +10,11 @@ export declare class DIContainer {
|
|
|
10
10
|
resolve<T>(token: any): T;
|
|
11
11
|
private createInstance;
|
|
12
12
|
private injectProperties;
|
|
13
|
+
private tryInjectAutowired;
|
|
14
|
+
private tryInjectByToken;
|
|
15
|
+
private tryInjectValue;
|
|
16
|
+
private tryInjectRepository;
|
|
17
|
+
private tryInjectLazy;
|
|
13
18
|
private resolveValue;
|
|
14
19
|
private resolveRepository;
|
|
15
20
|
has(token: any): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"di-container.d.ts","sourceRoot":"","sources":["../../../src/core/container/di-container.ts"],"names":[],"mappings":"AAGA,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAc;IACrC,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,UAAU,CAAuB;IAEzC,MAAM,CAAC,WAAW,IAAI,WAAW;IAOjC,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"di-container.d.ts","sourceRoot":"","sources":["../../../src/core/container/di-container.ts"],"names":[],"mappings":"AAGA,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAc;IACrC,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,UAAU,CAAuB;IAEzC,MAAM,CAAC,WAAW,IAAI,WAAW;IAOjC,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,GAAG,IAAI;IAU/D,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC;IAoDzB,OAAO,CAAC,cAAc;IAgCtB,OAAO,CAAC,gBAAgB;IA8BxB,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,gBAAgB;IAwBxB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,aAAa;IAyBrB,OAAO,CAAC,YAAY;IAoCpB,OAAO,CAAC,iBAAiB;IAiBzB,GAAG,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO;IAIxB,eAAe,IAAI,GAAG,EAAE;IAIxB,KAAK,IAAI,IAAI;IAQb,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -8,7 +8,7 @@ class DIContainer {
|
|
|
8
8
|
this.transients = new Map();
|
|
9
9
|
this.factories = new Map();
|
|
10
10
|
this.constructing = new Set();
|
|
11
|
-
this.registered = new Set();
|
|
11
|
+
this.registered = new Set();
|
|
12
12
|
}
|
|
13
13
|
static getInstance() {
|
|
14
14
|
if (!DIContainer.instance) {
|
|
@@ -17,7 +17,6 @@ class DIContainer {
|
|
|
17
17
|
return DIContainer.instance;
|
|
18
18
|
}
|
|
19
19
|
register(token, instance, factory) {
|
|
20
|
-
// Mark this token as registered
|
|
21
20
|
this.registered.add(token);
|
|
22
21
|
if (instance) {
|
|
23
22
|
this.singletons.set(token, instance);
|
|
@@ -25,10 +24,8 @@ class DIContainer {
|
|
|
25
24
|
else if (factory) {
|
|
26
25
|
this.factories.set(token, factory);
|
|
27
26
|
}
|
|
28
|
-
// If neither instance nor factory, it will be created on-demand
|
|
29
27
|
}
|
|
30
28
|
resolve(token) {
|
|
31
|
-
// Check if this is actually an injectable class
|
|
32
29
|
if (typeof token === "function" && !this.registered.has(token)) {
|
|
33
30
|
throw new Error(`Cannot resolve ${token.name}: Not registered as injectable. ` +
|
|
34
31
|
`Did you forget to add @Injectable(), @Service(), @Controller(), or @Repository()?`);
|
|
@@ -71,109 +68,125 @@ class DIContainer {
|
|
|
71
68
|
const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
|
|
72
69
|
const params = paramTypes.map((type, index) => {
|
|
73
70
|
if (!type || type === Object) {
|
|
74
|
-
console.warn(` ⚠️ Constructor param ${index} of ${target.name} has no type
|
|
71
|
+
console.warn(` ⚠️ Constructor param ${index} of ${target.name} has no type`);
|
|
75
72
|
return undefined;
|
|
76
73
|
}
|
|
77
74
|
console.log(` 📦 Resolving constructor dependency: ${type.name}`);
|
|
78
75
|
return this.resolve(type);
|
|
79
76
|
});
|
|
80
77
|
const instance = new target(...params);
|
|
81
|
-
// Inject properties
|
|
78
|
+
// CRITICAL: Inject properties
|
|
82
79
|
this.injectProperties(instance);
|
|
83
|
-
// Call
|
|
80
|
+
// Call @PostConstruct
|
|
84
81
|
const postConstructMethod = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.POST_CONSTRUCT, target);
|
|
85
|
-
if (postConstructMethod &&
|
|
86
|
-
typeof instance[postConstructMethod] === "function") {
|
|
82
|
+
if (postConstructMethod && typeof instance[postConstructMethod] === "function") {
|
|
87
83
|
console.log(` 🎯 Calling @PostConstruct: ${target.name}.${postConstructMethod}()`);
|
|
88
84
|
instance[postConstructMethod]();
|
|
89
85
|
}
|
|
90
86
|
return instance;
|
|
91
87
|
}
|
|
92
88
|
injectProperties(instance) {
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
//
|
|
89
|
+
const constructor = instance.constructor;
|
|
90
|
+
console.log(` 🔍 Checking properties for injection on ${constructor.name}`);
|
|
91
|
+
// Start from the instance's direct prototype
|
|
92
|
+
let currentProto = constructor.prototype;
|
|
93
|
+
// Walk up the prototype chain
|
|
96
94
|
while (currentProto && currentProto !== Object.prototype) {
|
|
97
|
-
// Get
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
// Get own property names (not inherited)
|
|
96
|
+
const ownProps = Object.getOwnPropertyNames(currentProto);
|
|
97
|
+
console.log(` 📋 Prototype ${currentProto.constructor?.name || 'Unknown'} has properties: ${ownProps.filter(p => p !== 'constructor').join(', ') || 'none'}`);
|
|
98
|
+
for (const prop of ownProps) {
|
|
101
99
|
if (prop === "constructor")
|
|
102
100
|
continue;
|
|
103
|
-
// Check
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
instance[prop] = this.resolve(autowiredType);
|
|
110
|
-
}
|
|
111
|
-
catch (error) {
|
|
112
|
-
if (!isOptional) {
|
|
113
|
-
throw new Error(`Failed to autowire ${autowiredType.name} into ${target.name}.${prop}: ${error}`);
|
|
114
|
-
}
|
|
115
|
-
console.warn(` ⚠️ Optional autowired dependency ${autowiredType.name} not available`);
|
|
116
|
-
instance[prop] = undefined;
|
|
117
|
-
}
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
// Check @Inject - stores the TOKEN to inject
|
|
121
|
-
const injectToken = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.INJECT, currentProto, prop);
|
|
122
|
-
if (injectToken) {
|
|
123
|
-
const tokenName = typeof injectToken === "string" ? injectToken : injectToken.name;
|
|
124
|
-
console.log(` 💉 @Inject: ${target.name}.${prop} = ${tokenName}`);
|
|
125
|
-
const isOptional = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.OPTIONAL, currentProto, prop);
|
|
126
|
-
try {
|
|
127
|
-
instance[prop] = this.resolve(injectToken);
|
|
128
|
-
}
|
|
129
|
-
catch (error) {
|
|
130
|
-
if (!isOptional) {
|
|
131
|
-
throw new Error(`Failed to inject ${tokenName} into ${target.name}.${prop}: ${error}`);
|
|
132
|
-
}
|
|
133
|
-
console.warn(` ⚠️ Optional inject dependency ${tokenName} not available`);
|
|
134
|
-
instance[prop] = undefined;
|
|
135
|
-
}
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
// Check @Value
|
|
139
|
-
const valueExpression = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.VALUE, currentProto, prop);
|
|
140
|
-
if (valueExpression !== undefined) {
|
|
141
|
-
console.log(` 🔧 @Value: ${target.name}.${prop} = ${valueExpression}`);
|
|
142
|
-
instance[prop] = this.resolveValue(valueExpression);
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
// Check @InjectRepository
|
|
146
|
-
const repositoryEntity = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.INJECT_REPOSITORY, currentProto, prop);
|
|
147
|
-
if (repositoryEntity) {
|
|
148
|
-
console.log(` 💾 @InjectRepository: ${target.name}.${prop} = Repository<${repositoryEntity.name}>`);
|
|
149
|
-
instance[prop] = this.resolveRepository(repositoryEntity);
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
// Check @Lazy
|
|
153
|
-
const isLazy = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.LAZY, currentProto, prop);
|
|
154
|
-
if (isLazy) {
|
|
155
|
-
const type = Reflect.getMetadata("design:type", currentProto, prop);
|
|
156
|
-
console.log(` ⏳ @Lazy: ${target.name}.${prop} (will resolve on access)`);
|
|
157
|
-
let cached = null;
|
|
158
|
-
let resolved = false;
|
|
159
|
-
Object.defineProperty(instance, prop, {
|
|
160
|
-
get: () => {
|
|
161
|
-
if (!resolved) {
|
|
162
|
-
console.log(` 🔓 Lazy-loading ${type.name} for ${target.name}.${prop}`);
|
|
163
|
-
cached = this.resolve(type);
|
|
164
|
-
resolved = true;
|
|
165
|
-
}
|
|
166
|
-
return cached;
|
|
167
|
-
},
|
|
168
|
-
enumerable: true,
|
|
169
|
-
configurable: true,
|
|
170
|
-
});
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
101
|
+
// Check each injection type
|
|
102
|
+
this.tryInjectAutowired(instance, currentProto, prop, constructor.name);
|
|
103
|
+
this.tryInjectByToken(instance, currentProto, prop, constructor.name);
|
|
104
|
+
this.tryInjectValue(instance, currentProto, prop, constructor.name);
|
|
105
|
+
this.tryInjectRepository(instance, currentProto, prop, constructor.name);
|
|
106
|
+
this.tryInjectLazy(instance, currentProto, prop, constructor.name);
|
|
173
107
|
}
|
|
174
108
|
currentProto = Object.getPrototypeOf(currentProto);
|
|
175
109
|
}
|
|
176
110
|
}
|
|
111
|
+
tryInjectAutowired(instance, proto, prop, className) {
|
|
112
|
+
const type = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.AUTOWIRED, proto, prop);
|
|
113
|
+
if (!type)
|
|
114
|
+
return;
|
|
115
|
+
console.log(` 💉 @Autowired found: ${className}.${prop} -> ${type.name}`);
|
|
116
|
+
const isOptional = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.OPTIONAL, proto, prop);
|
|
117
|
+
try {
|
|
118
|
+
instance[prop] = this.resolve(type);
|
|
119
|
+
console.log(` ✅ Injected ${type.name} into ${className}.${prop}`);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
if (!isOptional) {
|
|
123
|
+
throw new Error(`Failed to autowire ${type.name} into ${className}.${prop}: ${error}`);
|
|
124
|
+
}
|
|
125
|
+
console.warn(` ⚠️ Optional dependency ${type.name} not available for ${className}.${prop}`);
|
|
126
|
+
instance[prop] = undefined;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
tryInjectByToken(instance, proto, prop, className) {
|
|
130
|
+
const token = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.INJECT, proto, prop);
|
|
131
|
+
if (!token)
|
|
132
|
+
return;
|
|
133
|
+
const tokenName = typeof token === 'string' ? token : token.name;
|
|
134
|
+
console.log(` 💉 @Inject found: ${className}.${prop} -> ${tokenName}`);
|
|
135
|
+
const isOptional = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.OPTIONAL, proto, prop);
|
|
136
|
+
try {
|
|
137
|
+
instance[prop] = this.resolve(token);
|
|
138
|
+
console.log(` ✅ Injected ${tokenName} into ${className}.${prop}`);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (!isOptional) {
|
|
142
|
+
throw new Error(`Failed to inject ${tokenName} into ${className}.${prop}: ${error}`);
|
|
143
|
+
}
|
|
144
|
+
console.warn(` ⚠️ Optional dependency ${tokenName} not available for ${className}.${prop}`);
|
|
145
|
+
instance[prop] = undefined;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
tryInjectValue(instance, proto, prop, className) {
|
|
149
|
+
const expression = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.VALUE, proto, prop);
|
|
150
|
+
if (expression === undefined)
|
|
151
|
+
return;
|
|
152
|
+
console.log(` 🔧 @Value found: ${className}.${prop} = ${expression}`);
|
|
153
|
+
instance[prop] = this.resolveValue(expression);
|
|
154
|
+
console.log(` ✅ Set value for ${className}.${prop}`);
|
|
155
|
+
}
|
|
156
|
+
tryInjectRepository(instance, proto, prop, className) {
|
|
157
|
+
const entity = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.INJECT_REPOSITORY, proto, prop);
|
|
158
|
+
if (!entity)
|
|
159
|
+
return;
|
|
160
|
+
console.log(` 💾 @InjectRepository found: ${className}.${prop} -> Repository<${entity.name}>`);
|
|
161
|
+
try {
|
|
162
|
+
instance[prop] = this.resolveRepository(entity);
|
|
163
|
+
console.log(` ✅ Injected Repository<${entity.name}> into ${className}.${prop}`);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
throw new Error(`Failed to inject repository for ${entity.name} into ${className}.${prop}: ${error}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
tryInjectLazy(instance, proto, prop, className) {
|
|
170
|
+
const isLazy = Reflect.getMetadata(metadata_keys_1.METADATA_KEYS.LAZY, proto, prop);
|
|
171
|
+
if (!isLazy)
|
|
172
|
+
return;
|
|
173
|
+
const type = Reflect.getMetadata("design:type", proto, prop);
|
|
174
|
+
console.log(` ⏳ @Lazy found: ${className}.${prop} (${type?.name || 'unknown'})`);
|
|
175
|
+
let cached = null;
|
|
176
|
+
let resolved = false;
|
|
177
|
+
Object.defineProperty(instance, prop, {
|
|
178
|
+
get: () => {
|
|
179
|
+
if (!resolved) {
|
|
180
|
+
console.log(` 🔓 Lazy-loading ${type.name} for ${className}.${prop}`);
|
|
181
|
+
cached = this.resolve(type);
|
|
182
|
+
resolved = true;
|
|
183
|
+
}
|
|
184
|
+
return cached;
|
|
185
|
+
},
|
|
186
|
+
enumerable: true,
|
|
187
|
+
configurable: true,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
177
190
|
resolveValue(expression) {
|
|
178
191
|
const match = expression.match(/\$\{([^:}]+)(?::([^}]*))?\}|\$([A-Z_][A-Z0-9_]*)/i);
|
|
179
192
|
if (match) {
|
|
@@ -184,10 +197,9 @@ class DIContainer {
|
|
|
184
197
|
if (defaultValue !== undefined) {
|
|
185
198
|
return defaultValue;
|
|
186
199
|
}
|
|
187
|
-
console.warn(
|
|
200
|
+
console.warn(` ⚠️ Environment variable "${key}" not defined`);
|
|
188
201
|
return "";
|
|
189
202
|
}
|
|
190
|
-
// Parse JSON
|
|
191
203
|
if (value.startsWith("{") || value.startsWith("[")) {
|
|
192
204
|
try {
|
|
193
205
|
return JSON.parse(value);
|
|
@@ -196,11 +208,9 @@ class DIContainer {
|
|
|
196
208
|
return value;
|
|
197
209
|
}
|
|
198
210
|
}
|
|
199
|
-
// Parse numbers
|
|
200
211
|
if (/^\d+(\.\d+)?$/.test(value)) {
|
|
201
212
|
return parseFloat(value);
|
|
202
213
|
}
|
|
203
|
-
// Parse booleans
|
|
204
214
|
if (value.toLowerCase() === "true")
|
|
205
215
|
return true;
|
|
206
216
|
if (value.toLowerCase() === "false")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"di-container.js","sourceRoot":"","sources":["../../../src/core/container/di-container.ts"],"names":[],"mappings":";;;AAAA,6DAA0D;AAG1D,MAAa,WAAW;IAAxB;QAEU,eAAU,GAAkB,IAAI,GAAG,EAAE,CAAC;QACtC,eAAU,GAAkB,IAAI,GAAG,EAAE,CAAC;QACtC,cAAS,GAAwB,IAAI,GAAG,EAAE,CAAC;QAC3C,iBAAY,GAAa,IAAI,GAAG,EAAE,CAAC;QACnC,eAAU,GAAa,IAAI,GAAG,EAAE,CAAC
|
|
1
|
+
{"version":3,"file":"di-container.js","sourceRoot":"","sources":["../../../src/core/container/di-container.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@ export class DIContainer {
|
|
|
7
7
|
private transients: Map<any, any> = new Map();
|
|
8
8
|
private factories: Map<any, () => any> = new Map();
|
|
9
9
|
private constructing: Set<any> = new Set();
|
|
10
|
-
private registered: Set<any> = new Set();
|
|
10
|
+
private registered: Set<any> = new Set();
|
|
11
11
|
|
|
12
12
|
static getInstance(): DIContainer {
|
|
13
13
|
if (!DIContainer.instance) {
|
|
@@ -17,29 +17,26 @@ export class DIContainer {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
register(token: any, instance?: any, factory?: () => any): void {
|
|
20
|
-
// Mark this token as registered
|
|
21
20
|
this.registered.add(token);
|
|
22
|
-
|
|
21
|
+
|
|
23
22
|
if (instance) {
|
|
24
23
|
this.singletons.set(token, instance);
|
|
25
24
|
} else if (factory) {
|
|
26
25
|
this.factories.set(token, factory);
|
|
27
26
|
}
|
|
28
|
-
// If neither instance nor factory, it will be created on-demand
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
resolve<T>(token: any): T {
|
|
32
|
-
// Check if this is actually an injectable class
|
|
33
30
|
if (typeof token === "function" && !this.registered.has(token)) {
|
|
34
31
|
throw new Error(
|
|
35
32
|
`Cannot resolve ${token.name}: Not registered as injectable. ` +
|
|
36
|
-
|
|
33
|
+
`Did you forget to add @Injectable(), @Service(), @Controller(), or @Repository()?`
|
|
37
34
|
);
|
|
38
35
|
}
|
|
39
36
|
|
|
40
37
|
if (this.constructing.has(token)) {
|
|
41
38
|
throw new Error(
|
|
42
|
-
`Circular dependency detected for ${token.name || token}
|
|
39
|
+
`Circular dependency detected for ${token.name || token}`
|
|
43
40
|
);
|
|
44
41
|
}
|
|
45
42
|
|
|
@@ -50,8 +47,7 @@ export class DIContainer {
|
|
|
50
47
|
if (this.factories.has(token)) {
|
|
51
48
|
const factory = this.factories.get(token)!;
|
|
52
49
|
const instance = factory();
|
|
53
|
-
const scope =
|
|
54
|
-
Reflect.getMetadata(METADATA_KEYS.SCOPE, token) || "singleton";
|
|
50
|
+
const scope = Reflect.getMetadata(METADATA_KEYS.SCOPE, token) || "singleton";
|
|
55
51
|
|
|
56
52
|
if (scope === "singleton") {
|
|
57
53
|
this.singletons.set(token, instance);
|
|
@@ -65,8 +61,7 @@ export class DIContainer {
|
|
|
65
61
|
|
|
66
62
|
try {
|
|
67
63
|
const instance = this.createInstance(token);
|
|
68
|
-
const scope =
|
|
69
|
-
Reflect.getMetadata(METADATA_KEYS.SCOPE, token) || "singleton";
|
|
64
|
+
const scope = Reflect.getMetadata(METADATA_KEYS.SCOPE, token) || "singleton";
|
|
70
65
|
|
|
71
66
|
if (scope === "singleton") {
|
|
72
67
|
this.singletons.set(token, instance);
|
|
@@ -85,14 +80,12 @@ export class DIContainer {
|
|
|
85
80
|
|
|
86
81
|
private createInstance(target: any): any {
|
|
87
82
|
console.log(` 🔨 Creating instance of ${target.name}`);
|
|
88
|
-
|
|
83
|
+
|
|
89
84
|
const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
|
|
90
85
|
|
|
91
86
|
const params = paramTypes.map((type: any, index: number) => {
|
|
92
87
|
if (!type || type === Object) {
|
|
93
|
-
console.warn(
|
|
94
|
-
` ⚠️ Constructor param ${index} of ${target.name} has no type metadata`,
|
|
95
|
-
);
|
|
88
|
+
console.warn(` ⚠️ Constructor param ${index} of ${target.name} has no type`);
|
|
96
89
|
return undefined;
|
|
97
90
|
}
|
|
98
91
|
console.log(` 📦 Resolving constructor dependency: ${type.name}`);
|
|
@@ -101,21 +94,16 @@ export class DIContainer {
|
|
|
101
94
|
|
|
102
95
|
const instance = new target(...params);
|
|
103
96
|
|
|
104
|
-
// Inject properties
|
|
97
|
+
// CRITICAL: Inject properties
|
|
105
98
|
this.injectProperties(instance);
|
|
106
99
|
|
|
107
|
-
// Call
|
|
100
|
+
// Call @PostConstruct
|
|
108
101
|
const postConstructMethod = Reflect.getMetadata(
|
|
109
102
|
METADATA_KEYS.POST_CONSTRUCT,
|
|
110
|
-
target
|
|
103
|
+
target
|
|
111
104
|
);
|
|
112
|
-
if (
|
|
113
|
-
postConstructMethod
|
|
114
|
-
typeof instance[postConstructMethod] === "function"
|
|
115
|
-
) {
|
|
116
|
-
console.log(
|
|
117
|
-
` 🎯 Calling @PostConstruct: ${target.name}.${postConstructMethod}()`,
|
|
118
|
-
);
|
|
105
|
+
if (postConstructMethod && typeof instance[postConstructMethod] === "function") {
|
|
106
|
+
console.log(` 🎯 Calling @PostConstruct: ${target.name}.${postConstructMethod}()`);
|
|
119
107
|
instance[postConstructMethod]();
|
|
120
108
|
}
|
|
121
109
|
|
|
@@ -123,158 +111,136 @@ export class DIContainer {
|
|
|
123
111
|
}
|
|
124
112
|
|
|
125
113
|
private injectProperties(instance: any): void {
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
114
|
+
const constructor = instance.constructor;
|
|
115
|
+
|
|
116
|
+
console.log(` 🔍 Checking properties for injection on ${constructor.name}`);
|
|
117
|
+
|
|
118
|
+
// Start from the instance's direct prototype
|
|
119
|
+
let currentProto = constructor.prototype;
|
|
120
|
+
|
|
121
|
+
// Walk up the prototype chain
|
|
130
122
|
while (currentProto && currentProto !== Object.prototype) {
|
|
131
|
-
// Get
|
|
132
|
-
const
|
|
123
|
+
// Get own property names (not inherited)
|
|
124
|
+
const ownProps = Object.getOwnPropertyNames(currentProto);
|
|
125
|
+
|
|
126
|
+
console.log(` 📋 Prototype ${currentProto.constructor?.name || 'Unknown'} has properties: ${ownProps.filter(p => p !== 'constructor').join(', ') || 'none'}`);
|
|
133
127
|
|
|
134
|
-
for (const prop of
|
|
135
|
-
// Skip constructor
|
|
128
|
+
for (const prop of ownProps) {
|
|
136
129
|
if (prop === "constructor") continue;
|
|
137
130
|
|
|
138
|
-
// Check
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
);
|
|
131
|
+
// Check each injection type
|
|
132
|
+
this.tryInjectAutowired(instance, currentProto, prop, constructor.name);
|
|
133
|
+
this.tryInjectByToken(instance, currentProto, prop, constructor.name);
|
|
134
|
+
this.tryInjectValue(instance, currentProto, prop, constructor.name);
|
|
135
|
+
this.tryInjectRepository(instance, currentProto, prop, constructor.name);
|
|
136
|
+
this.tryInjectLazy(instance, currentProto, prop, constructor.name);
|
|
137
|
+
}
|
|
144
138
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
const isOptional = Reflect.getMetadata(
|
|
151
|
-
METADATA_KEYS.OPTIONAL,
|
|
152
|
-
currentProto,
|
|
153
|
-
prop,
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
try {
|
|
157
|
-
instance[prop] = this.resolve(autowiredType);
|
|
158
|
-
} catch (error) {
|
|
159
|
-
if (!isOptional) {
|
|
160
|
-
throw new Error(
|
|
161
|
-
`Failed to autowire ${autowiredType.name} into ${target.name}.${prop}: ${error}`,
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
console.warn(
|
|
165
|
-
` ⚠️ Optional autowired dependency ${autowiredType.name} not available`,
|
|
166
|
-
);
|
|
167
|
-
instance[prop] = undefined;
|
|
168
|
-
}
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
139
|
+
currentProto = Object.getPrototypeOf(currentProto);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
171
142
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
prop,
|
|
177
|
-
);
|
|
143
|
+
private tryInjectAutowired(instance: any, proto: any, prop: string, className: string): void {
|
|
144
|
+
const type = Reflect.getMetadata(METADATA_KEYS.AUTOWIRED, proto, prop);
|
|
145
|
+
|
|
146
|
+
if (!type) return;
|
|
178
147
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
console.log(` 💉 @Inject: ${target.name}.${prop} = ${tokenName}`);
|
|
183
|
-
|
|
184
|
-
const isOptional = Reflect.getMetadata(
|
|
185
|
-
METADATA_KEYS.OPTIONAL,
|
|
186
|
-
currentProto,
|
|
187
|
-
prop,
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
try {
|
|
191
|
-
instance[prop] = this.resolve(injectToken);
|
|
192
|
-
} catch (error) {
|
|
193
|
-
if (!isOptional) {
|
|
194
|
-
throw new Error(
|
|
195
|
-
`Failed to inject ${tokenName} into ${target.name}.${prop}: ${error}`,
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
console.warn(
|
|
199
|
-
` ⚠️ Optional inject dependency ${tokenName} not available`,
|
|
200
|
-
);
|
|
201
|
-
instance[prop] = undefined;
|
|
202
|
-
}
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
148
|
+
console.log(` 💉 @Autowired found: ${className}.${prop} -> ${type.name}`);
|
|
149
|
+
|
|
150
|
+
const isOptional = Reflect.getMetadata(METADATA_KEYS.OPTIONAL, proto, prop);
|
|
205
151
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
152
|
+
try {
|
|
153
|
+
instance[prop] = this.resolve(type);
|
|
154
|
+
console.log(` ✅ Injected ${type.name} into ${className}.${prop}`);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (!isOptional) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
`Failed to autowire ${type.name} into ${className}.${prop}: ${error}`
|
|
211
159
|
);
|
|
160
|
+
}
|
|
161
|
+
console.warn(` ⚠️ Optional dependency ${type.name} not available for ${className}.${prop}`);
|
|
162
|
+
instance[prop] = undefined;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
212
165
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
instance[prop] = this.resolveValue(valueExpression);
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
166
|
+
private tryInjectByToken(instance: any, proto: any, prop: string, className: string): void {
|
|
167
|
+
const token = Reflect.getMetadata(METADATA_KEYS.INJECT, proto, prop);
|
|
168
|
+
|
|
169
|
+
if (!token) return;
|
|
220
170
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
171
|
+
const tokenName = typeof token === 'string' ? token : token.name;
|
|
172
|
+
console.log(` 💉 @Inject found: ${className}.${prop} -> ${tokenName}`);
|
|
173
|
+
|
|
174
|
+
const isOptional = Reflect.getMetadata(METADATA_KEYS.OPTIONAL, proto, prop);
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
instance[prop] = this.resolve(token);
|
|
178
|
+
console.log(` ✅ Injected ${tokenName} into ${className}.${prop}`);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
if (!isOptional) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
`Failed to inject ${tokenName} into ${className}.${prop}: ${error}`
|
|
226
183
|
);
|
|
184
|
+
}
|
|
185
|
+
console.warn(` ⚠️ Optional dependency ${tokenName} not available for ${className}.${prop}`);
|
|
186
|
+
instance[prop] = undefined;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
227
189
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
instance[prop] = this.resolveRepository(repositoryEntity);
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
190
|
+
private tryInjectValue(instance: any, proto: any, prop: string, className: string): void {
|
|
191
|
+
const expression = Reflect.getMetadata(METADATA_KEYS.VALUE, proto, prop);
|
|
192
|
+
|
|
193
|
+
if (expression === undefined) return;
|
|
235
194
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
prop,
|
|
241
|
-
);
|
|
195
|
+
console.log(` 🔧 @Value found: ${className}.${prop} = ${expression}`);
|
|
196
|
+
instance[prop] = this.resolveValue(expression);
|
|
197
|
+
console.log(` ✅ Set value for ${className}.${prop}`);
|
|
198
|
+
}
|
|
242
199
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
let cached: any = null;
|
|
250
|
-
let resolved = false;
|
|
251
|
-
|
|
252
|
-
Object.defineProperty(instance, prop, {
|
|
253
|
-
get: () => {
|
|
254
|
-
if (!resolved) {
|
|
255
|
-
console.log(
|
|
256
|
-
` 🔓 Lazy-loading ${type.name} for ${target.name}.${prop}`,
|
|
257
|
-
);
|
|
258
|
-
cached = this.resolve(type);
|
|
259
|
-
resolved = true;
|
|
260
|
-
}
|
|
261
|
-
return cached;
|
|
262
|
-
},
|
|
263
|
-
enumerable: true,
|
|
264
|
-
configurable: true,
|
|
265
|
-
});
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
200
|
+
private tryInjectRepository(instance: any, proto: any, prop: string, className: string): void {
|
|
201
|
+
const entity = Reflect.getMetadata(METADATA_KEYS.INJECT_REPOSITORY, proto, prop);
|
|
202
|
+
|
|
203
|
+
if (!entity) return;
|
|
269
204
|
|
|
270
|
-
|
|
205
|
+
console.log(` 💾 @InjectRepository found: ${className}.${prop} -> Repository<${entity.name}>`);
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
instance[prop] = this.resolveRepository(entity);
|
|
209
|
+
console.log(` ✅ Injected Repository<${entity.name}> into ${className}.${prop}`);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
`Failed to inject repository for ${entity.name} into ${className}.${prop}: ${error}`
|
|
213
|
+
);
|
|
271
214
|
}
|
|
272
215
|
}
|
|
273
216
|
|
|
217
|
+
private tryInjectLazy(instance: any, proto: any, prop: string, className: string): void {
|
|
218
|
+
const isLazy = Reflect.getMetadata(METADATA_KEYS.LAZY, proto, prop);
|
|
219
|
+
|
|
220
|
+
if (!isLazy) return;
|
|
221
|
+
|
|
222
|
+
const type = Reflect.getMetadata("design:type", proto, prop);
|
|
223
|
+
console.log(` ⏳ @Lazy found: ${className}.${prop} (${type?.name || 'unknown'})`);
|
|
224
|
+
|
|
225
|
+
let cached: any = null;
|
|
226
|
+
let resolved = false;
|
|
227
|
+
|
|
228
|
+
Object.defineProperty(instance, prop, {
|
|
229
|
+
get: () => {
|
|
230
|
+
if (!resolved) {
|
|
231
|
+
console.log(` 🔓 Lazy-loading ${type.name} for ${className}.${prop}`);
|
|
232
|
+
cached = this.resolve(type);
|
|
233
|
+
resolved = true;
|
|
234
|
+
}
|
|
235
|
+
return cached;
|
|
236
|
+
},
|
|
237
|
+
enumerable: true,
|
|
238
|
+
configurable: true,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
274
242
|
private resolveValue(expression: string): any {
|
|
275
|
-
const match = expression.match(
|
|
276
|
-
/\$\{([^:}]+)(?::([^}]*))?\}|\$([A-Z_][A-Z0-9_]*)/i,
|
|
277
|
-
);
|
|
243
|
+
const match = expression.match(/\$\{([^:}]+)(?::([^}]*))?\}|\$([A-Z_][A-Z0-9_]*)/i);
|
|
278
244
|
if (match) {
|
|
279
245
|
const key = match[1] || match[3];
|
|
280
246
|
const defaultValue = match[2];
|
|
@@ -284,11 +250,10 @@ export class DIContainer {
|
|
|
284
250
|
if (defaultValue !== undefined) {
|
|
285
251
|
return defaultValue;
|
|
286
252
|
}
|
|
287
|
-
console.warn(
|
|
253
|
+
console.warn(` ⚠️ Environment variable "${key}" not defined`);
|
|
288
254
|
return "";
|
|
289
255
|
}
|
|
290
256
|
|
|
291
|
-
// Parse JSON
|
|
292
257
|
if (value.startsWith("{") || value.startsWith("[")) {
|
|
293
258
|
try {
|
|
294
259
|
return JSON.parse(value);
|
|
@@ -297,12 +262,10 @@ export class DIContainer {
|
|
|
297
262
|
}
|
|
298
263
|
}
|
|
299
264
|
|
|
300
|
-
// Parse numbers
|
|
301
265
|
if (/^\d+(\.\d+)?$/.test(value)) {
|
|
302
266
|
return parseFloat(value);
|
|
303
267
|
}
|
|
304
268
|
|
|
305
|
-
// Parse booleans
|
|
306
269
|
if (value.toLowerCase() === "true") return true;
|
|
307
270
|
if (value.toLowerCase() === "false") return false;
|
|
308
271
|
|
|
@@ -316,15 +279,15 @@ export class DIContainer {
|
|
|
316
279
|
try {
|
|
317
280
|
const { TypeORMModule } = require("../../typeorm/typeorm-module");
|
|
318
281
|
const dataSource = TypeORMModule.getDataSource();
|
|
319
|
-
|
|
282
|
+
|
|
320
283
|
if (!dataSource || !dataSource.isInitialized) {
|
|
321
284
|
throw new Error("TypeORM DataSource not initialized");
|
|
322
285
|
}
|
|
323
|
-
|
|
286
|
+
|
|
324
287
|
return dataSource.getRepository(entity);
|
|
325
288
|
} catch (error) {
|
|
326
289
|
throw new Error(
|
|
327
|
-
`Failed to resolve repository for ${entity.name}: ${(error as Error)?.message}
|
|
290
|
+
`Failed to resolve repository for ${entity.name}: ${(error as Error)?.message}`
|
|
328
291
|
);
|
|
329
292
|
}
|
|
330
293
|
}
|
|
@@ -348,4 +311,4 @@ export class DIContainer {
|
|
|
348
311
|
reset(): void {
|
|
349
312
|
this.clear();
|
|
350
313
|
}
|
|
351
|
-
}
|
|
314
|
+
}
|