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
|
@@ -1,97 +1,150 @@
|
|
|
1
|
-
import "reflect-metadata";
|
|
2
1
|
import { METADATA_KEYS } from "../metadata/metadata-keys";
|
|
3
|
-
import { MetadataStorage } from "../metadata/metadata-storage";
|
|
4
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @Autowired - Automatically inject dependencies by type
|
|
5
|
+
* Usage: @Autowired() private myService: MyService;
|
|
6
|
+
*/
|
|
5
7
|
export function Autowired(): PropertyDecorator {
|
|
6
|
-
return (target, propertyKey) => {
|
|
8
|
+
return (target: any, propertyKey: string | symbol) => {
|
|
9
|
+
// Get the design type from TypeScript metadata
|
|
7
10
|
const type = Reflect.getMetadata("design:type", target, propertyKey);
|
|
8
|
-
if (!type)
|
|
9
|
-
throw new Error(`Cannot use @Autowired on ${String(propertyKey)}`);
|
|
10
|
-
Reflect.defineMetadata(METADATA_KEYS.AUTOWIRED, type, target, propertyKey);
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
12
|
+
if (!type || type === Object) {
|
|
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
|
|
20
|
+
Reflect.defineMetadata(METADATA_KEYS.AUTOWIRED, type, target, propertyKey);
|
|
18
21
|
};
|
|
19
22
|
}
|
|
20
23
|
|
|
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
|
+
*/
|
|
21
29
|
export function Inject(token: string | Function): PropertyDecorator {
|
|
22
|
-
return (target, propertyKey) => {
|
|
30
|
+
return (target: any, propertyKey: string | symbol) => {
|
|
23
31
|
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
|
-
});
|
|
31
32
|
};
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
/**
|
|
36
|
+
* @InjectRepository - Inject TypeORM repository for an entity
|
|
37
|
+
* Usage: @InjectRepository(User) private userRepo: Repository<User>;
|
|
38
|
+
*/
|
|
34
39
|
export function InjectRepository(entity: Function): PropertyDecorator {
|
|
35
|
-
return (target, propertyKey) => {
|
|
40
|
+
return (target: any, propertyKey: string | symbol) => {
|
|
36
41
|
Reflect.defineMetadata(
|
|
37
42
|
METADATA_KEYS.INJECT_REPOSITORY,
|
|
38
43
|
entity,
|
|
39
44
|
target,
|
|
40
45
|
propertyKey,
|
|
41
46
|
);
|
|
42
|
-
MetadataStorage.getInstance().addParam({
|
|
43
|
-
target,
|
|
44
|
-
propertyKey: propertyKey.toString(),
|
|
45
|
-
index: -1,
|
|
46
|
-
type: "inject-repo",
|
|
47
|
-
});
|
|
48
47
|
};
|
|
49
48
|
}
|
|
50
49
|
|
|
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
|
+
*/
|
|
51
65
|
export function Value(expression: string): PropertyDecorator {
|
|
52
|
-
return (target, propertyKey) => {
|
|
66
|
+
return (target: any, propertyKey: string | symbol) => {
|
|
53
67
|
Reflect.defineMetadata(
|
|
54
68
|
METADATA_KEYS.VALUE,
|
|
55
69
|
expression,
|
|
56
70
|
target,
|
|
57
71
|
propertyKey,
|
|
58
72
|
);
|
|
59
|
-
MetadataStorage.getInstance().addParam({
|
|
60
|
-
target,
|
|
61
|
-
propertyKey: propertyKey.toString(),
|
|
62
|
-
index: -1,
|
|
63
|
-
type: "value",
|
|
64
|
-
});
|
|
65
73
|
};
|
|
66
74
|
}
|
|
67
75
|
|
|
68
76
|
/**
|
|
69
|
-
* @
|
|
70
|
-
* Usage: @
|
|
77
|
+
* @Optional - Mark dependency as optional (won't throw if not found)
|
|
78
|
+
* Usage: @Optional() @Autowired() private service?: MyService;
|
|
71
79
|
*/
|
|
72
|
-
export function
|
|
80
|
+
export function Optional(): PropertyDecorator {
|
|
73
81
|
return (target: any, propertyKey: string | symbol) => {
|
|
74
|
-
|
|
82
|
+
Reflect.defineMetadata(METADATA_KEYS.OPTIONAL, true, target, propertyKey);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
75
85
|
|
|
76
|
-
|
|
86
|
+
/**
|
|
87
|
+
* @Lazy - Lazy load dependency (create on first access)
|
|
88
|
+
* Usage: @Lazy() @Autowired() private service: MyService;
|
|
89
|
+
*/
|
|
90
|
+
export function Lazy(): PropertyDecorator {
|
|
91
|
+
return (target: any, propertyKey: string | symbol) => {
|
|
92
|
+
Reflect.defineMetadata(METADATA_KEYS.LAZY, true, target, propertyKey);
|
|
77
93
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
94
|
+
const type = Reflect.getMetadata("design:type", target, propertyKey);
|
|
95
|
+
|
|
96
|
+
// Create a getter that resolves on first access
|
|
97
|
+
let cached: any = null;
|
|
98
|
+
let resolved = false;
|
|
99
|
+
|
|
100
|
+
Object.defineProperty(target, propertyKey, {
|
|
101
|
+
get() {
|
|
102
|
+
if (!resolved) {
|
|
103
|
+
const { DIContainer } = require("../container/di-container");
|
|
104
|
+
const container = DIContainer.getInstance();
|
|
105
|
+
cached = container.resolve(type);
|
|
106
|
+
resolved = true;
|
|
107
|
+
}
|
|
108
|
+
return cached;
|
|
109
|
+
},
|
|
110
|
+
enumerable: true,
|
|
111
|
+
configurable: true,
|
|
83
112
|
});
|
|
84
113
|
};
|
|
85
114
|
}
|
|
86
115
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
116
|
+
/**
|
|
117
|
+
* @PostConstruct - Method called after dependency injection is complete
|
|
118
|
+
* Usage: @PostConstruct() init() { ... }
|
|
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
|
+
);
|
|
90
131
|
};
|
|
91
132
|
}
|
|
92
133
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
134
|
+
/**
|
|
135
|
+
* @PreDestroy - Method called before bean is destroyed
|
|
136
|
+
* Usage: @PreDestroy() cleanup() { ... }
|
|
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
|
+
);
|
|
96
149
|
};
|
|
97
150
|
}
|
|
@@ -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 Repository(): ClassDecorator {
|
|
6
6
|
return (target: any) => {
|
|
7
|
-
Injectable(
|
|
7
|
+
Injectable('singleton')(target);
|
|
8
8
|
Reflect.defineMetadata(METADATA_KEYS.REPOSITORY, true, target);
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
const storage = MetadataStorage.getInstance();
|
|
11
|
+
storage.addClass({
|
|
10
12
|
target,
|
|
11
|
-
type:
|
|
12
|
-
scope:
|
|
13
|
+
type: 'repository',
|
|
14
|
+
scope: 'singleton'
|
|
13
15
|
});
|
|
14
16
|
};
|
|
15
|
-
}
|
|
17
|
+
}
|
|
@@ -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 Service(): ClassDecorator {
|
|
6
6
|
return (target: any) => {
|
|
7
|
-
Injectable(
|
|
7
|
+
Injectable('singleton')(target);
|
|
8
8
|
Reflect.defineMetadata(METADATA_KEYS.SERVICE, true, target);
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
const storage = MetadataStorage.getInstance();
|
|
11
|
+
storage.addClass({
|
|
10
12
|
target,
|
|
11
|
-
type:
|
|
12
|
-
scope:
|
|
13
|
+
type: 'service',
|
|
14
|
+
scope: 'singleton'
|
|
13
15
|
});
|
|
14
16
|
};
|
|
15
|
-
}
|
|
17
|
+
}
|
|
@@ -1,21 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { METADATA_KEYS } from "./metadata-keys";
|
|
2
|
+
|
|
3
|
+
export interface ClassMetadata {
|
|
4
|
+
target: any;
|
|
5
|
+
type:
|
|
6
|
+
| "injectable"
|
|
7
|
+
| "service"
|
|
8
|
+
| "controller"
|
|
9
|
+
| "repository"
|
|
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
|
+
|
|
10
31
|
export class MetadataStorage {
|
|
11
32
|
private static instance: MetadataStorage;
|
|
12
|
-
|
|
13
|
-
// Maps for storing metadata
|
|
14
|
-
private classes: Map<Function, ClassMetadata> = new Map();
|
|
33
|
+
private classes: Map<any, ClassMetadata> = new Map();
|
|
15
34
|
private methods: Map<string, MethodMetadata> = new Map();
|
|
16
35
|
private params: Map<string, ParamMetadata[]> = new Map();
|
|
17
36
|
|
|
18
|
-
// Singleton instance
|
|
19
37
|
static getInstance(): MetadataStorage {
|
|
20
38
|
if (!MetadataStorage.instance) {
|
|
21
39
|
MetadataStorage.instance = new MetadataStorage();
|
|
@@ -23,16 +41,11 @@ export class MetadataStorage {
|
|
|
23
41
|
return MetadataStorage.instance;
|
|
24
42
|
}
|
|
25
43
|
|
|
26
|
-
// ----- Classes -----
|
|
27
44
|
addClass(metadata: ClassMetadata): void {
|
|
28
|
-
|
|
29
|
-
if (!this.classes.has(metadata.target)) {
|
|
30
|
-
this.classes.set(metadata.target, metadata);
|
|
31
|
-
}
|
|
45
|
+
this.classes.set(metadata.target, metadata);
|
|
32
46
|
}
|
|
33
47
|
|
|
34
48
|
getClass(target: any): ClassMetadata | undefined {
|
|
35
|
-
if (!target) return undefined;
|
|
36
49
|
return this.classes.get(target);
|
|
37
50
|
}
|
|
38
51
|
|
|
@@ -40,35 +53,20 @@ export class MetadataStorage {
|
|
|
40
53
|
return Array.from(this.classes.values());
|
|
41
54
|
}
|
|
42
55
|
|
|
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
|
-
|
|
52
56
|
addMethod(metadata: MethodMetadata): void {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const targetForKey = metadata.target.prototype || metadata.target;
|
|
56
|
-
const key = this.getMethodKey(metadata.target, metadata.propertyKey);
|
|
57
|
+
const key = `${metadata.target.name}.${metadata.propertyKey}`;
|
|
57
58
|
|
|
58
|
-
// Attach existing params for this method
|
|
59
59
|
const existingParams = this.getParams(
|
|
60
|
-
|
|
60
|
+
metadata.target,
|
|
61
61
|
metadata.propertyKey,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
metadata.paramMetadata = existingParams;
|
|
62
|
+
);
|
|
63
|
+
metadata.paramMetadata = existingParams.sort((a, b) => a.index - b.index);
|
|
65
64
|
|
|
66
65
|
this.methods.set(key, metadata);
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
getMethod(target: any, propertyKey: string): MethodMetadata | undefined {
|
|
70
|
-
|
|
71
|
-
const key = this.getMethodKey(target.constructor || target, propertyKey);
|
|
69
|
+
const key = `${target.name}.${propertyKey}`;
|
|
72
70
|
return this.methods.get(key);
|
|
73
71
|
}
|
|
74
72
|
|
|
@@ -76,48 +74,18 @@ export class MetadataStorage {
|
|
|
76
74
|
return Array.from(this.methods.values());
|
|
77
75
|
}
|
|
78
76
|
|
|
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
|
-
|
|
90
77
|
addParam(metadata: ParamMetadata): void {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const key = this.getParamKey(metadata.target, metadata.propertyKey);
|
|
78
|
+
const key = `${metadata.target.constructor.name}.${metadata.propertyKey}`;
|
|
94
79
|
const existing = this.params.get(key) || [];
|
|
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
|
-
|
|
80
|
+
existing.push(metadata);
|
|
106
81
|
this.params.set(key, existing);
|
|
107
82
|
}
|
|
108
83
|
|
|
109
84
|
getParams(target: any, propertyKey: string): ParamMetadata[] {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return this.params.get(key) || [];
|
|
113
|
-
}
|
|
85
|
+
const targetName = target.name || target.constructor?.name;
|
|
86
|
+
if (!targetName) return [];
|
|
114
87
|
|
|
115
|
-
|
|
116
|
-
|
|
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;
|
|
88
|
+
const key = `${targetName}.${propertyKey}`;
|
|
89
|
+
return this.params.get(key) || [];
|
|
122
90
|
}
|
|
123
91
|
}
|
package/src/web/application.ts
CHANGED
|
@@ -20,7 +20,7 @@ export class FragmentWebApplication {
|
|
|
20
20
|
this.container = DIContainer.getInstance();
|
|
21
21
|
this.metadataStorage = MetadataStorage.getInstance();
|
|
22
22
|
this.setupMiddleware();
|
|
23
|
-
this
|
|
23
|
+
this;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
private setupMiddleware(): void {
|
|
@@ -122,7 +122,9 @@ export class FragmentWebApplication {
|
|
|
122
122
|
private discoverAndRegisterComponents(): void {
|
|
123
123
|
const classes = this.metadataStorage.getAllClasses();
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
console.log(`\nš¦ Discovered ${classes.length} component(s)`);
|
|
126
|
+
|
|
127
|
+
// Group by type for display
|
|
126
128
|
const grouped = classes.reduce(
|
|
127
129
|
(acc, cls) => {
|
|
128
130
|
if (!acc[cls.type]) acc[cls.type] = [];
|
|
@@ -132,29 +134,37 @@ export class FragmentWebApplication {
|
|
|
132
134
|
{} as Record<string, any[]>,
|
|
133
135
|
);
|
|
134
136
|
|
|
135
|
-
const total = classes.length;
|
|
136
|
-
const registered = classes.filter((m) =>
|
|
137
|
-
this.shouldRegister(m.target),
|
|
138
|
-
).length;
|
|
139
|
-
|
|
140
|
-
console.log(`\nš¦ Discovered ${total} component(s)`);
|
|
141
|
-
|
|
142
137
|
Object.entries(grouped).forEach(([type, items]) => {
|
|
143
138
|
const icon = this.getTypeIcon(type);
|
|
144
139
|
console.log(` ${icon} ${items.length} ${type}(s)`);
|
|
145
140
|
});
|
|
146
141
|
|
|
147
|
-
let
|
|
142
|
+
let registered = 0;
|
|
143
|
+
let skipped = 0;
|
|
144
|
+
|
|
148
145
|
classes.forEach((metadata) => {
|
|
149
146
|
if (this.shouldRegister(metadata.target)) {
|
|
147
|
+
// CRITICAL: Register with container
|
|
150
148
|
if (!this.container.has(metadata.target)) {
|
|
151
149
|
this.container.register(metadata.target);
|
|
152
|
-
|
|
150
|
+
registered++;
|
|
151
|
+
console.log(` ā Registered: ${metadata.target.name}`);
|
|
153
152
|
}
|
|
153
|
+
} else {
|
|
154
|
+
skipped++;
|
|
155
|
+
console.log(
|
|
156
|
+
` ā Skipped: ${metadata.target.name} (conditional check failed)`,
|
|
157
|
+
);
|
|
154
158
|
}
|
|
155
159
|
});
|
|
156
160
|
|
|
157
|
-
console.log(
|
|
161
|
+
console.log(
|
|
162
|
+
`\n ā Registered ${registered}/${classes.length} component(s)`,
|
|
163
|
+
);
|
|
164
|
+
if (skipped > 0) {
|
|
165
|
+
console.log(` ā Skipped ${skipped} (conditions not met)`);
|
|
166
|
+
}
|
|
167
|
+
console.log("");
|
|
158
168
|
}
|
|
159
169
|
|
|
160
170
|
private getTypeIcon(type: string): string {
|