@nestia/migrate 12.0.0-dev.20260601.1 → 12.0.0-dev.20260612.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 (50) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +93 -93
  3. package/lib/NestiaMigrateApplication.js +19 -1
  4. package/lib/NestiaMigrateApplication.js.map +1 -1
  5. package/lib/bundles/NEST_TEMPLATE.js +47 -47
  6. package/lib/bundles/NEST_TEMPLATE.js.map +1 -1
  7. package/lib/bundles/SDK_TEMPLATE.js +20 -20
  8. package/lib/bundles/SDK_TEMPLATE.js.map +1 -1
  9. package/lib/index.mjs +94 -77
  10. package/lib/index.mjs.map +1 -1
  11. package/lib/programmers/NestiaMigrateApiFunctionProgrammer.js +6 -2
  12. package/lib/programmers/NestiaMigrateApiFunctionProgrammer.js.map +1 -1
  13. package/package.json +5 -5
  14. package/src/NestiaMigrateApplication.ts +196 -167
  15. package/src/analyzers/NestiaMigrateControllerAnalyzer.ts +51 -51
  16. package/src/archivers/NestiaMigrateFileArchiver.ts +28 -28
  17. package/src/bundles/NEST_TEMPLATE.ts +47 -47
  18. package/src/bundles/SDK_TEMPLATE.ts +20 -20
  19. package/src/executable/NestiaMigrateCommander.ts +115 -115
  20. package/src/executable/NestiaMigrateInquirer.ts +106 -106
  21. package/src/executable/bundle.js +349 -349
  22. package/src/executable/migrate.ts +7 -7
  23. package/src/factories/TypeLiteralFactory.ts +63 -63
  24. package/src/index.ts +4 -4
  25. package/src/internal/ts.ts +94 -94
  26. package/src/module.ts +6 -6
  27. package/src/programmers/NestiaMigrateApiFileProgrammer.ts +58 -58
  28. package/src/programmers/NestiaMigrateApiFunctionProgrammer.ts +373 -369
  29. package/src/programmers/NestiaMigrateApiNamespaceProgrammer.ts +528 -528
  30. package/src/programmers/NestiaMigrateApiProgrammer.ts +108 -108
  31. package/src/programmers/NestiaMigrateApiSimulationProgrammer.ts +314 -314
  32. package/src/programmers/NestiaMigrateApiStartProgrammer.ts +198 -198
  33. package/src/programmers/NestiaMigrateDtoProgrammer.ts +99 -99
  34. package/src/programmers/NestiaMigrateE2eFileProgrammer.ts +156 -156
  35. package/src/programmers/NestiaMigrateE2eProgrammer.ts +48 -48
  36. package/src/programmers/NestiaMigrateImportProgrammer.ts +119 -119
  37. package/src/programmers/NestiaMigrateNestControllerProgrammer.ts +70 -70
  38. package/src/programmers/NestiaMigrateNestMethodProgrammer.ts +414 -414
  39. package/src/programmers/NestiaMigrateNestModuleProgrammer.ts +66 -66
  40. package/src/programmers/NestiaMigrateNestProgrammer.ts +89 -89
  41. package/src/programmers/NestiaMigrateSchemaProgrammer.ts +477 -477
  42. package/src/programmers/index.ts +15 -15
  43. package/src/structures/INestiaMigrateConfig.ts +19 -19
  44. package/src/structures/INestiaMigrateContext.ts +9 -9
  45. package/src/structures/INestiaMigrateController.ts +8 -8
  46. package/src/structures/INestiaMigrateFile.ts +5 -5
  47. package/src/structures/index.ts +4 -4
  48. package/src/utils/FilePrinter.ts +44 -44
  49. package/src/utils/MapUtil.ts +13 -13
  50. package/src/utils/StringUtil.ts +109 -109
@@ -1,369 +1,373 @@
1
- import { TypeScriptFactory } from "@nestia/factory";
2
- import { IdentifierFactory, StatementFactory } from "@nestia/factory";
3
- import { IHttpMigrateRoute, OpenApi } from "@typia/interface";
4
- import * as typiaUtils from "@typia/utils";
5
- import ts from "../internal/ts";
6
-
7
- import { INestiaMigrateConfig } from "../structures/INestiaMigrateConfig";
8
- import { FilePrinter } from "../utils/FilePrinter";
9
- import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
10
- import { NestiaMigrateSchemaProgrammer } from "./NestiaMigrateSchemaProgrammer";
11
-
12
- const { NamingConvention } =
13
- (typiaUtils as { default?: typeof typiaUtils }).default ?? typiaUtils;
14
-
15
- export namespace NestiaMigrateApiFunctionProgrammer {
16
- export interface IContext {
17
- config: INestiaMigrateConfig;
18
- components: OpenApi.IComponents;
19
- importer: NestiaMigrateImportProgrammer;
20
- route: IHttpMigrateRoute;
21
- }
22
-
23
- export const write = (ctx: IContext): ts.FunctionDeclaration =>
24
- FilePrinter.description(
25
- TypeScriptFactory.createFunctionDeclaration(
26
- [
27
- TypeScriptFactory.createModifier(ts.SyntaxKind.ExportKeyword),
28
- TypeScriptFactory.createModifier(ts.SyntaxKind.AsyncKeyword),
29
- ],
30
- undefined,
31
- ctx.route.accessor.at(-1)!,
32
- undefined,
33
- writeParameterDeclarations(ctx),
34
- TypeScriptFactory.createTypeReferenceNode("Promise", [
35
- TypeScriptFactory.createTypeReferenceNode(
36
- ctx.route.success === null
37
- ? "void"
38
- : `${ctx.route.accessor.at(-1)!}.Response`,
39
- ),
40
- ]),
41
- TypeScriptFactory.createBlock(writeBody(ctx), true),
42
- ),
43
- writeDescription(ctx.config, ctx.route),
44
- );
45
-
46
- export const writeParameterDeclarations = (
47
- ctx: IContext,
48
- connectionName?: string,
49
- ): ts.ParameterDeclaration[] => {
50
- const connection: ts.ParameterDeclaration = IdentifierFactory.parameter(
51
- connectionName ?? "connection",
52
- TypeScriptFactory.createTypeReferenceNode(
53
- ctx.importer.external({
54
- type: "instance",
55
- library: "@nestia/fetcher",
56
- name: "IConnection",
57
- }),
58
- ctx.route.headers
59
- ? [
60
- TypeScriptFactory.createTypeReferenceNode(
61
- `${ctx.route.accessor.at(-1)!}.Headers`,
62
- ),
63
- ]
64
- : undefined,
65
- ),
66
- );
67
- if (ctx.config.keyword === true) {
68
- const isProps: boolean =
69
- ctx.route.parameters.length > 0 ||
70
- !!ctx.route.query ||
71
- !!ctx.route.body;
72
- if (isProps === false) return [connection];
73
- return [
74
- connection,
75
- TypeScriptFactory.createParameterDeclaration(
76
- undefined,
77
- undefined,
78
- "props",
79
- undefined,
80
- TypeScriptFactory.createTypeReferenceNode(
81
- `${ctx.route.accessor.at(-1)!}.Props`,
82
- ),
83
- ),
84
- ];
85
- }
86
- return [
87
- connection,
88
- ...ctx.route.parameters.map((p) =>
89
- IdentifierFactory.parameter(
90
- p.key,
91
- NestiaMigrateSchemaProgrammer.write({
92
- components: ctx.components,
93
- importer: ctx.importer,
94
- schema: p.schema,
95
- }),
96
- ),
97
- ),
98
- ...(ctx.route.query
99
- ? [
100
- IdentifierFactory.parameter(
101
- ctx.route.query.key,
102
- TypeScriptFactory.createTypeReferenceNode(
103
- `${ctx.route.accessor.at(-1)!}.Query`,
104
- ),
105
- ),
106
- ]
107
- : []),
108
- ...(ctx.route.body
109
- ? [
110
- IdentifierFactory.parameter(
111
- ctx.route.body.key,
112
- TypeScriptFactory.createTypeReferenceNode(
113
- `${ctx.route.accessor.at(-1)!}.Body`,
114
- ),
115
- (ctx.route.body.type === "application/json" ||
116
- ctx.route.body.type === "text/plain") &&
117
- ctx.route.operation().requestBody?.required === false
118
- ? TypeScriptFactory.createToken(ts.SyntaxKind.QuestionToken)
119
- : undefined,
120
- ),
121
- ]
122
- : []),
123
- ];
124
- };
125
-
126
- const writeDescription = (
127
- config: INestiaMigrateConfig,
128
- route: IHttpMigrateRoute,
129
- ): string => {
130
- const comment: string = route.comment();
131
- return [
132
- config.keyword === true
133
- ? comment.split("@param ").join("@param props.")
134
- : comment,
135
- `@path ${route.emendedPath}`,
136
- `@accessor api.functional.${route.accessor.join(".")}`,
137
- `@${config.author?.tag ?? "nestia"} ${config.author?.value ?? "Generated by Nestia - https://github.com/samchon/nestia"}`,
138
- ].join("\n");
139
- };
140
-
141
- const writeBody = (ctx: IContext): ts.Statement[] => {
142
- const encrypted: boolean = !!ctx.route.success?.["x-nestia-encrypted"];
143
- const contentType: string = ctx.route.body?.type ?? "application/json";
144
-
145
- const property = (key: string): ts.Expression =>
146
- ctx.config.keyword === true
147
- ? IdentifierFactory.access(
148
- TypeScriptFactory.createIdentifier("props"),
149
- key,
150
- )
151
- : TypeScriptFactory.createIdentifier(key);
152
- const fetch = () =>
153
- TypeScriptFactory.createAwaitExpression(
154
- TypeScriptFactory.createCallExpression(
155
- IdentifierFactory.access(
156
- TypeScriptFactory.createIdentifier(
157
- ctx.importer.external({
158
- type: "instance",
159
- library: encrypted
160
- ? "@nestia/fetcher/lib/EncryptedFetcher"
161
- : `@nestia/fetcher`,
162
- name: encrypted ? "EncryptedFetcher" : "PlainFetcher",
163
- }),
164
- ),
165
- "fetch",
166
- ),
167
- undefined,
168
- [
169
- contentType && contentType !== "multipart/form-data"
170
- ? TypeScriptFactory.createObjectLiteralExpression(
171
- [
172
- TypeScriptFactory.createSpreadAssignment(
173
- TypeScriptFactory.createIdentifier("connection"),
174
- ),
175
- TypeScriptFactory.createPropertyAssignment(
176
- "headers",
177
- TypeScriptFactory.createObjectLiteralExpression(
178
- [
179
- TypeScriptFactory.createSpreadAssignment(
180
- IdentifierFactory.access(
181
- TypeScriptFactory.createIdentifier("connection"),
182
- "headers",
183
- ),
184
- ),
185
- TypeScriptFactory.createPropertyAssignment(
186
- TypeScriptFactory.createStringLiteral(
187
- "Content-Type",
188
- ),
189
- TypeScriptFactory.createStringLiteral(contentType),
190
- ),
191
- ],
192
- true,
193
- ),
194
- ),
195
- ],
196
- true,
197
- )
198
- : TypeScriptFactory.createIdentifier("connection"),
199
- TypeScriptFactory.createObjectLiteralExpression(
200
- [
201
- TypeScriptFactory.createSpreadAssignment(
202
- IdentifierFactory.access(
203
- TypeScriptFactory.createIdentifier(
204
- ctx.route.accessor.at(-1)!,
205
- ),
206
- "METADATA",
207
- ),
208
- ),
209
- TypeScriptFactory.createPropertyAssignment(
210
- "path",
211
- TypeScriptFactory.createCallExpression(
212
- IdentifierFactory.access(
213
- TypeScriptFactory.createIdentifier(
214
- ctx.route.accessor.at(-1)!,
215
- ),
216
- "path",
217
- ),
218
- undefined,
219
- getArguments(ctx, false),
220
- ),
221
- ),
222
- TypeScriptFactory.createPropertyAssignment(
223
- "status",
224
- TypeScriptFactory.createNull(),
225
- ),
226
- ],
227
- true,
228
- ),
229
- ...(ctx.route.body ? [property(ctx.route.body.key)] : []),
230
- ],
231
- ),
232
- );
233
-
234
- const value: ts.Expression =
235
- ctx.config.simulate !== true
236
- ? fetch()
237
- : TypeScriptFactory.createConditionalExpression(
238
- TypeScriptFactory.createStrictEquality(
239
- TypeScriptFactory.createTrue(),
240
- TypeScriptFactory.createIdentifier("connection.simulate"),
241
- ),
242
- undefined,
243
- TypeScriptFactory.createCallExpression(
244
- TypeScriptFactory.createIdentifier(
245
- `${ctx.route.accessor.at(-1)!}.simulate`,
246
- ),
247
- [],
248
- [
249
- TypeScriptFactory.createIdentifier("connection"),
250
- ...getArguments(ctx, true),
251
- ],
252
- ),
253
- undefined,
254
- fetch(),
255
- );
256
- const headers: Array<IAssignHeader | ISetHeader> = getHeaders(
257
- ctx.route.comment(),
258
- );
259
- if (headers.length === 0)
260
- return [TypeScriptFactory.createReturnStatement(value)];
261
- return [
262
- StatementFactory.constant({
263
- name: "output",
264
- type: TypeScriptFactory.createTypeReferenceNode(
265
- `${ctx.route.accessor.at(-1)!}.Response`,
266
- ),
267
- value,
268
- }),
269
- TypeScriptFactory.createExpressionStatement(
270
- TypeScriptFactory.createBinaryExpression(
271
- TypeScriptFactory.createIdentifier("connection.headers"),
272
- TypeScriptFactory.createToken(
273
- ts.SyntaxKind.QuestionQuestionEqualsToken,
274
- ),
275
- TypeScriptFactory.createObjectLiteralExpression([]),
276
- ),
277
- ),
278
- ...headers.map((h) =>
279
- TypeScriptFactory.createExpressionStatement(
280
- h.type === "assign"
281
- ? TypeScriptFactory.createCallExpression(
282
- TypeScriptFactory.createIdentifier("Object.assign"),
283
- undefined,
284
- [
285
- TypeScriptFactory.createIdentifier("connection.headers"),
286
- TypeScriptFactory.createIdentifier(`output.${h.accessor}`),
287
- ],
288
- )
289
- : TypeScriptFactory.createBinaryExpression(
290
- TypeScriptFactory.createIdentifier(
291
- `connection.headers${
292
- NamingConvention.variable(h.property)
293
- ? `.${h.property}`
294
- : `[${JSON.stringify(h.property)}]`
295
- }`,
296
- ),
297
- TypeScriptFactory.createToken(ts.SyntaxKind.EqualsToken),
298
- TypeScriptFactory.createIdentifier(`output.${h.accessor}`),
299
- ),
300
- ),
301
- ),
302
- TypeScriptFactory.createReturnStatement(
303
- TypeScriptFactory.createIdentifier("output"),
304
- ),
305
- ];
306
- };
307
-
308
- const getArguments = (ctx: IContext, body: boolean): ts.Expression[] => {
309
- if (
310
- ctx.route.parameters.length === 0 &&
311
- ctx.route.query === null &&
312
- (body === false || ctx.route.body === null)
313
- )
314
- return [];
315
- else if (ctx.config.keyword === true)
316
- return [TypeScriptFactory.createIdentifier("props")];
317
- return [
318
- ...ctx.route.parameters.map((p) =>
319
- TypeScriptFactory.createIdentifier(p.key),
320
- ),
321
- ...(ctx.route.query
322
- ? [TypeScriptFactory.createIdentifier(ctx.route.query.key)]
323
- : []),
324
- ...(body && ctx.route.body
325
- ? [TypeScriptFactory.createIdentifier(ctx.route.body.key)]
326
- : []),
327
- ];
328
- };
329
-
330
- const getHeaders = (
331
- description: string,
332
- ): Array<IAssignHeader | ISetHeader> => {
333
- const directives: Array<IAssignHeader | ISetHeader> = [];
334
- for (const line of description.split("\n").map((l) => l.trim())) {
335
- if (line.startsWith("@setHeader ")) {
336
- const parts: string[] = line
337
- .substring("@setHeader ".length)
338
- .trim()
339
- .split(/\s+/);
340
- if (parts.length >= 2)
341
- directives.push({
342
- type: "set",
343
- accessor: parts[0]!,
344
- property: parts[1]!,
345
- });
346
- } else if (line.startsWith("@assignHeaders ")) {
347
- const accessor: string = line
348
- .substring("@assignHeaders ".length)
349
- .trim();
350
- if (accessor.length !== 0)
351
- directives.push({
352
- type: "assign",
353
- accessor,
354
- });
355
- }
356
- }
357
- return directives;
358
- };
359
- }
360
-
361
- interface IAssignHeader {
362
- type: "assign";
363
- accessor: string;
364
- }
365
- interface ISetHeader {
366
- type: "set";
367
- accessor: string;
368
- property: string;
369
- }
1
+ import { TypeScriptFactory } from "@nestia/factory";
2
+ import { IdentifierFactory, StatementFactory } from "@nestia/factory";
3
+ import { IHttpMigrateRoute, OpenApi } from "@typia/interface";
4
+ import * as typiaUtils from "@typia/utils";
5
+
6
+ import ts from "../internal/ts";
7
+ import { INestiaMigrateConfig } from "../structures/INestiaMigrateConfig";
8
+ import { FilePrinter } from "../utils/FilePrinter";
9
+ import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
10
+ import { NestiaMigrateSchemaProgrammer } from "./NestiaMigrateSchemaProgrammer";
11
+
12
+ const { NamingConvention } =
13
+ (typiaUtils as { default?: typeof typiaUtils }).default ?? typiaUtils;
14
+
15
+ export namespace NestiaMigrateApiFunctionProgrammer {
16
+ export interface IContext {
17
+ config: INestiaMigrateConfig;
18
+ components: OpenApi.IComponents;
19
+ importer: NestiaMigrateImportProgrammer;
20
+ route: IHttpMigrateRoute;
21
+ }
22
+
23
+ export const write = (ctx: IContext): ts.FunctionDeclaration =>
24
+ FilePrinter.description(
25
+ TypeScriptFactory.createFunctionDeclaration(
26
+ [
27
+ TypeScriptFactory.createModifier(ts.SyntaxKind.ExportKeyword),
28
+ TypeScriptFactory.createModifier(ts.SyntaxKind.AsyncKeyword),
29
+ ],
30
+ undefined,
31
+ ctx.route.accessor.at(-1)!,
32
+ undefined,
33
+ writeParameterDeclarations(ctx),
34
+ TypeScriptFactory.createTypeReferenceNode("Promise", [
35
+ TypeScriptFactory.createTypeReferenceNode(
36
+ ctx.route.success === null
37
+ ? "void"
38
+ : `${ctx.route.accessor.at(-1)!}.Response`,
39
+ ),
40
+ ]),
41
+ TypeScriptFactory.createBlock(writeBody(ctx), true),
42
+ ),
43
+ writeDescription(ctx.config, ctx.route),
44
+ );
45
+
46
+ export const writeParameterDeclarations = (
47
+ ctx: IContext,
48
+ connectionName?: string,
49
+ ): ts.ParameterDeclaration[] => {
50
+ const connection: ts.ParameterDeclaration = IdentifierFactory.parameter(
51
+ connectionName ?? "connection",
52
+ TypeScriptFactory.createTypeReferenceNode(
53
+ ctx.importer.external({
54
+ type: "instance",
55
+ library: "@nestia/fetcher",
56
+ name: "IConnection",
57
+ }),
58
+ ctx.route.headers
59
+ ? [
60
+ TypeScriptFactory.createTypeReferenceNode(
61
+ `${ctx.route.accessor.at(-1)!}.Headers`,
62
+ ),
63
+ ]
64
+ : undefined,
65
+ ),
66
+ );
67
+ if (ctx.config.keyword === true) {
68
+ const isProps: boolean =
69
+ ctx.route.parameters.length > 0 ||
70
+ !!ctx.route.query ||
71
+ !!ctx.route.body;
72
+ if (isProps === false) return [connection];
73
+ return [
74
+ connection,
75
+ TypeScriptFactory.createParameterDeclaration(
76
+ undefined,
77
+ undefined,
78
+ "props",
79
+ undefined,
80
+ TypeScriptFactory.createTypeReferenceNode(
81
+ `${ctx.route.accessor.at(-1)!}.Props`,
82
+ ),
83
+ ),
84
+ ];
85
+ }
86
+ return [
87
+ connection,
88
+ ...ctx.route.parameters.map((p) =>
89
+ IdentifierFactory.parameter(
90
+ p.key,
91
+ NestiaMigrateSchemaProgrammer.write({
92
+ components: ctx.components,
93
+ importer: ctx.importer,
94
+ schema: p.schema,
95
+ }),
96
+ ),
97
+ ),
98
+ ...(ctx.route.query
99
+ ? [
100
+ IdentifierFactory.parameter(
101
+ ctx.route.query.key,
102
+ TypeScriptFactory.createTypeReferenceNode(
103
+ `${ctx.route.accessor.at(-1)!}.Query`,
104
+ ),
105
+ ),
106
+ ]
107
+ : []),
108
+ ...(ctx.route.body
109
+ ? [
110
+ IdentifierFactory.parameter(
111
+ ctx.route.body.key,
112
+ TypeScriptFactory.createTypeReferenceNode(
113
+ `${ctx.route.accessor.at(-1)!}.Body`,
114
+ ),
115
+ (ctx.route.body.type === "application/json" ||
116
+ ctx.route.body.type === "text/plain") &&
117
+ ctx.route.operation().requestBody?.required === false
118
+ ? TypeScriptFactory.createToken(ts.SyntaxKind.QuestionToken)
119
+ : undefined,
120
+ ),
121
+ ]
122
+ : []),
123
+ ];
124
+ };
125
+
126
+ const writeDescription = (
127
+ config: INestiaMigrateConfig,
128
+ route: IHttpMigrateRoute,
129
+ ): string => {
130
+ const comment: string = route.comment();
131
+ return [
132
+ config.keyword === true
133
+ ? comment.split("@param ").join("@param props.")
134
+ : comment,
135
+ `@path ${route.emendedPath}`,
136
+ `@accessor api.functional.${route.accessor.join(".")}`,
137
+ `@${config.author?.tag ?? "nestia"} ${config.author?.value ?? "Generated by Nestia - https://github.com/samchon/nestia"}`,
138
+ ].join("\n");
139
+ };
140
+
141
+ const writeBody = (ctx: IContext): ts.Statement[] => {
142
+ const encrypted: boolean = !!ctx.route.success?.["x-nestia-encrypted"];
143
+ const contentType: string = ctx.route.body?.type ?? "application/json";
144
+
145
+ const property = (key: string): ts.Expression =>
146
+ ctx.config.keyword === true
147
+ ? IdentifierFactory.access(
148
+ TypeScriptFactory.createIdentifier("props"),
149
+ key,
150
+ )
151
+ : TypeScriptFactory.createIdentifier(key);
152
+ const fetch = () =>
153
+ TypeScriptFactory.createAwaitExpression(
154
+ TypeScriptFactory.createCallExpression(
155
+ IdentifierFactory.access(
156
+ TypeScriptFactory.createIdentifier(
157
+ ctx.importer.external({
158
+ type: "instance",
159
+ library: encrypted
160
+ ? "@nestia/fetcher/lib/EncryptedFetcher"
161
+ : `@nestia/fetcher`,
162
+ name: encrypted ? "EncryptedFetcher" : "PlainFetcher",
163
+ }),
164
+ ),
165
+ "fetch",
166
+ ),
167
+ undefined,
168
+ [
169
+ contentType && contentType !== "multipart/form-data"
170
+ ? TypeScriptFactory.createObjectLiteralExpression(
171
+ [
172
+ TypeScriptFactory.createSpreadAssignment(
173
+ TypeScriptFactory.createIdentifier("connection"),
174
+ ),
175
+ TypeScriptFactory.createPropertyAssignment(
176
+ "headers",
177
+ TypeScriptFactory.createObjectLiteralExpression(
178
+ [
179
+ TypeScriptFactory.createSpreadAssignment(
180
+ IdentifierFactory.access(
181
+ TypeScriptFactory.createIdentifier("connection"),
182
+ "headers",
183
+ ),
184
+ ),
185
+ TypeScriptFactory.createPropertyAssignment(
186
+ TypeScriptFactory.createStringLiteral(
187
+ "Content-Type",
188
+ ),
189
+ TypeScriptFactory.createStringLiteral(contentType),
190
+ ),
191
+ ],
192
+ true,
193
+ ),
194
+ ),
195
+ ],
196
+ true,
197
+ )
198
+ : TypeScriptFactory.createIdentifier("connection"),
199
+ TypeScriptFactory.createObjectLiteralExpression(
200
+ [
201
+ TypeScriptFactory.createSpreadAssignment(
202
+ IdentifierFactory.access(
203
+ TypeScriptFactory.createIdentifier(
204
+ ctx.route.accessor.at(-1)!,
205
+ ),
206
+ "METADATA",
207
+ ),
208
+ ),
209
+ TypeScriptFactory.createPropertyAssignment(
210
+ "path",
211
+ TypeScriptFactory.createCallExpression(
212
+ IdentifierFactory.access(
213
+ TypeScriptFactory.createIdentifier(
214
+ ctx.route.accessor.at(-1)!,
215
+ ),
216
+ "path",
217
+ ),
218
+ undefined,
219
+ getArguments(ctx, false),
220
+ ),
221
+ ),
222
+ TypeScriptFactory.createPropertyAssignment(
223
+ "status",
224
+ TypeScriptFactory.createNull(),
225
+ ),
226
+ ],
227
+ true,
228
+ ),
229
+ ...(ctx.route.body ? [property(ctx.route.body.key)] : []),
230
+ ],
231
+ ),
232
+ );
233
+
234
+ const value: ts.Expression =
235
+ ctx.config.simulate !== true
236
+ ? fetch()
237
+ : TypeScriptFactory.createConditionalExpression(
238
+ TypeScriptFactory.createStrictEquality(
239
+ TypeScriptFactory.createTrue(),
240
+ TypeScriptFactory.createIdentifier("connection.simulate"),
241
+ ),
242
+ undefined,
243
+ TypeScriptFactory.createCallExpression(
244
+ TypeScriptFactory.createIdentifier(
245
+ `${ctx.route.accessor.at(-1)!}.simulate`,
246
+ ),
247
+ [],
248
+ [
249
+ TypeScriptFactory.createIdentifier("connection"),
250
+ ...getArguments(ctx, true),
251
+ ],
252
+ ),
253
+ undefined,
254
+ fetch(),
255
+ );
256
+ const headers: Array<IAssignHeader | ISetHeader> = getHeaders(
257
+ ctx.route.comment(),
258
+ );
259
+ if (headers.length === 0)
260
+ return [TypeScriptFactory.createReturnStatement(value)];
261
+ return [
262
+ StatementFactory.constant({
263
+ name: "output",
264
+ type: TypeScriptFactory.createTypeReferenceNode(
265
+ `${ctx.route.accessor.at(-1)!}.Response`,
266
+ ),
267
+ value,
268
+ }),
269
+ TypeScriptFactory.createExpressionStatement(
270
+ TypeScriptFactory.createBinaryExpression(
271
+ TypeScriptFactory.createIdentifier("connection.headers"),
272
+ TypeScriptFactory.createToken(
273
+ ts.SyntaxKind.QuestionQuestionEqualsToken,
274
+ ),
275
+ TypeScriptFactory.createObjectLiteralExpression([]),
276
+ ),
277
+ ),
278
+ ...headers.map((h) =>
279
+ TypeScriptFactory.createExpressionStatement(
280
+ h.type === "assign"
281
+ ? TypeScriptFactory.createCallExpression(
282
+ TypeScriptFactory.createIdentifier("Object.assign"),
283
+ undefined,
284
+ [
285
+ TypeScriptFactory.createIdentifier("connection.headers"),
286
+ TypeScriptFactory.createIdentifier(`output.${h.accessor}`),
287
+ ],
288
+ )
289
+ : TypeScriptFactory.createBinaryExpression(
290
+ TypeScriptFactory.createIdentifier(
291
+ `connection.headers${
292
+ NamingConvention.variable(h.property)
293
+ ? `.${h.property}`
294
+ : `[${JSON.stringify(h.property)}]`
295
+ }`,
296
+ ),
297
+ TypeScriptFactory.createToken(ts.SyntaxKind.EqualsToken),
298
+ TypeScriptFactory.createIdentifier(`output.${h.accessor}`),
299
+ ),
300
+ ),
301
+ ),
302
+ TypeScriptFactory.createReturnStatement(
303
+ TypeScriptFactory.createIdentifier("output"),
304
+ ),
305
+ ];
306
+ };
307
+
308
+ const getArguments = (ctx: IContext, body: boolean): ts.Expression[] => {
309
+ if (
310
+ ctx.route.parameters.length === 0 &&
311
+ ctx.route.query === null &&
312
+ (body === false || ctx.route.body === null)
313
+ )
314
+ return [];
315
+ else if (ctx.config.keyword === true)
316
+ return [TypeScriptFactory.createIdentifier("props")];
317
+ return [
318
+ ...ctx.route.parameters.map((p) =>
319
+ TypeScriptFactory.createIdentifier(p.key),
320
+ ),
321
+ ...(ctx.route.query
322
+ ? [TypeScriptFactory.createIdentifier(ctx.route.query.key)]
323
+ : []),
324
+ ...(body && ctx.route.body
325
+ ? [TypeScriptFactory.createIdentifier(ctx.route.body.key)]
326
+ : []),
327
+ ];
328
+ };
329
+
330
+ const getHeaders = (
331
+ description: string,
332
+ ): Array<IAssignHeader | ISetHeader> => {
333
+ const directives: Array<IAssignHeader | ISetHeader> = [];
334
+ for (const line of description.split("\n").map((l) => l.trim())) {
335
+ const setHeaderTag: string | undefined = [
336
+ "@setHeader ",
337
+ "@setHeaders ",
338
+ ].find((tag) => line.startsWith(tag));
339
+ if (setHeaderTag !== undefined) {
340
+ const parts: string[] = line
341
+ .substring(setHeaderTag.length)
342
+ .trim()
343
+ .split(/\s+/);
344
+ if (parts.length >= 2)
345
+ directives.push({
346
+ type: "set",
347
+ accessor: parts[0]!,
348
+ property: parts[1]!,
349
+ });
350
+ } else if (line.startsWith("@assignHeaders ")) {
351
+ const accessor: string = line
352
+ .substring("@assignHeaders ".length)
353
+ .trim();
354
+ if (accessor.length !== 0)
355
+ directives.push({
356
+ type: "assign",
357
+ accessor,
358
+ });
359
+ }
360
+ }
361
+ return directives;
362
+ };
363
+ }
364
+
365
+ interface IAssignHeader {
366
+ type: "assign";
367
+ accessor: string;
368
+ }
369
+ interface ISetHeader {
370
+ type: "set";
371
+ accessor: string;
372
+ property: string;
373
+ }