@nestia/sdk 2.4.7-dev.20240126 → 2.5.0-dev.20240128

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