@nestia/migrate 0.6.0 → 0.6.2

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 (85) hide show
  1. package/lib/{NestiaMigrateApplication.d.ts → MigrateApplication.d.ts} +2 -2
  2. package/lib/{NestiaMigrateApplication.js → MigrateApplication.js} +54 -29
  3. package/lib/MigrateApplication.js.map +1 -0
  4. package/lib/analyzers/ControllerAnalyzer.d.ts +5 -0
  5. package/lib/{programmers/ControllerProgrammer.js → analyzers/ControllerAnalyzer.js} +19 -37
  6. package/lib/analyzers/ControllerAnalyzer.js.map +1 -0
  7. package/lib/analyzers/MethodAnalyzer.d.ts +9 -0
  8. package/lib/{programmers/RouteProgrammer.js → analyzers/MethodAnalyzer.js} +24 -112
  9. package/lib/analyzers/MethodAnalyzer.js.map +1 -0
  10. package/lib/analyzers/MigrateAnalyzer.d.ts +4 -0
  11. package/lib/analyzers/MigrateAnalyzer.js +12 -0
  12. package/lib/analyzers/MigrateAnalyzer.js.map +1 -0
  13. package/lib/archivers/FileArchiver.d.ts +3 -3
  14. package/lib/archivers/FileArchiver.js +16 -7
  15. package/lib/archivers/FileArchiver.js.map +1 -1
  16. package/lib/executable/migrate.js +18 -9
  17. package/lib/executable/migrate.js.map +1 -1
  18. package/lib/module.d.ts +1 -1
  19. package/lib/module.js +1 -1
  20. package/lib/module.js.map +1 -1
  21. package/lib/programmers/ApiFileProgrammer.d.ts +17 -0
  22. package/lib/programmers/ApiFileProgrammer.js +28 -0
  23. package/lib/programmers/ApiFileProgrammer.js.map +1 -0
  24. package/lib/programmers/ApiFunctionProgrammer.d.ts +13 -0
  25. package/lib/programmers/ApiFunctionProgrammer.js +85 -0
  26. package/lib/programmers/ApiFunctionProgrammer.js.map +1 -0
  27. package/lib/programmers/ApiNamespaceProgrammer.d.ts +13 -0
  28. package/lib/programmers/ApiNamespaceProgrammer.js +134 -0
  29. package/lib/programmers/ApiNamespaceProgrammer.js.map +1 -0
  30. package/lib/programmers/ApiProgrammer.d.ts +5 -0
  31. package/lib/programmers/ApiProgrammer.js +62 -0
  32. package/lib/programmers/ApiProgrammer.js.map +1 -0
  33. package/lib/programmers/DtoProgrammer.js +2 -2
  34. package/lib/programmers/DtoProgrammer.js.map +1 -1
  35. package/lib/programmers/ImportProgrammer.d.ts +2 -1
  36. package/lib/programmers/ImportProgrammer.js +19 -4
  37. package/lib/programmers/ImportProgrammer.js.map +1 -1
  38. package/lib/programmers/{ControllerProgrammer.d.ts → NestControllerProgrammer.d.ts} +1 -3
  39. package/lib/programmers/NestControllerProgrammer.js +31 -0
  40. package/lib/programmers/NestControllerProgrammer.js.map +1 -0
  41. package/lib/programmers/{RouteProgrammer.d.ts → NestMethodProgrammer.d.ts} +1 -7
  42. package/lib/programmers/NestMethodProgrammer.js +118 -0
  43. package/lib/programmers/NestMethodProgrammer.js.map +1 -0
  44. package/lib/programmers/{ModuleProgrammer.d.ts → NestModuleProgrammer.d.ts} +1 -1
  45. package/lib/programmers/{ModuleProgrammer.js → NestModuleProgrammer.js} +6 -6
  46. package/lib/programmers/NestModuleProgrammer.js.map +1 -0
  47. package/lib/programmers/{MigrateProgrammer.d.ts → NestProgrammer.d.ts} +1 -3
  48. package/lib/programmers/{MigrateProgrammer.js → NestProgrammer.js} +10 -14
  49. package/lib/programmers/NestProgrammer.js.map +1 -0
  50. package/lib/programmers/SchemaProgrammer.d.ts +1 -1
  51. package/lib/programmers/SchemaProgrammer.js +17 -17
  52. package/lib/programmers/SchemaProgrammer.js.map +1 -1
  53. package/lib/structures/IMigrateRoute.d.ts +13 -4
  54. package/lib/utils/SetupWizard.js +0 -3
  55. package/lib/utils/SetupWizard.js.map +1 -1
  56. package/lib/utils/StringUtil.d.ts +1 -0
  57. package/lib/utils/StringUtil.js +4 -2
  58. package/lib/utils/StringUtil.js.map +1 -1
  59. package/package.json +1 -1
  60. package/src/{NestiaMigrateApplication.ts → MigrateApplication.ts} +32 -22
  61. package/src/{programmers/ControllerProgrammer.ts → analyzers/ControllerAnalyzer.ts} +123 -155
  62. package/src/{programmers/RouteProgrammer.ts → analyzers/MethodAnalyzer.ts} +20 -218
  63. package/src/analyzers/MigrateAnalyzer.ts +9 -0
  64. package/src/archivers/FileArchiver.ts +10 -7
  65. package/src/executable/migrate.ts +8 -8
  66. package/src/module.ts +1 -1
  67. package/src/programmers/ApiFileProgrammer.ts +51 -0
  68. package/src/programmers/ApiFunctionProgrammer.ts +177 -0
  69. package/src/programmers/ApiNamespaceProgrammer.ts +395 -0
  70. package/src/programmers/ApiProgrammer.ts +68 -0
  71. package/src/programmers/DtoProgrammer.ts +3 -3
  72. package/src/programmers/ImportProgrammer.ts +37 -21
  73. package/src/programmers/NestControllerProgrammer.ts +48 -0
  74. package/src/programmers/NestMethodProgrammer.ts +228 -0
  75. package/src/programmers/{ModuleProgrammer.ts → NestModuleProgrammer.ts} +1 -1
  76. package/src/programmers/{MigrateProgrammer.ts → NestProgrammer.ts} +11 -12
  77. package/src/programmers/SchemaProgrammer.ts +22 -25
  78. package/src/structures/IMigrateRoute.ts +13 -5
  79. package/src/utils/SetupWizard.ts +0 -3
  80. package/src/utils/StringUtil.ts +11 -2
  81. package/lib/NestiaMigrateApplication.js.map +0 -1
  82. package/lib/programmers/ControllerProgrammer.js.map +0 -1
  83. package/lib/programmers/MigrateProgrammer.js.map +0 -1
  84. package/lib/programmers/ModuleProgrammer.js.map +0 -1
  85. package/lib/programmers/RouteProgrammer.js.map +0 -1
package/src/module.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from "./NestiaMigrateApplication";
1
+ export * from "./MigrateApplication";
2
2
 
3
3
  export * from "./structures/ISwagger";
4
4
  export * from "./structures/IMigrateProgram";
@@ -0,0 +1,51 @@
1
+ import ts from "typescript";
2
+
3
+ import { IMigrateController } from "../structures/IMigrateController";
4
+ import { IMigrateRoute } from "../structures/IMigrateRoute";
5
+ import { ISwaggerComponents } from "../structures/ISwaggerComponents";
6
+ import { ApiFunctionProgrammer } from "./ApiFunctionProgrammer";
7
+ import { ApiNamespaceProgrammer } from "./ApiNamespaceProgrammer";
8
+ import { ImportProgrammer } from "./ImportProgrammer";
9
+
10
+ export namespace ApiFileProgrammer {
11
+ export interface IProps {
12
+ namespace: string[];
13
+ entries: IEntry[];
14
+ children: Set<string>;
15
+ }
16
+ export interface IEntry {
17
+ controller: IMigrateController;
18
+ route: IMigrateRoute;
19
+ alias: string;
20
+ }
21
+
22
+ export const write =
23
+ (components: ISwaggerComponents) =>
24
+ (props: IProps): ts.Statement[] => {
25
+ const importer: ImportProgrammer = new ImportProgrammer();
26
+ const statements: ts.Statement[] = props.entries
27
+ .map((p) => [
28
+ ApiFunctionProgrammer.write(components)(importer)(p),
29
+ ApiNamespaceProgrammer.write(components)(importer)(p),
30
+ ])
31
+ .flat();
32
+ return [
33
+ ...importer.toStatements(
34
+ (ref) =>
35
+ `../${"../".repeat(props.namespace.length)}structures/${ref}`,
36
+ ),
37
+ ...[...props.children].map((child) =>
38
+ ts.factory.createExportDeclaration(
39
+ undefined,
40
+ false,
41
+ ts.factory.createNamespaceExport(
42
+ ts.factory.createIdentifier(child),
43
+ ),
44
+ ts.factory.createStringLiteral(`./${child}`),
45
+ undefined,
46
+ ),
47
+ ),
48
+ ...statements,
49
+ ];
50
+ };
51
+ }
@@ -0,0 +1,177 @@
1
+ import ts from "typescript";
2
+ import { IdentifierFactory } from "typia/lib/factories/IdentifierFactory";
3
+
4
+ import { IMigrateController } from "../structures/IMigrateController";
5
+ import { IMigrateRoute } from "../structures/IMigrateRoute";
6
+ import { ISwaggerComponents } from "../structures/ISwaggerComponents";
7
+ import { FilePrinter } from "../utils/FilePrinter";
8
+ import { ImportProgrammer } from "./ImportProgrammer";
9
+ import { SchemaProgrammer } from "./SchemaProgrammer";
10
+
11
+ export namespace ApiFunctionProgrammer {
12
+ export interface IProps {
13
+ controller: IMigrateController;
14
+ route: IMigrateRoute;
15
+ alias: string;
16
+ }
17
+
18
+ export const write =
19
+ (components: ISwaggerComponents) =>
20
+ (importer: ImportProgrammer) =>
21
+ (props: IProps): ts.FunctionDeclaration =>
22
+ FilePrinter.description(
23
+ ts.factory.createFunctionDeclaration(
24
+ [
25
+ ts.factory.createModifier(ts.SyntaxKind.ExportKeyword),
26
+ ts.factory.createModifier(ts.SyntaxKind.AsyncKeyword),
27
+ ],
28
+ undefined,
29
+ props.alias,
30
+ undefined,
31
+ writeParameteers(components)(importer)(props),
32
+ ts.factory.createTypeReferenceNode("Promise", [
33
+ ts.factory.createTypeReferenceNode(
34
+ props.route.success === null ? "void" : `${props.alias}.Output`,
35
+ ),
36
+ ]),
37
+ ts.factory.createBlock(writeBody(importer)(props), true),
38
+ ),
39
+ writeDescription(props),
40
+ );
41
+
42
+ const writeDescription = (props: IProps): string =>
43
+ [
44
+ ...(props.route.description?.length
45
+ ? [props.route.description.length, ""]
46
+ : []),
47
+ ...(props.route.deprecated ? ["@deprecated"] : []),
48
+ ...props.route.tags.map((value) => `@tag ${value}`),
49
+ `@controller ${props.controller.name}`,
50
+ `@path ${props.route.path}`,
51
+ "@nestia Generated by Nestia - https://github.com/samchon/nestia",
52
+ ].join("\n");
53
+
54
+ const writeParameteers =
55
+ (components: ISwaggerComponents) =>
56
+ (importer: ImportProgrammer) =>
57
+ (props: IProps): ts.ParameterDeclaration[] => [
58
+ IdentifierFactory.parameter(
59
+ "connection",
60
+ ts.factory.createTypeReferenceNode(
61
+ importer.external({
62
+ type: "instance",
63
+ library: "@nestia/Fetcher",
64
+ name: "IConnection",
65
+ }),
66
+ props.route.headers
67
+ ? [ts.factory.createTypeReferenceNode(`${props.alias}.Headers`)]
68
+ : undefined,
69
+ ),
70
+ ),
71
+ ...props.route.parameters.map((p) =>
72
+ IdentifierFactory.parameter(
73
+ p.key,
74
+ SchemaProgrammer.write(components)(importer)(p.schema),
75
+ ),
76
+ ),
77
+ ...(props.route.query
78
+ ? [
79
+ IdentifierFactory.parameter(
80
+ "query",
81
+ ts.factory.createTypeReferenceNode(`${props.alias}.Query`),
82
+ ),
83
+ ]
84
+ : []),
85
+ ...(props.route.body
86
+ ? [
87
+ IdentifierFactory.parameter(
88
+ "input",
89
+ ts.factory.createTypeReferenceNode(`${props.alias}.Input`),
90
+ ),
91
+ ]
92
+ : []),
93
+ ];
94
+
95
+ const writeBody =
96
+ (importer: ImportProgrammer) =>
97
+ (props: IProps): ts.Statement[] => {
98
+ const encrypted: boolean = !!props.route.success?.["x-nestia-encrypted"];
99
+ const contentType: string =
100
+ props.route.success?.type ?? "application/json";
101
+ const caller = () =>
102
+ ts.factory.createCallExpression(
103
+ IdentifierFactory.access(
104
+ ts.factory.createIdentifier(
105
+ importer.external({
106
+ type: "instance",
107
+ library: `@nestia/fetcher/lib/${encrypted ? "EncryptedFetcher" : "PlainFetcher"}`,
108
+ name: encrypted ? "EncryptedFetcher" : "PlainFetcher",
109
+ }),
110
+ ),
111
+ )("fetch"),
112
+ undefined,
113
+ [
114
+ contentType
115
+ ? ts.factory.createObjectLiteralExpression(
116
+ [
117
+ ts.factory.createSpreadAssignment(
118
+ ts.factory.createIdentifier("connection"),
119
+ ),
120
+ ts.factory.createPropertyAssignment(
121
+ "headers",
122
+ ts.factory.createObjectLiteralExpression(
123
+ [
124
+ ts.factory.createSpreadAssignment(
125
+ IdentifierFactory.access(
126
+ ts.factory.createIdentifier("connection"),
127
+ )("headers"),
128
+ ),
129
+ ts.factory.createPropertyAssignment(
130
+ ts.factory.createStringLiteral("Content-Type"),
131
+ ts.factory.createStringLiteral(contentType),
132
+ ),
133
+ ],
134
+ true,
135
+ ),
136
+ ),
137
+ ],
138
+ true,
139
+ )
140
+ : ts.factory.createIdentifier("connection"),
141
+ ts.factory.createObjectLiteralExpression(
142
+ [
143
+ ts.factory.createSpreadAssignment(
144
+ IdentifierFactory.access(
145
+ ts.factory.createIdentifier(props.alias),
146
+ )("METADATA"),
147
+ ),
148
+ ts.factory.createPropertyAssignment(
149
+ "path",
150
+ ts.factory.createCallExpression(
151
+ IdentifierFactory.access(
152
+ ts.factory.createIdentifier(props.alias),
153
+ )("path"),
154
+ undefined,
155
+ [
156
+ ...props.route.parameters.map((p) =>
157
+ ts.factory.createIdentifier(p.key),
158
+ ),
159
+ ...(props.route.query
160
+ ? [ts.factory.createIdentifier("query")]
161
+ : []),
162
+ ],
163
+ ),
164
+ ),
165
+ ts.factory.createPropertyAssignment(
166
+ "status",
167
+ ts.factory.createNull(),
168
+ ),
169
+ ],
170
+ true,
171
+ ),
172
+ ...(props.route.body ? [ts.factory.createIdentifier("input")] : []),
173
+ ],
174
+ );
175
+ return [ts.factory.createReturnStatement(caller())];
176
+ };
177
+ }
@@ -0,0 +1,395 @@
1
+ import ts from "typescript";
2
+ import { ExpressionFactory } from "typia/lib/factories/ExpressionFactory";
3
+ import { IdentifierFactory } from "typia/lib/factories/IdentifierFactory";
4
+ import { LiteralFactory } from "typia/lib/factories/LiteralFactory";
5
+ import { TypeFactory } from "typia/lib/factories/TypeFactory";
6
+
7
+ import { IMigrateController } from "../structures/IMigrateController";
8
+ import { IMigrateRoute } from "../structures/IMigrateRoute";
9
+ import { ISwaggerComponents } from "../structures/ISwaggerComponents";
10
+ import { FilePrinter } from "../utils/FilePrinter";
11
+ import { ImportProgrammer } from "./ImportProgrammer";
12
+ import { SchemaProgrammer } from "./SchemaProgrammer";
13
+
14
+ export namespace ApiNamespaceProgrammer {
15
+ export interface IProps {
16
+ controller: IMigrateController;
17
+ route: IMigrateRoute;
18
+ alias: string;
19
+ }
20
+
21
+ export const write =
22
+ (components: ISwaggerComponents) =>
23
+ (importer: ImportProgrammer) =>
24
+ (props: IProps): ts.ModuleDeclaration => {
25
+ const types = writeTypes(components)(importer)(props.route);
26
+ return ts.factory.createModuleDeclaration(
27
+ [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
28
+ ts.factory.createIdentifier(props.alias),
29
+ ts.factory.createModuleBlock([
30
+ ...types,
31
+ ...(types.length ? [FilePrinter.enter()] : []),
32
+ writeMetadata(components)(importer)(props),
33
+ FilePrinter.enter(),
34
+ writePath(components)(importer)(props),
35
+ ]),
36
+ ts.NodeFlags.Namespace,
37
+ );
38
+ };
39
+
40
+ const writeTypes =
41
+ (components: ISwaggerComponents) =>
42
+ (importer: ImportProgrammer) =>
43
+ (route: IMigrateRoute): ts.TypeAliasDeclaration[] => {
44
+ const array: ts.TypeAliasDeclaration[] = [];
45
+ const declare = (name: string, type: ts.TypeNode) =>
46
+ array.push(
47
+ ts.factory.createTypeAliasDeclaration(
48
+ [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
49
+ name,
50
+ undefined,
51
+ type,
52
+ ),
53
+ );
54
+ if (route.headers)
55
+ declare(
56
+ "Headers",
57
+ SchemaProgrammer.write(components)(importer)(route.headers.schema),
58
+ );
59
+ if (route.query)
60
+ declare(
61
+ "Query",
62
+ SchemaProgrammer.write(components)(importer)(route.query.schema),
63
+ );
64
+ if (route.body)
65
+ declare(
66
+ "Input",
67
+ SchemaProgrammer.write(components)(importer)(route.body.schema),
68
+ );
69
+ if (route.success)
70
+ declare(
71
+ "Output",
72
+ SchemaProgrammer.write(components)(importer)(route.success.schema),
73
+ );
74
+ return array;
75
+ };
76
+
77
+ const writeMetadata =
78
+ (components: ISwaggerComponents) =>
79
+ (importer: ImportProgrammer) =>
80
+ (props: IProps): ts.VariableStatement =>
81
+ constant("METADATA")(
82
+ ts.factory.createAsExpression(
83
+ ts.factory.createObjectLiteralExpression(
84
+ [
85
+ ts.factory.createPropertyAssignment(
86
+ "method",
87
+ ts.factory.createStringLiteral(
88
+ props.route.method.toUpperCase(),
89
+ ),
90
+ ),
91
+ ts.factory.createPropertyAssignment(
92
+ "path",
93
+ ts.factory.createStringLiteral(getPath(props)),
94
+ ),
95
+ ts.factory.createPropertyAssignment(
96
+ "request",
97
+ props.route.body
98
+ ? LiteralFactory.generate({
99
+ type: "application/json",
100
+ encrypted: !!props.route.body["x-nestia-encrypted"],
101
+ })
102
+ : ts.factory.createNull(),
103
+ ),
104
+ ts.factory.createPropertyAssignment(
105
+ "response",
106
+ props.route.method.toUpperCase() !== "HEAD"
107
+ ? LiteralFactory.generate({
108
+ type: props.route.success?.type ?? "application/json",
109
+ encrypted: !!props.route.success?.["x-nestia-encrypted"],
110
+ })
111
+ : ts.factory.createNull(),
112
+ ),
113
+ ...(props.route.success?.type ===
114
+ "application/x-www-form-urlencoded"
115
+ ? [
116
+ ts.factory.createPropertyAssignment(
117
+ "parseQuery",
118
+ ts.factory.createCallExpression(
119
+ ts.factory.createIdentifier(
120
+ `${importer.external({
121
+ type: "default",
122
+ library: "typia",
123
+ name: "typia",
124
+ })}.http.createAssertQuery`,
125
+ ),
126
+ [
127
+ SchemaProgrammer.write(components)(importer)(
128
+ props.route.success.schema,
129
+ ),
130
+ ],
131
+ undefined,
132
+ ),
133
+ ),
134
+ ]
135
+ : []),
136
+ ],
137
+ true,
138
+ ),
139
+ ts.factory.createTypeReferenceNode(
140
+ ts.factory.createIdentifier("const"),
141
+ ),
142
+ ),
143
+ );
144
+
145
+ const writePath =
146
+ (components: ISwaggerComponents) =>
147
+ (importer: ImportProgrammer) =>
148
+ (props: IProps): ts.VariableStatement => {
149
+ const out = (body: ts.ConciseBody) =>
150
+ constant("path")(
151
+ ts.factory.createArrowFunction(
152
+ [],
153
+ [],
154
+ [
155
+ ...props.route.parameters.map((p) =>
156
+ IdentifierFactory.parameter(
157
+ p.key,
158
+ SchemaProgrammer.write(components)(importer)(p.schema),
159
+ ),
160
+ ),
161
+ ...(props.route.query
162
+ ? [
163
+ IdentifierFactory.parameter(
164
+ props.route.query.key,
165
+ ts.factory.createTypeReferenceNode(
166
+ `${props.alias}.Query`,
167
+ ),
168
+ ),
169
+ ]
170
+ : []),
171
+ ],
172
+ undefined,
173
+ undefined,
174
+ body,
175
+ ),
176
+ );
177
+ const template = () => {
178
+ const path: string = getPath(props);
179
+ const splitted: string[] = path.split(":");
180
+ if (splitted.length === 1) return ts.factory.createStringLiteral(path);
181
+ return ts.factory.createTemplateExpression(
182
+ ts.factory.createTemplateHead(splitted[0]),
183
+ splitted.slice(1).map((s, i, arr) => {
184
+ const name: string = s.split("/")[0];
185
+ return ts.factory.createTemplateSpan(
186
+ ts.factory.createCallExpression(
187
+ ts.factory.createIdentifier("encodeURIComponent"),
188
+ undefined,
189
+ [
190
+ ts.factory.createBinaryExpression(
191
+ ts.factory.createIdentifier(
192
+ props.route.parameters.find((p) => p.key === name)!.key,
193
+ ),
194
+ ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken),
195
+ ts.factory.createStringLiteral("null"),
196
+ ),
197
+ ],
198
+ ),
199
+ (i !== arr.length - 1
200
+ ? ts.factory.createTemplateMiddle
201
+ : ts.factory.createTemplateTail)(s.substring(name.length)),
202
+ );
203
+ }),
204
+ );
205
+ };
206
+ if (!props.route.query) return out(template());
207
+
208
+ const computeName = (str: string): string =>
209
+ props.route.parameters.find((p) => p.key === str) !== undefined
210
+ ? computeName("_" + str)
211
+ : str;
212
+ const variables: string = computeName("variables");
213
+ return out(
214
+ ts.factory.createBlock(
215
+ [
216
+ local(variables)("URLSearchParams")(
217
+ ts.factory.createNewExpression(
218
+ ts.factory.createIdentifier("URLSearchParams"),
219
+ [],
220
+ [],
221
+ ),
222
+ ),
223
+ ts.factory.createForOfStatement(
224
+ undefined,
225
+ ts.factory.createVariableDeclarationList(
226
+ [
227
+ ts.factory.createVariableDeclaration(
228
+ ts.factory.createArrayBindingPattern([
229
+ ts.factory.createBindingElement(
230
+ undefined,
231
+ undefined,
232
+ ts.factory.createIdentifier("key"),
233
+ undefined,
234
+ ),
235
+ ts.factory.createBindingElement(
236
+ undefined,
237
+ undefined,
238
+ ts.factory.createIdentifier("value"),
239
+ undefined,
240
+ ),
241
+ ]),
242
+ undefined,
243
+ undefined,
244
+ undefined,
245
+ ),
246
+ ],
247
+ ts.NodeFlags.Const,
248
+ ),
249
+ ts.factory.createCallExpression(
250
+ ts.factory.createIdentifier("Object.entries"),
251
+ undefined,
252
+ [
253
+ ts.factory.createAsExpression(
254
+ ts.factory.createIdentifier("query"),
255
+ TypeFactory.keyword("any"),
256
+ ),
257
+ ],
258
+ ),
259
+ ts.factory.createIfStatement(
260
+ ts.factory.createStrictEquality(
261
+ ts.factory.createIdentifier("undefined"),
262
+ ts.factory.createIdentifier("value"),
263
+ ),
264
+ ts.factory.createContinueStatement(),
265
+ ts.factory.createIfStatement(
266
+ ts.factory.createCallExpression(
267
+ ts.factory.createIdentifier("Array.isArray"),
268
+ undefined,
269
+ [ts.factory.createIdentifier("value")],
270
+ ),
271
+ ts.factory.createExpressionStatement(
272
+ ts.factory.createCallExpression(
273
+ ts.factory.createPropertyAccessExpression(
274
+ ts.factory.createIdentifier("value"),
275
+ ts.factory.createIdentifier("forEach"),
276
+ ),
277
+ undefined,
278
+ [
279
+ ts.factory.createArrowFunction(
280
+ undefined,
281
+ undefined,
282
+ [IdentifierFactory.parameter("elem")],
283
+ undefined,
284
+ undefined,
285
+ ts.factory.createCallExpression(
286
+ IdentifierFactory.access(
287
+ ts.factory.createIdentifier(variables),
288
+ )("append"),
289
+ undefined,
290
+ [
291
+ ts.factory.createIdentifier("key"),
292
+ ts.factory.createCallExpression(
293
+ ts.factory.createIdentifier("String"),
294
+ undefined,
295
+ [ts.factory.createIdentifier("elem")],
296
+ ),
297
+ ],
298
+ ),
299
+ ),
300
+ ],
301
+ ),
302
+ ),
303
+ ts.factory.createExpressionStatement(
304
+ ts.factory.createCallExpression(
305
+ IdentifierFactory.access(
306
+ ts.factory.createIdentifier(variables),
307
+ )("set"),
308
+ undefined,
309
+ [
310
+ ts.factory.createIdentifier("key"),
311
+ ts.factory.createCallExpression(
312
+ ts.factory.createIdentifier("String"),
313
+ undefined,
314
+ [ts.factory.createIdentifier("value")],
315
+ ),
316
+ ],
317
+ ),
318
+ ),
319
+ ),
320
+ ),
321
+ ),
322
+ local("location")("string")(template()),
323
+ ts.factory.createReturnStatement(
324
+ ts.factory.createConditionalExpression(
325
+ ts.factory.createStrictEquality(
326
+ ExpressionFactory.number(0),
327
+ IdentifierFactory.access(
328
+ ts.factory.createIdentifier(variables),
329
+ )("size"),
330
+ ),
331
+ undefined,
332
+ ts.factory.createIdentifier("location"),
333
+ undefined,
334
+ ts.factory.createTemplateExpression(
335
+ ts.factory.createTemplateHead(""),
336
+ [
337
+ ts.factory.createTemplateSpan(
338
+ ts.factory.createIdentifier("location"),
339
+ ts.factory.createTemplateMiddle("?"),
340
+ ),
341
+ ts.factory.createTemplateSpan(
342
+ ts.factory.createCallExpression(
343
+ IdentifierFactory.access(
344
+ ts.factory.createIdentifier(variables),
345
+ )("toString"),
346
+ undefined,
347
+ undefined,
348
+ ),
349
+ ts.factory.createTemplateTail(""),
350
+ ),
351
+ ],
352
+ ),
353
+ ),
354
+ ),
355
+ ],
356
+ true,
357
+ ),
358
+ );
359
+ };
360
+ }
361
+
362
+ const constant = (name: string) => (expression: ts.Expression) =>
363
+ ts.factory.createVariableStatement(
364
+ [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
365
+ ts.factory.createVariableDeclarationList(
366
+ [
367
+ ts.factory.createVariableDeclaration(
368
+ name,
369
+ undefined,
370
+ undefined,
371
+ expression,
372
+ ),
373
+ ],
374
+ ts.NodeFlags.Const,
375
+ ),
376
+ );
377
+ const getPath = (props: ApiNamespaceProgrammer.IProps) =>
378
+ [...props.controller.path.split("/"), ...props.route.path.split("/")]
379
+ .filter((str) => !!str.length)
380
+ .join("/");
381
+ const local = (name: string) => (type: string) => (expression: ts.Expression) =>
382
+ ts.factory.createVariableStatement(
383
+ [],
384
+ ts.factory.createVariableDeclarationList(
385
+ [
386
+ ts.factory.createVariableDeclaration(
387
+ name,
388
+ undefined,
389
+ ts.factory.createTypeReferenceNode(type),
390
+ expression,
391
+ ),
392
+ ],
393
+ ts.NodeFlags.Const,
394
+ ),
395
+ );
@@ -0,0 +1,68 @@
1
+ import { HashMap, IPointer, hash } from "tstl";
2
+ import { Escaper } from "typia/lib/utils/Escaper";
3
+
4
+ import { IMigrateProgram } from "../module";
5
+ import { IMigrateFile } from "../structures/IMigrateFile";
6
+ import { FilePrinter } from "../utils/FilePrinter";
7
+ import { StringUtil } from "../utils/StringUtil";
8
+ import { ApiFileProgrammer } from "./ApiFileProgrammer";
9
+
10
+ export namespace ApiProgrammer {
11
+ export const write = (program: IMigrateProgram): IMigrateFile[] => {
12
+ const dict: HashMap<string[], ApiFileProgrammer.IProps> = new HashMap(
13
+ (x) => hash(x.join(".")),
14
+ (a, b) => a.join(".") === b.join("."),
15
+ );
16
+ for (const controller of program.controllers)
17
+ for (const route of controller.routes) {
18
+ const namespace: string[] = [
19
+ ...controller.path.split("/"),
20
+ ...route.path.split("/"),
21
+ ]
22
+ .filter((str) => !!str.length && str[0] !== ":")
23
+ .map(StringUtil.normalize)
24
+ .map((str) => (Escaper.variable(str) ? str : `_${str}`));
25
+ const last: IPointer<ApiFileProgrammer.IProps> = {
26
+ value: dict.take(namespace, () => ({
27
+ namespace,
28
+ children: new Set(),
29
+ entries: [],
30
+ })),
31
+ };
32
+ last.value.entries.push({
33
+ controller,
34
+ route,
35
+ alias: route.name,
36
+ });
37
+ namespace.slice(0, -1).forEach((_i, i, array) => {
38
+ const partial: string[] = namespace.slice(0, array.length - i);
39
+ const props: ApiFileProgrammer.IProps = dict.take(partial, () => ({
40
+ namespace: partial,
41
+ children: new Set(),
42
+ entries: [],
43
+ }));
44
+ props.children.add(last.value.namespace.at(-1)!);
45
+ last.value = props;
46
+ });
47
+ }
48
+ for (const { second: props } of dict)
49
+ props.entries.forEach(
50
+ (entry, i) =>
51
+ (entry.alias = StringUtil.escapeDuplicate([
52
+ ...props.children,
53
+ ...entry.route.parameters.map((p) => p.key),
54
+ ...(entry.route.body ? [entry.route.body.key] : []),
55
+ ...(entry.route.query ? [entry.route.query.key] : []),
56
+ ...props.entries.filter((_, j) => i !== j).map((e) => e.alias),
57
+ ])(entry.alias)),
58
+ );
59
+
60
+ return [...dict].map(({ second: props }) => ({
61
+ location: `src/api/functional/${props.namespace.join("/")}`,
62
+ file: "index.ts",
63
+ content: FilePrinter.write({
64
+ statements: ApiFileProgrammer.write(program.swagger.components)(props),
65
+ }),
66
+ }));
67
+ };
68
+ }