@nestia/sdk 2.6.2 → 2.6.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 (46) hide show
  1. package/lib/analyses/ControllerAnalyzer.js +3 -3
  2. package/lib/analyses/ControllerAnalyzer.js.map +1 -1
  3. package/lib/analyses/ImportAnalyzer.d.ts +1 -2
  4. package/lib/analyses/ImportAnalyzer.js +2 -2
  5. package/lib/analyses/ImportAnalyzer.js.map +1 -1
  6. package/lib/analyses/ReflectAnalyzer.js +2 -2
  7. package/lib/analyses/ReflectAnalyzer.js.map +1 -1
  8. package/lib/generates/SwaggerGenerator.js +4 -4
  9. package/lib/generates/SwaggerGenerator.js.map +1 -1
  10. package/lib/generates/internal/ImportDictionary.js +6 -8
  11. package/lib/generates/internal/ImportDictionary.js.map +1 -1
  12. package/lib/structures/TypeEntry.js +2 -2
  13. package/lib/structures/TypeEntry.js.map +1 -1
  14. package/package.json +4 -4
  15. package/src/INestiaConfig.ts +248 -248
  16. package/src/NestiaSdkApplication.ts +255 -255
  17. package/src/analyses/ControllerAnalyzer.ts +402 -402
  18. package/src/analyses/ExceptionAnalyzer.ts +148 -148
  19. package/src/analyses/ImportAnalyzer.ts +1 -2
  20. package/src/analyses/ReflectAnalyzer.ts +463 -463
  21. package/src/analyses/SecurityAnalyzer.ts +24 -24
  22. package/src/generates/CloneGenerator.ts +62 -62
  23. package/src/generates/E2eGenerator.ts +66 -66
  24. package/src/generates/SdkGenerator.ts +84 -84
  25. package/src/generates/SwaggerGenerator.ts +446 -446
  26. package/src/generates/internal/E2eFileProgrammer.ts +182 -182
  27. package/src/generates/internal/FilePrinter.ts +53 -53
  28. package/src/generates/internal/ImportDictionary.ts +147 -149
  29. package/src/generates/internal/SdkAliasCollection.ts +152 -152
  30. package/src/generates/internal/SdkCloneProgrammer.ts +155 -155
  31. package/src/generates/internal/SdkFileProgrammer.ts +115 -115
  32. package/src/generates/internal/SdkFunctionProgrammer.ts +298 -298
  33. package/src/generates/internal/SdkImportWizard.ts +55 -55
  34. package/src/generates/internal/SdkNamespaceProgrammer.ts +510 -510
  35. package/src/generates/internal/SdkRouteProgrammer.ts +83 -83
  36. package/src/generates/internal/SdkSimulationProgrammer.ts +365 -365
  37. package/src/generates/internal/SdkTypeProgrammer.ts +385 -385
  38. package/src/generates/internal/SwaggerSchemaGenerator.ts +438 -438
  39. package/src/structures/IController.ts +94 -94
  40. package/src/structures/IRoute.ts +53 -53
  41. package/src/structures/ISwagger.ts +91 -91
  42. package/src/structures/ISwaggerRoute.ts +54 -54
  43. package/src/structures/ISwaggerSecurityScheme.ts +65 -65
  44. package/src/structures/ParamCategory.ts +1 -1
  45. package/src/structures/TypeEntry.ts +1 -1
  46. package/src/utils/StringUtil.ts +6 -6
@@ -1,438 +1,438 @@
1
- import { Singleton, VariadicSingleton } from "tstl";
2
- import ts from "typescript";
3
- import { IJsonSchema } from "typia";
4
- import { MetadataCollection } from "typia/lib/factories/MetadataCollection";
5
- import { MetadataFactory } from "typia/lib/factories/MetadataFactory";
6
- import { JsonApplicationProgrammer } from "typia/lib/programmers/json/JsonApplicationProgrammer";
7
- import { Metadata } from "typia/lib/schemas/metadata/Metadata";
8
- import { ValidationPipe } from "typia/lib/typings/ValidationPipe";
9
-
10
- import { INestiaConfig } from "../../INestiaConfig";
11
- import { IRoute } from "../../structures/IRoute";
12
- import { ISwaggerError } from "../../structures/ISwaggerError";
13
- import { ISwaggerLazyProperty } from "../../structures/ISwaggerLazyProperty";
14
- import { ISwaggerLazySchema } from "../../structures/ISwaggerLazySchema";
15
- import { ISwaggerRoute } from "../../structures/ISwaggerRoute";
16
- import { SwaggerSchemaValidator } from "./SwaggerSchemaValidator";
17
-
18
- export namespace SwaggerSchemaGenerator {
19
- export interface IProps {
20
- config: INestiaConfig.ISwaggerConfig;
21
- checker: ts.TypeChecker;
22
- collection: MetadataCollection;
23
- lazySchemas: Array<ISwaggerLazySchema>;
24
- lazyProperties: Array<ISwaggerLazyProperty>;
25
- errors: ISwaggerError[];
26
- }
27
-
28
- export const response =
29
- (props: IProps) =>
30
- (route: IRoute): ISwaggerRoute.IResponseBody => {
31
- const output: ISwaggerRoute.IResponseBody = {};
32
-
33
- //----
34
- // EXCEPTION STATUSES
35
- //----
36
- // FROM DECORATOR
37
- for (const [status, exp] of Object.entries(route.exceptions)) {
38
- const result = MetadataFactory.analyze(props.checker)({
39
- escape: true,
40
- constant: true,
41
- absorb: false,
42
- validate: JsonApplicationProgrammer.validate,
43
- })(props.collection)(exp.type);
44
- if (result.success === false)
45
- props.errors.push(
46
- ...result.errors.map((e) => ({
47
- ...e,
48
- route,
49
- from: `response(status: ${status})`,
50
- })),
51
- );
52
-
53
- output[status] = {
54
- description: exp.description ?? "",
55
- content: {
56
- "application/json": {
57
- schema: coalesce(props)(result),
58
- },
59
- },
60
- };
61
- }
62
-
63
- // FROM COMMENT TAGS -> ANY
64
- for (const tag of route.jsDocTags) {
65
- if (tag.name !== "throw" && tag.name !== "throws") continue;
66
-
67
- const text: string | undefined = tag.text?.find(
68
- (elem) => elem.kind === "text",
69
- )?.text;
70
- if (text === undefined) continue;
71
-
72
- const elements: string[] = text.split(" ").map((str) => str.trim());
73
- const status: string = elements[0];
74
- if (
75
- isNaN(Number(status)) &&
76
- status !== "2XX" &&
77
- status !== "3XX" &&
78
- status !== "4XX" &&
79
- status !== "5XX"
80
- )
81
- continue;
82
-
83
- const description: string | undefined =
84
- elements.length === 1 ? undefined : elements.slice(1).join(" ");
85
- const oldbie = output[status];
86
- if (description && oldbie !== undefined)
87
- oldbie.description = description;
88
- else if (oldbie === undefined)
89
- output[status] = {
90
- description: description ?? "",
91
- content: {
92
- "application/json": {
93
- schema: {},
94
- },
95
- },
96
- };
97
- }
98
-
99
- //----
100
- // SUCCESS
101
- //----
102
- // STATUS
103
- const status: string =
104
- route.status !== undefined
105
- ? String(route.status)
106
- : route.method === "POST"
107
- ? "201"
108
- : "200";
109
-
110
- // SCHEMA
111
- const result = MetadataFactory.analyze(props.checker)({
112
- escape: true,
113
- constant: true,
114
- absorb: false,
115
- validate: (meta) => {
116
- const bigint: boolean =
117
- meta.atomics.some((a) => a.type === "bigint") ||
118
- meta.constants.some((a) => a.type === "bigint");
119
- return bigint ? ["bigint type is not allowed."] : [];
120
- },
121
- })(props.collection)(route.output.type);
122
- if (result.success === false)
123
- props.errors.push(
124
- ...result.errors.map((e) => ({
125
- ...e,
126
- route,
127
- from: "response",
128
- })),
129
- );
130
-
131
- // DO ASSIGN
132
- const description =
133
- describe(route, "return") ?? describe(route, "returns");
134
- output[status] = {
135
- description: route.encrypted
136
- ? `${warning.get(!!description, "response", route.method)}${
137
- description ?? ""
138
- }`
139
- : description ?? "",
140
- content:
141
- route.output.typeName === "void"
142
- ? undefined
143
- : {
144
- [route.output.contentType]: {
145
- schema: coalesce(props)(result),
146
- },
147
- },
148
- ...(props.config.additional === true
149
- ? {
150
- "x-nestia-encrypted": route.encrypted,
151
- }
152
- : route.encrypted === true
153
- ? {
154
- "x-nestia-encrypted": true,
155
- }
156
- : {}),
157
- };
158
- return output;
159
- };
160
-
161
- export const body =
162
- (props: IProps) =>
163
- (route: IRoute) =>
164
- (param: IRoute.IParameter): ISwaggerRoute.IRequestBody => {
165
- // ANALZE TYPE WITH VALIDATION
166
- const result = MetadataFactory.analyze(props.checker)({
167
- escape: true,
168
- constant: true,
169
- absorb: true,
170
- validate: (meta) => {
171
- const bigint: boolean =
172
- meta.atomics.some((a) => a.type === "bigint") ||
173
- meta.constants.some((a) => a.type === "bigint");
174
- return bigint ? ["bigint type is not allowed."] : [];
175
- },
176
- })(props.collection)(param.type);
177
- if (result.success === false)
178
- props.errors.push(
179
- ...result.errors.map((e) => ({
180
- ...e,
181
- route,
182
- from: param.name,
183
- })),
184
- );
185
-
186
- // LIST UP PROPERTIES
187
- const contentType =
188
- param.custom && param.category === "body"
189
- ? param.contentType
190
- : "application/json";
191
- const encrypted: boolean =
192
- param.custom && param.category === "body" && param.encrypted;
193
- const description: string | undefined = describe(
194
- route,
195
- "param",
196
- param.name,
197
- );
198
-
199
- // RETURNS WITH LAZY CONSTRUCTION
200
- const schema: IJsonSchema = coalesce(props)(result);
201
- return {
202
- description: encrypted
203
- ? `${warning.get(!!description, "request")}${description ?? ""}`
204
- : description,
205
- content: {
206
- [contentType]: {
207
- schema,
208
- },
209
- },
210
- required: true,
211
- ...(props.config.additional === true
212
- ? {
213
- "x-nestia-encrypted": encrypted,
214
- }
215
- : encrypted === true
216
- ? {
217
- "x-nestia-encrypted": true,
218
- }
219
- : {}),
220
- };
221
- };
222
-
223
- export const parameter =
224
- (props: IProps) =>
225
- (route: IRoute) =>
226
- (param: IRoute.IParameter): ISwaggerRoute.IParameter[] =>
227
- param.category === "headers"
228
- ? headers(props)(route)(param)
229
- : param.category === "param"
230
- ? [path(props)(route)(param)]
231
- : query(props)(route)(param);
232
-
233
- const path =
234
- (props: IProps) =>
235
- (route: IRoute) =>
236
- (param: IRoute.IParameter): ISwaggerRoute.IParameter => {
237
- // ANALZE TYPE WITH VALIDATION
238
- const result = MetadataFactory.analyze(props.checker)({
239
- escape: false,
240
- constant: true,
241
- absorb: true,
242
- validate: SwaggerSchemaValidator.path,
243
- })(props.collection)(param.type);
244
- if (result.success === false)
245
- props.errors.push(
246
- ...result.errors.map((e) => ({
247
- ...e,
248
- route,
249
- from: param.name,
250
- })),
251
- );
252
-
253
- // RETURNS WITH LAZY CONSTRUCTION
254
- return lazy(props)(route)(param, result);
255
- };
256
-
257
- const headers =
258
- (props: IProps) =>
259
- (route: IRoute) =>
260
- (param: IRoute.IParameter): ISwaggerRoute.IParameter[] =>
261
- decomposible(props)(route)(param)(
262
- MetadataFactory.analyze(props.checker)({
263
- escape: false,
264
- constant: true,
265
- absorb: true,
266
- validate: param.custom ? SwaggerSchemaValidator.headers : undefined,
267
- })(props.collection)(param.type),
268
- );
269
-
270
- const query =
271
- (props: IProps) =>
272
- (route: IRoute) =>
273
- (param: IRoute.IParameter): ISwaggerRoute.IParameter[] =>
274
- decomposible(props)(route)(param)(
275
- MetadataFactory.analyze(props.checker)({
276
- escape: false,
277
- constant: true,
278
- absorb: true,
279
- validate: param.custom ? SwaggerSchemaValidator.query : undefined,
280
- })(props.collection)(param.type),
281
- );
282
-
283
- const decomposible =
284
- (props: IProps) =>
285
- (route: IRoute) =>
286
- (param: IRoute.IParameter) =>
287
- (
288
- result: ValidationPipe<Metadata, MetadataFactory.IError>,
289
- ): ISwaggerRoute.IParameter[] => {
290
- const decoded: ISwaggerRoute.IParameter = lazy(props)(route)(
291
- param,
292
- result,
293
- );
294
- if (result.success === false) {
295
- props.errors.push(
296
- ...result.errors.map((e) => ({
297
- ...e,
298
- route,
299
- from: param.name,
300
- })),
301
- );
302
- return [decoded];
303
- } else if (
304
- props.config.decompose !== true ||
305
- result.data.objects.length === 0
306
- )
307
- return [decoded];
308
-
309
- return result.data.objects[0].properties
310
- .filter((p) => p.jsDocTags.every((tag) => tag.name !== "hidden"))
311
- .map((p) => {
312
- const schema: IJsonSchema = {};
313
- props.lazyProperties.push({
314
- schema,
315
- object: result.data.objects[0].name,
316
- property: p.key.constants[0].values[0] as string,
317
- });
318
- return {
319
- name: p.key.constants[0].values[0] as string,
320
- in: param.category === "headers" ? "header" : param.category,
321
- schema,
322
- description: p.description ?? undefined,
323
- required: p.value.isRequired(),
324
- };
325
- });
326
- };
327
-
328
- const lazy =
329
- (props: IProps) =>
330
- (route: IRoute) =>
331
- (
332
- param: IRoute.IParameter,
333
- result: ValidationPipe<Metadata, MetadataFactory.IError>,
334
- ): ISwaggerRoute.IParameter => {
335
- const schema: IJsonSchema = coalesce(props)(result);
336
- return {
337
- name: param.field ?? param.name,
338
- in:
339
- param.category === "headers"
340
- ? "header"
341
- : param.category === "param"
342
- ? "path"
343
- : param.category,
344
- schema,
345
- description: describe(route, "param", param.name) ?? "",
346
- required: result.success ? result.data.isRequired() : true,
347
- };
348
- };
349
-
350
- const coalesce =
351
- (props: IProps) =>
352
- (result: ValidationPipe<Metadata, MetadataFactory.IError>): IJsonSchema => {
353
- const schema: IJsonSchema = {} as any;
354
- props.lazySchemas.push({
355
- metadata: result.success ? result.data : any.get(),
356
- schema,
357
- });
358
- return schema;
359
- };
360
-
361
- const describe = (
362
- route: IRoute,
363
- tagName: string,
364
- parameterName?: string,
365
- ): string | undefined => {
366
- const parametric: (elem: ts.JSDocTagInfo) => boolean = parameterName
367
- ? (tag) =>
368
- tag.text!.find(
369
- (elem) =>
370
- elem.kind === "parameterName" && elem.text === parameterName,
371
- ) !== undefined
372
- : () => true;
373
-
374
- const tag: ts.JSDocTagInfo | undefined = route.jsDocTags.find(
375
- (tag) => tag.name === tagName && tag.text && parametric(tag),
376
- );
377
- return tag && tag.text
378
- ? tag.text.find((elem) => elem.kind === "text")?.text
379
- : undefined;
380
- };
381
- }
382
-
383
- const warning = new VariadicSingleton(
384
- (described: boolean, type: "request" | "response", method?: string) => {
385
- const summary =
386
- type === "request"
387
- ? "Request body must be encrypted."
388
- : "Response data have been encrypted.";
389
- const component =
390
- type === "request"
391
- ? "[EncryptedBody](https://github.com/samchon/@nestia/core#encryptedbody)"
392
- : `[EncryptedRoute.${method![0].toUpperCase()}.${method!
393
- .substring(1)
394
- .toLowerCase()}](https://github.com/samchon/@nestia/core#encryptedroute)`;
395
-
396
- const content: string[] = [
397
- "## Warning",
398
- "",
399
- summary,
400
- "",
401
- `The ${type} body data would be encrypted as "AES-128(256) / CBC mode / PKCS#5 Padding / Base64 Encoding", through the ${component} component.`,
402
- "",
403
- `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.`,
404
- ];
405
- if (described === true) content.push("", "----------------", "", "");
406
- return content.join("\n");
407
- },
408
- );
409
-
410
- const any = new Singleton(() =>
411
- Metadata.from(
412
- {
413
- any: true,
414
- required: true,
415
- optional: false,
416
- nullable: false,
417
- functional: false,
418
- atomics: [],
419
- constants: [],
420
- templates: [],
421
- escaped: null,
422
- rest: null,
423
- arrays: [],
424
- tuples: [],
425
- objects: [],
426
- aliases: [],
427
- natives: [],
428
- sets: [],
429
- maps: [],
430
- },
431
- {
432
- aliases: new Map(),
433
- arrays: new Map(),
434
- tuples: new Map(),
435
- objects: new Map(),
436
- },
437
- ),
438
- );
1
+ import { Singleton, VariadicSingleton } from "tstl";
2
+ import ts from "typescript";
3
+ import { IJsonSchema } from "typia";
4
+ import { MetadataCollection } from "typia/lib/factories/MetadataCollection";
5
+ import { MetadataFactory } from "typia/lib/factories/MetadataFactory";
6
+ import { JsonApplicationProgrammer } from "typia/lib/programmers/json/JsonApplicationProgrammer";
7
+ import { Metadata } from "typia/lib/schemas/metadata/Metadata";
8
+ import { ValidationPipe } from "typia/lib/typings/ValidationPipe";
9
+
10
+ import { INestiaConfig } from "../../INestiaConfig";
11
+ import { IRoute } from "../../structures/IRoute";
12
+ import { ISwaggerError } from "../../structures/ISwaggerError";
13
+ import { ISwaggerLazyProperty } from "../../structures/ISwaggerLazyProperty";
14
+ import { ISwaggerLazySchema } from "../../structures/ISwaggerLazySchema";
15
+ import { ISwaggerRoute } from "../../structures/ISwaggerRoute";
16
+ import { SwaggerSchemaValidator } from "./SwaggerSchemaValidator";
17
+
18
+ export namespace SwaggerSchemaGenerator {
19
+ export interface IProps {
20
+ config: INestiaConfig.ISwaggerConfig;
21
+ checker: ts.TypeChecker;
22
+ collection: MetadataCollection;
23
+ lazySchemas: Array<ISwaggerLazySchema>;
24
+ lazyProperties: Array<ISwaggerLazyProperty>;
25
+ errors: ISwaggerError[];
26
+ }
27
+
28
+ export const response =
29
+ (props: IProps) =>
30
+ (route: IRoute): ISwaggerRoute.IResponseBody => {
31
+ const output: ISwaggerRoute.IResponseBody = {};
32
+
33
+ //----
34
+ // EXCEPTION STATUSES
35
+ //----
36
+ // FROM DECORATOR
37
+ for (const [status, exp] of Object.entries(route.exceptions)) {
38
+ const result = MetadataFactory.analyze(props.checker)({
39
+ escape: true,
40
+ constant: true,
41
+ absorb: false,
42
+ validate: JsonApplicationProgrammer.validate,
43
+ })(props.collection)(exp.type);
44
+ if (result.success === false)
45
+ props.errors.push(
46
+ ...result.errors.map((e) => ({
47
+ ...e,
48
+ route,
49
+ from: `response(status: ${status})`,
50
+ })),
51
+ );
52
+
53
+ output[status] = {
54
+ description: exp.description ?? "",
55
+ content: {
56
+ "application/json": {
57
+ schema: coalesce(props)(result),
58
+ },
59
+ },
60
+ };
61
+ }
62
+
63
+ // FROM COMMENT TAGS -> ANY
64
+ for (const tag of route.jsDocTags) {
65
+ if (tag.name !== "throw" && tag.name !== "throws") continue;
66
+
67
+ const text: string | undefined = tag.text?.find(
68
+ (elem) => elem.kind === "text",
69
+ )?.text;
70
+ if (text === undefined) continue;
71
+
72
+ const elements: string[] = text.split(" ").map((str) => str.trim());
73
+ const status: string = elements[0];
74
+ if (
75
+ isNaN(Number(status)) &&
76
+ status !== "2XX" &&
77
+ status !== "3XX" &&
78
+ status !== "4XX" &&
79
+ status !== "5XX"
80
+ )
81
+ continue;
82
+
83
+ const description: string | undefined =
84
+ elements.length === 1 ? undefined : elements.slice(1).join(" ");
85
+ const oldbie = output[status];
86
+ if (description && oldbie !== undefined)
87
+ oldbie.description = description;
88
+ else if (oldbie === undefined)
89
+ output[status] = {
90
+ description: description ?? "",
91
+ content: {
92
+ "application/json": {
93
+ schema: {},
94
+ },
95
+ },
96
+ };
97
+ }
98
+
99
+ //----
100
+ // SUCCESS
101
+ //----
102
+ // STATUS
103
+ const status: string =
104
+ route.status !== undefined
105
+ ? String(route.status)
106
+ : route.method === "POST"
107
+ ? "201"
108
+ : "200";
109
+
110
+ // SCHEMA
111
+ const result = MetadataFactory.analyze(props.checker)({
112
+ escape: true,
113
+ constant: true,
114
+ absorb: false,
115
+ validate: (meta) => {
116
+ const bigint: boolean =
117
+ meta.atomics.some((a) => a.type === "bigint") ||
118
+ meta.constants.some((a) => a.type === "bigint");
119
+ return bigint ? ["bigint type is not allowed."] : [];
120
+ },
121
+ })(props.collection)(route.output.type);
122
+ if (result.success === false)
123
+ props.errors.push(
124
+ ...result.errors.map((e) => ({
125
+ ...e,
126
+ route,
127
+ from: "response",
128
+ })),
129
+ );
130
+
131
+ // DO ASSIGN
132
+ const description =
133
+ describe(route, "return") ?? describe(route, "returns");
134
+ output[status] = {
135
+ description: route.encrypted
136
+ ? `${warning.get(!!description, "response", route.method)}${
137
+ description ?? ""
138
+ }`
139
+ : description ?? "",
140
+ content:
141
+ route.output.typeName === "void"
142
+ ? undefined
143
+ : {
144
+ [route.output.contentType]: {
145
+ schema: coalesce(props)(result),
146
+ },
147
+ },
148
+ ...(props.config.additional === true
149
+ ? {
150
+ "x-nestia-encrypted": route.encrypted,
151
+ }
152
+ : route.encrypted === true
153
+ ? {
154
+ "x-nestia-encrypted": true,
155
+ }
156
+ : {}),
157
+ };
158
+ return output;
159
+ };
160
+
161
+ export const body =
162
+ (props: IProps) =>
163
+ (route: IRoute) =>
164
+ (param: IRoute.IParameter): ISwaggerRoute.IRequestBody => {
165
+ // ANALZE TYPE WITH VALIDATION
166
+ const result = MetadataFactory.analyze(props.checker)({
167
+ escape: true,
168
+ constant: true,
169
+ absorb: true,
170
+ validate: (meta) => {
171
+ const bigint: boolean =
172
+ meta.atomics.some((a) => a.type === "bigint") ||
173
+ meta.constants.some((a) => a.type === "bigint");
174
+ return bigint ? ["bigint type is not allowed."] : [];
175
+ },
176
+ })(props.collection)(param.type);
177
+ if (result.success === false)
178
+ props.errors.push(
179
+ ...result.errors.map((e) => ({
180
+ ...e,
181
+ route,
182
+ from: param.name,
183
+ })),
184
+ );
185
+
186
+ // LIST UP PROPERTIES
187
+ const contentType =
188
+ param.custom && param.category === "body"
189
+ ? param.contentType
190
+ : "application/json";
191
+ const encrypted: boolean =
192
+ param.custom && param.category === "body" && param.encrypted;
193
+ const description: string | undefined = describe(
194
+ route,
195
+ "param",
196
+ param.name,
197
+ );
198
+
199
+ // RETURNS WITH LAZY CONSTRUCTION
200
+ const schema: IJsonSchema = coalesce(props)(result);
201
+ return {
202
+ description: encrypted
203
+ ? `${warning.get(!!description, "request")}${description ?? ""}`
204
+ : description,
205
+ content: {
206
+ [contentType]: {
207
+ schema,
208
+ },
209
+ },
210
+ required: true,
211
+ ...(props.config.additional === true
212
+ ? {
213
+ "x-nestia-encrypted": encrypted,
214
+ }
215
+ : encrypted === true
216
+ ? {
217
+ "x-nestia-encrypted": true,
218
+ }
219
+ : {}),
220
+ };
221
+ };
222
+
223
+ export const parameter =
224
+ (props: IProps) =>
225
+ (route: IRoute) =>
226
+ (param: IRoute.IParameter): ISwaggerRoute.IParameter[] =>
227
+ param.category === "headers"
228
+ ? headers(props)(route)(param)
229
+ : param.category === "param"
230
+ ? [path(props)(route)(param)]
231
+ : query(props)(route)(param);
232
+
233
+ const path =
234
+ (props: IProps) =>
235
+ (route: IRoute) =>
236
+ (param: IRoute.IParameter): ISwaggerRoute.IParameter => {
237
+ // ANALZE TYPE WITH VALIDATION
238
+ const result = MetadataFactory.analyze(props.checker)({
239
+ escape: false,
240
+ constant: true,
241
+ absorb: true,
242
+ validate: SwaggerSchemaValidator.path,
243
+ })(props.collection)(param.type);
244
+ if (result.success === false)
245
+ props.errors.push(
246
+ ...result.errors.map((e) => ({
247
+ ...e,
248
+ route,
249
+ from: param.name,
250
+ })),
251
+ );
252
+
253
+ // RETURNS WITH LAZY CONSTRUCTION
254
+ return lazy(props)(route)(param, result);
255
+ };
256
+
257
+ const headers =
258
+ (props: IProps) =>
259
+ (route: IRoute) =>
260
+ (param: IRoute.IParameter): ISwaggerRoute.IParameter[] =>
261
+ decomposible(props)(route)(param)(
262
+ MetadataFactory.analyze(props.checker)({
263
+ escape: false,
264
+ constant: true,
265
+ absorb: true,
266
+ validate: param.custom ? SwaggerSchemaValidator.headers : undefined,
267
+ })(props.collection)(param.type),
268
+ );
269
+
270
+ const query =
271
+ (props: IProps) =>
272
+ (route: IRoute) =>
273
+ (param: IRoute.IParameter): ISwaggerRoute.IParameter[] =>
274
+ decomposible(props)(route)(param)(
275
+ MetadataFactory.analyze(props.checker)({
276
+ escape: false,
277
+ constant: true,
278
+ absorb: true,
279
+ validate: param.custom ? SwaggerSchemaValidator.query : undefined,
280
+ })(props.collection)(param.type),
281
+ );
282
+
283
+ const decomposible =
284
+ (props: IProps) =>
285
+ (route: IRoute) =>
286
+ (param: IRoute.IParameter) =>
287
+ (
288
+ result: ValidationPipe<Metadata, MetadataFactory.IError>,
289
+ ): ISwaggerRoute.IParameter[] => {
290
+ const decoded: ISwaggerRoute.IParameter = lazy(props)(route)(
291
+ param,
292
+ result,
293
+ );
294
+ if (result.success === false) {
295
+ props.errors.push(
296
+ ...result.errors.map((e) => ({
297
+ ...e,
298
+ route,
299
+ from: param.name,
300
+ })),
301
+ );
302
+ return [decoded];
303
+ } else if (
304
+ props.config.decompose !== true ||
305
+ result.data.objects.length === 0
306
+ )
307
+ return [decoded];
308
+
309
+ return result.data.objects[0].properties
310
+ .filter((p) => p.jsDocTags.every((tag) => tag.name !== "hidden"))
311
+ .map((p) => {
312
+ const schema: IJsonSchema = {};
313
+ props.lazyProperties.push({
314
+ schema,
315
+ object: result.data.objects[0].name,
316
+ property: p.key.constants[0].values[0] as string,
317
+ });
318
+ return {
319
+ name: p.key.constants[0].values[0] as string,
320
+ in: param.category === "headers" ? "header" : param.category,
321
+ schema,
322
+ description: p.description ?? undefined,
323
+ required: p.value.isRequired(),
324
+ };
325
+ });
326
+ };
327
+
328
+ const lazy =
329
+ (props: IProps) =>
330
+ (route: IRoute) =>
331
+ (
332
+ param: IRoute.IParameter,
333
+ result: ValidationPipe<Metadata, MetadataFactory.IError>,
334
+ ): ISwaggerRoute.IParameter => {
335
+ const schema: IJsonSchema = coalesce(props)(result);
336
+ return {
337
+ name: param.field ?? param.name,
338
+ in:
339
+ param.category === "headers"
340
+ ? "header"
341
+ : param.category === "param"
342
+ ? "path"
343
+ : param.category,
344
+ schema,
345
+ description: describe(route, "param", param.name) ?? "",
346
+ required: result.success ? result.data.isRequired() : true,
347
+ };
348
+ };
349
+
350
+ const coalesce =
351
+ (props: IProps) =>
352
+ (result: ValidationPipe<Metadata, MetadataFactory.IError>): IJsonSchema => {
353
+ const schema: IJsonSchema = {} as any;
354
+ props.lazySchemas.push({
355
+ metadata: result.success ? result.data : any.get(),
356
+ schema,
357
+ });
358
+ return schema;
359
+ };
360
+
361
+ const describe = (
362
+ route: IRoute,
363
+ tagName: string,
364
+ parameterName?: string,
365
+ ): string | undefined => {
366
+ const parametric: (elem: ts.JSDocTagInfo) => boolean = parameterName
367
+ ? (tag) =>
368
+ tag.text!.find(
369
+ (elem) =>
370
+ elem.kind === "parameterName" && elem.text === parameterName,
371
+ ) !== undefined
372
+ : () => true;
373
+
374
+ const tag: ts.JSDocTagInfo | undefined = route.jsDocTags.find(
375
+ (tag) => tag.name === tagName && tag.text && parametric(tag),
376
+ );
377
+ return tag && tag.text
378
+ ? tag.text.find((elem) => elem.kind === "text")?.text
379
+ : undefined;
380
+ };
381
+ }
382
+
383
+ const warning = new VariadicSingleton(
384
+ (described: boolean, type: "request" | "response", method?: string) => {
385
+ const summary =
386
+ type === "request"
387
+ ? "Request body must be encrypted."
388
+ : "Response data have been encrypted.";
389
+ const component =
390
+ type === "request"
391
+ ? "[EncryptedBody](https://github.com/samchon/@nestia/core#encryptedbody)"
392
+ : `[EncryptedRoute.${method![0].toUpperCase()}.${method!
393
+ .substring(1)
394
+ .toLowerCase()}](https://github.com/samchon/@nestia/core#encryptedroute)`;
395
+
396
+ const content: string[] = [
397
+ "## Warning",
398
+ "",
399
+ summary,
400
+ "",
401
+ `The ${type} body data would be encrypted as "AES-128(256) / CBC mode / PKCS#5 Padding / Base64 Encoding", through the ${component} component.`,
402
+ "",
403
+ `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.`,
404
+ ];
405
+ if (described === true) content.push("", "----------------", "", "");
406
+ return content.join("\n");
407
+ },
408
+ );
409
+
410
+ const any = new Singleton(() =>
411
+ Metadata.from(
412
+ {
413
+ any: true,
414
+ required: true,
415
+ optional: false,
416
+ nullable: false,
417
+ functional: false,
418
+ atomics: [],
419
+ constants: [],
420
+ templates: [],
421
+ escaped: null,
422
+ rest: null,
423
+ arrays: [],
424
+ tuples: [],
425
+ objects: [],
426
+ aliases: [],
427
+ natives: [],
428
+ sets: [],
429
+ maps: [],
430
+ },
431
+ {
432
+ aliases: new Map(),
433
+ arrays: new Map(),
434
+ tuples: new Map(),
435
+ objects: new Map(),
436
+ },
437
+ ),
438
+ );