@nestia/sdk 0.2.0 → 1.0.1
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/assets/config/nestia.config.ts +79 -70
- package/lib/INestiaConfig.d.ts +18 -14
- package/lib/executable/sdk.js +16 -16
- package/lib/generates/FunctionGenerator.js +9 -9
- package/lib/generates/FunctionGenerator.js.map +1 -1
- package/lib/generates/SwaggerGenerator.js +9 -9
- package/package.json +3 -3
- package/src/INestiaConfig.ts +124 -120
- package/src/NestiaSdkApplication.ts +183 -183
- package/src/analyses/ControllerAnalyzer.ts +203 -203
- package/src/analyses/GenericAnalyzer.ts +53 -53
- package/src/analyses/ImportAnalyzer.ts +143 -143
- package/src/analyses/PathAnalyzer.ts +58 -58
- package/src/analyses/ReflectAnalyzer.ts +279 -279
- package/src/analyses/SourceFinder.ts +59 -59
- package/src/executable/internal/CommandParser.ts +15 -15
- package/src/executable/internal/NestiaConfigCompilerOptions.ts +18 -18
- package/src/executable/internal/NestiaSdkCommand.ts +174 -174
- package/src/executable/internal/NestiaSdkConfig.ts +35 -35
- package/src/executable/internal/nestia.config.getter.ts +12 -12
- package/src/executable/sdk.ts +74 -74
- package/src/generates/FileGenerator.ts +156 -156
- package/src/generates/FunctionGenerator.ts +284 -287
- package/src/generates/SdkGenerator.ts +50 -50
- package/src/generates/SwaggerGenerator.ts +393 -393
- package/src/index.ts +3 -3
- package/src/module.ts +2 -2
- package/src/structures/IController.ts +27 -27
- package/src/structures/IRoute.ts +29 -29
- package/src/structures/ISwagger.ts +55 -55
- package/src/structures/ITypeTuple.ts +6 -6
- package/src/structures/MethodType.ts +11 -11
- package/src/structures/ParamCategory.ts +1 -1
- package/src/structures/TypeEntry.ts +22 -22
- package/src/utils/ArrayUtil.ts +26 -26
- package/src/utils/ImportDictionary.ts +56 -56
- package/src/utils/MapUtil.ts +14 -14
- package/src/utils/StripEnums.ts +10 -10
|
@@ -1,279 +1,279 @@
|
|
|
1
|
-
import { equal } from "tstl/ranges/module";
|
|
2
|
-
|
|
3
|
-
import { IController } from "../structures/IController";
|
|
4
|
-
import { ParamCategory } from "../structures/ParamCategory";
|
|
5
|
-
import { ArrayUtil } from "../utils/ArrayUtil";
|
|
6
|
-
import { PathAnalyzer } from "./PathAnalyzer";
|
|
7
|
-
|
|
8
|
-
type IModule = {
|
|
9
|
-
[key: string]: any;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export namespace ReflectAnalyzer {
|
|
13
|
-
export async function analyze(
|
|
14
|
-
unique: WeakSet<any>,
|
|
15
|
-
file: string,
|
|
16
|
-
): Promise<IController[]> {
|
|
17
|
-
const module: IModule = await import(file);
|
|
18
|
-
const ret: IController[] = [];
|
|
19
|
-
|
|
20
|
-
for (const tuple of Object.entries(module)) {
|
|
21
|
-
if (unique.has(tuple[1])) continue;
|
|
22
|
-
else unique.add(tuple[1]);
|
|
23
|
-
|
|
24
|
-
const controller: IController | null = _Analyze_controller(
|
|
25
|
-
file,
|
|
26
|
-
...tuple,
|
|
27
|
-
);
|
|
28
|
-
if (controller !== null) ret.push(controller);
|
|
29
|
-
}
|
|
30
|
-
return ret;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/* ---------------------------------------------------------
|
|
34
|
-
CONTROLLER
|
|
35
|
-
--------------------------------------------------------- */
|
|
36
|
-
function _Analyze_controller(
|
|
37
|
-
file: string,
|
|
38
|
-
name: string,
|
|
39
|
-
creator: any,
|
|
40
|
-
): IController | null {
|
|
41
|
-
//----
|
|
42
|
-
// VALIDATIONS
|
|
43
|
-
//----
|
|
44
|
-
// MUST BE TYPE OF A CREATOR WHO HAS THE CONSTRUCTOR
|
|
45
|
-
if (
|
|
46
|
-
!(
|
|
47
|
-
creator instanceof Function &&
|
|
48
|
-
creator.constructor instanceof Function
|
|
49
|
-
)
|
|
50
|
-
)
|
|
51
|
-
return null;
|
|
52
|
-
// MUST HAVE THOSE MATADATA
|
|
53
|
-
else if (
|
|
54
|
-
ArrayUtil.has(
|
|
55
|
-
Reflect.getMetadataKeys(creator),
|
|
56
|
-
"path",
|
|
57
|
-
"host",
|
|
58
|
-
"scope:options",
|
|
59
|
-
) === false
|
|
60
|
-
)
|
|
61
|
-
return null;
|
|
62
|
-
|
|
63
|
-
//----
|
|
64
|
-
// CONSTRUCTION
|
|
65
|
-
//----
|
|
66
|
-
// BASIC INFO
|
|
67
|
-
const paths: string[] = _Get_paths(
|
|
68
|
-
Reflect.getMetadata("path", creator),
|
|
69
|
-
);
|
|
70
|
-
const meta: IController = {
|
|
71
|
-
file,
|
|
72
|
-
name,
|
|
73
|
-
paths,
|
|
74
|
-
functions: [],
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// PARSE CHILDREN DATA
|
|
78
|
-
for (const tuple of _Get_prototype_entries(creator)) {
|
|
79
|
-
const child: IController.IFunction | null = _Analyze_function(
|
|
80
|
-
creator.prototype,
|
|
81
|
-
meta,
|
|
82
|
-
...tuple,
|
|
83
|
-
);
|
|
84
|
-
if (child !== null) meta.functions.push(child);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// RETURNS
|
|
88
|
-
return meta;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function _Get_prototype_entries(creator: any): Array<[string, unknown]> {
|
|
92
|
-
const keyList = Object.getOwnPropertyNames(creator.prototype);
|
|
93
|
-
const entries: Array<[string, unknown]> = keyList.map((key) => [
|
|
94
|
-
key,
|
|
95
|
-
creator.prototype[key],
|
|
96
|
-
]);
|
|
97
|
-
|
|
98
|
-
const parent = Object.getPrototypeOf(creator);
|
|
99
|
-
if (parent.prototype !== undefined)
|
|
100
|
-
entries.push(..._Get_prototype_entries(parent));
|
|
101
|
-
|
|
102
|
-
return entries;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function _Get_paths(value: string | string[]): string[] {
|
|
106
|
-
if (typeof value === "string") return [value];
|
|
107
|
-
else if (value.length === 0) return [""];
|
|
108
|
-
else return value;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/* ---------------------------------------------------------
|
|
112
|
-
FUNCTION
|
|
113
|
-
--------------------------------------------------------- */
|
|
114
|
-
function _Analyze_function(
|
|
115
|
-
classProto: any,
|
|
116
|
-
controller: IController,
|
|
117
|
-
name: string,
|
|
118
|
-
proto: any,
|
|
119
|
-
): IController.IFunction | null {
|
|
120
|
-
//----
|
|
121
|
-
// VALIDATIONS
|
|
122
|
-
//----
|
|
123
|
-
// MUST BE TYPE OF A FUNCTION
|
|
124
|
-
if (!(proto instanceof Function)) return null;
|
|
125
|
-
// MUST HAVE THOSE METADATE
|
|
126
|
-
else if (
|
|
127
|
-
ArrayUtil.has(Reflect.getMetadataKeys(proto), "path", "method") ===
|
|
128
|
-
false
|
|
129
|
-
)
|
|
130
|
-
return null;
|
|
131
|
-
|
|
132
|
-
//----
|
|
133
|
-
// CONSTRUCTION
|
|
134
|
-
//----
|
|
135
|
-
// BASIC INFO
|
|
136
|
-
const meta: IController.IFunction = {
|
|
137
|
-
name,
|
|
138
|
-
method: METHODS[Reflect.getMetadata("method", proto)],
|
|
139
|
-
paths: _Get_paths(Reflect.getMetadata("path", proto)),
|
|
140
|
-
parameters: [],
|
|
141
|
-
encrypted:
|
|
142
|
-
Reflect.hasMetadata("__interceptors__", proto) &&
|
|
143
|
-
Reflect.getMetadata("__interceptors__", proto)[0]?.constructor
|
|
144
|
-
?.name === "EncryptedRouteInterceptor",
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
// PARSE CHILDREN DATA
|
|
148
|
-
const nestParameters: NestParameters | undefined = Reflect.getMetadata(
|
|
149
|
-
"__routeArguments__",
|
|
150
|
-
classProto.constructor,
|
|
151
|
-
name,
|
|
152
|
-
);
|
|
153
|
-
if (nestParameters === undefined) meta.parameters = [];
|
|
154
|
-
else {
|
|
155
|
-
for (const tuple of Object.entries(nestParameters)) {
|
|
156
|
-
const child: IController.IParameter | null = _Analyze_parameter(
|
|
157
|
-
...tuple,
|
|
158
|
-
);
|
|
159
|
-
if (child !== null) meta.parameters.push(child);
|
|
160
|
-
}
|
|
161
|
-
meta.parameters = meta.parameters.sort((x, y) => x.index - y.index);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// VALIDATE PATH ARGUMENTS
|
|
165
|
-
for (const controllerLocation of controller.paths)
|
|
166
|
-
for (const metaLocation of meta.paths) {
|
|
167
|
-
// NORMALIZE LOCATION
|
|
168
|
-
const location: string = PathAnalyzer.join(
|
|
169
|
-
controllerLocation,
|
|
170
|
-
metaLocation,
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
// LIST UP PARAMETERS
|
|
174
|
-
const binded: string[] = PathAnalyzer.parameters(
|
|
175
|
-
location,
|
|
176
|
-
() => `${controller.name}.${name}()`,
|
|
177
|
-
).sort();
|
|
178
|
-
|
|
179
|
-
const parameters: string[] = meta.parameters
|
|
180
|
-
.filter((param) => param.category === "param")
|
|
181
|
-
.map((param) => param.field!)
|
|
182
|
-
.sort();
|
|
183
|
-
|
|
184
|
-
// DO VALIDATE
|
|
185
|
-
if (equal(binded, parameters) === false)
|
|
186
|
-
throw new Error(
|
|
187
|
-
`Error on ${
|
|
188
|
-
controller.name
|
|
189
|
-
}.${name}(): binded arguments in the "path" between function's decorator and parameters' decorators are different (function: [${binded.join(
|
|
190
|
-
", ",
|
|
191
|
-
)}], parameters: [${parameters.join(", ")}])`,
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// RETURNS
|
|
196
|
-
return meta;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH"];
|
|
200
|
-
|
|
201
|
-
/* ---------------------------------------------------------
|
|
202
|
-
PARAMETER
|
|
203
|
-
--------------------------------------------------------- */
|
|
204
|
-
function _Analyze_parameter(
|
|
205
|
-
key: string,
|
|
206
|
-
param: INestParam,
|
|
207
|
-
): IController.IParameter | null {
|
|
208
|
-
const symbol: string = key.split(":")[0];
|
|
209
|
-
if (symbol.indexOf("__custom") !== -1)
|
|
210
|
-
return _Analyze_custom_parameter(param);
|
|
211
|
-
|
|
212
|
-
const typeIndex: number = Number(symbol[0]);
|
|
213
|
-
if (isNaN(typeIndex) === true) return null;
|
|
214
|
-
|
|
215
|
-
const type: ParamCategory | undefined = NEST_PARAMETER_TYPES[typeIndex];
|
|
216
|
-
if (type === undefined) return null;
|
|
217
|
-
|
|
218
|
-
return {
|
|
219
|
-
name: key,
|
|
220
|
-
category: type,
|
|
221
|
-
index: param.index,
|
|
222
|
-
field: param.data,
|
|
223
|
-
encrypted: false,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function _Analyze_custom_parameter(
|
|
228
|
-
param: INestParam,
|
|
229
|
-
): IController.IParameter | null {
|
|
230
|
-
if (param.factory === undefined) return null;
|
|
231
|
-
else if (
|
|
232
|
-
param.factory.name === "TypedBody" ||
|
|
233
|
-
param.factory.name === "EncryptedBody" ||
|
|
234
|
-
param.factory.name === "PlainBody"
|
|
235
|
-
) {
|
|
236
|
-
return {
|
|
237
|
-
category: "body",
|
|
238
|
-
index: param.index,
|
|
239
|
-
name: param.name,
|
|
240
|
-
field: param.data,
|
|
241
|
-
encrypted: param.factory.name === "EncryptedBody",
|
|
242
|
-
};
|
|
243
|
-
} else if (param.factory.name === "TypedParam")
|
|
244
|
-
return {
|
|
245
|
-
name: param.name,
|
|
246
|
-
category: "param",
|
|
247
|
-
index: param.index,
|
|
248
|
-
field: param.data,
|
|
249
|
-
encrypted: false,
|
|
250
|
-
};
|
|
251
|
-
else return null;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
type NestParameters = {
|
|
255
|
-
[key: string]: INestParam;
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
interface INestParam {
|
|
259
|
-
name: string;
|
|
260
|
-
index: number;
|
|
261
|
-
factory?: (...args: any) => any;
|
|
262
|
-
data: string | undefined;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const NEST_PARAMETER_TYPES = [
|
|
266
|
-
undefined,
|
|
267
|
-
undefined,
|
|
268
|
-
undefined,
|
|
269
|
-
"body",
|
|
270
|
-
"query",
|
|
271
|
-
"param",
|
|
272
|
-
undefined,
|
|
273
|
-
undefined,
|
|
274
|
-
undefined,
|
|
275
|
-
undefined,
|
|
276
|
-
undefined,
|
|
277
|
-
undefined,
|
|
278
|
-
] as const;
|
|
279
|
-
}
|
|
1
|
+
import { equal } from "tstl/ranges/module";
|
|
2
|
+
|
|
3
|
+
import { IController } from "../structures/IController";
|
|
4
|
+
import { ParamCategory } from "../structures/ParamCategory";
|
|
5
|
+
import { ArrayUtil } from "../utils/ArrayUtil";
|
|
6
|
+
import { PathAnalyzer } from "./PathAnalyzer";
|
|
7
|
+
|
|
8
|
+
type IModule = {
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export namespace ReflectAnalyzer {
|
|
13
|
+
export async function analyze(
|
|
14
|
+
unique: WeakSet<any>,
|
|
15
|
+
file: string,
|
|
16
|
+
): Promise<IController[]> {
|
|
17
|
+
const module: IModule = await import(file);
|
|
18
|
+
const ret: IController[] = [];
|
|
19
|
+
|
|
20
|
+
for (const tuple of Object.entries(module)) {
|
|
21
|
+
if (unique.has(tuple[1])) continue;
|
|
22
|
+
else unique.add(tuple[1]);
|
|
23
|
+
|
|
24
|
+
const controller: IController | null = _Analyze_controller(
|
|
25
|
+
file,
|
|
26
|
+
...tuple,
|
|
27
|
+
);
|
|
28
|
+
if (controller !== null) ret.push(controller);
|
|
29
|
+
}
|
|
30
|
+
return ret;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* ---------------------------------------------------------
|
|
34
|
+
CONTROLLER
|
|
35
|
+
--------------------------------------------------------- */
|
|
36
|
+
function _Analyze_controller(
|
|
37
|
+
file: string,
|
|
38
|
+
name: string,
|
|
39
|
+
creator: any,
|
|
40
|
+
): IController | null {
|
|
41
|
+
//----
|
|
42
|
+
// VALIDATIONS
|
|
43
|
+
//----
|
|
44
|
+
// MUST BE TYPE OF A CREATOR WHO HAS THE CONSTRUCTOR
|
|
45
|
+
if (
|
|
46
|
+
!(
|
|
47
|
+
creator instanceof Function &&
|
|
48
|
+
creator.constructor instanceof Function
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
return null;
|
|
52
|
+
// MUST HAVE THOSE MATADATA
|
|
53
|
+
else if (
|
|
54
|
+
ArrayUtil.has(
|
|
55
|
+
Reflect.getMetadataKeys(creator),
|
|
56
|
+
"path",
|
|
57
|
+
"host",
|
|
58
|
+
"scope:options",
|
|
59
|
+
) === false
|
|
60
|
+
)
|
|
61
|
+
return null;
|
|
62
|
+
|
|
63
|
+
//----
|
|
64
|
+
// CONSTRUCTION
|
|
65
|
+
//----
|
|
66
|
+
// BASIC INFO
|
|
67
|
+
const paths: string[] = _Get_paths(
|
|
68
|
+
Reflect.getMetadata("path", creator),
|
|
69
|
+
);
|
|
70
|
+
const meta: IController = {
|
|
71
|
+
file,
|
|
72
|
+
name,
|
|
73
|
+
paths,
|
|
74
|
+
functions: [],
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// PARSE CHILDREN DATA
|
|
78
|
+
for (const tuple of _Get_prototype_entries(creator)) {
|
|
79
|
+
const child: IController.IFunction | null = _Analyze_function(
|
|
80
|
+
creator.prototype,
|
|
81
|
+
meta,
|
|
82
|
+
...tuple,
|
|
83
|
+
);
|
|
84
|
+
if (child !== null) meta.functions.push(child);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// RETURNS
|
|
88
|
+
return meta;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function _Get_prototype_entries(creator: any): Array<[string, unknown]> {
|
|
92
|
+
const keyList = Object.getOwnPropertyNames(creator.prototype);
|
|
93
|
+
const entries: Array<[string, unknown]> = keyList.map((key) => [
|
|
94
|
+
key,
|
|
95
|
+
creator.prototype[key],
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
const parent = Object.getPrototypeOf(creator);
|
|
99
|
+
if (parent.prototype !== undefined)
|
|
100
|
+
entries.push(..._Get_prototype_entries(parent));
|
|
101
|
+
|
|
102
|
+
return entries;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function _Get_paths(value: string | string[]): string[] {
|
|
106
|
+
if (typeof value === "string") return [value];
|
|
107
|
+
else if (value.length === 0) return [""];
|
|
108
|
+
else return value;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* ---------------------------------------------------------
|
|
112
|
+
FUNCTION
|
|
113
|
+
--------------------------------------------------------- */
|
|
114
|
+
function _Analyze_function(
|
|
115
|
+
classProto: any,
|
|
116
|
+
controller: IController,
|
|
117
|
+
name: string,
|
|
118
|
+
proto: any,
|
|
119
|
+
): IController.IFunction | null {
|
|
120
|
+
//----
|
|
121
|
+
// VALIDATIONS
|
|
122
|
+
//----
|
|
123
|
+
// MUST BE TYPE OF A FUNCTION
|
|
124
|
+
if (!(proto instanceof Function)) return null;
|
|
125
|
+
// MUST HAVE THOSE METADATE
|
|
126
|
+
else if (
|
|
127
|
+
ArrayUtil.has(Reflect.getMetadataKeys(proto), "path", "method") ===
|
|
128
|
+
false
|
|
129
|
+
)
|
|
130
|
+
return null;
|
|
131
|
+
|
|
132
|
+
//----
|
|
133
|
+
// CONSTRUCTION
|
|
134
|
+
//----
|
|
135
|
+
// BASIC INFO
|
|
136
|
+
const meta: IController.IFunction = {
|
|
137
|
+
name,
|
|
138
|
+
method: METHODS[Reflect.getMetadata("method", proto)],
|
|
139
|
+
paths: _Get_paths(Reflect.getMetadata("path", proto)),
|
|
140
|
+
parameters: [],
|
|
141
|
+
encrypted:
|
|
142
|
+
Reflect.hasMetadata("__interceptors__", proto) &&
|
|
143
|
+
Reflect.getMetadata("__interceptors__", proto)[0]?.constructor
|
|
144
|
+
?.name === "EncryptedRouteInterceptor",
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// PARSE CHILDREN DATA
|
|
148
|
+
const nestParameters: NestParameters | undefined = Reflect.getMetadata(
|
|
149
|
+
"__routeArguments__",
|
|
150
|
+
classProto.constructor,
|
|
151
|
+
name,
|
|
152
|
+
);
|
|
153
|
+
if (nestParameters === undefined) meta.parameters = [];
|
|
154
|
+
else {
|
|
155
|
+
for (const tuple of Object.entries(nestParameters)) {
|
|
156
|
+
const child: IController.IParameter | null = _Analyze_parameter(
|
|
157
|
+
...tuple,
|
|
158
|
+
);
|
|
159
|
+
if (child !== null) meta.parameters.push(child);
|
|
160
|
+
}
|
|
161
|
+
meta.parameters = meta.parameters.sort((x, y) => x.index - y.index);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// VALIDATE PATH ARGUMENTS
|
|
165
|
+
for (const controllerLocation of controller.paths)
|
|
166
|
+
for (const metaLocation of meta.paths) {
|
|
167
|
+
// NORMALIZE LOCATION
|
|
168
|
+
const location: string = PathAnalyzer.join(
|
|
169
|
+
controllerLocation,
|
|
170
|
+
metaLocation,
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
// LIST UP PARAMETERS
|
|
174
|
+
const binded: string[] = PathAnalyzer.parameters(
|
|
175
|
+
location,
|
|
176
|
+
() => `${controller.name}.${name}()`,
|
|
177
|
+
).sort();
|
|
178
|
+
|
|
179
|
+
const parameters: string[] = meta.parameters
|
|
180
|
+
.filter((param) => param.category === "param")
|
|
181
|
+
.map((param) => param.field!)
|
|
182
|
+
.sort();
|
|
183
|
+
|
|
184
|
+
// DO VALIDATE
|
|
185
|
+
if (equal(binded, parameters) === false)
|
|
186
|
+
throw new Error(
|
|
187
|
+
`Error on ${
|
|
188
|
+
controller.name
|
|
189
|
+
}.${name}(): binded arguments in the "path" between function's decorator and parameters' decorators are different (function: [${binded.join(
|
|
190
|
+
", ",
|
|
191
|
+
)}], parameters: [${parameters.join(", ")}])`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// RETURNS
|
|
196
|
+
return meta;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH"];
|
|
200
|
+
|
|
201
|
+
/* ---------------------------------------------------------
|
|
202
|
+
PARAMETER
|
|
203
|
+
--------------------------------------------------------- */
|
|
204
|
+
function _Analyze_parameter(
|
|
205
|
+
key: string,
|
|
206
|
+
param: INestParam,
|
|
207
|
+
): IController.IParameter | null {
|
|
208
|
+
const symbol: string = key.split(":")[0];
|
|
209
|
+
if (symbol.indexOf("__custom") !== -1)
|
|
210
|
+
return _Analyze_custom_parameter(param);
|
|
211
|
+
|
|
212
|
+
const typeIndex: number = Number(symbol[0]);
|
|
213
|
+
if (isNaN(typeIndex) === true) return null;
|
|
214
|
+
|
|
215
|
+
const type: ParamCategory | undefined = NEST_PARAMETER_TYPES[typeIndex];
|
|
216
|
+
if (type === undefined) return null;
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
name: key,
|
|
220
|
+
category: type,
|
|
221
|
+
index: param.index,
|
|
222
|
+
field: param.data,
|
|
223
|
+
encrypted: false,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function _Analyze_custom_parameter(
|
|
228
|
+
param: INestParam,
|
|
229
|
+
): IController.IParameter | null {
|
|
230
|
+
if (param.factory === undefined) return null;
|
|
231
|
+
else if (
|
|
232
|
+
param.factory.name === "TypedBody" ||
|
|
233
|
+
param.factory.name === "EncryptedBody" ||
|
|
234
|
+
param.factory.name === "PlainBody"
|
|
235
|
+
) {
|
|
236
|
+
return {
|
|
237
|
+
category: "body",
|
|
238
|
+
index: param.index,
|
|
239
|
+
name: param.name,
|
|
240
|
+
field: param.data,
|
|
241
|
+
encrypted: param.factory.name === "EncryptedBody",
|
|
242
|
+
};
|
|
243
|
+
} else if (param.factory.name === "TypedParam")
|
|
244
|
+
return {
|
|
245
|
+
name: param.name,
|
|
246
|
+
category: "param",
|
|
247
|
+
index: param.index,
|
|
248
|
+
field: param.data,
|
|
249
|
+
encrypted: false,
|
|
250
|
+
};
|
|
251
|
+
else return null;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
type NestParameters = {
|
|
255
|
+
[key: string]: INestParam;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
interface INestParam {
|
|
259
|
+
name: string;
|
|
260
|
+
index: number;
|
|
261
|
+
factory?: (...args: any) => any;
|
|
262
|
+
data: string | undefined;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const NEST_PARAMETER_TYPES = [
|
|
266
|
+
undefined,
|
|
267
|
+
undefined,
|
|
268
|
+
undefined,
|
|
269
|
+
"body",
|
|
270
|
+
"query",
|
|
271
|
+
"param",
|
|
272
|
+
undefined,
|
|
273
|
+
undefined,
|
|
274
|
+
undefined,
|
|
275
|
+
undefined,
|
|
276
|
+
undefined,
|
|
277
|
+
undefined,
|
|
278
|
+
] as const;
|
|
279
|
+
}
|
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import glob from "glob";
|
|
3
|
-
import path from "path";
|
|
4
|
-
|
|
5
|
-
import { INestiaConfig } from "../INestiaConfig";
|
|
6
|
-
|
|
7
|
-
export namespace SourceFinder {
|
|
8
|
-
export async function find(input: INestiaConfig.IInput): Promise<string[]> {
|
|
9
|
-
const dict: Set<string> = new Set();
|
|
10
|
-
|
|
11
|
-
await decode(input.include, (str) => dict.add(str));
|
|
12
|
-
if (input.exclude)
|
|
13
|
-
await decode(input.exclude, (str) => dict.delete(str));
|
|
14
|
-
|
|
15
|
-
return [...dict];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async function decode(
|
|
19
|
-
input: string[],
|
|
20
|
-
closure: (location: string) => void,
|
|
21
|
-
): Promise<void> {
|
|
22
|
-
for (const pattern of input) {
|
|
23
|
-
for (const location of await _Glob(path.resolve(pattern))) {
|
|
24
|
-
const stats: fs.Stats = await fs.promises.stat(location);
|
|
25
|
-
if (stats.isDirectory() === true)
|
|
26
|
-
await iterate(closure, location);
|
|
27
|
-
else if (stats.isFile() && _Is_ts_file(location))
|
|
28
|
-
closure(location);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function iterate(
|
|
34
|
-
closure: (location: string) => void,
|
|
35
|
-
location: string,
|
|
36
|
-
): Promise<void> {
|
|
37
|
-
const directory: string[] = await fs.promises.readdir(location);
|
|
38
|
-
for (const file of directory) {
|
|
39
|
-
const next: string = path.resolve(`${location}/${file}`);
|
|
40
|
-
const stats: fs.Stats = await fs.promises.stat(next);
|
|
41
|
-
|
|
42
|
-
if (stats.isDirectory() === true) await iterate(closure, next);
|
|
43
|
-
else if (stats.isFile() && _Is_ts_file(file)) closure(next);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function _Glob(pattern: string): Promise<string[]> {
|
|
48
|
-
return new Promise((resolve, reject) => {
|
|
49
|
-
glob(pattern, (err, matches) => {
|
|
50
|
-
if (err) reject(err);
|
|
51
|
-
else resolve(matches.map((str) => path.resolve(str)));
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function _Is_ts_file(file: string): boolean {
|
|
57
|
-
return file.substr(-3) === ".ts" && file.substr(-5) !== ".d.ts";
|
|
58
|
-
}
|
|
59
|
-
}
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import glob from "glob";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
import { INestiaConfig } from "../INestiaConfig";
|
|
6
|
+
|
|
7
|
+
export namespace SourceFinder {
|
|
8
|
+
export async function find(input: INestiaConfig.IInput): Promise<string[]> {
|
|
9
|
+
const dict: Set<string> = new Set();
|
|
10
|
+
|
|
11
|
+
await decode(input.include, (str) => dict.add(str));
|
|
12
|
+
if (input.exclude)
|
|
13
|
+
await decode(input.exclude, (str) => dict.delete(str));
|
|
14
|
+
|
|
15
|
+
return [...dict];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function decode(
|
|
19
|
+
input: string[],
|
|
20
|
+
closure: (location: string) => void,
|
|
21
|
+
): Promise<void> {
|
|
22
|
+
for (const pattern of input) {
|
|
23
|
+
for (const location of await _Glob(path.resolve(pattern))) {
|
|
24
|
+
const stats: fs.Stats = await fs.promises.stat(location);
|
|
25
|
+
if (stats.isDirectory() === true)
|
|
26
|
+
await iterate(closure, location);
|
|
27
|
+
else if (stats.isFile() && _Is_ts_file(location))
|
|
28
|
+
closure(location);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function iterate(
|
|
34
|
+
closure: (location: string) => void,
|
|
35
|
+
location: string,
|
|
36
|
+
): Promise<void> {
|
|
37
|
+
const directory: string[] = await fs.promises.readdir(location);
|
|
38
|
+
for (const file of directory) {
|
|
39
|
+
const next: string = path.resolve(`${location}/${file}`);
|
|
40
|
+
const stats: fs.Stats = await fs.promises.stat(next);
|
|
41
|
+
|
|
42
|
+
if (stats.isDirectory() === true) await iterate(closure, next);
|
|
43
|
+
else if (stats.isFile() && _Is_ts_file(file)) closure(next);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function _Glob(pattern: string): Promise<string[]> {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
glob(pattern, (err, matches) => {
|
|
50
|
+
if (err) reject(err);
|
|
51
|
+
else resolve(matches.map((str) => path.resolve(str)));
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function _Is_ts_file(file: string): boolean {
|
|
57
|
+
return file.substr(-3) === ".ts" && file.substr(-5) !== ".d.ts";
|
|
58
|
+
}
|
|
59
|
+
}
|