fragment-ts 1.0.21 → 1.0.23
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.d.ts +1 -0
- package/dist/cli/commands/init.command.d.ts.map +1 -1
- package/dist/cli/commands/init.command.js +56 -30
- package/dist/cli/commands/init.command.js.map +1 -1
- package/dist/core/decorators/application.decorator.d.ts +6 -1
- package/dist/core/decorators/application.decorator.d.ts.map +1 -1
- package/dist/core/decorators/application.decorator.js +7 -2
- 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 +4 -5
- package/dist/core/decorators/auto-configuration.decorator.js.map +1 -1
- package/dist/core/decorators/conditional.decorators.d.ts +4 -0
- package/dist/core/decorators/conditional.decorators.d.ts.map +1 -1
- package/dist/core/decorators/conditional.decorators.js +32 -0
- 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 +1 -2
- package/dist/core/decorators/controller.decorator.js.map +1 -1
- package/dist/core/decorators/http.decorators.d.ts +1 -0
- 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 +3 -0
- package/dist/core/decorators/injectable.decorator.d.ts.map +1 -1
- package/dist/core/decorators/injectable.decorator.js +12 -5
- package/dist/core/decorators/injectable.decorator.js.map +1 -1
- package/dist/core/decorators/injection.decorators.d.ts +2 -37
- package/dist/core/decorators/injection.decorators.d.ts.map +1 -1
- package/dist/core/decorators/injection.decorators.js +43 -75
- 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 +4 -5
- 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 +4 -5
- package/dist/core/decorators/service.decorator.js.map +1 -1
- package/dist/core/metadata/metadata-storage.d.ts +9 -20
- package/dist/core/metadata/metadata-storage.d.ts.map +1 -1
- package/dist/core/metadata/metadata-storage.js +58 -10
- package/dist/core/metadata/metadata-storage.js.map +1 -1
- package/dist/core/types/decoration.types.d.ts +21 -0
- package/dist/core/types/decoration.types.d.ts.map +1 -0
- package/dist/core/types/decoration.types.js +3 -0
- package/dist/core/types/decoration.types.js.map +1 -0
- package/examples/blog-api/package-lock.json +190 -6
- package/examples/blog-api/package.json +6 -3
- package/examples/blog-api/src/services/app.service.ts +2 -2
- package/examples/blog-api/src/test/app.spec.ts +23 -0
- package/package.json +1 -1
- package/src/cli/commands/init.command.ts +61 -31
- package/src/core/decorators/application.decorator.ts +13 -3
- package/src/core/decorators/auto-configuration.decorator.ts +8 -10
- package/src/core/decorators/conditional.decorators.ts +37 -1
- package/src/core/decorators/controller.decorator.ts +1 -3
- package/src/core/decorators/http.decorators.ts +11 -32
- package/src/core/decorators/injectable.decorator.ts +15 -8
- package/src/core/decorators/injection.decorators.ts +50 -103
- package/src/core/decorators/repository.decorator.ts +8 -10
- package/src/core/decorators/service.decorator.ts +8 -10
- package/src/core/metadata/metadata-storage.ts +75 -43
- package/src/core/types/decoration.types.ts +38 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { METADATA_KEYS } from "../metadata/metadata-keys";
|
|
2
|
+
import { MetadataStorage } from "../metadata/metadata-storage";
|
|
2
3
|
|
|
3
4
|
export interface ApplicationOptions {
|
|
4
5
|
port?: number;
|
|
@@ -8,19 +9,28 @@ export interface ApplicationOptions {
|
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export function FragmentApplication(
|
|
11
|
-
options:
|
|
12
|
+
options: {
|
|
13
|
+
port?: number;
|
|
14
|
+
host?: string;
|
|
15
|
+
configPath?: string;
|
|
16
|
+
autoScan?: boolean;
|
|
17
|
+
} = {},
|
|
12
18
|
): ClassDecorator {
|
|
13
19
|
return (target: any) => {
|
|
14
20
|
Reflect.defineMetadata(
|
|
15
21
|
METADATA_KEYS.APPLICATION,
|
|
16
22
|
{
|
|
17
|
-
...options,
|
|
18
23
|
port: options.port || 3000,
|
|
19
24
|
host: options.host || "0.0.0.0",
|
|
20
25
|
configPath: options.configPath || "fragment.json",
|
|
21
|
-
autoScan: options.autoScan
|
|
26
|
+
autoScan: options.autoScan ?? true,
|
|
22
27
|
},
|
|
23
28
|
target,
|
|
24
29
|
);
|
|
30
|
+
MetadataStorage.getInstance().addClass({
|
|
31
|
+
target,
|
|
32
|
+
type: "injectable",
|
|
33
|
+
scope: "singleton",
|
|
34
|
+
});
|
|
25
35
|
};
|
|
26
36
|
}
|
|
@@ -1,17 +1,15 @@
|
|
|
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
|
-
|
|
10
|
-
const storage = MetadataStorage.getInstance();
|
|
11
|
-
storage.addClass({
|
|
9
|
+
MetadataStorage.getInstance().addClass({
|
|
12
10
|
target,
|
|
13
|
-
type:
|
|
14
|
-
scope:
|
|
11
|
+
type: "auto-configuration",
|
|
12
|
+
scope: "singleton",
|
|
15
13
|
});
|
|
16
14
|
};
|
|
17
|
-
}
|
|
15
|
+
}
|
|
@@ -1,19 +1,55 @@
|
|
|
1
|
-
import { METADATA_KEYS } from
|
|
1
|
+
import { METADATA_KEYS } from "../metadata/metadata-keys";
|
|
2
|
+
import { MetadataStorage } from "../metadata/metadata-storage";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Conditional decorators
|
|
6
|
+
* Ensures the class is registered in MetadataStorage
|
|
7
|
+
*/
|
|
2
8
|
|
|
3
9
|
export function ConditionalOnClass(classRef: any): ClassDecorator {
|
|
4
10
|
return (target: any) => {
|
|
5
11
|
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
|
+
}
|
|
6
22
|
};
|
|
7
23
|
}
|
|
8
24
|
|
|
9
25
|
export function ConditionalOnMissingBean(token: any): ClassDecorator {
|
|
10
26
|
return (target: any) => {
|
|
11
27
|
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
|
+
}
|
|
12
38
|
};
|
|
13
39
|
}
|
|
14
40
|
|
|
15
41
|
export function ConditionalOnProperty(key: string, expectedValue?: any): ClassDecorator {
|
|
16
42
|
return (target: any) => {
|
|
17
43
|
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
|
+
}
|
|
18
54
|
};
|
|
19
55
|
}
|
|
@@ -6,9 +6,7 @@ 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
|
-
|
|
10
|
-
const storage = MetadataStorage.getInstance();
|
|
11
|
-
storage.addClass({
|
|
9
|
+
MetadataStorage.getInstance().addClass({
|
|
12
10
|
target,
|
|
13
11
|
type: "controller",
|
|
14
12
|
scope: "singleton",
|
|
@@ -1,33 +1,20 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
1
2
|
import { METADATA_KEYS } from "../metadata/metadata-keys";
|
|
2
3
|
import { MetadataStorage } from "../metadata/metadata-storage";
|
|
3
4
|
|
|
4
5
|
function createHttpMethodDecorator(method: string) {
|
|
5
6
|
return (path: string = ""): MethodDecorator => {
|
|
6
|
-
return (
|
|
7
|
-
target
|
|
8
|
-
|
|
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
|
-
);
|
|
7
|
+
return (target: any, propertyKey: string | symbol) => {
|
|
8
|
+
Reflect.defineMetadata(METADATA_KEYS.HTTP_METHOD, method, target, propertyKey);
|
|
9
|
+
Reflect.defineMetadata(METADATA_KEYS.ROUTE_PATH, path, target, propertyKey);
|
|
23
10
|
|
|
24
11
|
const storage = MetadataStorage.getInstance();
|
|
25
12
|
storage.addMethod({
|
|
26
13
|
target: target.constructor,
|
|
27
|
-
propertyKey: propertyKey
|
|
14
|
+
propertyKey: propertyKey.toString(),
|
|
28
15
|
method,
|
|
29
16
|
path,
|
|
30
|
-
paramMetadata: storage.getParams(target, propertyKey
|
|
17
|
+
paramMetadata: storage.getParams(target, propertyKey.toString()),
|
|
31
18
|
});
|
|
32
19
|
};
|
|
33
20
|
};
|
|
@@ -39,23 +26,15 @@ export const Put = createHttpMethodDecorator("PUT");
|
|
|
39
26
|
export const Delete = createHttpMethodDecorator("DELETE");
|
|
40
27
|
export const Patch = createHttpMethodDecorator("PATCH");
|
|
41
28
|
|
|
29
|
+
// Parameter decorators
|
|
42
30
|
function createParamDecorator(type: string) {
|
|
43
31
|
return (paramName?: string): ParameterDecorator => {
|
|
44
|
-
return (
|
|
45
|
-
|
|
46
|
-
|
|
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({
|
|
32
|
+
return (target, propertyKey, index) => {
|
|
33
|
+
if (!propertyKey) throw new Error(`@${type} cannot be used on constructor params`);
|
|
34
|
+
MetadataStorage.getInstance().addParam({
|
|
56
35
|
target,
|
|
57
36
|
propertyKey: propertyKey.toString(),
|
|
58
|
-
index
|
|
37
|
+
index,
|
|
59
38
|
type: type as any,
|
|
60
39
|
paramName,
|
|
61
40
|
});
|
|
@@ -1,18 +1,25 @@
|
|
|
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
|
+
*/
|
|
6
9
|
export function Injectable(scope: Scope = 'singleton'): ClassDecorator {
|
|
7
10
|
return (target: any) => {
|
|
11
|
+
// Define Reflect metadata
|
|
8
12
|
Reflect.defineMetadata(METADATA_KEYS.INJECTABLE, true, target);
|
|
9
13
|
Reflect.defineMetadata(METADATA_KEYS.SCOPE, scope, target);
|
|
10
|
-
|
|
14
|
+
|
|
15
|
+
// Register in MetadataStorage if not already
|
|
11
16
|
const storage = MetadataStorage.getInstance();
|
|
12
|
-
storage.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
if (!storage.getClass(target)) {
|
|
18
|
+
storage.addClass({
|
|
19
|
+
target,
|
|
20
|
+
type: 'injectable',
|
|
21
|
+
scope
|
|
22
|
+
});
|
|
23
|
+
}
|
|
17
24
|
};
|
|
18
25
|
}
|
|
@@ -1,150 +1,97 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
1
2
|
import { METADATA_KEYS } from "../metadata/metadata-keys";
|
|
3
|
+
import { MetadataStorage } from "../metadata/metadata-storage";
|
|
2
4
|
|
|
3
|
-
/**
|
|
4
|
-
* @Autowired - Automatically inject dependencies by type
|
|
5
|
-
* Usage: @Autowired() private myService: MyService;
|
|
6
|
-
*/
|
|
7
5
|
export function Autowired(): PropertyDecorator {
|
|
8
|
-
return (target
|
|
9
|
-
// Get the design type from TypeScript metadata
|
|
6
|
+
return (target, propertyKey) => {
|
|
10
7
|
const type = Reflect.getMetadata("design:type", target, propertyKey);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
throw new Error(
|
|
14
|
-
`Cannot use @Autowired on property "${String(propertyKey)}" in ${target.constructor.name}. ` +
|
|
15
|
-
`Make sure TypeScript emitDecoratorMetadata is enabled and the type is explicitly declared.`,
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Store the type in metadata so DI container can resolve it
|
|
8
|
+
if (!type)
|
|
9
|
+
throw new Error(`Cannot use @Autowired on ${String(propertyKey)}`);
|
|
20
10
|
Reflect.defineMetadata(METADATA_KEYS.AUTOWIRED, type, target, propertyKey);
|
|
11
|
+
|
|
12
|
+
MetadataStorage.getInstance().addParam({
|
|
13
|
+
target,
|
|
14
|
+
propertyKey: propertyKey.toString(),
|
|
15
|
+
index: -1,
|
|
16
|
+
type: "autowired",
|
|
17
|
+
});
|
|
21
18
|
};
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
/**
|
|
25
|
-
* @Inject - Inject dependency by token (string or class)
|
|
26
|
-
* Usage: @Inject('MyService') private service: MyService;
|
|
27
|
-
* or: @Inject(MyService) private service: MyService;
|
|
28
|
-
*/
|
|
29
21
|
export function Inject(token: string | Function): PropertyDecorator {
|
|
30
|
-
return (target
|
|
22
|
+
return (target, propertyKey) => {
|
|
31
23
|
Reflect.defineMetadata(METADATA_KEYS.INJECT, token, target, propertyKey);
|
|
24
|
+
MetadataStorage.getInstance().addParam({
|
|
25
|
+
target,
|
|
26
|
+
propertyKey: propertyKey.toString(),
|
|
27
|
+
index: -1,
|
|
28
|
+
type: "inject",
|
|
29
|
+
paramName: typeof token === "string" ? token : undefined,
|
|
30
|
+
});
|
|
32
31
|
};
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
/**
|
|
36
|
-
* @InjectRepository - Inject TypeORM repository for an entity
|
|
37
|
-
* Usage: @InjectRepository(User) private userRepo: Repository<User>;
|
|
38
|
-
*/
|
|
39
34
|
export function InjectRepository(entity: Function): PropertyDecorator {
|
|
40
|
-
return (target
|
|
35
|
+
return (target, propertyKey) => {
|
|
41
36
|
Reflect.defineMetadata(
|
|
42
37
|
METADATA_KEYS.INJECT_REPOSITORY,
|
|
43
38
|
entity,
|
|
44
39
|
target,
|
|
45
40
|
propertyKey,
|
|
46
41
|
);
|
|
42
|
+
MetadataStorage.getInstance().addParam({
|
|
43
|
+
target,
|
|
44
|
+
propertyKey: propertyKey.toString(),
|
|
45
|
+
index: -1,
|
|
46
|
+
type: "inject-repo",
|
|
47
|
+
});
|
|
47
48
|
};
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
/**
|
|
51
|
-
* @Qualifier - Specify which bean to inject when multiple exist
|
|
52
|
-
* Usage: @Qualifier('primary') @Autowired() private service: MyService;
|
|
53
|
-
*/
|
|
54
|
-
export function Qualifier(name: string): PropertyDecorator {
|
|
55
|
-
return (target: any, propertyKey: string | symbol) => {
|
|
56
|
-
Reflect.defineMetadata(METADATA_KEYS.QUALIFIER, name, target, propertyKey);
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @Value - Inject configuration value from environment or config
|
|
62
|
-
* Usage: @Value('${PORT}') private port: number;
|
|
63
|
-
* or: @Value('${DB_HOST:localhost}') private host: string;
|
|
64
|
-
*/
|
|
65
51
|
export function Value(expression: string): PropertyDecorator {
|
|
66
|
-
return (target
|
|
52
|
+
return (target, propertyKey) => {
|
|
67
53
|
Reflect.defineMetadata(
|
|
68
54
|
METADATA_KEYS.VALUE,
|
|
69
55
|
expression,
|
|
70
56
|
target,
|
|
71
57
|
propertyKey,
|
|
72
58
|
);
|
|
59
|
+
MetadataStorage.getInstance().addParam({
|
|
60
|
+
target,
|
|
61
|
+
propertyKey: propertyKey.toString(),
|
|
62
|
+
index: -1,
|
|
63
|
+
type: "value",
|
|
64
|
+
});
|
|
73
65
|
};
|
|
74
66
|
}
|
|
75
67
|
|
|
76
68
|
/**
|
|
77
|
-
* @
|
|
78
|
-
* Usage: @
|
|
79
|
-
*/
|
|
80
|
-
export function Optional(): PropertyDecorator {
|
|
81
|
-
return (target: any, propertyKey: string | symbol) => {
|
|
82
|
-
Reflect.defineMetadata(METADATA_KEYS.OPTIONAL, true, target, propertyKey);
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* @Lazy - Lazy load dependency (create on first access)
|
|
88
|
-
* Usage: @Lazy() @Autowired() private service: MyService;
|
|
69
|
+
* @Qualifier - Specify which bean to inject when multiple exist
|
|
70
|
+
* Usage: @Qualifier('primary') @Autowired() private service: MyService;
|
|
89
71
|
*/
|
|
90
|
-
export function
|
|
72
|
+
export function Qualifier(name: string): PropertyDecorator {
|
|
91
73
|
return (target: any, propertyKey: string | symbol) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const type = Reflect.getMetadata("design:type", target, propertyKey);
|
|
74
|
+
if (!propertyKey) return;
|
|
95
75
|
|
|
96
|
-
|
|
97
|
-
let cached: any = null;
|
|
98
|
-
let resolved = false;
|
|
76
|
+
Reflect.defineMetadata(METADATA_KEYS.QUALIFIER, name, target, propertyKey);
|
|
99
77
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
cached = container.resolve(type);
|
|
106
|
-
resolved = true;
|
|
107
|
-
}
|
|
108
|
-
return cached;
|
|
109
|
-
},
|
|
110
|
-
enumerable: true,
|
|
111
|
-
configurable: true,
|
|
78
|
+
MetadataStorage.getInstance().addParam({
|
|
79
|
+
target,
|
|
80
|
+
propertyKey: propertyKey.toString(),
|
|
81
|
+
index: -1,
|
|
82
|
+
type: "qualifier",
|
|
112
83
|
});
|
|
113
84
|
};
|
|
114
85
|
}
|
|
115
86
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
*/
|
|
120
|
-
export function PostConstruct(): MethodDecorator {
|
|
121
|
-
return (
|
|
122
|
-
target: any,
|
|
123
|
-
propertyKey: string | symbol,
|
|
124
|
-
descriptor: PropertyDescriptor,
|
|
125
|
-
) => {
|
|
126
|
-
Reflect.defineMetadata(
|
|
127
|
-
METADATA_KEYS.POST_CONSTRUCT,
|
|
128
|
-
propertyKey,
|
|
129
|
-
target.constructor,
|
|
130
|
-
);
|
|
87
|
+
export function Optional(): PropertyDecorator {
|
|
88
|
+
return (target, propertyKey) => {
|
|
89
|
+
Reflect.defineMetadata(METADATA_KEYS.OPTIONAL, true, target, propertyKey);
|
|
131
90
|
};
|
|
132
91
|
}
|
|
133
92
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
*/
|
|
138
|
-
export function PreDestroy(): MethodDecorator {
|
|
139
|
-
return (
|
|
140
|
-
target: any,
|
|
141
|
-
propertyKey: string | symbol,
|
|
142
|
-
descriptor: PropertyDescriptor,
|
|
143
|
-
) => {
|
|
144
|
-
Reflect.defineMetadata(
|
|
145
|
-
METADATA_KEYS.PRE_DESTROY,
|
|
146
|
-
propertyKey,
|
|
147
|
-
target.constructor,
|
|
148
|
-
);
|
|
93
|
+
export function Lazy(): PropertyDecorator {
|
|
94
|
+
return (target, propertyKey) => {
|
|
95
|
+
Reflect.defineMetadata(METADATA_KEYS.LAZY, true, target, propertyKey);
|
|
149
96
|
};
|
|
150
97
|
}
|
|
@@ -1,17 +1,15 @@
|
|
|
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 Repository(): ClassDecorator {
|
|
6
6
|
return (target: any) => {
|
|
7
|
-
Injectable(
|
|
7
|
+
Injectable("singleton")(target);
|
|
8
8
|
Reflect.defineMetadata(METADATA_KEYS.REPOSITORY, true, target);
|
|
9
|
-
|
|
10
|
-
const storage = MetadataStorage.getInstance();
|
|
11
|
-
storage.addClass({
|
|
9
|
+
MetadataStorage.getInstance().addClass({
|
|
12
10
|
target,
|
|
13
|
-
type:
|
|
14
|
-
scope:
|
|
11
|
+
type: "repository",
|
|
12
|
+
scope: "singleton",
|
|
15
13
|
});
|
|
16
14
|
};
|
|
17
|
-
}
|
|
15
|
+
}
|
|
@@ -1,17 +1,15 @@
|
|
|
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 Service(): ClassDecorator {
|
|
6
6
|
return (target: any) => {
|
|
7
|
-
Injectable(
|
|
7
|
+
Injectable("singleton")(target);
|
|
8
8
|
Reflect.defineMetadata(METADATA_KEYS.SERVICE, true, target);
|
|
9
|
-
|
|
10
|
-
const storage = MetadataStorage.getInstance();
|
|
11
|
-
storage.addClass({
|
|
9
|
+
MetadataStorage.getInstance().addClass({
|
|
12
10
|
target,
|
|
13
|
-
type:
|
|
14
|
-
scope:
|
|
11
|
+
type: "service",
|
|
12
|
+
scope: "singleton",
|
|
15
13
|
});
|
|
16
14
|
};
|
|
17
|
-
}
|
|
15
|
+
}
|
|
@@ -1,39 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
| "auto-configuration";
|
|
11
|
-
scope?: "singleton" | "request" | "transient";
|
|
12
|
-
path?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface MethodMetadata {
|
|
16
|
-
target: any;
|
|
17
|
-
propertyKey: string;
|
|
18
|
-
method: string;
|
|
19
|
-
path: string;
|
|
20
|
-
paramMetadata: ParamMetadata[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface ParamMetadata {
|
|
24
|
-
target: any;
|
|
25
|
-
propertyKey: string;
|
|
26
|
-
index: number;
|
|
27
|
-
type: "body" | "param" | "query" | "header" | "req" | "res";
|
|
28
|
-
paramName?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
1
|
+
import {
|
|
2
|
+
ClassMetadata,
|
|
3
|
+
MethodMetadata,
|
|
4
|
+
ParamMetadata,
|
|
5
|
+
} from "../types/decoration.types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Central storage for all metadata: classes, methods, parameters
|
|
9
|
+
*/
|
|
31
10
|
export class MetadataStorage {
|
|
32
11
|
private static instance: MetadataStorage;
|
|
33
|
-
|
|
12
|
+
|
|
13
|
+
// Maps for storing metadata
|
|
14
|
+
private classes: Map<Function, ClassMetadata> = new Map();
|
|
34
15
|
private methods: Map<string, MethodMetadata> = new Map();
|
|
35
16
|
private params: Map<string, ParamMetadata[]> = new Map();
|
|
36
17
|
|
|
18
|
+
// Singleton instance
|
|
37
19
|
static getInstance(): MetadataStorage {
|
|
38
20
|
if (!MetadataStorage.instance) {
|
|
39
21
|
MetadataStorage.instance = new MetadataStorage();
|
|
@@ -41,11 +23,16 @@ export class MetadataStorage {
|
|
|
41
23
|
return MetadataStorage.instance;
|
|
42
24
|
}
|
|
43
25
|
|
|
26
|
+
// ----- Classes -----
|
|
44
27
|
addClass(metadata: ClassMetadata): void {
|
|
45
|
-
|
|
28
|
+
if (!metadata?.target) return;
|
|
29
|
+
if (!this.classes.has(metadata.target)) {
|
|
30
|
+
this.classes.set(metadata.target, metadata);
|
|
31
|
+
}
|
|
46
32
|
}
|
|
47
33
|
|
|
48
34
|
getClass(target: any): ClassMetadata | undefined {
|
|
35
|
+
if (!target) return undefined;
|
|
49
36
|
return this.classes.get(target);
|
|
50
37
|
}
|
|
51
38
|
|
|
@@ -53,20 +40,35 @@ export class MetadataStorage {
|
|
|
53
40
|
return Array.from(this.classes.values());
|
|
54
41
|
}
|
|
55
42
|
|
|
43
|
+
hasClass(target: any): boolean {
|
|
44
|
+
return !!target && this.classes.has(target);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ----- Methods -----
|
|
48
|
+
private getMethodKey(target: Function, propertyKey: string): string {
|
|
49
|
+
return `${target.name}_${propertyKey}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
56
52
|
addMethod(metadata: MethodMetadata): void {
|
|
57
|
-
|
|
53
|
+
if (!metadata?.target || !metadata.propertyKey) return;
|
|
54
|
+
|
|
55
|
+
const targetForKey = metadata.target.prototype || metadata.target;
|
|
56
|
+
const key = this.getMethodKey(metadata.target, metadata.propertyKey);
|
|
58
57
|
|
|
58
|
+
// Attach existing params for this method
|
|
59
59
|
const existingParams = this.getParams(
|
|
60
|
-
|
|
60
|
+
targetForKey,
|
|
61
61
|
metadata.propertyKey,
|
|
62
|
-
);
|
|
63
|
-
|
|
62
|
+
).sort((a, b) => a.index - b.index);
|
|
63
|
+
|
|
64
|
+
metadata.paramMetadata = existingParams;
|
|
64
65
|
|
|
65
66
|
this.methods.set(key, metadata);
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
getMethod(target: any, propertyKey: string): MethodMetadata | undefined {
|
|
69
|
-
|
|
70
|
+
if (!target || !propertyKey) return undefined;
|
|
71
|
+
const key = this.getMethodKey(target.constructor || target, propertyKey);
|
|
70
72
|
return this.methods.get(key);
|
|
71
73
|
}
|
|
72
74
|
|
|
@@ -74,18 +76,48 @@ export class MetadataStorage {
|
|
|
74
76
|
return Array.from(this.methods.values());
|
|
75
77
|
}
|
|
76
78
|
|
|
79
|
+
hasMethod(target: any, propertyKey: string): boolean {
|
|
80
|
+
if (!target || !propertyKey) return false;
|
|
81
|
+
const key = this.getMethodKey(target.constructor || target, propertyKey);
|
|
82
|
+
return this.methods.has(key);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ----- Params -----
|
|
86
|
+
private getParamKey(target: any, propertyKey: string): string {
|
|
87
|
+
return `${target.constructor.name}_${propertyKey}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
77
90
|
addParam(metadata: ParamMetadata): void {
|
|
78
|
-
|
|
91
|
+
if (!metadata?.target || !metadata.propertyKey) return;
|
|
92
|
+
|
|
93
|
+
const key = this.getParamKey(metadata.target, metadata.propertyKey);
|
|
79
94
|
const existing = this.params.get(key) || [];
|
|
80
|
-
|
|
95
|
+
|
|
96
|
+
// Deduplicate by propertyKey + index
|
|
97
|
+
if (
|
|
98
|
+
!existing.some(
|
|
99
|
+
(p) =>
|
|
100
|
+
p.index === metadata.index && p.propertyKey === metadata.propertyKey,
|
|
101
|
+
)
|
|
102
|
+
) {
|
|
103
|
+
existing.push(metadata);
|
|
104
|
+
}
|
|
105
|
+
|
|
81
106
|
this.params.set(key, existing);
|
|
82
107
|
}
|
|
83
108
|
|
|
84
109
|
getParams(target: any, propertyKey: string): ParamMetadata[] {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const key = `${targetName}.${propertyKey}`;
|
|
110
|
+
if (!target || !propertyKey) return [];
|
|
111
|
+
const key = this.getParamKey(target, propertyKey);
|
|
89
112
|
return this.params.get(key) || [];
|
|
90
113
|
}
|
|
114
|
+
|
|
115
|
+
hasParam(target: any, propertyKey: string, index?: number): boolean {
|
|
116
|
+
if (!target || !propertyKey) return false;
|
|
117
|
+
const key = this.getParamKey(target, propertyKey);
|
|
118
|
+
const existing = this.params.get(key) || [];
|
|
119
|
+
return index !== undefined
|
|
120
|
+
? existing.some((p) => p.index === index)
|
|
121
|
+
: existing.length > 0;
|
|
122
|
+
}
|
|
91
123
|
}
|