fragment-ts 1.0.23 → 1.0.25
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 +1 -1
- package/dist/core/container/di-container.d.ts.map +1 -1
- package/dist/core/container/di-container.js +118 -63
- package/dist/core/container/di-container.js.map +1 -1
- package/dist/core/decorators/application.decorator.d.ts +1 -6
- package/dist/core/decorators/application.decorator.d.ts.map +1 -1
- package/dist/core/decorators/application.decorator.js +2 -7
- package/dist/core/decorators/application.decorator.js.map +1 -1
- package/dist/core/decorators/auto-configuration.decorator.d.ts.map +1 -1
- package/dist/core/decorators/auto-configuration.decorator.js +5 -4
- package/dist/core/decorators/auto-configuration.decorator.js.map +1 -1
- package/dist/core/decorators/conditional.decorators.d.ts +0 -4
- package/dist/core/decorators/conditional.decorators.d.ts.map +1 -1
- package/dist/core/decorators/conditional.decorators.js +0 -32
- package/dist/core/decorators/conditional.decorators.js.map +1 -1
- package/dist/core/decorators/controller.decorator.d.ts.map +1 -1
- package/dist/core/decorators/controller.decorator.js +2 -1
- package/dist/core/decorators/controller.decorator.js.map +1 -1
- package/dist/core/decorators/http.decorators.d.ts +0 -1
- package/dist/core/decorators/http.decorators.d.ts.map +1 -1
- package/dist/core/decorators/http.decorators.js +10 -10
- package/dist/core/decorators/http.decorators.js.map +1 -1
- package/dist/core/decorators/injectable.decorator.d.ts +0 -3
- package/dist/core/decorators/injectable.decorator.d.ts.map +1 -1
- package/dist/core/decorators/injectable.decorator.js +5 -12
- package/dist/core/decorators/injectable.decorator.js.map +1 -1
- package/dist/core/decorators/injection.decorators.d.ts +37 -2
- package/dist/core/decorators/injection.decorators.d.ts.map +1 -1
- package/dist/core/decorators/injection.decorators.js +75 -43
- package/dist/core/decorators/injection.decorators.js.map +1 -1
- package/dist/core/decorators/repository.decorator.d.ts.map +1 -1
- package/dist/core/decorators/repository.decorator.js +5 -4
- package/dist/core/decorators/repository.decorator.js.map +1 -1
- package/dist/core/decorators/service.decorator.d.ts.map +1 -1
- package/dist/core/decorators/service.decorator.js +5 -4
- package/dist/core/decorators/service.decorator.js.map +1 -1
- package/dist/core/metadata/metadata-storage.d.ts +20 -9
- package/dist/core/metadata/metadata-storage.d.ts.map +1 -1
- package/dist/core/metadata/metadata-storage.js +10 -58
- package/dist/core/metadata/metadata-storage.js.map +1 -1
- package/dist/web/application.d.ts.map +1 -1
- package/dist/web/application.js +16 -7
- package/dist/web/application.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 +193 -77
- package/src/core/decorators/application.decorator.ts +3 -13
- package/src/core/decorators/auto-configuration.decorator.ts +10 -8
- package/src/core/decorators/conditional.decorators.ts +1 -37
- package/src/core/decorators/controller.decorator.ts +3 -1
- package/src/core/decorators/http.decorators.ts +32 -11
- package/src/core/decorators/injectable.decorator.ts +8 -15
- package/src/core/decorators/injection.decorators.ts +103 -50
- package/src/core/decorators/repository.decorator.ts +10 -8
- package/src/core/decorators/service.decorator.ts +10 -8
- package/src/core/metadata/metadata-storage.ts +43 -75
- package/src/web/application.ts +22 -12
|
@@ -6,7 +6,8 @@ export class DIContainer {
|
|
|
6
6
|
private singletons: Map<any, any> = new Map();
|
|
7
7
|
private transients: Map<any, any> = new Map();
|
|
8
8
|
private factories: Map<any, () => any> = new Map();
|
|
9
|
-
private constructing: Set<any> = new Set();
|
|
9
|
+
private constructing: Set<any> = new Set();
|
|
10
|
+
private registered: Set<any> = new Set(); // Track what's actually injectable
|
|
10
11
|
|
|
11
12
|
static getInstance(): DIContainer {
|
|
12
13
|
if (!DIContainer.instance) {
|
|
@@ -16,27 +17,36 @@ export class DIContainer {
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
register(token: any, instance?: any, factory?: () => any): void {
|
|
20
|
+
// Mark this token as registered
|
|
21
|
+
this.registered.add(token);
|
|
22
|
+
|
|
19
23
|
if (instance) {
|
|
20
24
|
this.singletons.set(token, instance);
|
|
21
25
|
} else if (factory) {
|
|
22
26
|
this.factories.set(token, factory);
|
|
23
27
|
}
|
|
28
|
+
// If neither instance nor factory, it will be created on-demand
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
resolve<T>(token: any): T {
|
|
27
|
-
// Check
|
|
32
|
+
// Check if this is actually an injectable class
|
|
33
|
+
if (typeof token === "function" && !this.registered.has(token)) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Cannot resolve ${token.name}: Not registered as injectable. ` +
|
|
36
|
+
`Did you forget to add @Injectable(), @Service(), @Controller(), or @Repository()?`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
28
40
|
if (this.constructing.has(token)) {
|
|
29
41
|
throw new Error(
|
|
30
42
|
`Circular dependency detected for ${token.name || token}`,
|
|
31
43
|
);
|
|
32
44
|
}
|
|
33
45
|
|
|
34
|
-
// Return existing singleton
|
|
35
46
|
if (this.singletons.has(token)) {
|
|
36
47
|
return this.singletons.get(token);
|
|
37
48
|
}
|
|
38
49
|
|
|
39
|
-
// Use factory if available
|
|
40
50
|
if (this.factories.has(token)) {
|
|
41
51
|
const factory = this.factories.get(token)!;
|
|
42
52
|
const instance = factory();
|
|
@@ -50,7 +60,6 @@ export class DIContainer {
|
|
|
50
60
|
return instance;
|
|
51
61
|
}
|
|
52
62
|
|
|
53
|
-
// Create new instance
|
|
54
63
|
if (typeof token === "function") {
|
|
55
64
|
this.constructing.add(token);
|
|
56
65
|
|
|
@@ -75,103 +84,211 @@ export class DIContainer {
|
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
private createInstance(target: any): any {
|
|
78
|
-
|
|
87
|
+
console.log(` 🔨 Creating instance of ${target.name}`);
|
|
88
|
+
|
|
79
89
|
const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
|
|
80
90
|
|
|
81
|
-
|
|
82
|
-
const params = paramTypes.map((type: any) => {
|
|
91
|
+
const params = paramTypes.map((type: any, index: number) => {
|
|
83
92
|
if (!type || type === Object) {
|
|
93
|
+
console.warn(
|
|
94
|
+
` ⚠️ Constructor param ${index} of ${target.name} has no type metadata`,
|
|
95
|
+
);
|
|
84
96
|
return undefined;
|
|
85
97
|
}
|
|
98
|
+
console.log(` 📦 Resolving constructor dependency: ${type.name}`);
|
|
86
99
|
return this.resolve(type);
|
|
87
100
|
});
|
|
88
101
|
|
|
89
|
-
// Create instance
|
|
90
102
|
const instance = new target(...params);
|
|
91
103
|
|
|
92
|
-
// Inject properties
|
|
104
|
+
// Inject properties
|
|
93
105
|
this.injectProperties(instance);
|
|
94
106
|
|
|
95
|
-
// Call post-construct
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
// Call post-construct
|
|
108
|
+
const postConstructMethod = Reflect.getMetadata(
|
|
109
|
+
METADATA_KEYS.POST_CONSTRUCT,
|
|
110
|
+
target,
|
|
111
|
+
);
|
|
112
|
+
if (
|
|
113
|
+
postConstructMethod &&
|
|
114
|
+
typeof instance[postConstructMethod] === "function"
|
|
115
|
+
) {
|
|
116
|
+
console.log(
|
|
117
|
+
` 🎯 Calling @PostConstruct: ${target.name}.${postConstructMethod}()`,
|
|
118
|
+
);
|
|
119
|
+
instance[postConstructMethod]();
|
|
98
120
|
}
|
|
99
121
|
|
|
100
122
|
return instance;
|
|
101
123
|
}
|
|
102
124
|
|
|
103
125
|
private injectProperties(instance: any): void {
|
|
104
|
-
const
|
|
126
|
+
const target = instance.constructor;
|
|
127
|
+
let currentProto = target.prototype;
|
|
128
|
+
|
|
129
|
+
// Walk the prototype chain
|
|
130
|
+
while (currentProto && currentProto !== Object.prototype) {
|
|
131
|
+
// Get all property names including inherited ones
|
|
132
|
+
const propertyNames = Object.getOwnPropertyNames(currentProto);
|
|
133
|
+
|
|
134
|
+
for (const prop of propertyNames) {
|
|
135
|
+
// Skip constructor
|
|
136
|
+
if (prop === "constructor") continue;
|
|
137
|
+
|
|
138
|
+
// Check @Autowired - stores the TYPE to inject
|
|
139
|
+
const autowiredType = Reflect.getMetadata(
|
|
140
|
+
METADATA_KEYS.AUTOWIRED,
|
|
141
|
+
currentProto,
|
|
142
|
+
prop,
|
|
143
|
+
);
|
|
105
144
|
|
|
106
|
-
|
|
107
|
-
|
|
145
|
+
if (autowiredType) {
|
|
146
|
+
console.log(
|
|
147
|
+
` 💉 @Autowired: ${target.name}.${prop} = ${autowiredType.name}`,
|
|
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
|
+
}
|
|
108
171
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
);
|
|
116
|
-
if (autowired) {
|
|
117
|
-
instance[prop] = this.resolve(autowired);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
172
|
+
// Check @Inject - stores the TOKEN to inject
|
|
173
|
+
const injectToken = Reflect.getMetadata(
|
|
174
|
+
METADATA_KEYS.INJECT,
|
|
175
|
+
currentProto,
|
|
176
|
+
prop,
|
|
177
|
+
);
|
|
120
178
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
179
|
+
if (injectToken) {
|
|
180
|
+
const tokenName =
|
|
181
|
+
typeof injectToken === "string" ? injectToken : injectToken.name;
|
|
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
|
+
}
|
|
127
205
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
206
|
+
// Check @Value
|
|
207
|
+
const valueExpression = Reflect.getMetadata(
|
|
208
|
+
METADATA_KEYS.VALUE,
|
|
209
|
+
currentProto,
|
|
210
|
+
prop,
|
|
211
|
+
);
|
|
134
212
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
instance[prop] = this.resolveRepository(repositoryEntity);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
}
|
|
213
|
+
if (valueExpression !== undefined) {
|
|
214
|
+
console.log(
|
|
215
|
+
` 🔧 @Value: ${target.name}.${prop} = ${valueExpression}`,
|
|
216
|
+
);
|
|
217
|
+
instance[prop] = this.resolveValue(valueExpression);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
147
220
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
221
|
+
// Check @InjectRepository
|
|
222
|
+
const repositoryEntity = Reflect.getMetadata(
|
|
223
|
+
METADATA_KEYS.INJECT_REPOSITORY,
|
|
224
|
+
currentProto,
|
|
225
|
+
prop,
|
|
226
|
+
);
|
|
151
227
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
228
|
+
if (repositoryEntity) {
|
|
229
|
+
console.log(
|
|
230
|
+
` 💾 @InjectRepository: ${target.name}.${prop} = Repository<${repositoryEntity.name}>`,
|
|
231
|
+
);
|
|
232
|
+
instance[prop] = this.resolveRepository(repositoryEntity);
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Check @Lazy
|
|
237
|
+
const isLazy = Reflect.getMetadata(
|
|
238
|
+
METADATA_KEYS.LAZY,
|
|
239
|
+
currentProto,
|
|
240
|
+
prop,
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
if (isLazy) {
|
|
244
|
+
const type = Reflect.getMetadata("design:type", currentProto, prop);
|
|
245
|
+
console.log(
|
|
246
|
+
` ⏳ @Lazy: ${target.name}.${prop} (will resolve on access)`,
|
|
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
|
+
}
|
|
156
269
|
|
|
157
|
-
|
|
270
|
+
currentProto = Object.getPrototypeOf(currentProto);
|
|
271
|
+
}
|
|
158
272
|
}
|
|
159
273
|
|
|
160
274
|
private resolveValue(expression: string): any {
|
|
161
|
-
|
|
162
|
-
|
|
275
|
+
const match = expression.match(
|
|
276
|
+
/\$\{([^:}]+)(?::([^}]*))?\}|\$([A-Z_][A-Z0-9_]*)/i,
|
|
277
|
+
);
|
|
163
278
|
if (match) {
|
|
164
|
-
const key = match[1] || match[
|
|
279
|
+
const key = match[1] || match[3];
|
|
280
|
+
const defaultValue = match[2];
|
|
165
281
|
const value = process.env[key];
|
|
166
282
|
|
|
167
283
|
if (value === undefined) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
284
|
+
if (defaultValue !== undefined) {
|
|
285
|
+
return defaultValue;
|
|
286
|
+
}
|
|
287
|
+
console.warn(`⚠️ Environment variable "${key}" not defined`);
|
|
171
288
|
return "";
|
|
172
289
|
}
|
|
173
290
|
|
|
174
|
-
//
|
|
291
|
+
// Parse JSON
|
|
175
292
|
if (value.startsWith("{") || value.startsWith("[")) {
|
|
176
293
|
try {
|
|
177
294
|
return JSON.parse(value);
|
|
@@ -181,8 +298,8 @@ export class DIContainer {
|
|
|
181
298
|
}
|
|
182
299
|
|
|
183
300
|
// Parse numbers
|
|
184
|
-
if (/^\d
|
|
185
|
-
return
|
|
301
|
+
if (/^\d+(\.\d+)?$/.test(value)) {
|
|
302
|
+
return parseFloat(value);
|
|
186
303
|
}
|
|
187
304
|
|
|
188
305
|
// Parse booleans
|
|
@@ -197,24 +314,23 @@ export class DIContainer {
|
|
|
197
314
|
|
|
198
315
|
private resolveRepository(entity: any): any {
|
|
199
316
|
try {
|
|
200
|
-
// Import TypeORM module dynamically to avoid circular dependencies
|
|
201
317
|
const { TypeORMModule } = require("../../typeorm/typeorm-module");
|
|
202
318
|
const dataSource = TypeORMModule.getDataSource();
|
|
319
|
+
|
|
320
|
+
if (!dataSource || !dataSource.isInitialized) {
|
|
321
|
+
throw new Error("TypeORM DataSource not initialized");
|
|
322
|
+
}
|
|
323
|
+
|
|
203
324
|
return dataSource.getRepository(entity);
|
|
204
325
|
} catch (error) {
|
|
205
326
|
throw new Error(
|
|
206
|
-
`Failed to resolve repository for
|
|
207
|
-
`Make sure TypeORM is initialized before using @InjectRepository.`,
|
|
327
|
+
`Failed to resolve repository for ${entity.name}: ${(error as Error)?.message}`,
|
|
208
328
|
);
|
|
209
329
|
}
|
|
210
330
|
}
|
|
211
331
|
|
|
212
332
|
has(token: any): boolean {
|
|
213
|
-
return (
|
|
214
|
-
this.singletons.has(token) ||
|
|
215
|
-
this.factories.has(token) ||
|
|
216
|
-
typeof token === "function"
|
|
217
|
-
);
|
|
333
|
+
return this.registered.has(token);
|
|
218
334
|
}
|
|
219
335
|
|
|
220
336
|
getAllInstances(): any[] {
|
|
@@ -226,9 +342,9 @@ export class DIContainer {
|
|
|
226
342
|
this.transients.clear();
|
|
227
343
|
this.factories.clear();
|
|
228
344
|
this.constructing.clear();
|
|
345
|
+
this.registered.clear();
|
|
229
346
|
}
|
|
230
347
|
|
|
231
|
-
// For testing purposes
|
|
232
348
|
reset(): void {
|
|
233
349
|
this.clear();
|
|
234
350
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { METADATA_KEYS } from "../metadata/metadata-keys";
|
|
2
|
-
import { MetadataStorage } from "../metadata/metadata-storage";
|
|
3
2
|
|
|
4
3
|
export interface ApplicationOptions {
|
|
5
4
|
port?: number;
|
|
@@ -9,28 +8,19 @@ export interface ApplicationOptions {
|
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
export function FragmentApplication(
|
|
12
|
-
options: {
|
|
13
|
-
port?: number;
|
|
14
|
-
host?: string;
|
|
15
|
-
configPath?: string;
|
|
16
|
-
autoScan?: boolean;
|
|
17
|
-
} = {},
|
|
11
|
+
options: ApplicationOptions = {},
|
|
18
12
|
): ClassDecorator {
|
|
19
13
|
return (target: any) => {
|
|
20
14
|
Reflect.defineMetadata(
|
|
21
15
|
METADATA_KEYS.APPLICATION,
|
|
22
16
|
{
|
|
17
|
+
...options,
|
|
23
18
|
port: options.port || 3000,
|
|
24
19
|
host: options.host || "0.0.0.0",
|
|
25
20
|
configPath: options.configPath || "fragment.json",
|
|
26
|
-
autoScan: options.autoScan
|
|
21
|
+
autoScan: options.autoScan || true,
|
|
27
22
|
},
|
|
28
23
|
target,
|
|
29
24
|
);
|
|
30
|
-
MetadataStorage.getInstance().addClass({
|
|
31
|
-
target,
|
|
32
|
-
type: "injectable",
|
|
33
|
-
scope: "singleton",
|
|
34
|
-
});
|
|
35
25
|
};
|
|
36
26
|
}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { Injectable } from
|
|
2
|
-
import { METADATA_KEYS } from
|
|
3
|
-
import { MetadataStorage } from
|
|
1
|
+
import { Injectable } from './injectable.decorator';
|
|
2
|
+
import { METADATA_KEYS } from '../metadata/metadata-keys';
|
|
3
|
+
import { MetadataStorage } from '../metadata/metadata-storage';
|
|
4
4
|
|
|
5
5
|
export function AutoConfiguration(): ClassDecorator {
|
|
6
6
|
return (target: any) => {
|
|
7
|
-
Injectable(
|
|
7
|
+
Injectable('singleton')(target);
|
|
8
8
|
Reflect.defineMetadata(METADATA_KEYS.AUTO_CONFIGURATION, true, target);
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
const storage = MetadataStorage.getInstance();
|
|
11
|
+
storage.addClass({
|
|
10
12
|
target,
|
|
11
|
-
type:
|
|
12
|
-
scope:
|
|
13
|
+
type: 'auto-configuration',
|
|
14
|
+
scope: 'singleton'
|
|
13
15
|
});
|
|
14
16
|
};
|
|
15
|
-
}
|
|
17
|
+
}
|
|
@@ -1,55 +1,19 @@
|
|
|
1
|
-
import { METADATA_KEYS } from
|
|
2
|
-
import { MetadataStorage } from "../metadata/metadata-storage";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Conditional decorators
|
|
6
|
-
* Ensures the class is registered in MetadataStorage
|
|
7
|
-
*/
|
|
1
|
+
import { METADATA_KEYS } from '../metadata/metadata-keys';
|
|
8
2
|
|
|
9
3
|
export function ConditionalOnClass(classRef: any): ClassDecorator {
|
|
10
4
|
return (target: any) => {
|
|
11
5
|
Reflect.defineMetadata(METADATA_KEYS.CONDITIONAL_ON_CLASS, classRef, target);
|
|
12
|
-
|
|
13
|
-
// Register in MetadataStorage if not already
|
|
14
|
-
const storage = MetadataStorage.getInstance();
|
|
15
|
-
if (!storage.getClass(target)) {
|
|
16
|
-
storage.addClass({
|
|
17
|
-
target,
|
|
18
|
-
type: 'injectable', // default type
|
|
19
|
-
scope: 'singleton',
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
6
|
};
|
|
23
7
|
}
|
|
24
8
|
|
|
25
9
|
export function ConditionalOnMissingBean(token: any): ClassDecorator {
|
|
26
10
|
return (target: any) => {
|
|
27
11
|
Reflect.defineMetadata(METADATA_KEYS.CONDITIONAL_ON_MISSING_BEAN, token, target);
|
|
28
|
-
|
|
29
|
-
// Register in MetadataStorage if not already
|
|
30
|
-
const storage = MetadataStorage.getInstance();
|
|
31
|
-
if (!storage.getClass(target)) {
|
|
32
|
-
storage.addClass({
|
|
33
|
-
target,
|
|
34
|
-
type: 'injectable',
|
|
35
|
-
scope: 'singleton',
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
12
|
};
|
|
39
13
|
}
|
|
40
14
|
|
|
41
15
|
export function ConditionalOnProperty(key: string, expectedValue?: any): ClassDecorator {
|
|
42
16
|
return (target: any) => {
|
|
43
17
|
Reflect.defineMetadata(METADATA_KEYS.CONDITIONAL_ON_PROPERTY, { key, expectedValue }, target);
|
|
44
|
-
|
|
45
|
-
// Register in MetadataStorage if not already
|
|
46
|
-
const storage = MetadataStorage.getInstance();
|
|
47
|
-
if (!storage.getClass(target)) {
|
|
48
|
-
storage.addClass({
|
|
49
|
-
target,
|
|
50
|
-
type: 'injectable',
|
|
51
|
-
scope: 'singleton',
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
18
|
};
|
|
55
19
|
}
|
|
@@ -6,7 +6,9 @@ export function Controller(path: string = ""): ClassDecorator {
|
|
|
6
6
|
return (target: any) => {
|
|
7
7
|
Injectable("singleton")(target);
|
|
8
8
|
Reflect.defineMetadata(METADATA_KEYS.CONTROLLER, path, target);
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
const storage = MetadataStorage.getInstance();
|
|
11
|
+
storage.addClass({
|
|
10
12
|
target,
|
|
11
13
|
type: "controller",
|
|
12
14
|
scope: "singleton",
|
|
@@ -1,20 +1,33 @@
|
|
|
1
|
-
import "reflect-metadata";
|
|
2
1
|
import { METADATA_KEYS } from "../metadata/metadata-keys";
|
|
3
2
|
import { MetadataStorage } from "../metadata/metadata-storage";
|
|
4
3
|
|
|
5
4
|
function createHttpMethodDecorator(method: string) {
|
|
6
5
|
return (path: string = ""): MethodDecorator => {
|
|
7
|
-
return (
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
return (
|
|
7
|
+
target: any,
|
|
8
|
+
propertyKey: string | symbol,
|
|
9
|
+
descriptor: PropertyDescriptor,
|
|
10
|
+
) => {
|
|
11
|
+
Reflect.defineMetadata(
|
|
12
|
+
METADATA_KEYS.HTTP_METHOD,
|
|
13
|
+
method,
|
|
14
|
+
target,
|
|
15
|
+
propertyKey,
|
|
16
|
+
);
|
|
17
|
+
Reflect.defineMetadata(
|
|
18
|
+
METADATA_KEYS.ROUTE_PATH,
|
|
19
|
+
path,
|
|
20
|
+
target,
|
|
21
|
+
propertyKey,
|
|
22
|
+
);
|
|
10
23
|
|
|
11
24
|
const storage = MetadataStorage.getInstance();
|
|
12
25
|
storage.addMethod({
|
|
13
26
|
target: target.constructor,
|
|
14
|
-
propertyKey: propertyKey
|
|
27
|
+
propertyKey: propertyKey as string,
|
|
15
28
|
method,
|
|
16
29
|
path,
|
|
17
|
-
paramMetadata: storage.getParams(target, propertyKey
|
|
30
|
+
paramMetadata: storage.getParams(target, propertyKey as string),
|
|
18
31
|
});
|
|
19
32
|
};
|
|
20
33
|
};
|
|
@@ -26,15 +39,23 @@ export const Put = createHttpMethodDecorator("PUT");
|
|
|
26
39
|
export const Delete = createHttpMethodDecorator("DELETE");
|
|
27
40
|
export const Patch = createHttpMethodDecorator("PATCH");
|
|
28
41
|
|
|
29
|
-
// Parameter decorators
|
|
30
42
|
function createParamDecorator(type: string) {
|
|
31
43
|
return (paramName?: string): ParameterDecorator => {
|
|
32
|
-
return (
|
|
33
|
-
|
|
34
|
-
|
|
44
|
+
return (
|
|
45
|
+
target: Object,
|
|
46
|
+
propertyKey: string | symbol | undefined,
|
|
47
|
+
parameterIndex: number,
|
|
48
|
+
): void => {
|
|
49
|
+
if (!propertyKey) {
|
|
50
|
+
throw new Error(`@${type}() cannot be used on constructor parameters`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const storage = MetadataStorage.getInstance();
|
|
54
|
+
|
|
55
|
+
storage.addParam({
|
|
35
56
|
target,
|
|
36
57
|
propertyKey: propertyKey.toString(),
|
|
37
|
-
index,
|
|
58
|
+
index: parameterIndex,
|
|
38
59
|
type: type as any,
|
|
39
60
|
paramName,
|
|
40
61
|
});
|
|
@@ -1,25 +1,18 @@
|
|
|
1
|
-
import { METADATA_KEYS } from
|
|
2
|
-
import { MetadataStorage } from
|
|
1
|
+
import { METADATA_KEYS } from '../metadata/metadata-keys';
|
|
2
|
+
import { MetadataStorage } from '../metadata/metadata-storage';
|
|
3
3
|
|
|
4
4
|
export type Scope = 'singleton' | 'request' | 'transient';
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* @Injectable - Marks a class as injectable with a scope
|
|
8
|
-
*/
|
|
9
6
|
export function Injectable(scope: Scope = 'singleton'): ClassDecorator {
|
|
10
7
|
return (target: any) => {
|
|
11
|
-
// Define Reflect metadata
|
|
12
8
|
Reflect.defineMetadata(METADATA_KEYS.INJECTABLE, true, target);
|
|
13
9
|
Reflect.defineMetadata(METADATA_KEYS.SCOPE, scope, target);
|
|
14
|
-
|
|
15
|
-
// Register in MetadataStorage if not already
|
|
10
|
+
|
|
16
11
|
const storage = MetadataStorage.getInstance();
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
23
|
-
}
|
|
12
|
+
storage.addClass({
|
|
13
|
+
target,
|
|
14
|
+
type: 'injectable',
|
|
15
|
+
scope
|
|
16
|
+
});
|
|
24
17
|
};
|
|
25
18
|
}
|