-
-
Notifications
You must be signed in to change notification settings - Fork 25
/
scanner.ts
95 lines (82 loc) · 2.91 KB
/
scanner.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { INestApplicationContext } from '@nestjs/common';
import { COMMAND_METADATA_NAME, CONSOLE_METADATA_NAME } from './constants';
import { ConsoleOptions, CreateCommandOptions } from './decorators';
/**
* The interface for command method metadata
*/
export interface MethodsMetadata {
name: string;
metadata: CreateCommandOptions;
}
/**
* The response of the scanner
*/
export interface ScanResponse {
instance: any;
metadata: ConsoleOptions;
methods: MethodsMetadata[];
}
export class ConsoleScanner {
/**
* Get all the modules
*/
private getModules(modulesContainer: Map<any, any>, include: any[] = []): any[] {
const allModules = [...modulesContainer.values()];
if (!include.length) {
return allModules;
}
return allModules.filter(({ metatype }) => include.some((item) => item === metatype));
}
/**
* Get a list of classes methods
*/
private getInstanceMethods(instance: any): string[] {
return Object.getOwnPropertyNames(instance)
.concat(Object.getOwnPropertyNames(instance.__proto__))
.filter((m) => Reflect.hasMetadata(COMMAND_METADATA_NAME, instance, m));
}
/**
* Scan an application
* @param app
* @param includedModules
*/
public scan(app: INestApplicationContext, includedModules?: any[]): Set<ScanResponse> {
const set = new Set<ScanResponse>();
const { container } = app as any;
const modules = this.getModules(container.getModules(), includedModules);
modules.forEach((m) => {
m._providers.forEach((p) => {
const { metatype, name } = p;
if (typeof metatype !== 'function') {
return;
}
// ignore providers without instance
if (!p.instance) {
return;
}
const consoleMetadata: ConsoleOptions = Reflect.getMetadata(
CONSOLE_METADATA_NAME,
p.instance.constructor
);
// ignore providers without the console decorator
if (!consoleMetadata) {
return;
}
// get the provider instance from the container
const instance = app.get(name);
const methods = this.getInstanceMethods(instance);
// get the metadata of the methods
const methodsMetadata = methods.map<MethodsMetadata>((methodMetadata) => ({
name: methodMetadata,
metadata: Reflect.getMetadata(COMMAND_METADATA_NAME, instance, methodMetadata)
}));
set.add({
instance,
metadata: consoleMetadata,
methods: methodsMetadata
});
});
});
return set;
}
}