@nestia/sdk 7.0.0-dev.20250607 → 7.0.0

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 (111) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +92 -92
  3. package/assets/bundle/api/HttpError.ts +1 -1
  4. package/assets/bundle/api/IConnection.ts +1 -1
  5. package/assets/bundle/api/Primitive.ts +1 -1
  6. package/assets/bundle/api/Resolved.ts +1 -1
  7. package/assets/bundle/api/index.ts +4 -4
  8. package/assets/bundle/api/module.ts +6 -6
  9. package/assets/bundle/distribute/README.md +37 -37
  10. package/assets/bundle/distribute/package.json +28 -28
  11. package/assets/bundle/distribute/tsconfig.json +109 -109
  12. package/assets/bundle/e2e/index.ts +42 -42
  13. package/assets/config/nestia.config.ts +97 -97
  14. package/lib/executable/internal/NestiaConfigLoader.js +4 -4
  15. package/lib/executable/sdk.js +12 -12
  16. package/package.json +5 -5
  17. package/src/INestiaConfig.ts +269 -269
  18. package/src/NestiaSdkApplication.ts +307 -307
  19. package/src/NestiaSwaggerComposer.ts +138 -138
  20. package/src/analyses/AccessorAnalyzer.ts +67 -67
  21. package/src/analyses/ConfigAnalyzer.ts +155 -155
  22. package/src/analyses/ExceptionAnalyzer.ts +154 -154
  23. package/src/analyses/GenericAnalyzer.ts +49 -49
  24. package/src/analyses/ImportAnalyzer.ts +171 -171
  25. package/src/analyses/PathAnalyzer.ts +69 -69
  26. package/src/analyses/ReflectControllerAnalyzer.ts +105 -105
  27. package/src/analyses/ReflectHttpOperationAnalyzer.ts +183 -183
  28. package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +71 -71
  29. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +348 -348
  30. package/src/analyses/ReflectHttpOperationResponseAnalyzer.ts +127 -127
  31. package/src/analyses/ReflectMetadataAnalyzer.ts +44 -44
  32. package/src/analyses/ReflectWebSocketOperationAnalyzer.ts +172 -172
  33. package/src/analyses/SecurityAnalyzer.ts +25 -25
  34. package/src/analyses/TypedHttpRouteAnalyzer.ts +204 -204
  35. package/src/analyses/TypedWebSocketRouteAnalyzer.ts +33 -33
  36. package/src/decorators/OperationMetadata.ts +15 -15
  37. package/src/executable/internal/CommandParser.ts +15 -15
  38. package/src/executable/internal/NestiaConfigLoader.ts +78 -78
  39. package/src/executable/internal/NestiaSdkCommand.ts +103 -103
  40. package/src/executable/sdk.ts +75 -75
  41. package/src/generates/CloneGenerator.ts +66 -66
  42. package/src/generates/E2eGenerator.ts +32 -32
  43. package/src/generates/SdkGenerator.ts +160 -160
  44. package/src/generates/SwaggerGenerator.ts +284 -284
  45. package/src/generates/internal/E2eFileProgrammer.ts +205 -205
  46. package/src/generates/internal/FilePrinter.ts +53 -53
  47. package/src/generates/internal/ImportDictionary.ts +163 -163
  48. package/src/generates/internal/SdkAliasCollection.ts +255 -255
  49. package/src/generates/internal/SdkDistributionComposer.ts +103 -103
  50. package/src/generates/internal/SdkFileProgrammer.ts +116 -116
  51. package/src/generates/internal/SdkHttpCloneProgrammer.ts +124 -124
  52. package/src/generates/internal/SdkHttpCloneReferencer.ts +75 -75
  53. package/src/generates/internal/SdkHttpFunctionProgrammer.ts +276 -276
  54. package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +500 -500
  55. package/src/generates/internal/SdkHttpParameterProgrammer.ts +178 -178
  56. package/src/generates/internal/SdkHttpRouteProgrammer.ts +107 -107
  57. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +340 -340
  58. package/src/generates/internal/SdkImportWizard.ts +55 -55
  59. package/src/generates/internal/SdkRouteDirectory.ts +18 -18
  60. package/src/generates/internal/SdkTypeProgrammer.ts +384 -384
  61. package/src/generates/internal/SdkTypeTagProgrammer.ts +102 -102
  62. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +366 -366
  63. package/src/generates/internal/SdkWebSocketParameterProgrammer.ts +87 -87
  64. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +279 -279
  65. package/src/generates/internal/SwaggerDescriptionComposer.ts +64 -64
  66. package/src/generates/internal/SwaggerOperationComposer.ts +119 -119
  67. package/src/generates/internal/SwaggerOperationParameterComposer.ts +177 -177
  68. package/src/generates/internal/SwaggerOperationResponseComposer.ts +110 -110
  69. package/src/index.ts +4 -4
  70. package/src/module.ts +3 -3
  71. package/src/structures/INestiaProject.ts +13 -13
  72. package/src/structures/INestiaSdkInput.ts +20 -20
  73. package/src/structures/IReflectApplication.ts +8 -8
  74. package/src/structures/IReflectController.ts +15 -15
  75. package/src/structures/IReflectHttpOperation.ts +26 -26
  76. package/src/structures/IReflectHttpOperationException.ts +19 -19
  77. package/src/structures/IReflectHttpOperationParameter.ts +81 -81
  78. package/src/structures/IReflectHttpOperationSuccess.ts +22 -22
  79. package/src/structures/IReflectOperationError.ts +26 -26
  80. package/src/structures/IReflectType.ts +4 -4
  81. package/src/structures/IReflectTypeImport.ts +4 -4
  82. package/src/structures/IReflectWebSocketOperation.ts +17 -17
  83. package/src/structures/IReflectWebSocketOperationParameter.ts +38 -38
  84. package/src/structures/ITypedApplication.ts +11 -11
  85. package/src/structures/ITypedHttpRoute.ts +41 -41
  86. package/src/structures/ITypedHttpRouteException.ts +15 -15
  87. package/src/structures/ITypedHttpRouteParameter.ts +41 -41
  88. package/src/structures/ITypedHttpRouteSuccess.ts +22 -22
  89. package/src/structures/ITypedWebSocketRoute.ts +24 -24
  90. package/src/structures/ITypedWebSocketRouteParameter.ts +3 -3
  91. package/src/structures/MethodType.ts +5 -5
  92. package/src/structures/ParamCategory.ts +1 -1
  93. package/src/structures/TypeEntry.ts +22 -22
  94. package/src/transform.ts +9 -9
  95. package/src/transformers/IOperationMetadata.ts +44 -44
  96. package/src/transformers/ISdkOperationTransformerContext.ts +8 -8
  97. package/src/transformers/SdkOperationProgrammer.ts +209 -209
  98. package/src/transformers/SdkOperationTransformer.ts +253 -253
  99. package/src/transformers/TextPlainValidator.ts +17 -17
  100. package/src/typings/get-function-location.d.ts +7 -7
  101. package/src/utils/ArrayUtil.ts +26 -26
  102. package/src/utils/FileRetriever.ts +22 -22
  103. package/src/utils/MapUtil.ts +14 -14
  104. package/src/utils/MetadataUtil.ts +26 -26
  105. package/src/utils/PathUtil.ts +10 -10
  106. package/src/utils/SourceFinder.ts +66 -66
  107. package/src/utils/StringUtil.ts +17 -17
  108. package/src/utils/StripEnums.ts +5 -5
  109. package/src/utils/VersioningStrategy.ts +28 -28
  110. package/src/validators/HttpHeadersValidator.ts +34 -34
  111. package/src/validators/HttpQueryValidator.ts +34 -34
@@ -1,500 +1,500 @@
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
- import { Escaper } from "typia/lib/utils/Escaper";
7
-
8
- import { INestiaProject } from "../../structures/INestiaProject";
9
- import { ITypedHttpRoute } from "../../structures/ITypedHttpRoute";
10
- import { FilePrinter } from "./FilePrinter";
11
- import { ImportDictionary } from "./ImportDictionary";
12
- import { SdkAliasCollection } from "./SdkAliasCollection";
13
- import { SdkHttpParameterProgrammer } from "./SdkHttpParameterProgrammer";
14
- import { SdkHttpSimulationProgrammer } from "./SdkHttpSimulationProgrammer";
15
- import { SdkImportWizard } from "./SdkImportWizard";
16
-
17
- export namespace SdkHttpNamespaceProgrammer {
18
- export const write =
19
- (project: INestiaProject) =>
20
- (importer: ImportDictionary) =>
21
- (route: ITypedHttpRoute): ts.ModuleDeclaration => {
22
- const types: ts.TypeAliasDeclaration[] =
23
- writeTypes(project)(importer)(route);
24
- return ts.factory.createModuleDeclaration(
25
- [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
26
- ts.factory.createIdentifier(route.name),
27
- ts.factory.createModuleBlock([
28
- ...types,
29
- ...(types.length ? [FilePrinter.enter()] : []),
30
- writeMetadata(project)(importer)(route),
31
- FilePrinter.enter(),
32
- writePath(project)(importer)(route),
33
- ...(project.config.simulate
34
- ? [
35
- SdkHttpSimulationProgrammer.random(project)(importer)(route),
36
- SdkHttpSimulationProgrammer.simulate(project)(importer)(route),
37
- ]
38
- : []),
39
- ...(project.config.json &&
40
- route.body &&
41
- (route.body.contentType === "application/json" ||
42
- route.body.encrypted === true)
43
- ? [writeStringify(project)(importer)]
44
- : []),
45
- ]),
46
- ts.NodeFlags.Namespace,
47
- );
48
- };
49
-
50
- const writeTypes =
51
- (project: INestiaProject) =>
52
- (importer: ImportDictionary) =>
53
- (route: ITypedHttpRoute): ts.TypeAliasDeclaration[] => {
54
- const array: ts.TypeAliasDeclaration[] = [];
55
- const declare = (name: string, type: ts.TypeNode) =>
56
- array.push(
57
- ts.factory.createTypeAliasDeclaration(
58
- [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
59
- name,
60
- undefined,
61
- type,
62
- ),
63
- );
64
- if (
65
- project.config.keyword === true &&
66
- SdkHttpParameterProgrammer.getSignificant(route, true).length !== 0
67
- )
68
- declare(
69
- "Props",
70
- SdkAliasCollection.httpProps(project)(importer)(route),
71
- );
72
- if (route.headerObject)
73
- declare(
74
- "Headers",
75
- SdkAliasCollection.headers(project)(importer)(route.headerObject),
76
- );
77
- if (route.queryObject)
78
- declare(
79
- "Query",
80
- SdkAliasCollection.query(project)(importer)(route.queryObject),
81
- );
82
- if (route.body)
83
- declare("Body", SdkAliasCollection.body(project)(importer)(route.body));
84
- if (
85
- project.config.propagate === true ||
86
- route.success.metadata.size() !== 0
87
- )
88
- declare(
89
- "Output",
90
- SdkAliasCollection.response(project)(importer)(route),
91
- );
92
- return array;
93
- };
94
-
95
- const writeMetadata =
96
- (project: INestiaProject) =>
97
- (importer: ImportDictionary) =>
98
- (route: ITypedHttpRoute): ts.VariableStatement =>
99
- constant("METADATA")(
100
- ts.factory.createAsExpression(
101
- ts.factory.createObjectLiteralExpression(
102
- [
103
- ts.factory.createPropertyAssignment(
104
- "method",
105
- ts.factory.createStringLiteral(route.method),
106
- ),
107
- ts.factory.createPropertyAssignment(
108
- "path",
109
- ts.factory.createStringLiteral(route.path),
110
- ),
111
- ts.factory.createPropertyAssignment(
112
- "request",
113
- route.body
114
- ? LiteralFactory.write(
115
- route.body !== undefined
116
- ? {
117
- type: route.body.contentType,
118
- encrypted: !!route.body.encrypted,
119
- }
120
- : {
121
- type: "application/json",
122
- encrypted: false,
123
- },
124
- )
125
- : ts.factory.createNull(),
126
- ),
127
- ts.factory.createPropertyAssignment(
128
- "response",
129
- route.method !== "HEAD"
130
- ? LiteralFactory.write({
131
- type: route.success.contentType,
132
- encrypted: !!route.success.encrypted,
133
- })
134
- : ts.factory.createNull(),
135
- ),
136
- ts.factory.createPropertyAssignment(
137
- "status",
138
- route.success.status !== null
139
- ? ExpressionFactory.number(route.success.status)
140
- : ts.factory.createNull(),
141
- ),
142
- ...(route.success.contentType ===
143
- "application/x-www-form-urlencoded"
144
- ? [
145
- ts.factory.createPropertyAssignment(
146
- "parseQuery",
147
- ts.factory.createCallExpression(
148
- ts.factory.createIdentifier(
149
- `${SdkImportWizard.typia(importer)}.http.createAssertQuery`,
150
- ),
151
- [
152
- project.config.clone === true
153
- ? SdkAliasCollection.from(project)(importer)(
154
- route.success.metadata,
155
- )
156
- : SdkAliasCollection.name(route.success),
157
- ],
158
- undefined,
159
- ),
160
- ),
161
- ]
162
- : []),
163
- ],
164
- true,
165
- ),
166
- ts.factory.createTypeReferenceNode(
167
- ts.factory.createIdentifier("const"),
168
- ),
169
- ),
170
- );
171
-
172
- const writePath =
173
- (project: INestiaProject) =>
174
- (importer: ImportDictionary) =>
175
- (route: ITypedHttpRoute): ts.VariableStatement => {
176
- const out = (body: ts.ConciseBody) =>
177
- constant("path")(
178
- ts.factory.createArrowFunction(
179
- [],
180
- [],
181
- SdkHttpParameterProgrammer.getParameterDeclarations({
182
- project,
183
- importer,
184
- route,
185
- body: false,
186
- prefix: false,
187
- }),
188
- undefined,
189
- undefined,
190
- body,
191
- ),
192
- );
193
- const parameters = SdkHttpParameterProgrammer.getSignificant(
194
- route,
195
- false,
196
- );
197
- if (parameters.length === 0)
198
- return out(ts.factory.createStringLiteral(route.path));
199
-
200
- const access = (name: string) =>
201
- project.config.keyword === true ? `props.${name}` : name;
202
- const template = () => {
203
- const split: string[] = route.path.split(":");
204
- if (split.length === 1)
205
- return ts.factory.createStringLiteral(route.path);
206
- return ts.factory.createTemplateExpression(
207
- ts.factory.createTemplateHead(split[0]),
208
- split.slice(1).map((s, i, arr) => {
209
- const name: string = s.split("/")[0];
210
- return ts.factory.createTemplateSpan(
211
- ts.factory.createCallExpression(
212
- ts.factory.createIdentifier("encodeURIComponent"),
213
- undefined,
214
- [
215
- ts.factory.createBinaryExpression(
216
- ts.factory.createCallChain(
217
- ts.factory.createPropertyAccessChain(
218
- ts.factory.createIdentifier(
219
- access(
220
- route.pathParameters.find((p) => p.field === name)!
221
- .name,
222
- ),
223
- ),
224
- ts.factory.createToken(ts.SyntaxKind.QuestionDotToken),
225
- "toString",
226
- ),
227
- undefined,
228
- undefined,
229
- [],
230
- ),
231
- ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken),
232
- ts.factory.createStringLiteral("null"),
233
- ),
234
- ],
235
- ),
236
- (i !== arr.length - 1
237
- ? ts.factory.createTemplateMiddle
238
- : ts.factory.createTemplateTail)(s.substring(name.length)),
239
- );
240
- }),
241
- );
242
- };
243
- if (route.queryObject === null && route.queryParameters.length === 0)
244
- return out(template());
245
-
246
- const block = (expr: ts.Expression) => {
247
- const computeName = (str: string): string =>
248
- parameters.find((p) => p.name === str) !== undefined
249
- ? computeName("_" + str)
250
- : str;
251
- const variables: string = computeName("variables");
252
- return ts.factory.createBlock(
253
- [
254
- local(variables)("URLSearchParams")(
255
- ts.factory.createNewExpression(
256
- ts.factory.createIdentifier("URLSearchParams"),
257
- [],
258
- [],
259
- ),
260
- ),
261
- ts.factory.createForOfStatement(
262
- undefined,
263
- ts.factory.createVariableDeclarationList(
264
- [
265
- ts.factory.createVariableDeclaration(
266
- ts.factory.createArrayBindingPattern([
267
- ts.factory.createBindingElement(
268
- undefined,
269
- undefined,
270
- ts.factory.createIdentifier("key"),
271
- undefined,
272
- ),
273
- ts.factory.createBindingElement(
274
- undefined,
275
- undefined,
276
- ts.factory.createIdentifier("value"),
277
- undefined,
278
- ),
279
- ]),
280
- undefined,
281
- undefined,
282
- undefined,
283
- ),
284
- ],
285
- ts.NodeFlags.Const,
286
- ),
287
- ts.factory.createCallExpression(
288
- ts.factory.createIdentifier("Object.entries"),
289
- undefined,
290
- [
291
- ts.factory.createAsExpression(
292
- expr,
293
- TypeFactory.keyword("any"),
294
- ),
295
- ],
296
- ),
297
- ts.factory.createIfStatement(
298
- ts.factory.createStrictEquality(
299
- ts.factory.createIdentifier("undefined"),
300
- ts.factory.createIdentifier("value"),
301
- ),
302
- ts.factory.createContinueStatement(),
303
- ts.factory.createIfStatement(
304
- ts.factory.createCallExpression(
305
- ts.factory.createIdentifier("Array.isArray"),
306
- undefined,
307
- [ts.factory.createIdentifier("value")],
308
- ),
309
- ts.factory.createExpressionStatement(
310
- ts.factory.createCallExpression(
311
- ts.factory.createPropertyAccessExpression(
312
- ts.factory.createIdentifier("value"),
313
- ts.factory.createIdentifier("forEach"),
314
- ),
315
- undefined,
316
- [
317
- ts.factory.createArrowFunction(
318
- undefined,
319
- undefined,
320
- [IdentifierFactory.parameter("elem")],
321
- undefined,
322
- undefined,
323
- ts.factory.createCallExpression(
324
- IdentifierFactory.access(
325
- ts.factory.createIdentifier(variables),
326
- "append",
327
- ),
328
- undefined,
329
- [
330
- ts.factory.createIdentifier("key"),
331
- ts.factory.createCallExpression(
332
- ts.factory.createIdentifier("String"),
333
- undefined,
334
- [ts.factory.createIdentifier("elem")],
335
- ),
336
- ],
337
- ),
338
- ),
339
- ],
340
- ),
341
- ),
342
- ts.factory.createExpressionStatement(
343
- ts.factory.createCallExpression(
344
- IdentifierFactory.access(
345
- ts.factory.createIdentifier(variables),
346
- "set",
347
- ),
348
- undefined,
349
- [
350
- ts.factory.createIdentifier("key"),
351
- ts.factory.createCallExpression(
352
- ts.factory.createIdentifier("String"),
353
- undefined,
354
- [ts.factory.createIdentifier("value")],
355
- ),
356
- ],
357
- ),
358
- ),
359
- ),
360
- ),
361
- ),
362
- local("location")("string")(template()),
363
- ts.factory.createReturnStatement(
364
- ts.factory.createConditionalExpression(
365
- ts.factory.createStrictEquality(
366
- ExpressionFactory.number(0),
367
- IdentifierFactory.access(
368
- ts.factory.createIdentifier(variables),
369
- "size",
370
- ),
371
- ),
372
- undefined,
373
- ts.factory.createIdentifier("location"),
374
- undefined,
375
- ts.factory.createTemplateExpression(
376
- ts.factory.createTemplateHead(""),
377
- [
378
- ts.factory.createTemplateSpan(
379
- ts.factory.createIdentifier("location"),
380
- ts.factory.createTemplateMiddle("?"),
381
- ),
382
- ts.factory.createTemplateSpan(
383
- ts.factory.createCallExpression(
384
- IdentifierFactory.access(
385
- ts.factory.createIdentifier(variables),
386
- "toString",
387
- ),
388
- undefined,
389
- undefined,
390
- ),
391
- ts.factory.createTemplateTail(""),
392
- ),
393
- ],
394
- ),
395
- ),
396
- ),
397
- ],
398
- true,
399
- );
400
- };
401
- if (route.queryObject !== null && route.queryParameters.length === 0)
402
- return out(
403
- block(
404
- route.queryObject.metadata.isRequired() === false
405
- ? ts.factory.createBinaryExpression(
406
- ts.factory.createIdentifier(route.queryObject.name),
407
- ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken),
408
- ts.factory.createObjectLiteralExpression([], false),
409
- )
410
- : ts.factory.createIdentifier(access(route.queryObject.name)),
411
- ),
412
- );
413
- return out(
414
- block(
415
- ts.factory.createObjectLiteralExpression(
416
- [
417
- ...(route.queryObject
418
- ? [
419
- ts.factory.createSpreadAssignment(
420
- ts.factory.createIdentifier(
421
- access(route.queryObject.name),
422
- ),
423
- ),
424
- ]
425
- : []),
426
- ...route.queryParameters.map((q) =>
427
- ts.factory.createPropertyAssignment(
428
- Escaper.variable(q.field!)
429
- ? q.field!
430
- : ts.factory.createStringLiteral(q.field!),
431
- ts.factory.createIdentifier(access(q.name)),
432
- ),
433
- ),
434
- ],
435
- true,
436
- ),
437
- ),
438
- );
439
- };
440
-
441
- const writeStringify =
442
- (project: INestiaProject) =>
443
- (importer: ImportDictionary): ts.VariableStatement =>
444
- constant("stringify")(
445
- ts.factory.createArrowFunction(
446
- [],
447
- undefined,
448
- [
449
- IdentifierFactory.parameter(
450
- "input",
451
- ts.factory.createTypeReferenceNode("Body"),
452
- ),
453
- ],
454
- undefined,
455
- undefined,
456
- ts.factory.createCallExpression(
457
- IdentifierFactory.access(
458
- IdentifierFactory.access(
459
- ts.factory.createIdentifier(SdkImportWizard.typia(importer)),
460
- "json",
461
- ),
462
- project.config.assert ? "stringify" : "assertStringify",
463
- ),
464
- undefined,
465
- [ts.factory.createIdentifier("input")],
466
- ),
467
- ),
468
- );
469
- }
470
-
471
- const local = (name: string) => (type: string) => (expression: ts.Expression) =>
472
- ts.factory.createVariableStatement(
473
- [],
474
- ts.factory.createVariableDeclarationList(
475
- [
476
- ts.factory.createVariableDeclaration(
477
- name,
478
- undefined,
479
- ts.factory.createTypeReferenceNode(type),
480
- expression,
481
- ),
482
- ],
483
- ts.NodeFlags.Const,
484
- ),
485
- );
486
- const constant = (name: string) => (expression: ts.Expression) =>
487
- ts.factory.createVariableStatement(
488
- [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
489
- ts.factory.createVariableDeclarationList(
490
- [
491
- ts.factory.createVariableDeclaration(
492
- name,
493
- undefined,
494
- undefined,
495
- expression,
496
- ),
497
- ],
498
- ts.NodeFlags.Const,
499
- ),
500
- );
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
+ import { Escaper } from "typia/lib/utils/Escaper";
7
+
8
+ import { INestiaProject } from "../../structures/INestiaProject";
9
+ import { ITypedHttpRoute } from "../../structures/ITypedHttpRoute";
10
+ import { FilePrinter } from "./FilePrinter";
11
+ import { ImportDictionary } from "./ImportDictionary";
12
+ import { SdkAliasCollection } from "./SdkAliasCollection";
13
+ import { SdkHttpParameterProgrammer } from "./SdkHttpParameterProgrammer";
14
+ import { SdkHttpSimulationProgrammer } from "./SdkHttpSimulationProgrammer";
15
+ import { SdkImportWizard } from "./SdkImportWizard";
16
+
17
+ export namespace SdkHttpNamespaceProgrammer {
18
+ export const write =
19
+ (project: INestiaProject) =>
20
+ (importer: ImportDictionary) =>
21
+ (route: ITypedHttpRoute): ts.ModuleDeclaration => {
22
+ const types: ts.TypeAliasDeclaration[] =
23
+ writeTypes(project)(importer)(route);
24
+ return ts.factory.createModuleDeclaration(
25
+ [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
26
+ ts.factory.createIdentifier(route.name),
27
+ ts.factory.createModuleBlock([
28
+ ...types,
29
+ ...(types.length ? [FilePrinter.enter()] : []),
30
+ writeMetadata(project)(importer)(route),
31
+ FilePrinter.enter(),
32
+ writePath(project)(importer)(route),
33
+ ...(project.config.simulate
34
+ ? [
35
+ SdkHttpSimulationProgrammer.random(project)(importer)(route),
36
+ SdkHttpSimulationProgrammer.simulate(project)(importer)(route),
37
+ ]
38
+ : []),
39
+ ...(project.config.json &&
40
+ route.body &&
41
+ (route.body.contentType === "application/json" ||
42
+ route.body.encrypted === true)
43
+ ? [writeStringify(project)(importer)]
44
+ : []),
45
+ ]),
46
+ ts.NodeFlags.Namespace,
47
+ );
48
+ };
49
+
50
+ const writeTypes =
51
+ (project: INestiaProject) =>
52
+ (importer: ImportDictionary) =>
53
+ (route: ITypedHttpRoute): ts.TypeAliasDeclaration[] => {
54
+ const array: ts.TypeAliasDeclaration[] = [];
55
+ const declare = (name: string, type: ts.TypeNode) =>
56
+ array.push(
57
+ ts.factory.createTypeAliasDeclaration(
58
+ [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
59
+ name,
60
+ undefined,
61
+ type,
62
+ ),
63
+ );
64
+ if (
65
+ project.config.keyword === true &&
66
+ SdkHttpParameterProgrammer.getSignificant(route, true).length !== 0
67
+ )
68
+ declare(
69
+ "Props",
70
+ SdkAliasCollection.httpProps(project)(importer)(route),
71
+ );
72
+ if (route.headerObject)
73
+ declare(
74
+ "Headers",
75
+ SdkAliasCollection.headers(project)(importer)(route.headerObject),
76
+ );
77
+ if (route.queryObject)
78
+ declare(
79
+ "Query",
80
+ SdkAliasCollection.query(project)(importer)(route.queryObject),
81
+ );
82
+ if (route.body)
83
+ declare("Body", SdkAliasCollection.body(project)(importer)(route.body));
84
+ if (
85
+ project.config.propagate === true ||
86
+ route.success.metadata.size() !== 0
87
+ )
88
+ declare(
89
+ "Output",
90
+ SdkAliasCollection.response(project)(importer)(route),
91
+ );
92
+ return array;
93
+ };
94
+
95
+ const writeMetadata =
96
+ (project: INestiaProject) =>
97
+ (importer: ImportDictionary) =>
98
+ (route: ITypedHttpRoute): ts.VariableStatement =>
99
+ constant("METADATA")(
100
+ ts.factory.createAsExpression(
101
+ ts.factory.createObjectLiteralExpression(
102
+ [
103
+ ts.factory.createPropertyAssignment(
104
+ "method",
105
+ ts.factory.createStringLiteral(route.method),
106
+ ),
107
+ ts.factory.createPropertyAssignment(
108
+ "path",
109
+ ts.factory.createStringLiteral(route.path),
110
+ ),
111
+ ts.factory.createPropertyAssignment(
112
+ "request",
113
+ route.body
114
+ ? LiteralFactory.write(
115
+ route.body !== undefined
116
+ ? {
117
+ type: route.body.contentType,
118
+ encrypted: !!route.body.encrypted,
119
+ }
120
+ : {
121
+ type: "application/json",
122
+ encrypted: false,
123
+ },
124
+ )
125
+ : ts.factory.createNull(),
126
+ ),
127
+ ts.factory.createPropertyAssignment(
128
+ "response",
129
+ route.method !== "HEAD"
130
+ ? LiteralFactory.write({
131
+ type: route.success.contentType,
132
+ encrypted: !!route.success.encrypted,
133
+ })
134
+ : ts.factory.createNull(),
135
+ ),
136
+ ts.factory.createPropertyAssignment(
137
+ "status",
138
+ route.success.status !== null
139
+ ? ExpressionFactory.number(route.success.status)
140
+ : ts.factory.createNull(),
141
+ ),
142
+ ...(route.success.contentType ===
143
+ "application/x-www-form-urlencoded"
144
+ ? [
145
+ ts.factory.createPropertyAssignment(
146
+ "parseQuery",
147
+ ts.factory.createCallExpression(
148
+ ts.factory.createIdentifier(
149
+ `${SdkImportWizard.typia(importer)}.http.createAssertQuery`,
150
+ ),
151
+ [
152
+ project.config.clone === true
153
+ ? SdkAliasCollection.from(project)(importer)(
154
+ route.success.metadata,
155
+ )
156
+ : SdkAliasCollection.name(route.success),
157
+ ],
158
+ undefined,
159
+ ),
160
+ ),
161
+ ]
162
+ : []),
163
+ ],
164
+ true,
165
+ ),
166
+ ts.factory.createTypeReferenceNode(
167
+ ts.factory.createIdentifier("const"),
168
+ ),
169
+ ),
170
+ );
171
+
172
+ const writePath =
173
+ (project: INestiaProject) =>
174
+ (importer: ImportDictionary) =>
175
+ (route: ITypedHttpRoute): ts.VariableStatement => {
176
+ const out = (body: ts.ConciseBody) =>
177
+ constant("path")(
178
+ ts.factory.createArrowFunction(
179
+ [],
180
+ [],
181
+ SdkHttpParameterProgrammer.getParameterDeclarations({
182
+ project,
183
+ importer,
184
+ route,
185
+ body: false,
186
+ prefix: false,
187
+ }),
188
+ undefined,
189
+ undefined,
190
+ body,
191
+ ),
192
+ );
193
+ const parameters = SdkHttpParameterProgrammer.getSignificant(
194
+ route,
195
+ false,
196
+ );
197
+ if (parameters.length === 0)
198
+ return out(ts.factory.createStringLiteral(route.path));
199
+
200
+ const access = (name: string) =>
201
+ project.config.keyword === true ? `props.${name}` : name;
202
+ const template = () => {
203
+ const split: string[] = route.path.split(":");
204
+ if (split.length === 1)
205
+ return ts.factory.createStringLiteral(route.path);
206
+ return ts.factory.createTemplateExpression(
207
+ ts.factory.createTemplateHead(split[0]),
208
+ split.slice(1).map((s, i, arr) => {
209
+ const name: string = s.split("/")[0];
210
+ return ts.factory.createTemplateSpan(
211
+ ts.factory.createCallExpression(
212
+ ts.factory.createIdentifier("encodeURIComponent"),
213
+ undefined,
214
+ [
215
+ ts.factory.createBinaryExpression(
216
+ ts.factory.createCallChain(
217
+ ts.factory.createPropertyAccessChain(
218
+ ts.factory.createIdentifier(
219
+ access(
220
+ route.pathParameters.find((p) => p.field === name)!
221
+ .name,
222
+ ),
223
+ ),
224
+ ts.factory.createToken(ts.SyntaxKind.QuestionDotToken),
225
+ "toString",
226
+ ),
227
+ undefined,
228
+ undefined,
229
+ [],
230
+ ),
231
+ ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken),
232
+ ts.factory.createStringLiteral("null"),
233
+ ),
234
+ ],
235
+ ),
236
+ (i !== arr.length - 1
237
+ ? ts.factory.createTemplateMiddle
238
+ : ts.factory.createTemplateTail)(s.substring(name.length)),
239
+ );
240
+ }),
241
+ );
242
+ };
243
+ if (route.queryObject === null && route.queryParameters.length === 0)
244
+ return out(template());
245
+
246
+ const block = (expr: ts.Expression) => {
247
+ const computeName = (str: string): string =>
248
+ parameters.find((p) => p.name === str) !== undefined
249
+ ? computeName("_" + str)
250
+ : str;
251
+ const variables: string = computeName("variables");
252
+ return ts.factory.createBlock(
253
+ [
254
+ local(variables)("URLSearchParams")(
255
+ ts.factory.createNewExpression(
256
+ ts.factory.createIdentifier("URLSearchParams"),
257
+ [],
258
+ [],
259
+ ),
260
+ ),
261
+ ts.factory.createForOfStatement(
262
+ undefined,
263
+ ts.factory.createVariableDeclarationList(
264
+ [
265
+ ts.factory.createVariableDeclaration(
266
+ ts.factory.createArrayBindingPattern([
267
+ ts.factory.createBindingElement(
268
+ undefined,
269
+ undefined,
270
+ ts.factory.createIdentifier("key"),
271
+ undefined,
272
+ ),
273
+ ts.factory.createBindingElement(
274
+ undefined,
275
+ undefined,
276
+ ts.factory.createIdentifier("value"),
277
+ undefined,
278
+ ),
279
+ ]),
280
+ undefined,
281
+ undefined,
282
+ undefined,
283
+ ),
284
+ ],
285
+ ts.NodeFlags.Const,
286
+ ),
287
+ ts.factory.createCallExpression(
288
+ ts.factory.createIdentifier("Object.entries"),
289
+ undefined,
290
+ [
291
+ ts.factory.createAsExpression(
292
+ expr,
293
+ TypeFactory.keyword("any"),
294
+ ),
295
+ ],
296
+ ),
297
+ ts.factory.createIfStatement(
298
+ ts.factory.createStrictEquality(
299
+ ts.factory.createIdentifier("undefined"),
300
+ ts.factory.createIdentifier("value"),
301
+ ),
302
+ ts.factory.createContinueStatement(),
303
+ ts.factory.createIfStatement(
304
+ ts.factory.createCallExpression(
305
+ ts.factory.createIdentifier("Array.isArray"),
306
+ undefined,
307
+ [ts.factory.createIdentifier("value")],
308
+ ),
309
+ ts.factory.createExpressionStatement(
310
+ ts.factory.createCallExpression(
311
+ ts.factory.createPropertyAccessExpression(
312
+ ts.factory.createIdentifier("value"),
313
+ ts.factory.createIdentifier("forEach"),
314
+ ),
315
+ undefined,
316
+ [
317
+ ts.factory.createArrowFunction(
318
+ undefined,
319
+ undefined,
320
+ [IdentifierFactory.parameter("elem")],
321
+ undefined,
322
+ undefined,
323
+ ts.factory.createCallExpression(
324
+ IdentifierFactory.access(
325
+ ts.factory.createIdentifier(variables),
326
+ "append",
327
+ ),
328
+ undefined,
329
+ [
330
+ ts.factory.createIdentifier("key"),
331
+ ts.factory.createCallExpression(
332
+ ts.factory.createIdentifier("String"),
333
+ undefined,
334
+ [ts.factory.createIdentifier("elem")],
335
+ ),
336
+ ],
337
+ ),
338
+ ),
339
+ ],
340
+ ),
341
+ ),
342
+ ts.factory.createExpressionStatement(
343
+ ts.factory.createCallExpression(
344
+ IdentifierFactory.access(
345
+ ts.factory.createIdentifier(variables),
346
+ "set",
347
+ ),
348
+ undefined,
349
+ [
350
+ ts.factory.createIdentifier("key"),
351
+ ts.factory.createCallExpression(
352
+ ts.factory.createIdentifier("String"),
353
+ undefined,
354
+ [ts.factory.createIdentifier("value")],
355
+ ),
356
+ ],
357
+ ),
358
+ ),
359
+ ),
360
+ ),
361
+ ),
362
+ local("location")("string")(template()),
363
+ ts.factory.createReturnStatement(
364
+ ts.factory.createConditionalExpression(
365
+ ts.factory.createStrictEquality(
366
+ ExpressionFactory.number(0),
367
+ IdentifierFactory.access(
368
+ ts.factory.createIdentifier(variables),
369
+ "size",
370
+ ),
371
+ ),
372
+ undefined,
373
+ ts.factory.createIdentifier("location"),
374
+ undefined,
375
+ ts.factory.createTemplateExpression(
376
+ ts.factory.createTemplateHead(""),
377
+ [
378
+ ts.factory.createTemplateSpan(
379
+ ts.factory.createIdentifier("location"),
380
+ ts.factory.createTemplateMiddle("?"),
381
+ ),
382
+ ts.factory.createTemplateSpan(
383
+ ts.factory.createCallExpression(
384
+ IdentifierFactory.access(
385
+ ts.factory.createIdentifier(variables),
386
+ "toString",
387
+ ),
388
+ undefined,
389
+ undefined,
390
+ ),
391
+ ts.factory.createTemplateTail(""),
392
+ ),
393
+ ],
394
+ ),
395
+ ),
396
+ ),
397
+ ],
398
+ true,
399
+ );
400
+ };
401
+ if (route.queryObject !== null && route.queryParameters.length === 0)
402
+ return out(
403
+ block(
404
+ route.queryObject.metadata.isRequired() === false
405
+ ? ts.factory.createBinaryExpression(
406
+ ts.factory.createIdentifier(route.queryObject.name),
407
+ ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken),
408
+ ts.factory.createObjectLiteralExpression([], false),
409
+ )
410
+ : ts.factory.createIdentifier(access(route.queryObject.name)),
411
+ ),
412
+ );
413
+ return out(
414
+ block(
415
+ ts.factory.createObjectLiteralExpression(
416
+ [
417
+ ...(route.queryObject
418
+ ? [
419
+ ts.factory.createSpreadAssignment(
420
+ ts.factory.createIdentifier(
421
+ access(route.queryObject.name),
422
+ ),
423
+ ),
424
+ ]
425
+ : []),
426
+ ...route.queryParameters.map((q) =>
427
+ ts.factory.createPropertyAssignment(
428
+ Escaper.variable(q.field!)
429
+ ? q.field!
430
+ : ts.factory.createStringLiteral(q.field!),
431
+ ts.factory.createIdentifier(access(q.name)),
432
+ ),
433
+ ),
434
+ ],
435
+ true,
436
+ ),
437
+ ),
438
+ );
439
+ };
440
+
441
+ const writeStringify =
442
+ (project: INestiaProject) =>
443
+ (importer: ImportDictionary): ts.VariableStatement =>
444
+ constant("stringify")(
445
+ ts.factory.createArrowFunction(
446
+ [],
447
+ undefined,
448
+ [
449
+ IdentifierFactory.parameter(
450
+ "input",
451
+ ts.factory.createTypeReferenceNode("Body"),
452
+ ),
453
+ ],
454
+ undefined,
455
+ undefined,
456
+ ts.factory.createCallExpression(
457
+ IdentifierFactory.access(
458
+ IdentifierFactory.access(
459
+ ts.factory.createIdentifier(SdkImportWizard.typia(importer)),
460
+ "json",
461
+ ),
462
+ project.config.assert ? "stringify" : "assertStringify",
463
+ ),
464
+ undefined,
465
+ [ts.factory.createIdentifier("input")],
466
+ ),
467
+ ),
468
+ );
469
+ }
470
+
471
+ const local = (name: string) => (type: string) => (expression: ts.Expression) =>
472
+ ts.factory.createVariableStatement(
473
+ [],
474
+ ts.factory.createVariableDeclarationList(
475
+ [
476
+ ts.factory.createVariableDeclaration(
477
+ name,
478
+ undefined,
479
+ ts.factory.createTypeReferenceNode(type),
480
+ expression,
481
+ ),
482
+ ],
483
+ ts.NodeFlags.Const,
484
+ ),
485
+ );
486
+ const constant = (name: string) => (expression: ts.Expression) =>
487
+ ts.factory.createVariableStatement(
488
+ [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
489
+ ts.factory.createVariableDeclarationList(
490
+ [
491
+ ts.factory.createVariableDeclaration(
492
+ name,
493
+ undefined,
494
+ undefined,
495
+ expression,
496
+ ),
497
+ ],
498
+ ts.NodeFlags.Const,
499
+ ),
500
+ );