@nestia/sdk 2.0.0-dev.20230991 → 2.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 (93) hide show
  1. package/assets/bundle/api/utils/NestiaSimulator.ts +5 -14
  2. package/lib/INestiaConfig.d.ts +60 -47
  3. package/lib/NestiaSdkApplication.d.ts +6 -5
  4. package/lib/NestiaSdkApplication.js +30 -87
  5. package/lib/NestiaSdkApplication.js.map +1 -1
  6. package/lib/analyses/ControllerAnalyzer.js +8 -5
  7. package/lib/analyses/ControllerAnalyzer.js.map +1 -1
  8. package/lib/analyses/ReflectAnalyzer.js +9 -1
  9. package/lib/analyses/ReflectAnalyzer.js.map +1 -1
  10. package/lib/executable/internal/NestiaConfigLoader.d.ts +7 -0
  11. package/lib/executable/internal/NestiaConfigLoader.js +582 -0
  12. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -0
  13. package/lib/executable/internal/NestiaProjectGetter.d.ts +3 -0
  14. package/lib/executable/internal/NestiaProjectGetter.js +28 -0
  15. package/lib/executable/internal/NestiaProjectGetter.js.map +1 -0
  16. package/lib/executable/internal/NestiaSdkCommand.d.ts +3 -3
  17. package/lib/executable/internal/NestiaSdkCommand.js +13 -104
  18. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  19. package/lib/executable/internal/{nestia.config.getter.js → nestia.project.getter.js} +3 -3
  20. package/lib/executable/internal/nestia.project.getter.js.map +1 -0
  21. package/lib/executable/sdk.js +3 -3
  22. package/lib/executable/sdk.js.map +1 -1
  23. package/lib/generates/SdkGenerator.d.ts +2 -1
  24. package/lib/generates/SdkGenerator.js +7 -3
  25. package/lib/generates/SdkGenerator.js.map +1 -1
  26. package/lib/generates/SwaggerGenerator.js +26 -9
  27. package/lib/generates/SwaggerGenerator.js.map +1 -1
  28. package/lib/generates/internal/E2eFileProgrammer.js +21 -15
  29. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  30. package/lib/generates/internal/{DistributionComposer.d.ts → SdkDistributionComposer.d.ts} +1 -1
  31. package/lib/generates/internal/{DistributionComposer.js → SdkDistributionComposer.js} +8 -12
  32. package/lib/generates/internal/SdkDistributionComposer.js.map +1 -0
  33. package/lib/generates/internal/SdkDtoGenerator.d.ts +9 -0
  34. package/lib/generates/internal/SdkDtoGenerator.js +264 -0
  35. package/lib/generates/internal/SdkDtoGenerator.js.map +1 -0
  36. package/lib/generates/internal/SdkFileProgrammer.js +8 -7
  37. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  38. package/lib/generates/internal/SdkFunctionProgrammer.js +32 -22
  39. package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -1
  40. package/lib/generates/internal/SdkImportWizard.d.ts +2 -0
  41. package/lib/generates/internal/SdkImportWizard.js +10 -0
  42. package/lib/generates/internal/SdkImportWizard.js.map +1 -1
  43. package/lib/generates/internal/SdkSimulationProgrammer.js +61 -25
  44. package/lib/generates/internal/SdkSimulationProgrammer.js.map +1 -1
  45. package/lib/generates/internal/SdkTypeDefiner.d.ts +11 -0
  46. package/lib/generates/internal/SdkTypeDefiner.js +82 -0
  47. package/lib/generates/internal/SdkTypeDefiner.js.map +1 -0
  48. package/lib/generates/internal/SwaggerSchemaGenerator.d.ts +1 -1
  49. package/lib/generates/internal/SwaggerSchemaGenerator.js +67 -75
  50. package/lib/generates/internal/SwaggerSchemaGenerator.js.map +1 -1
  51. package/lib/generates/internal/SwaggerSchemaValidator.js +0 -8
  52. package/lib/generates/internal/SwaggerSchemaValidator.js.map +1 -1
  53. package/lib/structures/IController.d.ts +2 -0
  54. package/lib/structures/IRoute.d.ts +9 -2
  55. package/lib/utils/ImportDictionary.d.ts +1 -2
  56. package/lib/utils/ImportDictionary.js +28 -24
  57. package/lib/utils/ImportDictionary.js.map +1 -1
  58. package/package.json +8 -8
  59. package/src/INestiaConfig.ts +65 -50
  60. package/src/NestiaSdkApplication.ts +39 -84
  61. package/src/analyses/ControllerAnalyzer.ts +10 -8
  62. package/src/analyses/ReflectAnalyzer.ts +8 -0
  63. package/src/executable/internal/NestiaConfigLoader.ts +82 -0
  64. package/src/executable/internal/NestiaProjectGetter.ts +11 -0
  65. package/src/executable/internal/NestiaSdkCommand.ts +23 -146
  66. package/src/executable/internal/{nestia.config.getter.ts → nestia.project.getter.ts} +2 -2
  67. package/src/executable/sdk.ts +3 -3
  68. package/src/generates/SdkGenerator.ts +9 -2
  69. package/src/generates/SwaggerGenerator.ts +37 -9
  70. package/src/generates/internal/E2eFileProgrammer.ts +33 -20
  71. package/src/generates/internal/{DistributionComposer.ts → SdkDistributionComposer.ts} +3 -6
  72. package/src/generates/internal/SdkDtoGenerator.ts +384 -0
  73. package/src/generates/internal/SdkFileProgrammer.ts +8 -7
  74. package/src/generates/internal/SdkFunctionProgrammer.ts +71 -37
  75. package/src/generates/internal/SdkImportWizard.ts +14 -0
  76. package/src/generates/internal/SdkSimulationProgrammer.ts +71 -37
  77. package/src/generates/internal/SdkTypeDefiner.ts +120 -0
  78. package/src/generates/internal/SwaggerSchemaGenerator.ts +94 -92
  79. package/src/generates/internal/SwaggerSchemaValidator.ts +0 -12
  80. package/src/structures/IController.ts +2 -0
  81. package/src/structures/IRoute.ts +10 -2
  82. package/src/utils/ImportDictionary.ts +29 -26
  83. package/lib/executable/internal/NestiaConfigCompilerOptions.d.ts +0 -12
  84. package/lib/executable/internal/NestiaConfigCompilerOptions.js +0 -18
  85. package/lib/executable/internal/NestiaConfigCompilerOptions.js.map +0 -1
  86. package/lib/executable/internal/NestiaSdkConfig.d.ts +0 -4
  87. package/lib/executable/internal/NestiaSdkConfig.js +0 -1019
  88. package/lib/executable/internal/NestiaSdkConfig.js.map +0 -1
  89. package/lib/executable/internal/nestia.config.getter.js.map +0 -1
  90. package/lib/generates/internal/DistributionComposer.js.map +0 -1
  91. package/src/executable/internal/NestiaConfigCompilerOptions.ts +0 -19
  92. package/src/executable/internal/NestiaSdkConfig.ts +0 -36
  93. /package/lib/executable/internal/{nestia.config.getter.d.ts → nestia.project.getter.d.ts} +0 -0
@@ -2,27 +2,21 @@ import { INestiaConfig } from "../../INestiaConfig";
2
2
  import { IRoute } from "../../structures/IRoute";
3
3
  import { ImportDictionary } from "../../utils/ImportDictionary";
4
4
  import { SdkImportWizard } from "./SdkImportWizard";
5
+ import { SdkTypeDefiner } from "./SdkTypeDefiner";
5
6
 
6
7
  export namespace SdkSimulationProgrammer {
7
8
  export const generate =
8
9
  (config: INestiaConfig) =>
9
10
  (importer: ImportDictionary) =>
10
11
  (route: IRoute): string => {
11
- const output: boolean = route.output.typeName !== "void";
12
- const returns = () => [
13
- `return random(`,
14
- ` typeof connection.simulate === 'object' &&`,
15
- ` connection.simulate !== null`,
16
- ` ? connection.simulate`,
17
- ` : undefined`,
18
- `);`,
19
- ];
12
+ const output: boolean =
13
+ config.propagate === true || route.output.typeName !== "void";
20
14
  const body: string[] = [
21
15
  ...(route.parameters.filter((p) => p.category !== "headers")
22
16
  .length !== 0
23
- ? assert(config)(importer)(route.parameters)
17
+ ? assert(config)(importer)(route)
24
18
  : []),
25
- ...(output ? returns() : []),
19
+ ...(output ? returns(config)(route) : []),
26
20
  ];
27
21
  return [
28
22
  `export const simulate = async (`,
@@ -52,7 +46,7 @@ export namespace SdkSimulationProgrammer {
52
46
  ? "Query"
53
47
  : "Input"
54
48
  }`
55
- : p.typeName
49
+ : SdkTypeDefiner.name(config)(importer)(p)
56
50
  },`,
57
51
  ),
58
52
  `): Promise<${output ? "Output" : "void"}> => {`,
@@ -66,8 +60,9 @@ export namespace SdkSimulationProgrammer {
66
60
  const assert =
67
61
  (config: INestiaConfig) =>
68
62
  (importer: ImportDictionary) =>
69
- (parameters: IRoute.IParameter[]): string[] => {
70
- return [
63
+ (route: IRoute): string[] => {
64
+ const typia = SdkImportWizard.typia(importer);
65
+ const func: string[] = [
71
66
  `const assert = ${importer.internal({
72
67
  file: `${config.output}/utils/NestiaSimulator.ts`,
73
68
  instance: "NestiaSimulator",
@@ -75,34 +70,73 @@ export namespace SdkSimulationProgrammer {
75
70
  })}.assert({`,
76
71
  ` method: METADATA.method,`,
77
72
  ` host: connection.host,`,
78
- ` path: path(${parameters
73
+ ` path: path(${route.parameters
79
74
  .filter(
80
75
  (p) => p.category === "param" || p.category === "query",
81
76
  )
82
77
  .map((p) => p.name)
83
- .join(", ")})`,
78
+ .join(", ")}),`,
79
+ ` contentType: ${JSON.stringify(route.output.contentType)},`,
84
80
  `});`,
85
- ...parameters
86
- .filter((p) => p.category !== "headers")
87
- .map((p) =>
88
- p.category === "body"
89
- ? `assert.body(() => ${SdkImportWizard.typia(
90
- importer,
91
- )}.assert(${p.name}));`
92
- : p.category === "query"
93
- ? `assert.query(() => ${SdkImportWizard.typia(
94
- importer,
95
- )}.assert(${p.name}));`
96
- : p.category === "headers"
97
- ? `assert.headers(() => ${SdkImportWizard.typia(
98
- importer,
99
- )}.assert(connection.headers);` // not reachable
100
- : `assert.param("${
101
- p.field
102
- }")(() => ${SdkImportWizard.typia(
103
- importer,
104
- )}.assert(${p.name}));`,
105
- ),
81
+ ];
82
+ const individual: string[] = route.parameters
83
+ .filter((p) => p.category !== "headers")
84
+ .map((p) =>
85
+ p.category === "body"
86
+ ? `assert.body(() => ${typia}.assert(${p.name}));`
87
+ : p.category === "query"
88
+ ? `assert.query(() => ${typia}.assert(${p.name}));`
89
+ : p.category === "headers"
90
+ ? `assert.headers(() => ${typia}.assert(connection.headers);`
91
+ : `assert.param("${p.field}")(() => ${typia}.assert(${p.name}));`,
92
+ );
93
+ if (config.propagate !== true) return [...func, ...individual];
94
+
95
+ return [
96
+ ...func,
97
+ `try {`,
98
+ ...individual.map((l) => ` ${l}`),
99
+ `} catch (exp) {`,
100
+ ` if (!${typia}.is<${SdkImportWizard.HttpError(
101
+ importer,
102
+ )}>(exp)) throw exp;`,
103
+ ` return {`,
104
+ ` success: false,`,
105
+ ` status: exp.status,`,
106
+ ` headers: exp.headers,`,
107
+ ` data: exp.toJSON().message,`,
108
+ ` } as any;`,
109
+ `}`,
110
+ ];
111
+ };
112
+
113
+ const returns =
114
+ (config: INestiaConfig) =>
115
+ (route: IRoute): string[] => {
116
+ const random = (prefix: string, postfix: string) =>
117
+ route.output.typeName === "void"
118
+ ? [`${prefix} undefined${postfix}`]
119
+ : [
120
+ `${prefix} random(`,
121
+ ` typeof connection.simulate === 'object' &&`,
122
+ ` connection.simulate !== null`,
123
+ ` ? connection.simulate`,
124
+ ` : undefined`,
125
+ `)${postfix}`,
126
+ ];
127
+ if (config.propagate !== true) return random("return", ";");
128
+
129
+ return [
130
+ `return {`,
131
+ ` success: true,`,
132
+ ` status: ${
133
+ route.status ?? route.method === "POST" ? 201 : 200
134
+ },`,
135
+ ` headers: {`,
136
+ ` "Content-Type": "${route.output.contentType}",`,
137
+ ` },`,
138
+ ...random("data:", ",").map((r) => ` ${r}`),
139
+ `}`,
106
140
  ];
107
141
  };
108
142
  }
@@ -0,0 +1,120 @@
1
+ import { INestiaConfig } from "../../INestiaConfig";
2
+ import { IRoute } from "../../structures/IRoute";
3
+ import { ImportDictionary } from "../../utils/ImportDictionary";
4
+ import { SdkDtoGenerator } from "./SdkDtoGenerator";
5
+
6
+ export namespace SdkTypeDefiner {
7
+ export const name =
8
+ (config: INestiaConfig) =>
9
+ (importer: ImportDictionary) =>
10
+ (p: IRoute.IParameter | IRoute.IOutput): string =>
11
+ p.metadata
12
+ ? SdkDtoGenerator.decode(config)(importer)(p.metadata)
13
+ : p.typeName;
14
+
15
+ export const headers =
16
+ (config: INestiaConfig) =>
17
+ (importer: ImportDictionary) =>
18
+ (param: IRoute.IParameter): string => {
19
+ const type: string = name(config)(importer)(param);
20
+ if (config.primitive === false) return type;
21
+
22
+ const resolved: string = importer.external({
23
+ type: true,
24
+ library: "@nestia/fetcher",
25
+ instance: "Resolved",
26
+ });
27
+ return `${resolved}<${type}>`;
28
+ };
29
+
30
+ export const query =
31
+ (config: INestiaConfig) =>
32
+ (importer: ImportDictionary) =>
33
+ (param: IRoute.IParameter): string => {
34
+ const type: string = name(config)(importer)(param);
35
+ if (config.primitive === false) return type;
36
+
37
+ const resolved: string = importer.external({
38
+ type: true,
39
+ library: "@nestia/fetcher",
40
+ instance: "Resolved",
41
+ });
42
+ return `${resolved}<${type}>`;
43
+ };
44
+
45
+ export const input =
46
+ (config: INestiaConfig) =>
47
+ (importer: ImportDictionary) =>
48
+ (param: IRoute.IParameter): string => {
49
+ const type: string = name(config)(importer)(param);
50
+ if (config.primitive === false) return type;
51
+
52
+ const primitive: string = importer.external({
53
+ type: true,
54
+ library: "@nestia/fetcher",
55
+ instance: "Primitive",
56
+ });
57
+ return `${primitive}<${type}>`;
58
+ };
59
+
60
+ export const output =
61
+ (config: INestiaConfig) =>
62
+ (importer: ImportDictionary) =>
63
+ (route: IRoute): string => {
64
+ if (config.propagate !== true) {
65
+ const type: string = name(config)(importer)(route.output);
66
+ if (type === "void" || config.primitive === false) return type;
67
+
68
+ const primitive: string = importer.external({
69
+ type: true,
70
+ library: "@nestia/fetcher",
71
+ instance: "Primitive",
72
+ });
73
+ return `${primitive}<${type}>`;
74
+ }
75
+
76
+ const propagation: string = importer.external({
77
+ type: true,
78
+ library: "@nestia/fetcher",
79
+ instance: "IPropagation",
80
+ });
81
+ const branches: IBranch[] = [
82
+ {
83
+ status: String(
84
+ route.status ?? route.method === "POST" ? 201 : 200,
85
+ ),
86
+ type: name(config)(importer)(route.output),
87
+ },
88
+ ...Object.entries(route.exceptions).map(([status, value]) => ({
89
+ status,
90
+ type: name(config)(importer)(value),
91
+ })),
92
+ ];
93
+ return (
94
+ `${propagation}<{\n` +
95
+ branches
96
+ .map(
97
+ (b) =>
98
+ ` ${
99
+ b.status.endsWith("XX")
100
+ ? `"${b.status}"`
101
+ : b.status
102
+ }: ${b.type};`,
103
+ )
104
+ .join("\n") +
105
+ "\n" +
106
+ ` }${route.status ? `, ${route.status}` : ""}>`
107
+ );
108
+ };
109
+
110
+ export const responseBody =
111
+ (config: INestiaConfig) =>
112
+ (importer: ImportDictionary) =>
113
+ (route: IRoute): string =>
114
+ output({ ...config, propagate: false })(importer)(route);
115
+ }
116
+
117
+ interface IBranch {
118
+ status: string;
119
+ type: string;
120
+ }
@@ -49,7 +49,7 @@ export namespace SwaggerSchemaGenerator {
49
49
  ...result.errors.map((e) => ({
50
50
  ...e,
51
51
  route,
52
- from: `response body (status: ${status})`,
52
+ from: `response(status: ${status})`,
53
53
  })),
54
54
  );
55
55
 
@@ -57,14 +57,14 @@ export namespace SwaggerSchemaGenerator {
57
57
  description: exp.description ?? "",
58
58
  content: {
59
59
  "application/json": {
60
- schema: coalesceSchema(props)(result),
60
+ schema: coalesce(props)(result),
61
61
  },
62
62
  },
63
63
  };
64
64
  }
65
65
 
66
66
  // FROM COMMENT TAGS -> ANY
67
- for (const tag of route.tags) {
67
+ for (const tag of route.jsDocTags) {
68
68
  if (tag.name !== "throw" && tag.name !== "throws") continue;
69
69
 
70
70
  const text: string | undefined = tag.text?.find(
@@ -133,7 +133,7 @@ export namespace SwaggerSchemaGenerator {
133
133
  ...result.errors.map((e) => ({
134
134
  ...e,
135
135
  route,
136
- from: `response body (status: ${status})`,
136
+ from: "response",
137
137
  })),
138
138
  );
139
139
 
@@ -151,7 +151,7 @@ export namespace SwaggerSchemaGenerator {
151
151
  ? undefined
152
152
  : {
153
153
  [route.output.contentType]: {
154
- schema: coalesceSchema(props)(result),
154
+ schema: coalesce(props)(result),
155
155
  },
156
156
  },
157
157
  "x-nestia-encrypted": route.encrypted,
@@ -180,7 +180,7 @@ export namespace SwaggerSchemaGenerator {
180
180
  ...result.errors.map((e) => ({
181
181
  ...e,
182
182
  route,
183
- from: `body parameter ${param.name}`,
183
+ from: param.name,
184
184
  })),
185
185
  );
186
186
 
@@ -198,7 +198,7 @@ export namespace SwaggerSchemaGenerator {
198
198
  );
199
199
 
200
200
  // RETURNS WITH LAZY CONSTRUCTION
201
- const schema: IJsonSchema = coalesceSchema(props)(result);
201
+ const schema: IJsonSchema = coalesce(props)(result);
202
202
  return {
203
203
  description: encrypted
204
204
  ? `${warning.get(!!description).get("request")}${
@@ -218,49 +218,13 @@ export namespace SwaggerSchemaGenerator {
218
218
  export const parameter =
219
219
  (props: IProps) =>
220
220
  (route: IRoute) =>
221
- (param: IRoute.IParameter): ISwaggerRoute.IParameter =>
221
+ (param: IRoute.IParameter): ISwaggerRoute.IParameter[] =>
222
222
  param.category === "headers"
223
223
  ? headers(props)(route)(param)
224
224
  : param.category === "param"
225
- ? path(props)(route)(param)
225
+ ? [path(props)(route)(param)]
226
226
  : query(props)(route)(param);
227
227
 
228
- const headers =
229
- (props: IProps) =>
230
- (route: IRoute) =>
231
- (param: IRoute.IParameter): ISwaggerRoute.IParameter => {
232
- // ANALYZE TYPE WITH VALIDATIONS
233
- const result = (() => {
234
- const result = MetadataFactory.analyze(props.checker)({
235
- escape: false,
236
- constant: true,
237
- absorb: true,
238
- })(props.collection)(param.type);
239
- if (result.success === false)
240
- props.errors.push(
241
- ...result.errors.map((e) => ({
242
- ...e,
243
- route,
244
- from: `header parameter ${param.name}`,
245
- })),
246
- );
247
- else if (result.data.objects.length === 1) {
248
- // WHEN OBJECT CASE, VALIDATE IT MORE DETAILY
249
- const again = MetadataFactory.analyze(props.checker)({
250
- escape: false,
251
- constant: true,
252
- absorb: true,
253
- validate: SwaggerSchemaValidator.headers,
254
- })(new MetadataCollection())(param.type);
255
- if (again.success === false) return again;
256
- }
257
- return result;
258
- })();
259
-
260
- // RETURNS WITH LAZY CONSTRUCTION
261
- return lazyParameterReturns(props)(route)("header")(param, result);
262
- };
263
-
264
228
  const path =
265
229
  (props: IProps) =>
266
230
  (route: IRoute) =>
@@ -277,86 +241,124 @@ export namespace SwaggerSchemaGenerator {
277
241
  ...result.errors.map((e) => ({
278
242
  ...e,
279
243
  route,
280
- from: `path parameter ${param.name}`,
244
+ from: param.name,
281
245
  })),
282
246
  );
283
247
 
284
248
  // RETURNS WITH LAZY CONSTRUCTION
285
- return lazyParameterReturns(props)(route)("path")(param, result);
249
+ return lazy(props)(route)(param, result);
286
250
  };
287
251
 
288
- const query =
252
+ const headers =
289
253
  (props: IProps) =>
290
254
  (route: IRoute) =>
291
- (param: IRoute.IParameter): ISwaggerRoute.IParameter => {
292
- // ANALYZE TYPE WITH VALIDATIONS
293
- const result = (() => {
294
- const result = MetadataFactory.analyze(props.checker)({
255
+ (param: IRoute.IParameter): ISwaggerRoute.IParameter[] =>
256
+ decomposible(props)(route)(param)(
257
+ MetadataFactory.analyze(props.checker)({
295
258
  escape: false,
296
259
  constant: true,
297
260
  absorb: true,
298
- })(props.collection)(param.type);
299
- if (result.success === false) {
300
- props.errors.push(
301
- ...result.errors.map((e) => ({
302
- ...e,
303
- route,
304
- from: `query parameter ${param.name}`,
305
- })),
306
- );
307
- } else if (result.data.objects.length === 1) {
308
- // WHEN OBJECT CASE, VALIDATE IT MORE DETAILY
309
- const again = MetadataFactory.analyze(props.checker)({
310
- escape: false,
311
- constant: true,
312
- absorb: true,
313
- validate: SwaggerSchemaValidator.query,
314
- })(new MetadataCollection())(param.type);
315
- if (again.success === false) return again;
316
- }
317
- return result;
318
- })();
261
+ validate: param.custom
262
+ ? SwaggerSchemaValidator.headers
263
+ : undefined,
264
+ })(new MetadataCollection())(param.type),
265
+ );
319
266
 
320
- // RETURNS WITH LAZY CONSTRUCTION
321
- return lazyParameterReturns(props)(route)("query")(param, result);
322
- };
267
+ const query =
268
+ (props: IProps) =>
269
+ (route: IRoute) =>
270
+ (param: IRoute.IParameter): ISwaggerRoute.IParameter[] =>
271
+ decomposible(props)(route)(param)(
272
+ MetadataFactory.analyze(props.checker)({
273
+ escape: false,
274
+ constant: true,
275
+ absorb: true,
276
+ validate: param.custom
277
+ ? SwaggerSchemaValidator.query
278
+ : undefined,
279
+ })(new MetadataCollection())(param.type),
280
+ );
323
281
 
324
- const coalesceSchema =
282
+ const decomposible =
325
283
  (props: IProps) =>
284
+ (route: IRoute) =>
285
+ (param: IRoute.IParameter) =>
326
286
  (
327
287
  result: ValidationPipe<Metadata, MetadataFactory.IError>,
328
- ): IJsonSchema => {
329
- const schema: IJsonSchema = {} as any;
330
- props.tuples.push({
331
- metadata: result.success ? result.data : any.get(),
332
- schema,
288
+ ): ISwaggerRoute.IParameter[] => {
289
+ if (result.success === false) {
290
+ props.errors.push(
291
+ ...result.errors.map((e) => ({
292
+ ...e,
293
+ route,
294
+ from: param.name,
295
+ })),
296
+ );
297
+ return [lazy(props)(route)(param, result)];
298
+ } else if (
299
+ props.config.decompose !== true ||
300
+ result.data.objects.length === 0
301
+ )
302
+ return [lazy(props)(route)(param, result)];
303
+
304
+ return result.data.objects[0].properties.map((p) => {
305
+ const schema = coalesce(props)({
306
+ success: true,
307
+ data: p.value,
308
+ });
309
+ return {
310
+ name: p.key.constants[0].values[0] as string,
311
+ in:
312
+ param.category === "headers"
313
+ ? "header"
314
+ : param.category,
315
+ schema,
316
+ description: p.description ?? undefined,
317
+ required: p.value.isRequired(),
318
+ };
333
319
  });
334
- return schema;
335
320
  };
336
321
 
337
- const lazyParameterReturns =
322
+ const lazy =
338
323
  (props: IProps) =>
339
324
  (route: IRoute) =>
340
- (inKeyword: string) =>
341
325
  (
342
326
  param: IRoute.IParameter,
343
327
  result: ValidationPipe<Metadata, MetadataFactory.IError>,
344
- ) => {
345
- const schema: IJsonSchema = coalesceSchema(props)(result);
328
+ ): ISwaggerRoute.IParameter => {
329
+ const schema: IJsonSchema = coalesce(props)(result);
346
330
  return {
347
331
  name: param.field ?? param.name,
348
- in: inKeyword,
332
+ in:
333
+ param.category === "headers"
334
+ ? "header"
335
+ : param.category === "param"
336
+ ? "path"
337
+ : param.category,
349
338
  schema,
350
339
  description: describe(route, "param", param.name) ?? "",
351
340
  required: result.success ? result.data.isRequired() : true,
352
341
  };
353
342
  };
354
343
 
355
- function describe(
344
+ const coalesce =
345
+ (props: IProps) =>
346
+ (
347
+ result: ValidationPipe<Metadata, MetadataFactory.IError>,
348
+ ): IJsonSchema => {
349
+ const schema: IJsonSchema = {} as any;
350
+ props.tuples.push({
351
+ metadata: result.success ? result.data : any.get(),
352
+ schema,
353
+ });
354
+ return schema;
355
+ };
356
+
357
+ const describe = (
356
358
  route: IRoute,
357
359
  tagName: string,
358
360
  parameterName?: string,
359
- ): string | undefined {
361
+ ): string | undefined => {
360
362
  const parametric: (elem: ts.JSDocTagInfo) => boolean = parameterName
361
363
  ? (tag) =>
362
364
  tag.text!.find(
@@ -366,13 +368,13 @@ export namespace SwaggerSchemaGenerator {
366
368
  ) !== undefined
367
369
  : () => true;
368
370
 
369
- const tag: ts.JSDocTagInfo | undefined = route.tags.find(
371
+ const tag: ts.JSDocTagInfo | undefined = route.jsDocTags.find(
370
372
  (tag) => tag.name === tagName && tag.text && parametric(tag),
371
373
  );
372
374
  return tag && tag.text
373
375
  ? tag.text.find((elem) => elem.kind === "text")?.text
374
376
  : undefined;
375
- }
377
+ };
376
378
  }
377
379
 
378
380
  const warning = new Singleton((described: boolean) => {
@@ -64,12 +64,6 @@ export namespace SwaggerSchemaValidator {
64
64
  // PROPERTY MUST BE SOLE
65
65
  if (typeof explore.property === "object")
66
66
  insert("dynamic property is not allowed.");
67
- // MUST BE LOWER-CASE
68
- if (
69
- typeof explore.property === "string" &&
70
- explore.property !== explore.property.toLowerCase()
71
- )
72
- insert("property name must be lower-case.");
73
67
  // DO NOT ALLOW TUPLE TYPE
74
68
  if (meta.tuples.length) insert("tuple type is not allowed.");
75
69
  // DO NOT ALLOW UNION TYPE
@@ -136,12 +130,6 @@ export namespace SwaggerSchemaValidator {
136
130
  // PROPERTY MUST BE SOLE
137
131
  if (typeof explore.property === "object")
138
132
  insert("dynamic property is not allowed.");
139
- // MUST BE LOWER-CASE
140
- if (
141
- typeof explore.property === "string" &&
142
- explore.property !== explore.property.toLowerCase()
143
- )
144
- insert("property name must be lower-case.");
145
133
  // DO NOT ALLOW TUPLE TYPE
146
134
  if (meta.tuples.length) insert("tuple type is not allowed.");
147
135
  // DO NOT ALLOW UNION TYPE
@@ -6,6 +6,7 @@ export interface IController {
6
6
  paths: string[];
7
7
  functions: IController.IFunction[];
8
8
  security: Record<string, string[]>[];
9
+ swaggerTgas: string[];
9
10
  }
10
11
 
11
12
  export namespace IController {
@@ -23,6 +24,7 @@ export namespace IController {
23
24
  number | "2XX" | "3XX" | "4XX" | "5XX",
24
25
  IController.IException
25
26
  >;
27
+ swaggerTags: string[];
26
28
  }
27
29
 
28
30
  export type IParameter =
@@ -1,5 +1,7 @@
1
1
  import ts from "typescript";
2
2
 
3
+ import { Metadata } from "typia/lib/schemas/metadata/Metadata";
4
+
3
5
  import { IController } from "./IController";
4
6
 
5
7
  export interface IRoute {
@@ -15,16 +17,20 @@ export interface IRoute {
15
17
  output: IRoute.IOutput;
16
18
 
17
19
  location: string;
18
- symbol: string;
20
+ symbol: {
21
+ class: string;
22
+ function: string;
23
+ };
19
24
  description?: string;
20
25
  operationId?: string;
21
- tags: ts.JSDocTagInfo[];
26
+ jsDocTags: ts.JSDocTagInfo[];
22
27
  setHeaders: Array<
23
28
  | { type: "setter"; source: string; target?: string }
24
29
  | { type: "assigner"; source: string }
25
30
  >;
26
31
  security: Record<string, string[]>[];
27
32
  exceptions: Record<number | "2XX" | "3XX" | "4XX" | "5XX", IRoute.IOutput>;
33
+ swaggerTags: string[];
28
34
  }
29
35
 
30
36
  export namespace IRoute {
@@ -32,10 +38,12 @@ export namespace IRoute {
32
38
  optional: boolean;
33
39
  type: ts.Type;
34
40
  typeName: string;
41
+ metadata?: Metadata;
35
42
  };
36
43
  export interface IOutput {
37
44
  type: ts.Type;
38
45
  typeName: string;
46
+ metadata?: Metadata;
39
47
  description?: string;
40
48
  contentType: "application/json" | "text/plain";
41
49
  }