@nestia/sdk 2.4.2 → 2.4.3

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.
Files changed (111) hide show
  1. package/lib/NestiaSdkApplication.js +2 -6
  2. package/lib/NestiaSdkApplication.js.map +1 -1
  3. package/lib/analyses/AccessorAnalyzer.js.map +1 -1
  4. package/lib/analyses/ConfigAnalyzer.js +4 -8
  5. package/lib/analyses/ConfigAnalyzer.js.map +1 -1
  6. package/lib/analyses/ControllerAnalyzer.js +6 -8
  7. package/lib/analyses/ControllerAnalyzer.js.map +1 -1
  8. package/lib/analyses/ExceptionAnalyzer.js.map +1 -1
  9. package/lib/analyses/GenericAnalyzer.js +1 -2
  10. package/lib/analyses/GenericAnalyzer.js.map +1 -1
  11. package/lib/analyses/ImportAnalyzer.js +4 -4
  12. package/lib/analyses/ImportAnalyzer.js.map +1 -1
  13. package/lib/analyses/PathAnalyzer.js.map +1 -1
  14. package/lib/analyses/ReflectAnalyzer.js +7 -8
  15. package/lib/analyses/ReflectAnalyzer.js.map +1 -1
  16. package/lib/analyses/SecurityAnalyzer.js.map +1 -1
  17. package/lib/executable/internal/CommandParser.js.map +1 -1
  18. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  19. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  20. package/lib/executable/sdk.js +11 -11
  21. package/lib/executable/sdk.js.map +1 -1
  22. package/lib/generates/E2eGenerator.js.map +1 -1
  23. package/lib/generates/SdkGenerator.js.map +1 -1
  24. package/lib/generates/SwaggerGenerator.js +5 -11
  25. package/lib/generates/SwaggerGenerator.js.map +1 -1
  26. package/lib/generates/internal/E2eFileProgrammer.js +2 -8
  27. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  28. package/lib/generates/internal/SdkDistributionComposer.js.map +1 -1
  29. package/lib/generates/internal/SdkDtoGenerator.js +3 -9
  30. package/lib/generates/internal/SdkDtoGenerator.js.map +1 -1
  31. package/lib/generates/internal/SdkFileProgrammer.js +4 -4
  32. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  33. package/lib/generates/internal/SdkFunctionProgrammer.js +12 -20
  34. package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -1
  35. package/lib/generates/internal/SdkImportWizard.js.map +1 -1
  36. package/lib/generates/internal/SdkRouteDirectory.js +1 -3
  37. package/lib/generates/internal/SdkRouteDirectory.js.map +1 -1
  38. package/lib/generates/internal/SdkSimulationProgrammer.js +5 -7
  39. package/lib/generates/internal/SdkSimulationProgrammer.js.map +1 -1
  40. package/lib/generates/internal/SdkTypeDefiner.js +2 -5
  41. package/lib/generates/internal/SdkTypeDefiner.js.map +1 -1
  42. package/lib/generates/internal/SwaggerSchemaGenerator.js +29 -44
  43. package/lib/generates/internal/SwaggerSchemaGenerator.js.map +1 -1
  44. package/lib/generates/internal/SwaggerSchemaValidator.js +3 -9
  45. package/lib/generates/internal/SwaggerSchemaValidator.js.map +1 -1
  46. package/lib/structures/MethodType.js +1 -7
  47. package/lib/structures/MethodType.js.map +1 -1
  48. package/lib/structures/TypeEntry.js.map +1 -1
  49. package/lib/utils/ArrayUtil.js.map +1 -1
  50. package/lib/utils/FileRetriever.js.map +1 -1
  51. package/lib/utils/ImportDictionary.js +1 -4
  52. package/lib/utils/ImportDictionary.js.map +1 -1
  53. package/lib/utils/MapUtil.js.map +1 -1
  54. package/lib/utils/PathUtil.js.map +1 -1
  55. package/lib/utils/SourceFinder.js.map +1 -1
  56. package/package.json +4 -7
  57. package/src/INestiaConfig.ts +234 -234
  58. package/src/NestiaSdkApplication.ts +253 -268
  59. package/src/analyses/AccessorAnalyzer.ts +60 -60
  60. package/src/analyses/ConfigAnalyzer.ts +147 -164
  61. package/src/analyses/ControllerAnalyzer.ts +379 -399
  62. package/src/analyses/ExceptionAnalyzer.ts +115 -124
  63. package/src/analyses/GenericAnalyzer.ts +51 -57
  64. package/src/analyses/ImportAnalyzer.ts +138 -159
  65. package/src/analyses/PathAnalyzer.ts +98 -100
  66. package/src/analyses/ReflectAnalyzer.ts +425 -433
  67. package/src/analyses/SecurityAnalyzer.ts +20 -20
  68. package/src/executable/internal/CommandParser.ts +15 -15
  69. package/src/executable/internal/NestiaConfigLoader.ts +67 -68
  70. package/src/executable/internal/NestiaSdkCommand.ts +60 -64
  71. package/src/executable/sdk.ts +73 -73
  72. package/src/generates/E2eGenerator.ts +64 -67
  73. package/src/generates/SdkGenerator.ts +96 -100
  74. package/src/generates/SwaggerGenerator.ts +372 -410
  75. package/src/generates/internal/E2eFileProgrammer.ts +123 -129
  76. package/src/generates/internal/SdkDistributionComposer.ts +91 -91
  77. package/src/generates/internal/SdkDtoGenerator.ts +424 -450
  78. package/src/generates/internal/SdkFileProgrammer.ts +106 -111
  79. package/src/generates/internal/SdkFunctionProgrammer.ts +466 -501
  80. package/src/generates/internal/SdkImportWizard.ts +55 -55
  81. package/src/generates/internal/SdkRouteDirectory.ts +17 -19
  82. package/src/generates/internal/SdkSimulationProgrammer.ts +133 -142
  83. package/src/generates/internal/SdkTypeDefiner.ts +119 -124
  84. package/src/generates/internal/SwaggerSchemaGenerator.ts +382 -401
  85. package/src/generates/internal/SwaggerSchemaValidator.ts +198 -210
  86. package/src/index.ts +4 -4
  87. package/src/module.ts +2 -2
  88. package/src/structures/IController.ts +79 -81
  89. package/src/structures/IErrorReport.ts +6 -6
  90. package/src/structures/INestiaProject.ts +13 -13
  91. package/src/structures/INormalizedInput.ts +20 -20
  92. package/src/structures/IRoute.ts +40 -41
  93. package/src/structures/ISwagger.ts +91 -91
  94. package/src/structures/ISwaggerComponents.ts +29 -29
  95. package/src/structures/ISwaggerError.ts +8 -8
  96. package/src/structures/ISwaggerInfo.ts +80 -80
  97. package/src/structures/ISwaggerLazyProperty.ts +7 -7
  98. package/src/structures/ISwaggerLazySchema.ts +7 -7
  99. package/src/structures/ISwaggerRoute.ts +51 -51
  100. package/src/structures/ISwaggerSecurityScheme.ts +65 -65
  101. package/src/structures/ITypeTuple.ts +6 -6
  102. package/src/structures/MethodType.ts +5 -11
  103. package/src/structures/ParamCategory.ts +1 -1
  104. package/src/structures/TypeEntry.ts +22 -22
  105. package/src/utils/ArrayUtil.ts +26 -26
  106. package/src/utils/FileRetriever.ts +22 -22
  107. package/src/utils/ImportDictionary.ts +125 -128
  108. package/src/utils/MapUtil.ts +14 -14
  109. package/src/utils/PathUtil.ts +10 -10
  110. package/src/utils/SourceFinder.ts +66 -70
  111. package/src/utils/StripEnums.ts +5 -10
@@ -12,456 +12,448 @@ import { PathAnalyzer } from "./PathAnalyzer";
12
12
  import { SecurityAnalyzer } from "./SecurityAnalyzer";
13
13
 
14
14
  type IModule = {
15
- [key: string]: any;
15
+ [key: string]: any;
16
16
  };
17
17
 
18
18
  export namespace ReflectAnalyzer {
19
- export const analyze =
20
- (project: INestiaProject) =>
21
- async (
22
- unique: WeakSet<any>,
23
- file: string,
24
- prefixes: string[],
25
- target?: Function,
26
- ): Promise<IController[]> => {
27
- const module: IModule = await (async () => {
28
- try {
29
- return await import(file);
30
- } catch (exp) {
31
- console.log(
32
- ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
33
- );
34
- console.log(`Error on "${file}" file. Check your code.`);
35
- console.log(exp);
36
- console.log(
37
- ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
38
- );
39
- process.exit(-1);
40
- }
41
- })();
42
- const ret: IController[] = [];
43
-
44
- for (const [key, value] of Object.entries(module)) {
45
- if (typeof value !== "function" || unique.has(value)) continue;
46
- else if ((target ?? value) !== value) continue;
47
- else unique.add(value);
48
-
49
- const result: IController | null = _Analyze_controller(project)(
50
- file,
51
- key,
52
- value,
53
- prefixes,
54
- );
55
- if (result !== null) ret.push(result);
56
- }
57
- return ret;
58
- };
59
-
60
- /* ---------------------------------------------------------
19
+ export const analyze =
20
+ (project: INestiaProject) =>
21
+ async (
22
+ unique: WeakSet<any>,
23
+ file: string,
24
+ prefixes: string[],
25
+ target?: Function,
26
+ ): Promise<IController[]> => {
27
+ const module: IModule = await (async () => {
28
+ try {
29
+ return await import(file);
30
+ } catch (exp) {
31
+ console.log(
32
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
33
+ );
34
+ console.log(`Error on "${file}" file. Check your code.`);
35
+ console.log(exp);
36
+ console.log(
37
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
38
+ );
39
+ process.exit(-1);
40
+ }
41
+ })();
42
+ const ret: IController[] = [];
43
+
44
+ for (const [key, value] of Object.entries(module)) {
45
+ if (typeof value !== "function" || unique.has(value)) continue;
46
+ else if ((target ?? value) !== value) continue;
47
+ else unique.add(value);
48
+
49
+ const result: IController | null = _Analyze_controller(project)(
50
+ file,
51
+ key,
52
+ value,
53
+ prefixes,
54
+ );
55
+ if (result !== null) ret.push(result);
56
+ }
57
+ return ret;
58
+ };
59
+
60
+ /* ---------------------------------------------------------
61
61
  CONTROLLER
62
62
  --------------------------------------------------------- */
63
- const _Analyze_controller =
64
- (project: INestiaProject) =>
65
- (
66
- file: string,
67
- name: string,
68
- creator: any,
69
- prefixes: string[],
70
- ): IController | null => {
71
- //----
72
- // VALIDATIONS
73
- //----
74
- // MUST BE TYPE OF A CREATOR WHO HAS THE CONSTRUCTOR
75
- if (
76
- !(
77
- creator instanceof Function &&
78
- creator.constructor instanceof Function
79
- )
80
- )
81
- return null;
82
- // MUST HAVE THOSE MATADATA
83
- else if (
84
- ArrayUtil.has(
85
- Reflect.getMetadataKeys(creator),
86
- Constants.PATH_METADATA,
87
- Constants.HOST_METADATA,
88
- Constants.SCOPE_OPTIONS_METADATA,
89
- ) === false
90
- )
91
- return null;
92
-
93
- //----
94
- // CONSTRUCTION
95
- //----
96
- // BASIC INFO
97
- const meta: IController = {
98
- file,
99
- name,
100
- functions: [],
101
- prefixes,
102
- paths: _Get_paths(creator).filter((str) => {
103
- if (str.includes("*") === true) {
104
- project.warnings.push({
105
- file,
106
- controller: name,
107
- function: null,
108
- message:
109
- "@nestia/sdk does not compose wildcard controller.",
110
- });
111
- return false;
112
- }
113
- return true;
114
- }),
115
- versions: _Get_versions(creator),
116
- security: _Get_securities(creator),
117
- swaggerTgas:
118
- Reflect.getMetadata("swagger/apiUseTags", creator) ?? [],
119
- };
120
-
121
- // PARSE CHILDREN DATA
122
- for (const tuple of _Get_prototype_entries(creator)) {
123
- const child: IController.IFunction | null = _Analyze_function(
124
- project,
125
- )(creator.prototype, meta, ...tuple);
126
- if (child !== null) meta.functions.push(child);
127
- }
128
-
129
- // RETURNS
130
- return meta;
131
- };
132
-
133
- function _Get_prototype_entries(creator: any): Array<[string, unknown]> {
134
- const keyList = Object.getOwnPropertyNames(creator.prototype);
135
- const entries: Array<[string, unknown]> = keyList.map((key) => [
136
- key,
137
- creator.prototype[key],
138
- ]);
139
-
140
- const parent = Object.getPrototypeOf(creator);
141
- if (parent.prototype !== undefined)
142
- entries.push(..._Get_prototype_entries(parent));
143
-
144
- return entries;
145
- }
146
-
147
- function _Get_paths(target: any): string[] {
148
- const value: string | string[] = Reflect.getMetadata(
149
- Constants.PATH_METADATA,
150
- target,
151
- );
152
- if (typeof value === "string") return [value];
153
- else if (value.length === 0) return [""];
154
- else return value;
155
- }
156
-
157
- function _Get_versions(
158
- target: any,
159
- ):
160
- | Array<Exclude<VersionValue, Array<string | typeof VERSION_NEUTRAL>>>
161
- | undefined {
162
- const value: VersionValue | undefined = Reflect.getMetadata(
163
- Constants.VERSION_METADATA,
164
- target,
63
+ const _Analyze_controller =
64
+ (project: INestiaProject) =>
65
+ (
66
+ file: string,
67
+ name: string,
68
+ creator: any,
69
+ prefixes: string[],
70
+ ): IController | null => {
71
+ //----
72
+ // VALIDATIONS
73
+ //----
74
+ // MUST BE TYPE OF A CREATOR WHO HAS THE CONSTRUCTOR
75
+ if (
76
+ !(
77
+ creator instanceof Function && creator.constructor instanceof Function
78
+ )
79
+ )
80
+ return null;
81
+ // MUST HAVE THOSE MATADATA
82
+ else if (
83
+ ArrayUtil.has(
84
+ Reflect.getMetadataKeys(creator),
85
+ Constants.PATH_METADATA,
86
+ Constants.HOST_METADATA,
87
+ Constants.SCOPE_OPTIONS_METADATA,
88
+ ) === false
89
+ )
90
+ return null;
91
+
92
+ //----
93
+ // CONSTRUCTION
94
+ //----
95
+ // BASIC INFO
96
+ const meta: IController = {
97
+ file,
98
+ name,
99
+ functions: [],
100
+ prefixes,
101
+ paths: _Get_paths(creator).filter((str) => {
102
+ if (str.includes("*") === true) {
103
+ project.warnings.push({
104
+ file,
105
+ controller: name,
106
+ function: null,
107
+ message: "@nestia/sdk does not compose wildcard controller.",
108
+ });
109
+ return false;
110
+ }
111
+ return true;
112
+ }),
113
+ versions: _Get_versions(creator),
114
+ security: _Get_securities(creator),
115
+ swaggerTgas: Reflect.getMetadata("swagger/apiUseTags", creator) ?? [],
116
+ };
117
+
118
+ // PARSE CHILDREN DATA
119
+ for (const tuple of _Get_prototype_entries(creator)) {
120
+ const child: IController.IFunction | null = _Analyze_function(project)(
121
+ creator.prototype,
122
+ meta,
123
+ ...tuple,
165
124
  );
166
- return value === undefined || Array.isArray(value) ? value : [value];
167
- }
168
-
169
- function _Get_securities(value: any): Record<string, string[]>[] {
170
- const entire: Record<string, string[]>[] | undefined =
171
- Reflect.getMetadata("swagger/apiSecurity", value);
172
- return entire ? SecurityAnalyzer.merge(...entire) : [];
173
- }
174
-
175
- function _Get_exceptions(
176
- value: any,
177
- ): Record<number | "2XX" | "3XX" | "4XX" | "5XX", IController.IException> {
178
- const entire: IController.IException[] | undefined =
179
- Reflect.getMetadata("nestia/TypedException", value);
180
- return Object.fromEntries(
181
- (entire ?? []).map((exp) => [exp.status, exp]),
182
- ) as Record<
183
- number | "2XX" | "3XX" | "4XX" | "5XX",
184
- IController.IException
185
- >;
186
- }
187
-
188
- /* ---------------------------------------------------------
125
+ if (child !== null) meta.functions.push(child);
126
+ }
127
+
128
+ // RETURNS
129
+ return meta;
130
+ };
131
+
132
+ function _Get_prototype_entries(creator: any): Array<[string, unknown]> {
133
+ const keyList = Object.getOwnPropertyNames(creator.prototype);
134
+ const entries: Array<[string, unknown]> = keyList.map((key) => [
135
+ key,
136
+ creator.prototype[key],
137
+ ]);
138
+
139
+ const parent = Object.getPrototypeOf(creator);
140
+ if (parent.prototype !== undefined)
141
+ entries.push(..._Get_prototype_entries(parent));
142
+
143
+ return entries;
144
+ }
145
+
146
+ function _Get_paths(target: any): string[] {
147
+ const value: string | string[] = Reflect.getMetadata(
148
+ Constants.PATH_METADATA,
149
+ target,
150
+ );
151
+ if (typeof value === "string") return [value];
152
+ else if (value.length === 0) return [""];
153
+ else return value;
154
+ }
155
+
156
+ function _Get_versions(
157
+ target: any,
158
+ ):
159
+ | Array<Exclude<VersionValue, Array<string | typeof VERSION_NEUTRAL>>>
160
+ | undefined {
161
+ const value: VersionValue | undefined = Reflect.getMetadata(
162
+ Constants.VERSION_METADATA,
163
+ target,
164
+ );
165
+ return value === undefined || Array.isArray(value) ? value : [value];
166
+ }
167
+
168
+ function _Get_securities(value: any): Record<string, string[]>[] {
169
+ const entire: Record<string, string[]>[] | undefined = Reflect.getMetadata(
170
+ "swagger/apiSecurity",
171
+ value,
172
+ );
173
+ return entire ? SecurityAnalyzer.merge(...entire) : [];
174
+ }
175
+
176
+ function _Get_exceptions(
177
+ value: any,
178
+ ): Record<number | "2XX" | "3XX" | "4XX" | "5XX", IController.IException> {
179
+ const entire: IController.IException[] | undefined = Reflect.getMetadata(
180
+ "nestia/TypedException",
181
+ value,
182
+ );
183
+ return Object.fromEntries(
184
+ (entire ?? []).map((exp) => [exp.status, exp]),
185
+ ) as Record<number | "2XX" | "3XX" | "4XX" | "5XX", IController.IException>;
186
+ }
187
+
188
+ /* ---------------------------------------------------------
189
189
  FUNCTION
190
190
  --------------------------------------------------------- */
191
- const _Analyze_function =
192
- (project: INestiaProject) =>
193
- (
194
- classProto: any,
195
- controller: IController,
196
- name: string,
197
- proto: any,
198
- ): IController.IFunction | null => {
199
- //----
200
- // VALIDATIONS
201
- //----
202
- // MUST BE TYPE OF A FUNCTION
203
- if (!(proto instanceof Function)) return null;
204
- // MUST HAVE THOSE METADATE
205
- else if (
206
- ArrayUtil.has(
207
- Reflect.getMetadataKeys(proto),
208
- Constants.PATH_METADATA,
209
- Constants.METHOD_METADATA,
210
- ) === false
211
- )
212
- return null;
213
-
214
- const errors: IErrorReport[] = [];
215
-
216
- //----
217
- // CONSTRUCTION
218
- //----
219
- // BASIC INFO
220
- const encrypted: boolean =
221
- Reflect.getMetadata(Constants.INTERCEPTORS_METADATA, proto)?.[0]
222
- ?.constructor?.name === "EncryptedRouteInterceptor";
223
- const query: boolean =
224
- Reflect.getMetadata(Constants.INTERCEPTORS_METADATA, proto)?.[0]
225
- ?.constructor?.name === "TypedQueryRouteInterceptor";
226
- const method: string =
227
- METHODS[Reflect.getMetadata(Constants.METHOD_METADATA, proto)];
228
- if (method === undefined || method === "OPTIONS") return null;
229
-
230
- const parameters: IController.IParameter[] = (() => {
231
- const nestParameters: NestParameters | undefined =
232
- Reflect.getMetadata(
233
- Constants.ROUTE_ARGS_METADATA,
234
- classProto.constructor,
235
- name,
236
- );
237
- if (nestParameters === undefined) return [];
238
-
239
- const output: IController.IParameter[] = [];
240
- for (const tuple of Object.entries(nestParameters)) {
241
- const child: IController.IParameter | null =
242
- _Analyze_parameter(...tuple);
243
- if (child !== null) output.push(child);
244
- }
245
- return output.sort((x, y) => x.index - y.index);
246
- })();
247
-
248
- // VALIDATE BODY
249
- const body: IController.IParameter | undefined = parameters.find(
250
- (param) => param.category === "body",
251
- );
252
- if (body !== undefined && (method === "GET" || method === "HEAD")) {
253
- project.errors.push({
254
- file: controller.file,
255
- controller: controller.name,
256
- function: name,
257
- message: `"body" parameter cannot be used in the "${method}" method.`,
258
- });
259
- return null;
260
- }
261
-
262
- // DO CONSTRUCT
263
- const meta: IController.IFunction = {
264
- name,
265
- method: method === "ALL" ? "POST" : method,
266
- paths: _Get_paths(proto).filter((str) => {
267
- if (str.includes("*") === true) {
268
- project.warnings.push({
269
- file: controller.file,
270
- controller: controller.name,
271
- function: name,
272
- message:
273
- "@nestia/sdk does not compose wildcard method.",
274
- });
275
- return false;
276
- }
277
- return true;
278
- }),
279
- versions: _Get_versions(proto),
280
- parameters,
281
- status: Reflect.getMetadata(
282
- Constants.HTTP_CODE_METADATA,
283
- proto,
284
- ),
285
- encrypted,
286
- contentType: encrypted
287
- ? "text/plain"
288
- : query
289
- ? "application/x-www-form-urlencoded"
290
- : Reflect.getMetadata(
291
- Constants.HEADERS_METADATA,
292
- proto,
293
- )?.find(
294
- (h: Record<string, string>) =>
295
- typeof h?.name === "string" &&
296
- typeof h?.value === "string" &&
297
- h.name.toLowerCase() === "content-type",
298
- )?.value ?? "application/json",
299
- security: _Get_securities(proto),
300
- exceptions: _Get_exceptions(proto),
301
- swaggerTags: [
302
- ...new Set([
303
- ...controller.swaggerTgas,
304
- ...(Reflect.getMetadata("swagger/apiUseTags", proto) ??
305
- []),
306
- ]),
307
- ],
308
- };
309
-
310
- // VALIDATE PATH ARGUMENTS
311
- for (const controllerLocation of controller.paths)
312
- for (const metaLocation of meta.paths) {
313
- // NORMALIZE LOCATION
314
- const location: string = PathAnalyzer.join(
315
- controllerLocation,
316
- metaLocation,
317
- );
318
- if (location.includes("*")) continue;
319
-
320
- // LIST UP PARAMETERS
321
- const binded: string[] = PathAnalyzer.parameters(
322
- location,
323
- () => `${controller.name}.${name}()`,
324
- ).sort();
325
-
326
- const parameters: string[] = meta.parameters
327
- .filter((param) => param.category === "param")
328
- .map((param) => param.field!)
329
- .sort();
330
-
331
- // DO VALIDATE
332
- if (equal(binded, parameters) === false)
333
- errors.push({
334
- file: controller.file,
335
- controller: controller.name,
336
- function: name,
337
- message: `binded arguments in the "path" between function's decorator and parameters' decorators are different (function: [${binded.join(
338
- ", ",
339
- )}], parameters: [${parameters.join(", ")}]).`,
340
- });
341
- }
342
-
343
- // RETURNS
344
- if (errors.length) {
345
- project.errors.push(...errors);
346
- return null;
347
- }
348
- return meta;
349
- };
350
-
351
- /* ---------------------------------------------------------
191
+ const _Analyze_function =
192
+ (project: INestiaProject) =>
193
+ (
194
+ classProto: any,
195
+ controller: IController,
196
+ name: string,
197
+ proto: any,
198
+ ): IController.IFunction | null => {
199
+ //----
200
+ // VALIDATIONS
201
+ //----
202
+ // MUST BE TYPE OF A FUNCTION
203
+ if (!(proto instanceof Function)) return null;
204
+ // MUST HAVE THOSE METADATE
205
+ else if (
206
+ ArrayUtil.has(
207
+ Reflect.getMetadataKeys(proto),
208
+ Constants.PATH_METADATA,
209
+ Constants.METHOD_METADATA,
210
+ ) === false
211
+ )
212
+ return null;
213
+
214
+ const errors: IErrorReport[] = [];
215
+
216
+ //----
217
+ // CONSTRUCTION
218
+ //----
219
+ // BASIC INFO
220
+ const encrypted: boolean =
221
+ Reflect.getMetadata(Constants.INTERCEPTORS_METADATA, proto)?.[0]
222
+ ?.constructor?.name === "EncryptedRouteInterceptor";
223
+ const query: boolean =
224
+ Reflect.getMetadata(Constants.INTERCEPTORS_METADATA, proto)?.[0]
225
+ ?.constructor?.name === "TypedQueryRouteInterceptor";
226
+ const method: string =
227
+ METHODS[Reflect.getMetadata(Constants.METHOD_METADATA, proto)];
228
+ if (method === undefined || method === "OPTIONS") return null;
229
+
230
+ const parameters: IController.IParameter[] = (() => {
231
+ const nestParameters: NestParameters | undefined = Reflect.getMetadata(
232
+ Constants.ROUTE_ARGS_METADATA,
233
+ classProto.constructor,
234
+ name,
235
+ );
236
+ if (nestParameters === undefined) return [];
237
+
238
+ const output: IController.IParameter[] = [];
239
+ for (const tuple of Object.entries(nestParameters)) {
240
+ const child: IController.IParameter | null = _Analyze_parameter(
241
+ ...tuple,
242
+ );
243
+ if (child !== null) output.push(child);
244
+ }
245
+ return output.sort((x, y) => x.index - y.index);
246
+ })();
247
+
248
+ // VALIDATE BODY
249
+ const body: IController.IParameter | undefined = parameters.find(
250
+ (param) => param.category === "body",
251
+ );
252
+ if (body !== undefined && (method === "GET" || method === "HEAD")) {
253
+ project.errors.push({
254
+ file: controller.file,
255
+ controller: controller.name,
256
+ function: name,
257
+ message: `"body" parameter cannot be used in the "${method}" method.`,
258
+ });
259
+ return null;
260
+ }
261
+
262
+ // DO CONSTRUCT
263
+ const meta: IController.IFunction = {
264
+ name,
265
+ method: method === "ALL" ? "POST" : method,
266
+ paths: _Get_paths(proto).filter((str) => {
267
+ if (str.includes("*") === true) {
268
+ project.warnings.push({
269
+ file: controller.file,
270
+ controller: controller.name,
271
+ function: name,
272
+ message: "@nestia/sdk does not compose wildcard method.",
273
+ });
274
+ return false;
275
+ }
276
+ return true;
277
+ }),
278
+ versions: _Get_versions(proto),
279
+ parameters,
280
+ status: Reflect.getMetadata(Constants.HTTP_CODE_METADATA, proto),
281
+ encrypted,
282
+ contentType: encrypted
283
+ ? "text/plain"
284
+ : query
285
+ ? "application/x-www-form-urlencoded"
286
+ : Reflect.getMetadata(Constants.HEADERS_METADATA, proto)?.find(
287
+ (h: Record<string, string>) =>
288
+ typeof h?.name === "string" &&
289
+ typeof h?.value === "string" &&
290
+ h.name.toLowerCase() === "content-type",
291
+ )?.value ?? "application/json",
292
+ security: _Get_securities(proto),
293
+ exceptions: _Get_exceptions(proto),
294
+ swaggerTags: [
295
+ ...new Set([
296
+ ...controller.swaggerTgas,
297
+ ...(Reflect.getMetadata("swagger/apiUseTags", proto) ?? []),
298
+ ]),
299
+ ],
300
+ };
301
+
302
+ // VALIDATE PATH ARGUMENTS
303
+ for (const controllerLocation of controller.paths)
304
+ for (const metaLocation of meta.paths) {
305
+ // NORMALIZE LOCATION
306
+ const location: string = PathAnalyzer.join(
307
+ controllerLocation,
308
+ metaLocation,
309
+ );
310
+ if (location.includes("*")) continue;
311
+
312
+ // LIST UP PARAMETERS
313
+ const binded: string[] = PathAnalyzer.parameters(
314
+ location,
315
+ () => `${controller.name}.${name}()`,
316
+ ).sort();
317
+
318
+ const parameters: string[] = meta.parameters
319
+ .filter((param) => param.category === "param")
320
+ .map((param) => param.field!)
321
+ .sort();
322
+
323
+ // DO VALIDATE
324
+ if (equal(binded, parameters) === false)
325
+ errors.push({
326
+ file: controller.file,
327
+ controller: controller.name,
328
+ function: name,
329
+ message: `binded arguments in the "path" between function's decorator and parameters' decorators are different (function: [${binded.join(
330
+ ", ",
331
+ )}], parameters: [${parameters.join(", ")}]).`,
332
+ });
333
+ }
334
+
335
+ // RETURNS
336
+ if (errors.length) {
337
+ project.errors.push(...errors);
338
+ return null;
339
+ }
340
+ return meta;
341
+ };
342
+
343
+ /* ---------------------------------------------------------
352
344
  PARAMETER
353
345
  --------------------------------------------------------- */
354
- function _Analyze_parameter(
355
- key: string,
356
- param: INestParam,
357
- ): IController.IParameter | null {
358
- const symbol: string = key.split(":")[0];
359
- if (symbol.indexOf("__custom") !== -1)
360
- return _Analyze_custom_parameter(param);
361
-
362
- const typeIndex: number = Number(symbol[0]);
363
- if (isNaN(typeIndex) === true) return null;
364
-
365
- const type: ParamCategory | undefined = NEST_PARAMETER_TYPES[typeIndex];
366
- if (type === undefined) return null;
367
-
368
- return {
369
- custom: false,
370
- name: key,
371
- category: type,
372
- index: param.index,
373
- field: param.data,
374
- };
375
- }
376
-
377
- function _Analyze_custom_parameter(
378
- param: INestParam,
379
- ): IController.IParameter | null {
380
- if (param.factory === undefined) return null;
381
- else if (
382
- param.factory.name === "EncryptedBody" ||
383
- param.factory.name === "PlainBody" ||
384
- param.factory.name === "TypedQueryBody" ||
385
- param.factory.name === "TypedBody"
386
- )
387
- return {
388
- custom: true,
389
- category: "body",
390
- index: param.index,
391
- name: param.name,
392
- field: param.data,
393
- encrypted: param.factory.name === "EncryptedBody",
394
- contentType:
395
- param.factory.name === "PlainBody" ||
396
- param.factory.name === "EncryptedBody"
397
- ? "text/plain"
398
- : param.factory.name === "TypedQueryBody"
399
- ? "application/x-www-form-urlencoded"
400
- : "application/json",
401
- };
402
- else if (param.factory.name === "TypedHeaders")
403
- return {
404
- custom: true,
405
- category: "headers",
406
- name: param.name,
407
- index: param.index,
408
- field: param.data,
409
- };
410
- else if (param.factory.name === "TypedParam")
411
- return {
412
- custom: true,
413
- category: "param",
414
- name: param.name,
415
- index: param.index,
416
- field: param.data,
417
- };
418
- else if (param.factory.name === "TypedQuery")
419
- return {
420
- custom: true,
421
- name: param.name,
422
- category: "query",
423
- index: param.index,
424
- field: undefined,
425
- };
426
- else return null;
427
- }
428
-
429
- type NestParameters = {
430
- [key: string]: INestParam;
346
+ function _Analyze_parameter(
347
+ key: string,
348
+ param: INestParam,
349
+ ): IController.IParameter | null {
350
+ const symbol: string = key.split(":")[0];
351
+ if (symbol.indexOf("__custom") !== -1)
352
+ return _Analyze_custom_parameter(param);
353
+
354
+ const typeIndex: number = Number(symbol[0]);
355
+ if (isNaN(typeIndex) === true) return null;
356
+
357
+ const type: ParamCategory | undefined = NEST_PARAMETER_TYPES[typeIndex];
358
+ if (type === undefined) return null;
359
+
360
+ return {
361
+ custom: false,
362
+ name: key,
363
+ category: type,
364
+ index: param.index,
365
+ field: param.data,
431
366
  };
432
-
433
- interface INestParam {
434
- name: string;
435
- index: number;
436
- factory?: (...args: any) => any;
437
- data: string | undefined;
438
- }
367
+ }
368
+
369
+ function _Analyze_custom_parameter(
370
+ param: INestParam,
371
+ ): IController.IParameter | null {
372
+ if (param.factory === undefined) return null;
373
+ else if (
374
+ param.factory.name === "EncryptedBody" ||
375
+ param.factory.name === "PlainBody" ||
376
+ param.factory.name === "TypedQueryBody" ||
377
+ param.factory.name === "TypedBody"
378
+ )
379
+ return {
380
+ custom: true,
381
+ category: "body",
382
+ index: param.index,
383
+ name: param.name,
384
+ field: param.data,
385
+ encrypted: param.factory.name === "EncryptedBody",
386
+ contentType:
387
+ param.factory.name === "PlainBody" ||
388
+ param.factory.name === "EncryptedBody"
389
+ ? "text/plain"
390
+ : param.factory.name === "TypedQueryBody"
391
+ ? "application/x-www-form-urlencoded"
392
+ : "application/json",
393
+ };
394
+ else if (param.factory.name === "TypedHeaders")
395
+ return {
396
+ custom: true,
397
+ category: "headers",
398
+ name: param.name,
399
+ index: param.index,
400
+ field: param.data,
401
+ };
402
+ else if (param.factory.name === "TypedParam")
403
+ return {
404
+ custom: true,
405
+ category: "param",
406
+ name: param.name,
407
+ index: param.index,
408
+ field: param.data,
409
+ };
410
+ else if (param.factory.name === "TypedQuery")
411
+ return {
412
+ custom: true,
413
+ name: param.name,
414
+ category: "query",
415
+ index: param.index,
416
+ field: undefined,
417
+ };
418
+ else return null;
419
+ }
420
+
421
+ type NestParameters = {
422
+ [key: string]: INestParam;
423
+ };
424
+
425
+ interface INestParam {
426
+ name: string;
427
+ index: number;
428
+ factory?: (...args: any) => any;
429
+ data: string | undefined;
430
+ }
439
431
  }
440
432
 
441
433
  // node_modules/@nestjs/common/lib/enums/request-method.enum.ts
442
434
  const METHODS = [
443
- "GET",
444
- "POST",
445
- "PUT",
446
- "DELETE",
447
- "PATCH",
448
- "ALL",
449
- "OPTIONS",
450
- "HEAD",
435
+ "GET",
436
+ "POST",
437
+ "PUT",
438
+ "DELETE",
439
+ "PATCH",
440
+ "ALL",
441
+ "OPTIONS",
442
+ "HEAD",
451
443
  ];
452
444
 
453
445
  // node_modules/@nestjs/common/lib/route-paramtypes.enum.ts
454
446
  const NEST_PARAMETER_TYPES = [
455
- undefined,
456
- undefined,
457
- undefined,
458
- "body",
459
- "query",
460
- "param",
461
- "headers",
462
- undefined,
463
- undefined,
464
- undefined,
465
- undefined,
466
- undefined,
447
+ undefined,
448
+ undefined,
449
+ undefined,
450
+ "body",
451
+ "query",
452
+ "param",
453
+ "headers",
454
+ undefined,
455
+ undefined,
456
+ undefined,
457
+ undefined,
458
+ undefined,
467
459
  ] as const;