@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.
Files changed (38) hide show
  1. package/assets/config/nestia.config.ts +79 -70
  2. package/lib/INestiaConfig.d.ts +18 -14
  3. package/lib/executable/sdk.js +16 -16
  4. package/lib/generates/FunctionGenerator.js +9 -9
  5. package/lib/generates/FunctionGenerator.js.map +1 -1
  6. package/lib/generates/SwaggerGenerator.js +9 -9
  7. package/package.json +3 -3
  8. package/src/INestiaConfig.ts +124 -120
  9. package/src/NestiaSdkApplication.ts +183 -183
  10. package/src/analyses/ControllerAnalyzer.ts +203 -203
  11. package/src/analyses/GenericAnalyzer.ts +53 -53
  12. package/src/analyses/ImportAnalyzer.ts +143 -143
  13. package/src/analyses/PathAnalyzer.ts +58 -58
  14. package/src/analyses/ReflectAnalyzer.ts +279 -279
  15. package/src/analyses/SourceFinder.ts +59 -59
  16. package/src/executable/internal/CommandParser.ts +15 -15
  17. package/src/executable/internal/NestiaConfigCompilerOptions.ts +18 -18
  18. package/src/executable/internal/NestiaSdkCommand.ts +174 -174
  19. package/src/executable/internal/NestiaSdkConfig.ts +35 -35
  20. package/src/executable/internal/nestia.config.getter.ts +12 -12
  21. package/src/executable/sdk.ts +74 -74
  22. package/src/generates/FileGenerator.ts +156 -156
  23. package/src/generates/FunctionGenerator.ts +284 -287
  24. package/src/generates/SdkGenerator.ts +50 -50
  25. package/src/generates/SwaggerGenerator.ts +393 -393
  26. package/src/index.ts +3 -3
  27. package/src/module.ts +2 -2
  28. package/src/structures/IController.ts +27 -27
  29. package/src/structures/IRoute.ts +29 -29
  30. package/src/structures/ISwagger.ts +55 -55
  31. package/src/structures/ITypeTuple.ts +6 -6
  32. package/src/structures/MethodType.ts +11 -11
  33. package/src/structures/ParamCategory.ts +1 -1
  34. package/src/structures/TypeEntry.ts +22 -22
  35. package/src/utils/ArrayUtil.ts +26 -26
  36. package/src/utils/ImportDictionary.ts +56 -56
  37. package/src/utils/MapUtil.ts +14 -14
  38. package/src/utils/StripEnums.ts +10 -10
@@ -1,393 +1,393 @@
1
- import fs from "fs";
2
- import NodePath from "path";
3
- import { Singleton } from "tstl/thread/Singleton";
4
- import { VariadicSingleton } from "tstl/thread/VariadicSingleton";
5
- import ts from "typescript";
6
- import { IJsonApplication, IJsonSchema } from "typia";
7
- import { CommentFactory } from "typia/lib/factories/CommentFactory";
8
- import { MetadataCollection } from "typia/lib/factories/MetadataCollection";
9
- import { MetadataFactory } from "typia/lib/factories/MetadataFactory";
10
- import { Metadata } from "typia/lib/metadata/Metadata";
11
- import { ApplicationProgrammer } from "typia/lib/programmers/ApplicationProgrammer";
12
-
13
- import { INestiaConfig } from "../INestiaConfig";
14
- import { IRoute } from "../structures/IRoute";
15
- import { ISwagger } from "../structures/ISwagger";
16
- import { MapUtil } from "../utils/MapUtil";
17
-
18
- export namespace SwaggerGenerator {
19
- export async function generate(
20
- checker: ts.TypeChecker,
21
- config: INestiaConfig.ISwagger,
22
- routeList: IRoute[],
23
- ): Promise<void> {
24
- // PREPARE ASSETS
25
- const parsed: NodePath.ParsedPath = NodePath.parse(config.output);
26
- const location: string = !!parsed.ext
27
- ? NodePath.resolve(config.output)
28
- : NodePath.join(NodePath.resolve(config.output), "swagger.json");
29
-
30
- const collection: MetadataCollection = new MetadataCollection({
31
- replace: MetadataCollection.replace,
32
- });
33
-
34
- // CONSTRUCT SWAGGER DOCUMENTS
35
- const tupleList: Array<ISchemaTuple> = [];
36
- const swagger: ISwagger = await initialize(location);
37
- const pathDict: Map<string, ISwagger.IPath> = new Map();
38
-
39
- for (const route of routeList) {
40
- const path: ISwagger.IPath = MapUtil.take(
41
- pathDict,
42
- get_path(route.path, route.parameters),
43
- () => ({}),
44
- );
45
- path[route.method.toLowerCase()] = generate_route(
46
- checker,
47
- collection,
48
- tupleList,
49
- route,
50
- );
51
- }
52
- swagger.paths = {};
53
- for (const [path, routes] of pathDict) {
54
- swagger.paths[path] = routes;
55
- }
56
-
57
- // FILL JSON-SCHEMAS
58
- const application: IJsonApplication = ApplicationProgrammer.generate(
59
- tupleList.map(({ metadata }) => metadata),
60
- {
61
- purpose: "swagger",
62
- },
63
- );
64
- swagger.components = {
65
- ...(swagger.components || {}),
66
- schemas: application.components.schemas,
67
- };
68
- tupleList.forEach(({ schema }, index) => {
69
- Object.assign(schema, application.schemas[index]!);
70
- });
71
-
72
- // ERASE IJsonComponents.IObject.$id
73
- for (const obj of Object.values(swagger.components.schemas))
74
- if (obj.$id) delete obj.$id;
75
-
76
- // DO GENERATE
77
- await fs.promises.writeFile(
78
- location,
79
- JSON.stringify(swagger, null, 2),
80
- "utf8",
81
- );
82
- }
83
-
84
- /* ---------------------------------------------------------
85
- INITIALIZERS
86
- --------------------------------------------------------- */
87
- async function initialize(path: string): Promise<ISwagger> {
88
- // LOAD OR CREATE NEW SWAGGER DATA
89
- const swagger: ISwagger = fs.existsSync(path)
90
- ? JSON.parse(await fs.promises.readFile(path, "utf8"))
91
- : {
92
- openapi: "3.0.1",
93
- servers: [
94
- {
95
- url: "https://github.com/samchon/nestia",
96
- description: "insert your server url",
97
- },
98
- ],
99
- info: {
100
- version: "0.1.0",
101
- title: "Generated by nestia - https://github.com/samchon/nestia",
102
- },
103
- paths: {},
104
- components: {},
105
- };
106
-
107
- // RETURNS
108
- return swagger;
109
- }
110
-
111
- function get_path(path: string, parameters: IRoute.IParameter[]): string {
112
- const filtered: IRoute.IParameter[] = parameters.filter(
113
- (param) => param.category === "param" && !!param.field,
114
- );
115
- for (const param of filtered)
116
- path = path.replace(`:${param.field}`, `{${param.field}}`);
117
- return path;
118
- }
119
-
120
- function generate_route(
121
- checker: ts.TypeChecker,
122
- collection: MetadataCollection,
123
- tupleList: Array<ISchemaTuple>,
124
- route: IRoute,
125
- ): ISwagger.IRoute {
126
- const bodyParam = route.parameters.find(
127
- (param) => param.category === "body",
128
- );
129
- const tags: string[] = route.tags
130
- .filter(
131
- (tag) =>
132
- tag.name === "tag" &&
133
- tag.text &&
134
- tag.text.find(
135
- (elem) => elem.kind === "text" && elem.text.length,
136
- ) !== undefined,
137
- )
138
- .map((tag) => tag.text!.find((elem) => elem.kind === "text")!.text);
139
-
140
- const encrypted: boolean =
141
- route.encrypted === true ||
142
- !!route.parameters.find((param) => param.encrypted === true);
143
- return {
144
- tags,
145
- summary: encrypted ? "encrypted" : undefined,
146
- parameters: route.parameters
147
- .filter((param) => param.category !== "body")
148
- .map((param) =>
149
- generate_parameter(
150
- checker,
151
- collection,
152
- tupleList,
153
- route,
154
- param,
155
- ),
156
- ),
157
- requestBody: bodyParam
158
- ? generate_request_body(
159
- checker,
160
- collection,
161
- tupleList,
162
- route,
163
- bodyParam,
164
- )
165
- : undefined,
166
- responses: generate_response_body(
167
- checker,
168
- collection,
169
- tupleList,
170
- route,
171
- ),
172
- description: CommentFactory.generate(route.comments),
173
- };
174
- }
175
-
176
- /* ---------------------------------------------------------
177
- REQUEST & RESPONSE
178
- --------------------------------------------------------- */
179
- function generate_parameter(
180
- checker: ts.TypeChecker,
181
- collection: MetadataCollection,
182
- tupleList: Array<ISchemaTuple>,
183
- route: IRoute,
184
- parameter: IRoute.IParameter,
185
- ): ISwagger.IParameter {
186
- const schema: IJsonSchema | null = generate_schema(
187
- checker,
188
- collection,
189
- tupleList,
190
- parameter.type.type,
191
- );
192
- if (schema === null)
193
- throw new Error(
194
- `Error on NestiaApplication.sdk(): invalid parameter type on ${route.symbol}#${parameter.name}`,
195
- );
196
-
197
- return {
198
- name: parameter.field || parameter.name,
199
- in: parameter.category === "param" ? "path" : parameter.category,
200
- description:
201
- get_parametric_description(route, "param", parameter.name) ||
202
- "",
203
- schema,
204
- required: true,
205
- };
206
- }
207
-
208
- function generate_request_body(
209
- checker: ts.TypeChecker,
210
- collection: MetadataCollection,
211
- tupleList: Array<ISchemaTuple>,
212
- route: IRoute,
213
- parameter: IRoute.IParameter,
214
- ): ISwagger.IRequestBody {
215
- const schema: IJsonSchema | null = generate_schema(
216
- checker,
217
- collection,
218
- tupleList,
219
- parameter.type.type,
220
- );
221
- if (schema === null)
222
- throw new Error(
223
- `Error on NestiaApplication.sdk(): invalid request body type on ${route.symbol}.`,
224
- );
225
-
226
- return {
227
- description:
228
- warning.get(parameter.encrypted).get("request") +
229
- (get_parametric_description(route, "param", parameter.name) ||
230
- ""),
231
- content: {
232
- "application/json": {
233
- schema,
234
- },
235
- },
236
- required: true,
237
- };
238
- }
239
-
240
- function generate_response_body(
241
- checker: ts.TypeChecker,
242
- collection: MetadataCollection,
243
- tupleList: Array<ISchemaTuple>,
244
- route: IRoute,
245
- ): ISwagger.IResponseBody {
246
- // OUTPUT WITH SUCCESS STATUS
247
- const status: string =
248
- route.method === "GET" || route.method === "DELETE" ? "200" : "201";
249
- const schema: IJsonSchema | null = generate_schema(
250
- checker,
251
- collection,
252
- tupleList,
253
- route.output.type,
254
- );
255
- const success: ISwagger.IResponseBody = {
256
- [status]: {
257
- description:
258
- warning.get(route.encrypted).get("response", route.method) +
259
- (get_parametric_description(route, "return") ||
260
- get_parametric_description(route, "returns") ||
261
- ""),
262
- content:
263
- schema === null || route.output.name === "void"
264
- ? undefined
265
- : {
266
- "application/json": {
267
- schema,
268
- },
269
- },
270
- },
271
- };
272
-
273
- // EXCEPTION STATUSES
274
- const exceptions: ISwagger.IResponseBody = Object.fromEntries(
275
- route.tags
276
- .filter(
277
- (tag) =>
278
- tag.name === "throw" &&
279
- tag.text &&
280
- tag.text.find(
281
- (elem) =>
282
- elem.kind === "text" &&
283
- isNaN(
284
- Number(
285
- elem.text
286
- .split(" ")
287
- .map((str) => str.trim())[0],
288
- ),
289
- ) === false,
290
- ) !== undefined,
291
- )
292
- .map((tag) => {
293
- const text: string = tag.text!.find(
294
- (elem) => elem.kind === "text",
295
- )!.text;
296
- const elements: string[] = text
297
- .split(" ")
298
- .map((str) => str.trim());
299
-
300
- return [
301
- elements[0],
302
- {
303
- description: elements.slice(1).join(" "),
304
- },
305
- ];
306
- }),
307
- );
308
- return { ...exceptions, ...success };
309
- }
310
-
311
- /* ---------------------------------------------------------
312
- UTILS
313
- --------------------------------------------------------- */
314
- function generate_schema(
315
- checker: ts.TypeChecker,
316
- collection: MetadataCollection,
317
- tupleList: Array<ISchemaTuple>,
318
- type: ts.Type,
319
- ): IJsonSchema | null {
320
- const metadata: Metadata = MetadataFactory.generate(
321
- checker,
322
- collection,
323
- type,
324
- {
325
- resolve: false,
326
- constant: true,
327
- },
328
- );
329
- if (metadata.empty() && metadata.nullable === false) return null;
330
-
331
- const schema: IJsonSchema = {} as IJsonSchema;
332
- tupleList.push({ metadata, schema });
333
- return schema;
334
- }
335
-
336
- function get_parametric_description(
337
- route: IRoute,
338
- tagName: string,
339
- parameterName?: string,
340
- ): string | undefined {
341
- const parametric: (elem: ts.JSDocTagInfo) => boolean = parameterName
342
- ? (tag) =>
343
- tag.text!.find(
344
- (elem) =>
345
- elem.kind === "parameterName" &&
346
- elem.text === parameterName,
347
- ) !== undefined
348
- : () => true;
349
-
350
- const tag: ts.JSDocTagInfo | undefined = route.tags.find(
351
- (tag) => tag.name === tagName && tag.text && parametric(tag),
352
- );
353
- return tag && tag.text
354
- ? tag.text.find((elem) => elem.kind === "text")?.text
355
- : undefined;
356
- }
357
- }
358
-
359
- const warning = new VariadicSingleton((encrypted: boolean) => {
360
- if (encrypted === false) return new Singleton(() => "");
361
-
362
- return new VariadicSingleton(
363
- (type: "request" | "response", method?: string) => {
364
- const summary =
365
- type === "request"
366
- ? "Request body must be encrypted."
367
- : "Response data have been encrypted.";
368
-
369
- const component =
370
- type === "request"
371
- ? "[EncryptedBody](https://github.com/samchon/@nestia/core#encryptedbody)"
372
- : `[EncryptedRoute.${method![0].toUpperCase()}.${method!
373
- .substring(1)
374
- .toLowerCase()}](https://github.com/samchon/@nestia/core#encryptedroute)`;
375
-
376
- return `## Warning
377
- ${summary}
378
-
379
- The ${type} body data would be encrypted as "AES-128(256) / CBC mode / PKCS#5 Padding / Base64 Encoding", through the ${component} component.
380
-
381
- Therefore, just utilize this swagger editor only for referencing. If you need to call the real API, using [SDK](https://github.com/samchon/nestia#software-development-kit) would be much better.
382
-
383
- -----------------
384
-
385
- `;
386
- },
387
- );
388
- });
389
-
390
- interface ISchemaTuple {
391
- metadata: Metadata;
392
- schema: IJsonSchema;
393
- }
1
+ import fs from "fs";
2
+ import NodePath from "path";
3
+ import { Singleton } from "tstl/thread/Singleton";
4
+ import { VariadicSingleton } from "tstl/thread/VariadicSingleton";
5
+ import ts from "typescript";
6
+ import { IJsonApplication, IJsonSchema } from "typia";
7
+ import { CommentFactory } from "typia/lib/factories/CommentFactory";
8
+ import { MetadataCollection } from "typia/lib/factories/MetadataCollection";
9
+ import { MetadataFactory } from "typia/lib/factories/MetadataFactory";
10
+ import { Metadata } from "typia/lib/metadata/Metadata";
11
+ import { ApplicationProgrammer } from "typia/lib/programmers/ApplicationProgrammer";
12
+
13
+ import { INestiaConfig } from "../INestiaConfig";
14
+ import { IRoute } from "../structures/IRoute";
15
+ import { ISwagger } from "../structures/ISwagger";
16
+ import { MapUtil } from "../utils/MapUtil";
17
+
18
+ export namespace SwaggerGenerator {
19
+ export async function generate(
20
+ checker: ts.TypeChecker,
21
+ config: INestiaConfig.ISwagger,
22
+ routeList: IRoute[],
23
+ ): Promise<void> {
24
+ // PREPARE ASSETS
25
+ const parsed: NodePath.ParsedPath = NodePath.parse(config.output);
26
+ const location: string = !!parsed.ext
27
+ ? NodePath.resolve(config.output)
28
+ : NodePath.join(NodePath.resolve(config.output), "swagger.json");
29
+
30
+ const collection: MetadataCollection = new MetadataCollection({
31
+ replace: MetadataCollection.replace,
32
+ });
33
+
34
+ // CONSTRUCT SWAGGER DOCUMENTS
35
+ const tupleList: Array<ISchemaTuple> = [];
36
+ const swagger: ISwagger = await initialize(location);
37
+ const pathDict: Map<string, ISwagger.IPath> = new Map();
38
+
39
+ for (const route of routeList) {
40
+ const path: ISwagger.IPath = MapUtil.take(
41
+ pathDict,
42
+ get_path(route.path, route.parameters),
43
+ () => ({}),
44
+ );
45
+ path[route.method.toLowerCase()] = generate_route(
46
+ checker,
47
+ collection,
48
+ tupleList,
49
+ route,
50
+ );
51
+ }
52
+ swagger.paths = {};
53
+ for (const [path, routes] of pathDict) {
54
+ swagger.paths[path] = routes;
55
+ }
56
+
57
+ // FILL JSON-SCHEMAS
58
+ const application: IJsonApplication = ApplicationProgrammer.generate(
59
+ tupleList.map(({ metadata }) => metadata),
60
+ {
61
+ purpose: "swagger",
62
+ },
63
+ );
64
+ swagger.components = {
65
+ ...(swagger.components || {}),
66
+ schemas: application.components.schemas,
67
+ };
68
+ tupleList.forEach(({ schema }, index) => {
69
+ Object.assign(schema, application.schemas[index]!);
70
+ });
71
+
72
+ // ERASE IJsonComponents.IObject.$id
73
+ for (const obj of Object.values(swagger.components.schemas))
74
+ if (obj.$id) delete obj.$id;
75
+
76
+ // DO GENERATE
77
+ await fs.promises.writeFile(
78
+ location,
79
+ JSON.stringify(swagger, null, 2),
80
+ "utf8",
81
+ );
82
+ }
83
+
84
+ /* ---------------------------------------------------------
85
+ INITIALIZERS
86
+ --------------------------------------------------------- */
87
+ async function initialize(path: string): Promise<ISwagger> {
88
+ // LOAD OR CREATE NEW SWAGGER DATA
89
+ const swagger: ISwagger = fs.existsSync(path)
90
+ ? JSON.parse(await fs.promises.readFile(path, "utf8"))
91
+ : {
92
+ openapi: "3.0.1",
93
+ servers: [
94
+ {
95
+ url: "https://github.com/samchon/nestia",
96
+ description: "insert your server url",
97
+ },
98
+ ],
99
+ info: {
100
+ version: "0.1.0",
101
+ title: "Generated by nestia - https://github.com/samchon/nestia",
102
+ },
103
+ paths: {},
104
+ components: {},
105
+ };
106
+
107
+ // RETURNS
108
+ return swagger;
109
+ }
110
+
111
+ function get_path(path: string, parameters: IRoute.IParameter[]): string {
112
+ const filtered: IRoute.IParameter[] = parameters.filter(
113
+ (param) => param.category === "param" && !!param.field,
114
+ );
115
+ for (const param of filtered)
116
+ path = path.replace(`:${param.field}`, `{${param.field}}`);
117
+ return path;
118
+ }
119
+
120
+ function generate_route(
121
+ checker: ts.TypeChecker,
122
+ collection: MetadataCollection,
123
+ tupleList: Array<ISchemaTuple>,
124
+ route: IRoute,
125
+ ): ISwagger.IRoute {
126
+ const bodyParam = route.parameters.find(
127
+ (param) => param.category === "body",
128
+ );
129
+ const tags: string[] = route.tags
130
+ .filter(
131
+ (tag) =>
132
+ tag.name === "tag" &&
133
+ tag.text &&
134
+ tag.text.find(
135
+ (elem) => elem.kind === "text" && elem.text.length,
136
+ ) !== undefined,
137
+ )
138
+ .map((tag) => tag.text!.find((elem) => elem.kind === "text")!.text);
139
+
140
+ const encrypted: boolean =
141
+ route.encrypted === true ||
142
+ !!route.parameters.find((param) => param.encrypted === true);
143
+ return {
144
+ tags,
145
+ summary: encrypted ? "encrypted" : undefined,
146
+ parameters: route.parameters
147
+ .filter((param) => param.category !== "body")
148
+ .map((param) =>
149
+ generate_parameter(
150
+ checker,
151
+ collection,
152
+ tupleList,
153
+ route,
154
+ param,
155
+ ),
156
+ ),
157
+ requestBody: bodyParam
158
+ ? generate_request_body(
159
+ checker,
160
+ collection,
161
+ tupleList,
162
+ route,
163
+ bodyParam,
164
+ )
165
+ : undefined,
166
+ responses: generate_response_body(
167
+ checker,
168
+ collection,
169
+ tupleList,
170
+ route,
171
+ ),
172
+ description: CommentFactory.generate(route.comments),
173
+ };
174
+ }
175
+
176
+ /* ---------------------------------------------------------
177
+ REQUEST & RESPONSE
178
+ --------------------------------------------------------- */
179
+ function generate_parameter(
180
+ checker: ts.TypeChecker,
181
+ collection: MetadataCollection,
182
+ tupleList: Array<ISchemaTuple>,
183
+ route: IRoute,
184
+ parameter: IRoute.IParameter,
185
+ ): ISwagger.IParameter {
186
+ const schema: IJsonSchema | null = generate_schema(
187
+ checker,
188
+ collection,
189
+ tupleList,
190
+ parameter.type.type,
191
+ );
192
+ if (schema === null)
193
+ throw new Error(
194
+ `Error on NestiaApplication.sdk(): invalid parameter type on ${route.symbol}#${parameter.name}`,
195
+ );
196
+
197
+ return {
198
+ name: parameter.field || parameter.name,
199
+ in: parameter.category === "param" ? "path" : parameter.category,
200
+ description:
201
+ get_parametric_description(route, "param", parameter.name) ||
202
+ "",
203
+ schema,
204
+ required: true,
205
+ };
206
+ }
207
+
208
+ function generate_request_body(
209
+ checker: ts.TypeChecker,
210
+ collection: MetadataCollection,
211
+ tupleList: Array<ISchemaTuple>,
212
+ route: IRoute,
213
+ parameter: IRoute.IParameter,
214
+ ): ISwagger.IRequestBody {
215
+ const schema: IJsonSchema | null = generate_schema(
216
+ checker,
217
+ collection,
218
+ tupleList,
219
+ parameter.type.type,
220
+ );
221
+ if (schema === null)
222
+ throw new Error(
223
+ `Error on NestiaApplication.sdk(): invalid request body type on ${route.symbol}.`,
224
+ );
225
+
226
+ return {
227
+ description:
228
+ warning.get(parameter.encrypted).get("request") +
229
+ (get_parametric_description(route, "param", parameter.name) ||
230
+ ""),
231
+ content: {
232
+ "application/json": {
233
+ schema,
234
+ },
235
+ },
236
+ required: true,
237
+ };
238
+ }
239
+
240
+ function generate_response_body(
241
+ checker: ts.TypeChecker,
242
+ collection: MetadataCollection,
243
+ tupleList: Array<ISchemaTuple>,
244
+ route: IRoute,
245
+ ): ISwagger.IResponseBody {
246
+ // OUTPUT WITH SUCCESS STATUS
247
+ const status: string =
248
+ route.method === "GET" || route.method === "DELETE" ? "200" : "201";
249
+ const schema: IJsonSchema | null = generate_schema(
250
+ checker,
251
+ collection,
252
+ tupleList,
253
+ route.output.type,
254
+ );
255
+ const success: ISwagger.IResponseBody = {
256
+ [status]: {
257
+ description:
258
+ warning.get(route.encrypted).get("response", route.method) +
259
+ (get_parametric_description(route, "return") ||
260
+ get_parametric_description(route, "returns") ||
261
+ ""),
262
+ content:
263
+ schema === null || route.output.name === "void"
264
+ ? undefined
265
+ : {
266
+ "application/json": {
267
+ schema,
268
+ },
269
+ },
270
+ },
271
+ };
272
+
273
+ // EXCEPTION STATUSES
274
+ const exceptions: ISwagger.IResponseBody = Object.fromEntries(
275
+ route.tags
276
+ .filter(
277
+ (tag) =>
278
+ tag.name === "throw" &&
279
+ tag.text &&
280
+ tag.text.find(
281
+ (elem) =>
282
+ elem.kind === "text" &&
283
+ isNaN(
284
+ Number(
285
+ elem.text
286
+ .split(" ")
287
+ .map((str) => str.trim())[0],
288
+ ),
289
+ ) === false,
290
+ ) !== undefined,
291
+ )
292
+ .map((tag) => {
293
+ const text: string = tag.text!.find(
294
+ (elem) => elem.kind === "text",
295
+ )!.text;
296
+ const elements: string[] = text
297
+ .split(" ")
298
+ .map((str) => str.trim());
299
+
300
+ return [
301
+ elements[0],
302
+ {
303
+ description: elements.slice(1).join(" "),
304
+ },
305
+ ];
306
+ }),
307
+ );
308
+ return { ...exceptions, ...success };
309
+ }
310
+
311
+ /* ---------------------------------------------------------
312
+ UTILS
313
+ --------------------------------------------------------- */
314
+ function generate_schema(
315
+ checker: ts.TypeChecker,
316
+ collection: MetadataCollection,
317
+ tupleList: Array<ISchemaTuple>,
318
+ type: ts.Type,
319
+ ): IJsonSchema | null {
320
+ const metadata: Metadata = MetadataFactory.generate(
321
+ checker,
322
+ collection,
323
+ type,
324
+ {
325
+ resolve: false,
326
+ constant: true,
327
+ },
328
+ );
329
+ if (metadata.empty() && metadata.nullable === false) return null;
330
+
331
+ const schema: IJsonSchema = {} as IJsonSchema;
332
+ tupleList.push({ metadata, schema });
333
+ return schema;
334
+ }
335
+
336
+ function get_parametric_description(
337
+ route: IRoute,
338
+ tagName: string,
339
+ parameterName?: string,
340
+ ): string | undefined {
341
+ const parametric: (elem: ts.JSDocTagInfo) => boolean = parameterName
342
+ ? (tag) =>
343
+ tag.text!.find(
344
+ (elem) =>
345
+ elem.kind === "parameterName" &&
346
+ elem.text === parameterName,
347
+ ) !== undefined
348
+ : () => true;
349
+
350
+ const tag: ts.JSDocTagInfo | undefined = route.tags.find(
351
+ (tag) => tag.name === tagName && tag.text && parametric(tag),
352
+ );
353
+ return tag && tag.text
354
+ ? tag.text.find((elem) => elem.kind === "text")?.text
355
+ : undefined;
356
+ }
357
+ }
358
+
359
+ const warning = new VariadicSingleton((encrypted: boolean) => {
360
+ if (encrypted === false) return new Singleton(() => "");
361
+
362
+ return new VariadicSingleton(
363
+ (type: "request" | "response", method?: string) => {
364
+ const summary =
365
+ type === "request"
366
+ ? "Request body must be encrypted."
367
+ : "Response data have been encrypted.";
368
+
369
+ const component =
370
+ type === "request"
371
+ ? "[EncryptedBody](https://github.com/samchon/@nestia/core#encryptedbody)"
372
+ : `[EncryptedRoute.${method![0].toUpperCase()}.${method!
373
+ .substring(1)
374
+ .toLowerCase()}](https://github.com/samchon/@nestia/core#encryptedroute)`;
375
+
376
+ return `## Warning
377
+ ${summary}
378
+
379
+ The ${type} body data would be encrypted as "AES-128(256) / CBC mode / PKCS#5 Padding / Base64 Encoding", through the ${component} component.
380
+
381
+ Therefore, just utilize this swagger editor only for referencing. If you need to call the real API, using [SDK](https://github.com/samchon/nestia#software-development-kit) would be much better.
382
+
383
+ -----------------
384
+
385
+ `;
386
+ },
387
+ );
388
+ });
389
+
390
+ interface ISchemaTuple {
391
+ metadata: Metadata;
392
+ schema: IJsonSchema;
393
+ }