@nestia/migrate 10.0.2 → 11.0.0-dev.20260305

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 (162) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -93
  3. package/package.json +32 -46
  4. package/src/NestiaMigrateApplication.ts +161 -159
  5. package/src/analyzers/NestiaMigrateControllerAnalyzer.ts +51 -51
  6. package/src/archivers/NestiaMigrateFileArchiver.ts +28 -28
  7. package/src/bundles/NEST_TEMPLATE.ts +48 -48
  8. package/src/bundles/SDK_TEMPLATE.ts +21 -21
  9. package/src/executable/NestiaMigrateCommander.ts +98 -98
  10. package/src/executable/NestiaMigrateInquirer.ts +106 -106
  11. package/src/executable/bundle.js +125 -125
  12. package/src/executable/migrate.ts +7 -7
  13. package/src/factories/TypeLiteralFactory.ts +57 -57
  14. package/src/index.ts +4 -4
  15. package/src/module.ts +6 -2
  16. package/src/programmers/NestiaMigrateApiFileProgrammer.ts +55 -55
  17. package/src/programmers/NestiaMigrateApiFunctionProgrammer.ts +347 -344
  18. package/src/programmers/NestiaMigrateApiNamespaceProgrammer.ts +517 -514
  19. package/src/programmers/NestiaMigrateApiProgrammer.ts +107 -107
  20. package/src/programmers/NestiaMigrateApiSimulationProgrammer.ts +308 -309
  21. package/src/programmers/NestiaMigrateApiStartProgrammer.ts +197 -198
  22. package/src/programmers/NestiaMigrateDtoProgrammer.ts +98 -98
  23. package/src/programmers/NestiaMigrateE2eFileProgrammer.ts +153 -153
  24. package/src/programmers/NestiaMigrateE2eProgrammer.ts +48 -48
  25. package/src/programmers/NestiaMigrateImportProgrammer.ts +118 -118
  26. package/src/programmers/NestiaMigrateNestControllerProgrammer.ts +69 -69
  27. package/src/programmers/NestiaMigrateNestMethodProgrammer.ts +409 -406
  28. package/src/programmers/NestiaMigrateNestModuleProgrammer.ts +65 -65
  29. package/src/programmers/NestiaMigrateNestProgrammer.ts +88 -88
  30. package/src/programmers/NestiaMigrateSchemaProgrammer.ts +465 -467
  31. package/src/structures/INestiaMigrateConfig.ts +19 -19
  32. package/src/structures/INestiaMigrateContext.ts +9 -9
  33. package/src/structures/INestiaMigrateController.ts +8 -8
  34. package/src/structures/INestiaMigrateDto.ts +8 -8
  35. package/src/structures/INestiaMigrateFile.ts +5 -5
  36. package/src/structures/INestiaMigrateProgram.ts +11 -11
  37. package/src/structures/INestiaMigrateSchema.ts +4 -4
  38. package/src/utils/FilePrinter.ts +49 -49
  39. package/src/utils/MapUtil.ts +13 -13
  40. package/src/utils/SetupWizard.ts +12 -12
  41. package/src/utils/StringUtil.ts +114 -113
  42. package/src/utils/openapi-down-convert/RefVisitor.ts +134 -134
  43. package/src/utils/openapi-down-convert/converter.ts +536 -536
  44. package/lib/NestiaMigrateApplication.d.ts +0 -24
  45. package/lib/NestiaMigrateApplication.js +0 -18757
  46. package/lib/NestiaMigrateApplication.js.map +0 -1
  47. package/lib/analyzers/NestiaMigrateControllerAnalyzer.d.ts +0 -5
  48. package/lib/analyzers/NestiaMigrateControllerAnalyzer.js +0 -46
  49. package/lib/analyzers/NestiaMigrateControllerAnalyzer.js.map +0 -1
  50. package/lib/archivers/NestiaMigrateFileArchiver.d.ts +0 -8
  51. package/lib/archivers/NestiaMigrateFileArchiver.js +0 -36
  52. package/lib/archivers/NestiaMigrateFileArchiver.js.map +0 -1
  53. package/lib/bundles/NEST_TEMPLATE.d.ts +0 -1
  54. package/lib/bundles/NEST_TEMPLATE.js +0 -55
  55. package/lib/bundles/NEST_TEMPLATE.js.map +0 -1
  56. package/lib/bundles/SDK_TEMPLATE.d.ts +0 -1
  57. package/lib/bundles/SDK_TEMPLATE.js +0 -27
  58. package/lib/bundles/SDK_TEMPLATE.js.map +0 -1
  59. package/lib/executable/NestiaMigrateCommander.d.ts +0 -4
  60. package/lib/executable/NestiaMigrateCommander.js +0 -125
  61. package/lib/executable/NestiaMigrateCommander.js.map +0 -1
  62. package/lib/executable/NestiaMigrateInquirer.d.ts +0 -12
  63. package/lib/executable/NestiaMigrateInquirer.js +0 -94
  64. package/lib/executable/NestiaMigrateInquirer.js.map +0 -1
  65. package/lib/executable/migrate.d.ts +0 -2
  66. package/lib/executable/migrate.js +0 -9
  67. package/lib/executable/migrate.js.map +0 -1
  68. package/lib/factories/TypeLiteralFactory.d.ts +0 -4
  69. package/lib/factories/TypeLiteralFactory.js +0 -35
  70. package/lib/factories/TypeLiteralFactory.js.map +0 -1
  71. package/lib/index.d.ts +0 -3
  72. package/lib/index.js +0 -42
  73. package/lib/index.js.map +0 -1
  74. package/lib/index.mjs +0 -19359
  75. package/lib/index.mjs.map +0 -1
  76. package/lib/module.d.ts +0 -2
  77. package/lib/module.js +0 -19
  78. package/lib/module.js.map +0 -1
  79. package/lib/programmers/NestiaMigrateApiFileProgrammer.d.ts +0 -13
  80. package/lib/programmers/NestiaMigrateApiFileProgrammer.js +0 -40
  81. package/lib/programmers/NestiaMigrateApiFileProgrammer.js.map +0 -1
  82. package/lib/programmers/NestiaMigrateApiFunctionProgrammer.d.ts +0 -14
  83. package/lib/programmers/NestiaMigrateApiFunctionProgrammer.js +0 -179
  84. package/lib/programmers/NestiaMigrateApiFunctionProgrammer.js.map +0 -1
  85. package/lib/programmers/NestiaMigrateApiNamespaceProgrammer.d.ts +0 -14
  86. package/lib/programmers/NestiaMigrateApiNamespaceProgrammer.js +0 -226
  87. package/lib/programmers/NestiaMigrateApiNamespaceProgrammer.js.map +0 -1
  88. package/lib/programmers/NestiaMigrateApiProgrammer.d.ts +0 -4
  89. package/lib/programmers/NestiaMigrateApiProgrammer.js +0 -82
  90. package/lib/programmers/NestiaMigrateApiProgrammer.js.map +0 -1
  91. package/lib/programmers/NestiaMigrateApiSimulationProgrammer.d.ts +0 -14
  92. package/lib/programmers/NestiaMigrateApiSimulationProgrammer.js +0 -142
  93. package/lib/programmers/NestiaMigrateApiSimulationProgrammer.js.map +0 -1
  94. package/lib/programmers/NestiaMigrateApiStartProgrammer.d.ts +0 -4
  95. package/lib/programmers/NestiaMigrateApiStartProgrammer.js +0 -80
  96. package/lib/programmers/NestiaMigrateApiStartProgrammer.js.map +0 -1
  97. package/lib/programmers/NestiaMigrateDtoProgrammer.d.ts +0 -15
  98. package/lib/programmers/NestiaMigrateDtoProgrammer.js +0 -65
  99. package/lib/programmers/NestiaMigrateDtoProgrammer.js.map +0 -1
  100. package/lib/programmers/NestiaMigrateE2eFileProgrammer.d.ts +0 -14
  101. package/lib/programmers/NestiaMigrateE2eFileProgrammer.js +0 -81
  102. package/lib/programmers/NestiaMigrateE2eFileProgrammer.js.map +0 -1
  103. package/lib/programmers/NestiaMigrateE2eProgrammer.d.ts +0 -4
  104. package/lib/programmers/NestiaMigrateE2eProgrammer.js +0 -32
  105. package/lib/programmers/NestiaMigrateE2eProgrammer.js.map +0 -1
  106. package/lib/programmers/NestiaMigrateImportProgrammer.d.ts +0 -18
  107. package/lib/programmers/NestiaMigrateImportProgrammer.js +0 -65
  108. package/lib/programmers/NestiaMigrateImportProgrammer.js.map +0 -1
  109. package/lib/programmers/NestiaMigrateNestControllerProgrammer.d.ts +0 -12
  110. package/lib/programmers/NestiaMigrateNestControllerProgrammer.js +0 -46
  111. package/lib/programmers/NestiaMigrateNestControllerProgrammer.js.map +0 -1
  112. package/lib/programmers/NestiaMigrateNestMethodProgrammer.d.ts +0 -15
  113. package/lib/programmers/NestiaMigrateNestMethodProgrammer.js +0 -224
  114. package/lib/programmers/NestiaMigrateNestMethodProgrammer.js.map +0 -1
  115. package/lib/programmers/NestiaMigrateNestModuleProgrammer.d.ts +0 -5
  116. package/lib/programmers/NestiaMigrateNestModuleProgrammer.js +0 -29
  117. package/lib/programmers/NestiaMigrateNestModuleProgrammer.js.map +0 -1
  118. package/lib/programmers/NestiaMigrateNestProgrammer.d.ts +0 -4
  119. package/lib/programmers/NestiaMigrateNestProgrammer.js +0 -65
  120. package/lib/programmers/NestiaMigrateNestProgrammer.js.map +0 -1
  121. package/lib/programmers/NestiaMigrateSchemaProgrammer.d.ts +0 -10
  122. package/lib/programmers/NestiaMigrateSchemaProgrammer.js +0 -341
  123. package/lib/programmers/NestiaMigrateSchemaProgrammer.js.map +0 -1
  124. package/lib/structures/INestiaMigrateConfig.d.ts +0 -15
  125. package/lib/structures/INestiaMigrateConfig.js +0 -3
  126. package/lib/structures/INestiaMigrateConfig.js.map +0 -1
  127. package/lib/structures/INestiaMigrateContext.d.ts +0 -7
  128. package/lib/structures/INestiaMigrateContext.js +0 -3
  129. package/lib/structures/INestiaMigrateContext.js.map +0 -1
  130. package/lib/structures/INestiaMigrateController.d.ts +0 -7
  131. package/lib/structures/INestiaMigrateController.js +0 -3
  132. package/lib/structures/INestiaMigrateController.js.map +0 -1
  133. package/lib/structures/INestiaMigrateDto.d.ts +0 -7
  134. package/lib/structures/INestiaMigrateDto.js +0 -3
  135. package/lib/structures/INestiaMigrateDto.js.map +0 -1
  136. package/lib/structures/INestiaMigrateFile.d.ts +0 -5
  137. package/lib/structures/INestiaMigrateFile.js +0 -3
  138. package/lib/structures/INestiaMigrateFile.js.map +0 -1
  139. package/lib/structures/INestiaMigrateProgram.d.ts +0 -9
  140. package/lib/structures/INestiaMigrateProgram.js +0 -3
  141. package/lib/structures/INestiaMigrateProgram.js.map +0 -1
  142. package/lib/structures/INestiaMigrateSchema.d.ts +0 -4
  143. package/lib/structures/INestiaMigrateSchema.js +0 -3
  144. package/lib/structures/INestiaMigrateSchema.js.map +0 -1
  145. package/lib/utils/FilePrinter.d.ts +0 -9
  146. package/lib/utils/FilePrinter.js +0 -35
  147. package/lib/utils/FilePrinter.js.map +0 -1
  148. package/lib/utils/MapUtil.d.ts +0 -3
  149. package/lib/utils/MapUtil.js +0 -15
  150. package/lib/utils/MapUtil.js.map +0 -1
  151. package/lib/utils/SetupWizard.d.ts +0 -3
  152. package/lib/utils/SetupWizard.js +0 -18
  153. package/lib/utils/SetupWizard.js.map +0 -1
  154. package/lib/utils/StringUtil.d.ts +0 -6
  155. package/lib/utils/StringUtil.js +0 -108
  156. package/lib/utils/StringUtil.js.map +0 -1
  157. package/lib/utils/openapi-down-convert/RefVisitor.d.ts +0 -52
  158. package/lib/utils/openapi-down-convert/RefVisitor.js +0 -102
  159. package/lib/utils/openapi-down-convert/RefVisitor.js.map +0 -1
  160. package/lib/utils/openapi-down-convert/converter.d.ts +0 -146
  161. package/lib/utils/openapi-down-convert/converter.js +0 -441
  162. package/lib/utils/openapi-down-convert/converter.js.map +0 -1
@@ -1,406 +1,409 @@
1
- import { IHttpMigrateRoute, OpenApi } from "@samchon/openapi";
2
- import ts from "typescript";
3
- import { ExpressionFactory } from "typia/lib/factories/ExpressionFactory";
4
- import { IdentifierFactory } from "typia/lib/factories/IdentifierFactory";
5
- import { LiteralFactory } from "typia/lib/factories/LiteralFactory";
6
- import { TypeFactory } from "typia/lib/factories/TypeFactory";
7
-
8
- import { INestiaMigrateConfig } from "../structures/INestiaMigrateConfig";
9
- import { INestiaMigrateController } from "../structures/INestiaMigrateController";
10
- import { FilePrinter } from "../utils/FilePrinter";
11
- import { StringUtil } from "../utils/StringUtil";
12
- import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
13
- import { NestiaMigrateSchemaProgrammer } from "./NestiaMigrateSchemaProgrammer";
14
-
15
- export namespace NestiaMigrateNestMethodProgrammer {
16
- export interface IContext {
17
- config: INestiaMigrateConfig;
18
- components: OpenApi.IComponents;
19
- importer: NestiaMigrateImportProgrammer;
20
- controller: INestiaMigrateController;
21
- route: IHttpMigrateRoute;
22
- }
23
-
24
- export const write = (ctx: IContext): ts.MethodDeclaration => {
25
- const output: ts.TypeNode = ctx.route.success
26
- ? NestiaMigrateSchemaProgrammer.write({
27
- components: ctx.components,
28
- importer: ctx.importer,
29
- schema: ctx.route.success.schema,
30
- })
31
- : TypeFactory.keyword("void");
32
-
33
- const method: ts.MethodDeclaration = ts.factory.createMethodDeclaration(
34
- [
35
- ...writeMethodDecorators(ctx),
36
- ts.factory.createToken(ts.SyntaxKind.PublicKeyword),
37
- ts.factory.createToken(ts.SyntaxKind.AsyncKeyword),
38
- ],
39
- undefined,
40
- ctx.route.accessor.at(-1)!,
41
- undefined,
42
- undefined,
43
- writeParameters(ctx),
44
- ts.factory.createTypeReferenceNode("Promise", [output]),
45
- ts.factory.createBlock(
46
- [
47
- ...[
48
- ...ctx.route.parameters.map((p) => p.key),
49
- ...(ctx.route.headers ? ["headers"] : []),
50
- ...(ctx.route.query ? ["query"] : []),
51
- ...(ctx.route.body ? ["body"] : []),
52
- ].map((str) =>
53
- ts.factory.createExpressionStatement(
54
- ts.factory.createIdentifier(str),
55
- ),
56
- ),
57
- ts.factory.createReturnStatement(
58
- ts.factory.createCallExpression(
59
- IdentifierFactory.access(
60
- ts.factory.createIdentifier(
61
- ctx.importer.external({
62
- type: "default",
63
- library: "typia",
64
- name: "typia",
65
- }),
66
- ),
67
- "random",
68
- ),
69
- [output],
70
- undefined,
71
- ),
72
- ),
73
- ],
74
- true,
75
- ),
76
- );
77
- return FilePrinter.description(
78
- method,
79
- writeDescription(ctx.config, ctx.route),
80
- );
81
- };
82
-
83
- const writeDescription = (
84
- config: INestiaMigrateConfig,
85
- method: IHttpMigrateRoute,
86
- ): string =>
87
- [
88
- method.comment(),
89
- `@${config.author?.tag ?? "nestia"} ${config.author?.value ?? "Generated by Nestia - https://github.com/samchon/nestia"}`,
90
- ].join("\n");
91
-
92
- const writeMethodDecorators = (ctx: IContext): ts.Decorator[] => {
93
- const external = (lib: string, instance: string): ts.Identifier =>
94
- ts.factory.createIdentifier(
95
- ctx.importer.external({
96
- type: "instance",
97
- library: lib,
98
- name: instance,
99
- }),
100
- );
101
-
102
- // EXAMPLES
103
- const decorators: ts.Decorator[] = [];
104
- if (ctx.route.success)
105
- decorators.push(
106
- ...writeExampleDecorators("Response")(ctx.importer)(
107
- ctx.route.success.media(),
108
- ),
109
- );
110
-
111
- // HUMAN-ONLY
112
- if (ctx.route.operation()["x-samchon-human"] === true)
113
- decorators.push(
114
- ts.factory.createDecorator(
115
- ts.factory.createCallExpression(
116
- external("@nestia/core", "HumanRoute"),
117
- undefined,
118
- undefined,
119
- ),
120
- ),
121
- );
122
-
123
- // ROUTER
124
- const localPath: string = ctx.route.emendedPath
125
- .slice(ctx.controller.path.length)
126
- .split("/")
127
- .filter((str) => !!str.length)
128
- .join("/");
129
- const router = (instance: string) =>
130
- ts.factory.createDecorator(
131
- ts.factory.createCallExpression(
132
- IdentifierFactory.access(
133
- external("@nestia/core", instance),
134
- StringUtil.capitalize(ctx.route.method),
135
- ),
136
- [],
137
- localPath.length
138
- ? [ts.factory.createStringLiteral(localPath)]
139
- : undefined,
140
- ),
141
- );
142
- if (ctx.route.success?.["x-nestia-encrypted"])
143
- decorators.push(router("EncryptedRoute"));
144
- else if (ctx.route.success?.type === "text/plain")
145
- decorators.push(
146
- ts.factory.createDecorator(
147
- ts.factory.createCallExpression(
148
- external("@nestjs/common", StringUtil.capitalize(ctx.route.method)),
149
- [],
150
- [ts.factory.createStringLiteral(ctx.route.path)],
151
- ),
152
- ),
153
- );
154
- else if (ctx.route.success?.type === "application/x-www-form-urlencoded")
155
- decorators.push(router("TypedQuery"));
156
- else if (ctx.route.method === "head")
157
- decorators.push(
158
- ts.factory.createDecorator(
159
- ts.factory.createCallExpression(
160
- external("@nestjs/common", "Head"),
161
- [],
162
- [ts.factory.createStringLiteral(ctx.route.path)],
163
- ),
164
- ),
165
- );
166
- else if (
167
- ctx.route.success === null ||
168
- ctx.route.success?.type === "application/json"
169
- )
170
- decorators.push(router("TypedRoute"));
171
- for (const [key, value] of Object.entries(ctx.route.exceptions ?? {}))
172
- decorators.push(
173
- ts.factory.createDecorator(
174
- ts.factory.createCallExpression(
175
- external("@nestia/core", "TypedException"),
176
- [
177
- NestiaMigrateSchemaProgrammer.write({
178
- components: ctx.components,
179
- importer: ctx.importer,
180
- schema: value.schema,
181
- }),
182
- ],
183
- [
184
- isNaN(Number(key))
185
- ? ts.factory.createStringLiteral(key)
186
- : ExpressionFactory.number(Number(key)),
187
- ...(value.response().description?.length
188
- ? [
189
- ts.factory.createStringLiteral(
190
- value.response().description!,
191
- ),
192
- ]
193
- : []),
194
- ],
195
- ),
196
- ),
197
- );
198
- return decorators;
199
- };
200
-
201
- const writeParameters = (ctx: IContext): ts.ParameterDeclaration[] => [
202
- ...ctx.route.parameters.map((p) =>
203
- ts.factory.createParameterDeclaration(
204
- [
205
- ...writeExampleDecorators("Parameter")(ctx.importer)(p.parameter()),
206
- ts.factory.createDecorator(
207
- ts.factory.createCallExpression(
208
- ts.factory.createIdentifier(
209
- ctx.importer.external({
210
- type: "instance",
211
- library: "@nestia/core",
212
- name: "TypedParam",
213
- }),
214
- ),
215
- undefined,
216
- [ts.factory.createStringLiteral(p.key)],
217
- ),
218
- ),
219
- ],
220
- undefined,
221
- p.key,
222
- undefined,
223
- NestiaMigrateSchemaProgrammer.write({
224
- components: ctx.components,
225
- importer: ctx.importer,
226
- schema: p.schema,
227
- }),
228
- ),
229
- ),
230
- ...(ctx.route.headers
231
- ? [
232
- writeDtoParameter({
233
- method: "TypedHeaders",
234
- variable: "headers",
235
- arguments: [],
236
- })(ctx.components)(ctx.importer)({
237
- required: true,
238
- schema: ctx.route.headers.schema,
239
- example: ctx.route.headers.example(),
240
- examples: ctx.route.headers.examples(),
241
- }),
242
- ]
243
- : []),
244
- ...(ctx.route.query
245
- ? [
246
- writeDtoParameter({
247
- method: "TypedQuery",
248
- variable: "query",
249
- arguments: [],
250
- })(ctx.components)(ctx.importer)({
251
- required: true,
252
- schema: ctx.route.query.schema,
253
- example: ctx.route.query.example(),
254
- examples: ctx.route.query.examples(),
255
- }),
256
- ]
257
- : []),
258
- ...(ctx.route.body
259
- ? [
260
- writeDtoParameter({
261
- method: ctx.route.body["x-nestia-encrypted"]
262
- ? "EncryptedBody"
263
- : ctx.route.body.type === "application/json"
264
- ? "TypedBody"
265
- : ctx.route.body.type === "application/x-www-form-urlencoded"
266
- ? ["TypedQuery", "Body"]
267
- : ctx.route.body.type === "text/plain"
268
- ? "PlainBody"
269
- : ctx.route.body.type === "multipart/form-data"
270
- ? ["TypedFormData", "Body"]
271
- : "TypedBody",
272
- variable: "body",
273
- arguments:
274
- ctx.route.body.type === "multipart/form-data"
275
- ? [
276
- ts.factory.createArrowFunction(
277
- undefined,
278
- undefined,
279
- [],
280
- undefined,
281
- undefined,
282
- ts.factory.createCallExpression(
283
- ts.factory.createIdentifier(
284
- ctx.importer.external({
285
- type: "default",
286
- library: "multer",
287
- name: "Multer",
288
- }),
289
- ),
290
- undefined,
291
- undefined,
292
- ),
293
- ),
294
- ]
295
- : [],
296
- })(ctx.components)(ctx.importer)({
297
- schema: ctx.route.body.schema,
298
- required: !(
299
- (ctx.route.body.type === "application/json" ||
300
- ctx.route.body.type === "text/plain") &&
301
- ctx.route.operation().requestBody?.required === false
302
- ),
303
- example: ctx.route.body.media().example,
304
- examples: ctx.route.body.media().examples,
305
- }),
306
- ]
307
- : []),
308
- ];
309
-
310
- const writeDtoParameter =
311
- (accessor: {
312
- method: string | [string, string];
313
- variable: string;
314
- arguments: ts.Expression[];
315
- }) =>
316
- (components: OpenApi.IComponents) =>
317
- (importer: NestiaMigrateImportProgrammer) =>
318
- (props: {
319
- schema: OpenApi.IJsonSchema;
320
- required: boolean;
321
- example?: any;
322
- examples?: Record<string, any>;
323
- }): ts.ParameterDeclaration => {
324
- const instance = ts.factory.createIdentifier(
325
- importer.external({
326
- type: "instance",
327
- library: "@nestia/core",
328
- name:
329
- typeof accessor.method === "string"
330
- ? accessor.method
331
- : accessor.method[0],
332
- }),
333
- );
334
- return ts.factory.createParameterDeclaration(
335
- [
336
- ...writeExampleDecorators("Parameter")(importer)(props),
337
- ts.factory.createDecorator(
338
- ts.factory.createCallExpression(
339
- typeof accessor.method === "string"
340
- ? instance
341
- : IdentifierFactory.access(instance, accessor.method[1]),
342
- undefined,
343
- accessor.arguments,
344
- ),
345
- ),
346
- ],
347
- undefined,
348
- accessor.variable,
349
- props.required === false
350
- ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
351
- : undefined,
352
- NestiaMigrateSchemaProgrammer.write({
353
- components,
354
- importer,
355
- schema: props.schema,
356
- }),
357
- );
358
- };
359
-
360
- const writeExampleDecorators =
361
- (kind: "Response" | "Parameter") =>
362
- (importer: NestiaMigrateImportProgrammer) =>
363
- (media: {
364
- example?: any;
365
- examples?: Record<string, any>;
366
- }): ts.Decorator[] => [
367
- ...(media.example !== undefined
368
- ? [
369
- ts.factory.createDecorator(
370
- ts.factory.createCallExpression(
371
- IdentifierFactory.access(
372
- ts.factory.createIdentifier(
373
- importer.external({
374
- type: "instance",
375
- library: "@nestia/core",
376
- name: "SwaggerExample",
377
- }),
378
- ),
379
- kind,
380
- ),
381
- [],
382
- [LiteralFactory.write(media.example)],
383
- ),
384
- ),
385
- ]
386
- : []),
387
- ...Object.entries(media.examples ?? {}).map(([key, value]) =>
388
- ts.factory.createDecorator(
389
- ts.factory.createCallExpression(
390
- IdentifierFactory.access(
391
- ts.factory.createIdentifier(
392
- importer.external({
393
- type: "instance",
394
- library: "@nestia/core",
395
- name: "SwaggerExample",
396
- }),
397
- ),
398
- kind,
399
- ),
400
- [],
401
- [ts.factory.createStringLiteral(key), LiteralFactory.write(value)],
402
- ),
403
- ),
404
- ),
405
- ];
406
- }
1
+ import {
2
+ ExpressionFactory,
3
+ IdentifierFactory,
4
+ LiteralFactory,
5
+ TypeFactory,
6
+ } from "@typia/core";
7
+ import { IHttpMigrateRoute } from "@typia/interface";
8
+ import ts from "typescript";
9
+ import { OpenApi } from "typia";
10
+
11
+ import { INestiaMigrateConfig } from "../structures/INestiaMigrateConfig";
12
+ import { INestiaMigrateController } from "../structures/INestiaMigrateController";
13
+ import { FilePrinter } from "../utils/FilePrinter";
14
+ import { StringUtil } from "../utils/StringUtil";
15
+ import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
16
+ import { NestiaMigrateSchemaProgrammer } from "./NestiaMigrateSchemaProgrammer";
17
+
18
+ export namespace NestiaMigrateNestMethodProgrammer {
19
+ export interface IContext {
20
+ config: INestiaMigrateConfig;
21
+ components: OpenApi.IComponents;
22
+ importer: NestiaMigrateImportProgrammer;
23
+ controller: INestiaMigrateController;
24
+ route: IHttpMigrateRoute;
25
+ }
26
+
27
+ export const write = (ctx: IContext): ts.MethodDeclaration => {
28
+ const output: ts.TypeNode = ctx.route.success
29
+ ? NestiaMigrateSchemaProgrammer.write({
30
+ components: ctx.components,
31
+ importer: ctx.importer,
32
+ schema: ctx.route.success.schema,
33
+ })
34
+ : TypeFactory.keyword("void");
35
+
36
+ const method: ts.MethodDeclaration = ts.factory.createMethodDeclaration(
37
+ [
38
+ ...writeMethodDecorators(ctx),
39
+ ts.factory.createToken(ts.SyntaxKind.PublicKeyword),
40
+ ts.factory.createToken(ts.SyntaxKind.AsyncKeyword),
41
+ ],
42
+ undefined,
43
+ ctx.route.accessor.at(-1)!,
44
+ undefined,
45
+ undefined,
46
+ writeParameters(ctx),
47
+ ts.factory.createTypeReferenceNode("Promise", [output]),
48
+ ts.factory.createBlock(
49
+ [
50
+ ...[
51
+ ...ctx.route.parameters.map((p) => p.key),
52
+ ...(ctx.route.headers ? ["headers"] : []),
53
+ ...(ctx.route.query ? ["query"] : []),
54
+ ...(ctx.route.body ? ["body"] : []),
55
+ ].map((str) =>
56
+ ts.factory.createExpressionStatement(
57
+ ts.factory.createIdentifier(str),
58
+ ),
59
+ ),
60
+ ts.factory.createReturnStatement(
61
+ ts.factory.createCallExpression(
62
+ IdentifierFactory.access(
63
+ ts.factory.createIdentifier(
64
+ ctx.importer.external({
65
+ type: "default",
66
+ library: "typia",
67
+ name: "typia",
68
+ }),
69
+ ),
70
+ "random",
71
+ ),
72
+ [output],
73
+ undefined,
74
+ ),
75
+ ),
76
+ ],
77
+ true,
78
+ ),
79
+ );
80
+ return FilePrinter.description(
81
+ method,
82
+ writeDescription(ctx.config, ctx.route),
83
+ );
84
+ };
85
+
86
+ const writeDescription = (
87
+ config: INestiaMigrateConfig,
88
+ method: IHttpMigrateRoute,
89
+ ): string =>
90
+ [
91
+ method.comment(),
92
+ `@${config.author?.tag ?? "nestia"} ${config.author?.value ?? "Generated by Nestia - https://github.com/samchon/nestia"}`,
93
+ ].join("\n");
94
+
95
+ const writeMethodDecorators = (ctx: IContext): ts.Decorator[] => {
96
+ const external = (lib: string, instance: string): ts.Identifier =>
97
+ ts.factory.createIdentifier(
98
+ ctx.importer.external({
99
+ type: "instance",
100
+ library: lib,
101
+ name: instance,
102
+ }),
103
+ );
104
+
105
+ // EXAMPLES
106
+ const decorators: ts.Decorator[] = [];
107
+ if (ctx.route.success)
108
+ decorators.push(
109
+ ...writeExampleDecorators("Response")(ctx.importer)(
110
+ ctx.route.success.media(),
111
+ ),
112
+ );
113
+
114
+ // HUMAN-ONLY
115
+ if (ctx.route.operation()["x-samchon-human"] === true)
116
+ decorators.push(
117
+ ts.factory.createDecorator(
118
+ ts.factory.createCallExpression(
119
+ external("@nestia/core", "HumanRoute"),
120
+ undefined,
121
+ undefined,
122
+ ),
123
+ ),
124
+ );
125
+
126
+ // ROUTER
127
+ const localPath: string = ctx.route.emendedPath
128
+ .slice(ctx.controller.path.length)
129
+ .split("/")
130
+ .filter((str) => !!str.length)
131
+ .join("/");
132
+ const router = (instance: string) =>
133
+ ts.factory.createDecorator(
134
+ ts.factory.createCallExpression(
135
+ IdentifierFactory.access(
136
+ external("@nestia/core", instance),
137
+ StringUtil.capitalize(ctx.route.method),
138
+ ),
139
+ [],
140
+ localPath.length
141
+ ? [ts.factory.createStringLiteral(localPath)]
142
+ : undefined,
143
+ ),
144
+ );
145
+ if (ctx.route.success?.["x-nestia-encrypted"])
146
+ decorators.push(router("EncryptedRoute"));
147
+ else if (ctx.route.success?.type === "text/plain")
148
+ decorators.push(
149
+ ts.factory.createDecorator(
150
+ ts.factory.createCallExpression(
151
+ external("@nestjs/common", StringUtil.capitalize(ctx.route.method)),
152
+ [],
153
+ [ts.factory.createStringLiteral(ctx.route.path)],
154
+ ),
155
+ ),
156
+ );
157
+ else if (ctx.route.success?.type === "application/x-www-form-urlencoded")
158
+ decorators.push(router("TypedQuery"));
159
+ else if (ctx.route.method === "head")
160
+ decorators.push(
161
+ ts.factory.createDecorator(
162
+ ts.factory.createCallExpression(
163
+ external("@nestjs/common", "Head"),
164
+ [],
165
+ [ts.factory.createStringLiteral(ctx.route.path)],
166
+ ),
167
+ ),
168
+ );
169
+ else if (
170
+ ctx.route.success === null ||
171
+ ctx.route.success?.type === "application/json"
172
+ )
173
+ decorators.push(router("TypedRoute"));
174
+ for (const [key, value] of Object.entries(ctx.route.exceptions ?? {}))
175
+ decorators.push(
176
+ ts.factory.createDecorator(
177
+ ts.factory.createCallExpression(
178
+ external("@nestia/core", "TypedException"),
179
+ [
180
+ NestiaMigrateSchemaProgrammer.write({
181
+ components: ctx.components,
182
+ importer: ctx.importer,
183
+ schema: value.schema,
184
+ }),
185
+ ],
186
+ [
187
+ isNaN(Number(key))
188
+ ? ts.factory.createStringLiteral(key)
189
+ : ExpressionFactory.number(Number(key)),
190
+ ...(value.response().description?.length
191
+ ? [
192
+ ts.factory.createStringLiteral(
193
+ value.response().description!,
194
+ ),
195
+ ]
196
+ : []),
197
+ ],
198
+ ),
199
+ ),
200
+ );
201
+ return decorators;
202
+ };
203
+
204
+ const writeParameters = (ctx: IContext): ts.ParameterDeclaration[] => [
205
+ ...ctx.route.parameters.map((p) =>
206
+ ts.factory.createParameterDeclaration(
207
+ [
208
+ ...writeExampleDecorators("Parameter")(ctx.importer)(p.parameter()),
209
+ ts.factory.createDecorator(
210
+ ts.factory.createCallExpression(
211
+ ts.factory.createIdentifier(
212
+ ctx.importer.external({
213
+ type: "instance",
214
+ library: "@nestia/core",
215
+ name: "TypedParam",
216
+ }),
217
+ ),
218
+ undefined,
219
+ [ts.factory.createStringLiteral(p.key)],
220
+ ),
221
+ ),
222
+ ],
223
+ undefined,
224
+ p.key,
225
+ undefined,
226
+ NestiaMigrateSchemaProgrammer.write({
227
+ components: ctx.components,
228
+ importer: ctx.importer,
229
+ schema: p.schema,
230
+ }),
231
+ ),
232
+ ),
233
+ ...(ctx.route.headers
234
+ ? [
235
+ writeDtoParameter({
236
+ method: "TypedHeaders",
237
+ variable: "headers",
238
+ arguments: [],
239
+ })(ctx.components)(ctx.importer)({
240
+ required: true,
241
+ schema: ctx.route.headers.schema,
242
+ example: ctx.route.headers.example(),
243
+ examples: ctx.route.headers.examples(),
244
+ }),
245
+ ]
246
+ : []),
247
+ ...(ctx.route.query
248
+ ? [
249
+ writeDtoParameter({
250
+ method: "TypedQuery",
251
+ variable: "query",
252
+ arguments: [],
253
+ })(ctx.components)(ctx.importer)({
254
+ required: true,
255
+ schema: ctx.route.query.schema,
256
+ example: ctx.route.query.example(),
257
+ examples: ctx.route.query.examples(),
258
+ }),
259
+ ]
260
+ : []),
261
+ ...(ctx.route.body
262
+ ? [
263
+ writeDtoParameter({
264
+ method: ctx.route.body["x-nestia-encrypted"]
265
+ ? "EncryptedBody"
266
+ : ctx.route.body.type === "application/json"
267
+ ? "TypedBody"
268
+ : ctx.route.body.type === "application/x-www-form-urlencoded"
269
+ ? ["TypedQuery", "Body"]
270
+ : ctx.route.body.type === "text/plain"
271
+ ? "PlainBody"
272
+ : ctx.route.body.type === "multipart/form-data"
273
+ ? ["TypedFormData", "Body"]
274
+ : "TypedBody",
275
+ variable: "body",
276
+ arguments:
277
+ ctx.route.body.type === "multipart/form-data"
278
+ ? [
279
+ ts.factory.createArrowFunction(
280
+ undefined,
281
+ undefined,
282
+ [],
283
+ undefined,
284
+ undefined,
285
+ ts.factory.createCallExpression(
286
+ ts.factory.createIdentifier(
287
+ ctx.importer.external({
288
+ type: "default",
289
+ library: "multer",
290
+ name: "Multer",
291
+ }),
292
+ ),
293
+ undefined,
294
+ undefined,
295
+ ),
296
+ ),
297
+ ]
298
+ : [],
299
+ })(ctx.components)(ctx.importer)({
300
+ schema: ctx.route.body.schema,
301
+ required: !(
302
+ (ctx.route.body.type === "application/json" ||
303
+ ctx.route.body.type === "text/plain") &&
304
+ ctx.route.operation().requestBody?.required === false
305
+ ),
306
+ example: ctx.route.body.media().example,
307
+ examples: ctx.route.body.media().examples,
308
+ }),
309
+ ]
310
+ : []),
311
+ ];
312
+
313
+ const writeDtoParameter =
314
+ (accessor: {
315
+ method: string | [string, string];
316
+ variable: string;
317
+ arguments: ts.Expression[];
318
+ }) =>
319
+ (components: OpenApi.IComponents) =>
320
+ (importer: NestiaMigrateImportProgrammer) =>
321
+ (props: {
322
+ schema: OpenApi.IJsonSchema;
323
+ required: boolean;
324
+ example?: any;
325
+ examples?: Record<string, any>;
326
+ }): ts.ParameterDeclaration => {
327
+ const instance = ts.factory.createIdentifier(
328
+ importer.external({
329
+ type: "instance",
330
+ library: "@nestia/core",
331
+ name:
332
+ typeof accessor.method === "string"
333
+ ? accessor.method
334
+ : accessor.method[0],
335
+ }),
336
+ );
337
+ return ts.factory.createParameterDeclaration(
338
+ [
339
+ ...writeExampleDecorators("Parameter")(importer)(props),
340
+ ts.factory.createDecorator(
341
+ ts.factory.createCallExpression(
342
+ typeof accessor.method === "string"
343
+ ? instance
344
+ : IdentifierFactory.access(instance, accessor.method[1]),
345
+ undefined,
346
+ accessor.arguments,
347
+ ),
348
+ ),
349
+ ],
350
+ undefined,
351
+ accessor.variable,
352
+ props.required === false
353
+ ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
354
+ : undefined,
355
+ NestiaMigrateSchemaProgrammer.write({
356
+ components,
357
+ importer,
358
+ schema: props.schema,
359
+ }),
360
+ );
361
+ };
362
+
363
+ const writeExampleDecorators =
364
+ (kind: "Response" | "Parameter") =>
365
+ (importer: NestiaMigrateImportProgrammer) =>
366
+ (media: {
367
+ example?: any;
368
+ examples?: Record<string, any>;
369
+ }): ts.Decorator[] => [
370
+ ...(media.example !== undefined
371
+ ? [
372
+ ts.factory.createDecorator(
373
+ ts.factory.createCallExpression(
374
+ IdentifierFactory.access(
375
+ ts.factory.createIdentifier(
376
+ importer.external({
377
+ type: "instance",
378
+ library: "@nestia/core",
379
+ name: "SwaggerExample",
380
+ }),
381
+ ),
382
+ kind,
383
+ ),
384
+ [],
385
+ [LiteralFactory.write(media.example)],
386
+ ),
387
+ ),
388
+ ]
389
+ : []),
390
+ ...Object.entries(media.examples ?? {}).map(([key, value]) =>
391
+ ts.factory.createDecorator(
392
+ ts.factory.createCallExpression(
393
+ IdentifierFactory.access(
394
+ ts.factory.createIdentifier(
395
+ importer.external({
396
+ type: "instance",
397
+ library: "@nestia/core",
398
+ name: "SwaggerExample",
399
+ }),
400
+ ),
401
+ kind,
402
+ ),
403
+ [],
404
+ [ts.factory.createStringLiteral(key), LiteralFactory.write(value)],
405
+ ),
406
+ ),
407
+ ),
408
+ ];
409
+ }