@nestia/sdk 6.0.6 → 7.0.0-dev.20250605

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