@nestia/sdk 10.0.2 → 11.0.0-dev.20260312

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 (151) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +93 -93
  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 +3 -3
  15. package/lib/NestiaSdkApplication.js.map +1 -1
  16. package/lib/NestiaSwaggerComposer.d.ts +3 -2
  17. package/lib/NestiaSwaggerComposer.js +5 -6
  18. package/lib/NestiaSwaggerComposer.js.map +1 -1
  19. package/lib/analyses/AccessorAnalyzer.js +2 -2
  20. package/lib/analyses/AccessorAnalyzer.js.map +1 -1
  21. package/lib/analyses/DtoAnalyzer.js.map +1 -1
  22. package/lib/analyses/ImportAnalyzer.js.map +1 -1
  23. package/lib/analyses/ReflectHttpOperationAnalyzer.js +3 -3
  24. package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -1
  25. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js +4 -2
  26. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js.map +1 -1
  27. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js +7 -11
  28. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js.map +1 -1
  29. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js +6 -6
  30. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js.map +1 -1
  31. package/lib/analyses/TypedHttpRouteAnalyzer.d.ts +1 -1
  32. package/lib/analyses/TypedHttpRouteAnalyzer.js +6 -8
  33. package/lib/analyses/TypedHttpRouteAnalyzer.js.map +1 -1
  34. package/lib/executable/internal/NestiaConfigLoader.js +111 -52
  35. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  36. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  37. package/lib/executable/sdk.js +0 -0
  38. package/lib/generates/SwaggerGenerator.d.ts +1 -1
  39. package/lib/generates/SwaggerGenerator.js +11 -12
  40. package/lib/generates/SwaggerGenerator.js.map +1 -1
  41. package/lib/generates/internal/E2eFileProgrammer.js +8 -9
  42. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  43. package/lib/generates/internal/SdkAliasCollection.d.ts +2 -2
  44. package/lib/generates/internal/SdkAliasCollection.js +2 -2
  45. package/lib/generates/internal/SdkAliasCollection.js.map +1 -1
  46. package/lib/generates/internal/SdkDistributionComposer.js +1 -1
  47. package/lib/generates/internal/SdkHttpCloneProgrammer.js.map +1 -1
  48. package/lib/generates/internal/SdkHttpCloneReferencer.js.map +1 -1
  49. package/lib/generates/internal/SdkHttpFunctionProgrammer.js +11 -12
  50. package/lib/generates/internal/SdkHttpFunctionProgrammer.js.map +1 -1
  51. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js +13 -16
  52. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js.map +1 -1
  53. package/lib/generates/internal/SdkHttpRouteProgrammer.js +4 -4
  54. package/lib/generates/internal/SdkHttpRouteProgrammer.js.map +1 -1
  55. package/lib/generates/internal/SdkHttpSimulationProgrammer.js +12 -16
  56. package/lib/generates/internal/SdkHttpSimulationProgrammer.js.map +1 -1
  57. package/lib/generates/internal/SdkImportWizard.js +2 -2
  58. package/lib/generates/internal/SdkImportWizard.js.map +1 -1
  59. package/lib/generates/internal/SdkTypeProgrammer.d.ts +2 -3
  60. package/lib/generates/internal/SdkTypeProgrammer.js +6 -7
  61. package/lib/generates/internal/SdkTypeProgrammer.js.map +1 -1
  62. package/lib/generates/internal/SdkTypeTagProgrammer.d.ts +1 -1
  63. package/lib/generates/internal/SdkTypeTagProgrammer.js +11 -11
  64. package/lib/generates/internal/SdkTypeTagProgrammer.js.map +1 -1
  65. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js +6 -8
  66. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js.map +1 -1
  67. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js +2 -2
  68. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js.map +1 -1
  69. package/lib/generates/internal/SwaggerOperationComposer.d.ts +3 -3
  70. package/lib/generates/internal/SwaggerOperationComposer.js.map +1 -1
  71. package/lib/generates/internal/SwaggerOperationParameterComposer.d.ts +1 -1
  72. package/lib/generates/internal/SwaggerOperationParameterComposer.js +10 -8
  73. package/lib/generates/internal/SwaggerOperationParameterComposer.js.map +1 -1
  74. package/lib/generates/internal/SwaggerOperationResponseComposer.d.ts +3 -3
  75. package/lib/generates/internal/SwaggerOperationResponseComposer.js.map +1 -1
  76. package/lib/module.d.ts +1 -0
  77. package/lib/module.js +1 -0
  78. package/lib/module.js.map +1 -1
  79. package/lib/structures/IReflectHttpOperationException.d.ts +3 -4
  80. package/lib/structures/IReflectHttpOperationParameter.d.ts +3 -5
  81. package/lib/structures/IReflectHttpOperationSuccess.d.ts +3 -4
  82. package/lib/structures/ITypedApplication.d.ts +1 -1
  83. package/lib/structures/ITypedHttpRouteException.d.ts +2 -2
  84. package/lib/structures/ITypedHttpRouteParameter.d.ts +2 -2
  85. package/lib/structures/ITypedHttpRouteSuccess.d.ts +2 -2
  86. package/lib/transformers/IOperationMetadata.d.ts +2 -4
  87. package/lib/transformers/ISdkOperationTransformerContext.d.ts +1 -1
  88. package/lib/transformers/SdkOperationProgrammer.js +8 -10
  89. package/lib/transformers/SdkOperationProgrammer.js.map +1 -1
  90. package/lib/transformers/SdkOperationTransformer.js +6 -8
  91. package/lib/transformers/SdkOperationTransformer.js.map +1 -1
  92. package/lib/transformers/TextPlainValidator.d.ts +2 -2
  93. package/lib/transformers/TextPlainValidator.js.map +1 -1
  94. package/lib/utils/MetadataUtil.d.ts +2 -2
  95. package/lib/utils/MetadataUtil.js.map +1 -1
  96. package/lib/validators/HttpHeadersValidator.d.ts +2 -3
  97. package/lib/validators/HttpHeadersValidator.js +2 -2
  98. package/lib/validators/HttpHeadersValidator.js.map +1 -1
  99. package/lib/validators/HttpQueryValidator.d.ts +2 -3
  100. package/lib/validators/HttpQueryValidator.js +2 -2
  101. package/lib/validators/HttpQueryValidator.js.map +1 -1
  102. package/package.json +44 -30
  103. package/src/INestiaConfig.ts +267 -267
  104. package/src/NestiaSdkApplication.ts +307 -307
  105. package/src/NestiaSwaggerComposer.ts +143 -138
  106. package/src/analyses/AccessorAnalyzer.ts +67 -67
  107. package/src/analyses/DtoAnalyzer.ts +260 -260
  108. package/src/analyses/ImportAnalyzer.ts +126 -126
  109. package/src/analyses/ReflectHttpOperationAnalyzer.ts +183 -183
  110. package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +72 -71
  111. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +350 -348
  112. package/src/analyses/ReflectHttpOperationResponseAnalyzer.ts +126 -127
  113. package/src/analyses/TypedHttpRouteAnalyzer.ts +208 -204
  114. package/src/executable/internal/NestiaConfigLoader.ts +85 -78
  115. package/src/executable/internal/NestiaSdkCommand.ts +107 -103
  116. package/src/generates/SwaggerGenerator.ts +291 -284
  117. package/src/generates/internal/E2eFileProgrammer.ts +196 -197
  118. package/src/generates/internal/FilePrinter.ts +64 -64
  119. package/src/generates/internal/ImportDictionary.ts +192 -192
  120. package/src/generates/internal/SdkAliasCollection.ts +260 -261
  121. package/src/generates/internal/SdkFileProgrammer.ts +110 -110
  122. package/src/generates/internal/SdkHttpCloneProgrammer.ts +126 -124
  123. package/src/generates/internal/SdkHttpCloneReferencer.ts +77 -77
  124. package/src/generates/internal/SdkHttpFunctionProgrammer.ts +278 -279
  125. package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +502 -500
  126. package/src/generates/internal/SdkHttpRouteProgrammer.ts +109 -108
  127. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +312 -310
  128. package/src/generates/internal/SdkImportWizard.ts +62 -62
  129. package/src/generates/internal/SdkTypeProgrammer.ts +388 -385
  130. package/src/generates/internal/SdkTypeTagProgrammer.ts +114 -104
  131. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +379 -381
  132. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +302 -302
  133. package/src/generates/internal/SwaggerOperationComposer.ts +119 -119
  134. package/src/generates/internal/SwaggerOperationParameterComposer.ts +161 -162
  135. package/src/generates/internal/SwaggerOperationResponseComposer.ts +110 -110
  136. package/src/module.ts +4 -3
  137. package/src/structures/IReflectHttpOperationException.ts +18 -19
  138. package/src/structures/IReflectHttpOperationParameter.ts +79 -77
  139. package/src/structures/IReflectHttpOperationSuccess.ts +21 -22
  140. package/src/structures/ITypedApplication.ts +11 -11
  141. package/src/structures/ITypedHttpRouteException.ts +15 -15
  142. package/src/structures/ITypedHttpRouteParameter.ts +41 -41
  143. package/src/structures/ITypedHttpRouteSuccess.ts +22 -22
  144. package/src/transformers/IOperationMetadata.ts +46 -44
  145. package/src/transformers/ISdkOperationTransformerContext.ts +8 -8
  146. package/src/transformers/SdkOperationProgrammer.ts +240 -238
  147. package/src/transformers/SdkOperationTransformer.ts +248 -252
  148. package/src/transformers/TextPlainValidator.ts +17 -17
  149. package/src/utils/MetadataUtil.ts +26 -26
  150. package/src/validators/HttpHeadersValidator.ts +36 -34
  151. package/src/validators/HttpQueryValidator.ts +36 -34
@@ -1,385 +1,388 @@
1
- import ts from "typescript";
2
- import { IJsDocTagInfo } from "typia";
3
- import { ExpressionFactory } from "typia/lib/factories/ExpressionFactory";
4
- import { TypeFactory } from "typia/lib/factories/TypeFactory";
5
- import { IMetadataTypeTag } from "typia/lib/schemas/metadata/IMetadataTypeTag";
6
- import { Metadata } from "typia/lib/schemas/metadata/Metadata";
7
- import { MetadataAliasType } from "typia/lib/schemas/metadata/MetadataAliasType";
8
- import { MetadataArray } from "typia/lib/schemas/metadata/MetadataArray";
9
- import { MetadataAtomic } from "typia/lib/schemas/metadata/MetadataAtomic";
10
- import { MetadataConstantValue } from "typia/lib/schemas/metadata/MetadataConstantValue";
11
- import { MetadataEscaped } from "typia/lib/schemas/metadata/MetadataEscaped";
12
- import { MetadataObjectType } from "typia/lib/schemas/metadata/MetadataObjectType";
13
- import { MetadataProperty } from "typia/lib/schemas/metadata/MetadataProperty";
14
- import { MetadataTuple } from "typia/lib/schemas/metadata/MetadataTuple";
15
- import { Escaper } from "typia/lib/utils/Escaper";
16
-
17
- import { INestiaProject } from "../../structures/INestiaProject";
18
- import { FilePrinter } from "./FilePrinter";
19
- import { ImportDictionary } from "./ImportDictionary";
20
- import { SdkTypeTagProgrammer } from "./SdkTypeTagProgrammer";
21
-
22
- export namespace SdkTypeProgrammer {
23
- /* -----------------------------------------------------------
24
- FACADE
25
- ----------------------------------------------------------- */
26
- export const write =
27
- (project: INestiaProject) =>
28
- (importer: ImportDictionary) =>
29
- (meta: Metadata, parentEscaped: boolean = false): ts.TypeNode => {
30
- const union: ts.TypeNode[] = [];
31
-
32
- // COALESCES
33
- if (meta.any) union.push(TypeFactory.keyword("any"));
34
- if (meta.nullable) union.push(writeNode("null"));
35
- if (meta.isRequired() === false) union.push(writeNode("undefined"));
36
- if (parentEscaped === false && meta.escaped)
37
- union.push(write_escaped(project)(importer)(meta.escaped));
38
-
39
- // ATOMIC TYPES
40
- for (const c of meta.constants)
41
- for (const value of c.values) union.push(write_constant(value));
42
- for (const tpl of meta.templates)
43
- union.push(write_template(project)(importer)(tpl.row ?? tpl));
44
- for (const atom of meta.atomics) union.push(write_atomic(importer)(atom));
45
-
46
- // OBJECT TYPES
47
- for (const tuple of meta.tuples)
48
- union.push(write_tuple(project)(importer)(tuple));
49
- for (const array of meta.arrays)
50
- union.push(write_array(project)(importer)(array));
51
- for (const object of meta.objects)
52
- if (
53
- object.type.name === "object" ||
54
- object.type.name === "__type" ||
55
- object.type.name.startsWith("__type.") ||
56
- object.type.name === "__object" ||
57
- object.type.name.startsWith("__object.")
58
- )
59
- union.push(write_object(project)(importer)(object.type));
60
- else union.push(writeAlias(project)(importer)(object.type));
61
- for (const alias of meta.aliases)
62
- union.push(writeAlias(project)(importer)(alias.type));
63
- for (const native of meta.natives)
64
- if (native.name === "Blob" || native.name === "File")
65
- union.push(write_native(native.name));
66
-
67
- return union.length === 1
68
- ? union[0]
69
- : ts.factory.createUnionTypeNode(union);
70
- };
71
-
72
- export const write_object =
73
- (project: INestiaProject) =>
74
- (importer: ImportDictionary) =>
75
- (object: MetadataObjectType): ts.TypeNode => {
76
- const regular = object.properties.filter((p) => p.key.isSoleLiteral());
77
- const dynamic = object.properties.filter((p) => !p.key.isSoleLiteral());
78
- return regular.length && dynamic.length
79
- ? ts.factory.createIntersectionTypeNode([
80
- write_regular_property(project)(importer)(regular),
81
- ...dynamic.map(write_dynamic_property(project)(importer)),
82
- ])
83
- : dynamic.length
84
- ? ts.factory.createIntersectionTypeNode(
85
- dynamic.map(write_dynamic_property(project)(importer)),
86
- )
87
- : write_regular_property(project)(importer)(regular);
88
- };
89
-
90
- const write_escaped =
91
- (project: INestiaProject) =>
92
- (importer: ImportDictionary) =>
93
- (meta: MetadataEscaped): ts.TypeNode => {
94
- if (
95
- meta.original.size() === 1 &&
96
- meta.original.natives.length === 1 &&
97
- meta.original.natives[0].name === "Date"
98
- )
99
- return ts.factory.createIntersectionTypeNode([
100
- TypeFactory.keyword("string"),
101
- SdkTypeTagProgrammer.write(importer, "string", {
102
- name: "Format",
103
- value: "date-time",
104
- } as IMetadataTypeTag),
105
- ]);
106
- return write(project)(importer)(meta.returns, true);
107
- };
108
-
109
- /* -----------------------------------------------------------
110
- ATOMICS
111
- ----------------------------------------------------------- */
112
- const write_constant = (value: MetadataConstantValue) => {
113
- if (typeof value.value === "boolean")
114
- return ts.factory.createLiteralTypeNode(
115
- value ? ts.factory.createTrue() : ts.factory.createFalse(),
116
- );
117
- else if (typeof value.value === "bigint")
118
- return ts.factory.createLiteralTypeNode(
119
- value.value < BigInt(0)
120
- ? ts.factory.createPrefixUnaryExpression(
121
- ts.SyntaxKind.MinusToken,
122
- ts.factory.createBigIntLiteral((-value).toString()),
123
- )
124
- : ts.factory.createBigIntLiteral(value.toString()),
125
- );
126
- else if (typeof value.value === "number")
127
- return ts.factory.createLiteralTypeNode(
128
- ExpressionFactory.number(value.value),
129
- );
130
- return ts.factory.createLiteralTypeNode(
131
- ts.factory.createStringLiteral(value.value as string),
132
- );
133
- };
134
-
135
- const write_template =
136
- (project: INestiaProject) =>
137
- (importer: ImportDictionary) =>
138
- (meta: Metadata[]): ts.TypeNode => {
139
- const head: boolean = meta[0].isSoleLiteral();
140
- const spans: [ts.TypeNode | null, string | null][] = [];
141
- for (const elem of meta.slice(head ? 1 : 0)) {
142
- const last =
143
- spans.at(-1) ??
144
- (() => {
145
- const tuple = [null!, null!] as [ts.TypeNode | null, string | null];
146
- spans.push(tuple);
147
- return tuple;
148
- })();
149
- if (elem.isSoleLiteral())
150
- if (last[1] === null)
151
- last[1] = String(elem.constants[0].values[0].value);
152
- else
153
- spans.push([
154
- ts.factory.createLiteralTypeNode(
155
- ts.factory.createStringLiteral(
156
- String(elem.constants[0].values[0].value),
157
- ),
158
- ),
159
- null,
160
- ]);
161
- else if (last[0] === null) last[0] = write(project)(importer)(elem);
162
- else spans.push([write(project)(importer)(elem), null]);
163
- }
164
- return ts.factory.createTemplateLiteralType(
165
- ts.factory.createTemplateHead(
166
- head ? (meta[0].constants[0].values[0].value as string) : "",
167
- ),
168
- spans
169
- .filter(([node]) => node !== null)
170
- .map(([node, str], i, array) =>
171
- ts.factory.createTemplateLiteralTypeSpan(
172
- node!,
173
- (i !== array.length - 1
174
- ? ts.factory.createTemplateMiddle
175
- : ts.factory.createTemplateTail)(str ?? ""),
176
- ),
177
- ),
178
- );
179
- };
180
-
181
- const write_atomic =
182
- (importer: ImportDictionary) =>
183
- (meta: MetadataAtomic): ts.TypeNode =>
184
- write_type_tag_matrix(importer)(
185
- meta.type as "boolean" | "bigint" | "number" | "string",
186
- ts.factory.createKeywordTypeNode(
187
- meta.type === "boolean"
188
- ? ts.SyntaxKind.BooleanKeyword
189
- : meta.type === "bigint"
190
- ? ts.SyntaxKind.BigIntKeyword
191
- : meta.type === "number"
192
- ? ts.SyntaxKind.NumberKeyword
193
- : ts.SyntaxKind.StringKeyword,
194
- ),
195
- meta.tags,
196
- );
197
-
198
- /* -----------------------------------------------------------
199
- INSTANCES
200
- ----------------------------------------------------------- */
201
- const write_array =
202
- (project: INestiaProject) =>
203
- (importer: ImportDictionary) =>
204
- (meta: MetadataArray): ts.TypeNode =>
205
- write_type_tag_matrix(importer)(
206
- "array",
207
- ts.factory.createArrayTypeNode(
208
- write(project)(importer)(meta.type.value),
209
- ),
210
- meta.tags,
211
- );
212
-
213
- const write_tuple =
214
- (project: INestiaProject) =>
215
- (importer: ImportDictionary) =>
216
- (meta: MetadataTuple): ts.TypeNode =>
217
- ts.factory.createTupleTypeNode(
218
- meta.type.elements.map((elem) =>
219
- elem.rest
220
- ? ts.factory.createRestTypeNode(
221
- ts.factory.createArrayTypeNode(
222
- write(project)(importer)(elem.rest),
223
- ),
224
- )
225
- : elem.optional
226
- ? ts.factory.createOptionalTypeNode(
227
- write(project)(importer)(elem),
228
- )
229
- : write(project)(importer)(elem),
230
- ),
231
- );
232
-
233
- const write_regular_property =
234
- (project: INestiaProject) =>
235
- (importer: ImportDictionary) =>
236
- (properties: MetadataProperty[]): ts.TypeLiteralNode =>
237
- ts.factory.createTypeLiteralNode(
238
- properties
239
- .map((p) => {
240
- const description: string = writeComment(p.value.atomics)(
241
- p.description,
242
- p.jsDocTags,
243
- );
244
- const signature: ts.PropertySignature =
245
- ts.factory.createPropertySignature(
246
- undefined,
247
- Escaper.variable(String(p.key.constants[0].values[0].value))
248
- ? ts.factory.createIdentifier(
249
- String(p.key.constants[0].values[0].value),
250
- )
251
- : ts.factory.createStringLiteral(
252
- String(p.key.constants[0].values[0].value),
253
- ),
254
- p.value.isRequired() === false
255
- ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
256
- : undefined,
257
- SdkTypeProgrammer.write(project)(importer)(p.value),
258
- );
259
- return !!description.length
260
- ? [
261
- ts.factory.createIdentifier("\n") as any,
262
- FilePrinter.description(signature, description),
263
- ]
264
- : signature;
265
- })
266
- .flat(),
267
- );
268
-
269
- const write_dynamic_property =
270
- (project: INestiaProject) =>
271
- (importer: ImportDictionary) =>
272
- (property: MetadataProperty): ts.TypeLiteralNode =>
273
- ts.factory.createTypeLiteralNode([
274
- FilePrinter.description(
275
- ts.factory.createIndexSignature(
276
- undefined,
277
- [
278
- ts.factory.createParameterDeclaration(
279
- undefined,
280
- undefined,
281
- ts.factory.createIdentifier("key"),
282
- undefined,
283
- SdkTypeProgrammer.write(project)(importer)(property.key),
284
- ),
285
- ],
286
- SdkTypeProgrammer.write(project)(importer)(property.value),
287
- ),
288
- writeComment(property.value.atomics)(
289
- property.description,
290
- property.jsDocTags,
291
- ),
292
- ),
293
- ]);
294
-
295
- const writeAlias =
296
- (project: INestiaProject) =>
297
- (importer: ImportDictionary) =>
298
- (meta: MetadataAliasType | MetadataObjectType): ts.TypeNode => {
299
- importInternalFile(project)(importer)(meta.name);
300
- return ts.factory.createTypeReferenceNode(meta.name);
301
- };
302
-
303
- const write_native = (name: string): ts.TypeNode =>
304
- ts.factory.createTypeReferenceNode(name);
305
-
306
- /* -----------------------------------------------------------
307
- MISCELLANEOUS
308
- ----------------------------------------------------------- */
309
- const write_type_tag_matrix =
310
- (importer: ImportDictionary) =>
311
- (
312
- from: "array" | "boolean" | "number" | "bigint" | "string" | "object",
313
- base: ts.TypeNode,
314
- matrix: IMetadataTypeTag[][],
315
- ): ts.TypeNode => {
316
- matrix = matrix.filter((row) => row.length !== 0);
317
- if (matrix.length === 0) return base;
318
- else if (matrix.length === 1)
319
- return ts.factory.createIntersectionTypeNode([
320
- base,
321
- ...matrix[0].map((tag) =>
322
- SdkTypeTagProgrammer.write(importer, from, tag),
323
- ),
324
- ]);
325
- return ts.factory.createIntersectionTypeNode([
326
- base,
327
- ts.factory.createUnionTypeNode(
328
- matrix.map((row) =>
329
- row.length === 1
330
- ? SdkTypeTagProgrammer.write(importer, from, row[0])
331
- : ts.factory.createIntersectionTypeNode(
332
- row.map((tag) =>
333
- SdkTypeTagProgrammer.write(importer, from, tag),
334
- ),
335
- ),
336
- ),
337
- ),
338
- ]);
339
- };
340
- }
341
-
342
- const writeNode = (text: string) => ts.factory.createTypeReferenceNode(text);
343
- const writeComment =
344
- (atomics: MetadataAtomic[]) =>
345
- (description: string | null, jsDocTags: IJsDocTagInfo[]): string => {
346
- const lines: string[] = [];
347
- if (description?.length)
348
- lines.push(...description.split("\n").map((s) => `${s}`));
349
-
350
- const filtered: IJsDocTagInfo[] =
351
- !!atomics.length && !!jsDocTags?.length
352
- ? jsDocTags.filter(
353
- (tag) =>
354
- !atomics.some((a) =>
355
- a.tags.some((r) => r.some((t) => t.kind === tag.name)),
356
- ),
357
- )
358
- : (jsDocTags ?? []);
359
-
360
- if (description?.length && filtered.length) lines.push("");
361
- if (filtered.length)
362
- lines.push(
363
- ...filtered.map((t) =>
364
- t.text?.length
365
- ? `@${t.name} ${t.text.map((e) => e.text).join("")}`
366
- : `@${t.name}`,
367
- ),
368
- );
369
- return lines.join("\n");
370
- };
371
-
372
- const importInternalFile =
373
- (project: INestiaProject) =>
374
- (importer: ImportDictionary) =>
375
- (name: string) => {
376
- const top = name.split(".")[0];
377
- if (importer.file === `${project.config.output}/structures/${top}.ts`)
378
- return;
379
- importer.internal({
380
- declaration: true,
381
- file: `${project.config.output}/structures/${name.split(".")[0]}`,
382
- type: "element",
383
- name: top,
384
- });
385
- };
1
+ import {
2
+ ExpressionFactory,
3
+ MetadataAliasType,
4
+ MetadataArray,
5
+ MetadataAtomic,
6
+ MetadataConstantValue,
7
+ MetadataEscaped,
8
+ MetadataObjectType,
9
+ MetadataProperty,
10
+ MetadataSchema,
11
+ MetadataTuple,
12
+ TypeFactory,
13
+ } from "@typia/core";
14
+ import { NamingConvention } from "@typia/utils";
15
+ import ts from "typescript";
16
+ import { IJsDocTagInfo, IMetadataTypeTag } from "typia";
17
+
18
+ import { INestiaProject } from "../../structures/INestiaProject";
19
+ import { FilePrinter } from "./FilePrinter";
20
+ import { ImportDictionary } from "./ImportDictionary";
21
+ import { SdkTypeTagProgrammer } from "./SdkTypeTagProgrammer";
22
+
23
+ export namespace SdkTypeProgrammer {
24
+ /* -----------------------------------------------------------
25
+ FACADE
26
+ ----------------------------------------------------------- */
27
+ export const write =
28
+ (project: INestiaProject) =>
29
+ (importer: ImportDictionary) =>
30
+ (meta: MetadataSchema, parentEscaped: boolean = false): ts.TypeNode => {
31
+ const union: ts.TypeNode[] = [];
32
+
33
+ // COALESCES
34
+ if (meta.any) union.push(TypeFactory.keyword("any"));
35
+ if (meta.nullable) union.push(writeNode("null"));
36
+ if (meta.isRequired() === false) union.push(writeNode("undefined"));
37
+ if (parentEscaped === false && meta.escaped)
38
+ union.push(write_escaped(project)(importer)(meta.escaped));
39
+
40
+ // ATOMIC TYPES
41
+ for (const c of meta.constants)
42
+ for (const value of c.values) union.push(write_constant(value));
43
+ for (const tpl of meta.templates)
44
+ union.push(write_template(project)(importer)(tpl.row ?? tpl));
45
+ for (const atom of meta.atomics) union.push(write_atomic(importer)(atom));
46
+
47
+ // OBJECT TYPES
48
+ for (const tuple of meta.tuples)
49
+ union.push(write_tuple(project)(importer)(tuple));
50
+ for (const array of meta.arrays)
51
+ union.push(write_array(project)(importer)(array));
52
+ for (const object of meta.objects)
53
+ if (
54
+ object.type.name === "object" ||
55
+ object.type.name === "__type" ||
56
+ object.type.name.startsWith("__type.") ||
57
+ object.type.name === "__object" ||
58
+ object.type.name.startsWith("__object.")
59
+ )
60
+ union.push(write_object(project)(importer)(object.type));
61
+ else union.push(writeAlias(project)(importer)(object.type));
62
+ for (const alias of meta.aliases)
63
+ union.push(writeAlias(project)(importer)(alias.type));
64
+ for (const native of meta.natives)
65
+ if (native.name === "Blob" || native.name === "File")
66
+ union.push(write_native(native.name));
67
+
68
+ return union.length === 1
69
+ ? union[0]!
70
+ : ts.factory.createUnionTypeNode(union);
71
+ };
72
+
73
+ export const write_object =
74
+ (project: INestiaProject) =>
75
+ (importer: ImportDictionary) =>
76
+ (object: MetadataObjectType): ts.TypeNode => {
77
+ const regular = object.properties.filter((p) => p.key.isSoleLiteral());
78
+ const dynamic = object.properties.filter((p) => !p.key.isSoleLiteral());
79
+ return regular.length && dynamic.length
80
+ ? ts.factory.createIntersectionTypeNode([
81
+ write_regular_property(project)(importer)(regular),
82
+ ...dynamic.map(write_dynamic_property(project)(importer)),
83
+ ])
84
+ : dynamic.length
85
+ ? ts.factory.createIntersectionTypeNode(
86
+ dynamic.map(write_dynamic_property(project)(importer)),
87
+ )
88
+ : write_regular_property(project)(importer)(regular);
89
+ };
90
+
91
+ const write_escaped =
92
+ (project: INestiaProject) =>
93
+ (importer: ImportDictionary) =>
94
+ (meta: MetadataEscaped): ts.TypeNode => {
95
+ if (
96
+ meta.original.size() === 1 &&
97
+ meta.original.natives.length === 1 &&
98
+ meta.original.natives[0]!.name === "Date"
99
+ )
100
+ return ts.factory.createIntersectionTypeNode([
101
+ TypeFactory.keyword("string"),
102
+ SdkTypeTagProgrammer.write(importer, "string", {
103
+ name: "Format",
104
+ value: "date-time",
105
+ } as IMetadataTypeTag),
106
+ ]);
107
+ return write(project)(importer)(meta.returns, true);
108
+ };
109
+
110
+ /* -----------------------------------------------------------
111
+ ATOMICS
112
+ ----------------------------------------------------------- */
113
+ const write_constant = (value: MetadataConstantValue) => {
114
+ if (typeof value.value === "boolean")
115
+ return ts.factory.createLiteralTypeNode(
116
+ value ? ts.factory.createTrue() : ts.factory.createFalse(),
117
+ );
118
+ else if (typeof value.value === "bigint")
119
+ return ts.factory.createLiteralTypeNode(
120
+ value.value < BigInt(0)
121
+ ? ts.factory.createPrefixUnaryExpression(
122
+ ts.SyntaxKind.MinusToken,
123
+ ts.factory.createBigIntLiteral((-value).toString()),
124
+ )
125
+ : ts.factory.createBigIntLiteral(value.toString()),
126
+ );
127
+ else if (typeof value.value === "number")
128
+ return ts.factory.createLiteralTypeNode(
129
+ ExpressionFactory.number(value.value),
130
+ );
131
+ return ts.factory.createLiteralTypeNode(
132
+ ts.factory.createStringLiteral(value.value as string),
133
+ );
134
+ };
135
+
136
+ const write_template =
137
+ (project: INestiaProject) =>
138
+ (importer: ImportDictionary) =>
139
+ (meta: MetadataSchema[]): ts.TypeNode => {
140
+ const head: boolean = meta[0]!.isSoleLiteral();
141
+ const spans: [ts.TypeNode | null, string | null][] = [];
142
+ for (const elem of meta.slice(head ? 1 : 0)) {
143
+ const last =
144
+ spans.at(-1) ??
145
+ (() => {
146
+ const tuple = [null!, null!] as [ts.TypeNode | null, string | null];
147
+ spans.push(tuple);
148
+ return tuple;
149
+ })();
150
+ if (elem.isSoleLiteral())
151
+ if (last[1] === null)
152
+ last[1] = String(elem.constants[0]!.values[0]!.value);
153
+ else
154
+ spans.push([
155
+ ts.factory.createLiteralTypeNode(
156
+ ts.factory.createStringLiteral(
157
+ String(elem.constants[0]!.values[0]!.value),
158
+ ),
159
+ ),
160
+ null,
161
+ ]);
162
+ else if (last[0] === null) last[0] = write(project)(importer)(elem);
163
+ else spans.push([write(project)(importer)(elem), null]);
164
+ }
165
+ return ts.factory.createTemplateLiteralType(
166
+ ts.factory.createTemplateHead(
167
+ head ? (meta[0]!.constants[0]!.values[0]!.value as string) : "",
168
+ ),
169
+ spans
170
+ .filter(([node]) => node !== null)
171
+ .map(([node, str], i, array) =>
172
+ ts.factory.createTemplateLiteralTypeSpan(
173
+ node!,
174
+ (i !== array.length - 1
175
+ ? ts.factory.createTemplateMiddle
176
+ : ts.factory.createTemplateTail)(str ?? ""),
177
+ ),
178
+ ),
179
+ );
180
+ };
181
+
182
+ const write_atomic =
183
+ (importer: ImportDictionary) =>
184
+ (meta: MetadataAtomic): ts.TypeNode =>
185
+ write_type_tag_matrix(importer)(
186
+ meta.type as "boolean" | "bigint" | "number" | "string",
187
+ ts.factory.createKeywordTypeNode(
188
+ meta.type === "boolean"
189
+ ? ts.SyntaxKind.BooleanKeyword
190
+ : meta.type === "bigint"
191
+ ? ts.SyntaxKind.BigIntKeyword
192
+ : meta.type === "number"
193
+ ? ts.SyntaxKind.NumberKeyword
194
+ : ts.SyntaxKind.StringKeyword,
195
+ ),
196
+ meta.tags,
197
+ );
198
+
199
+ /* -----------------------------------------------------------
200
+ INSTANCES
201
+ ----------------------------------------------------------- */
202
+ const write_array =
203
+ (project: INestiaProject) =>
204
+ (importer: ImportDictionary) =>
205
+ (meta: MetadataArray): ts.TypeNode =>
206
+ write_type_tag_matrix(importer)(
207
+ "array",
208
+ ts.factory.createArrayTypeNode(
209
+ write(project)(importer)(meta.type.value),
210
+ ),
211
+ meta.tags,
212
+ );
213
+
214
+ const write_tuple =
215
+ (project: INestiaProject) =>
216
+ (importer: ImportDictionary) =>
217
+ (meta: MetadataTuple): ts.TypeNode =>
218
+ ts.factory.createTupleTypeNode(
219
+ meta.type.elements.map((elem) =>
220
+ elem.rest
221
+ ? ts.factory.createRestTypeNode(
222
+ ts.factory.createArrayTypeNode(
223
+ write(project)(importer)(elem.rest),
224
+ ),
225
+ )
226
+ : elem.optional
227
+ ? ts.factory.createOptionalTypeNode(
228
+ write(project)(importer)(elem),
229
+ )
230
+ : write(project)(importer)(elem),
231
+ ),
232
+ );
233
+
234
+ const write_regular_property =
235
+ (project: INestiaProject) =>
236
+ (importer: ImportDictionary) =>
237
+ (properties: MetadataProperty[]): ts.TypeLiteralNode =>
238
+ ts.factory.createTypeLiteralNode(
239
+ properties
240
+ .map((p) => {
241
+ const description: string = writeComment(p.value.atomics)(
242
+ p.description,
243
+ p.jsDocTags,
244
+ );
245
+ const signature: ts.PropertySignature =
246
+ ts.factory.createPropertySignature(
247
+ undefined,
248
+ NamingConvention.variable(
249
+ String(p.key.constants[0]!.values[0]!.value),
250
+ )
251
+ ? ts.factory.createIdentifier(
252
+ String(p.key.constants[0]!.values[0]!.value),
253
+ )
254
+ : ts.factory.createStringLiteral(
255
+ String(p.key.constants[0]!.values[0]!.value),
256
+ ),
257
+ p.value.isRequired() === false
258
+ ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
259
+ : undefined,
260
+ SdkTypeProgrammer.write(project)(importer)(p.value),
261
+ );
262
+ return !!description.length
263
+ ? [
264
+ ts.factory.createIdentifier("\n") as any,
265
+ FilePrinter.description(signature, description),
266
+ ]
267
+ : signature;
268
+ })
269
+ .flat(),
270
+ );
271
+
272
+ const write_dynamic_property =
273
+ (project: INestiaProject) =>
274
+ (importer: ImportDictionary) =>
275
+ (property: MetadataProperty): ts.TypeLiteralNode =>
276
+ ts.factory.createTypeLiteralNode([
277
+ FilePrinter.description(
278
+ ts.factory.createIndexSignature(
279
+ undefined,
280
+ [
281
+ ts.factory.createParameterDeclaration(
282
+ undefined,
283
+ undefined,
284
+ ts.factory.createIdentifier("key"),
285
+ undefined,
286
+ SdkTypeProgrammer.write(project)(importer)(property.key),
287
+ ),
288
+ ],
289
+ SdkTypeProgrammer.write(project)(importer)(property.value),
290
+ ),
291
+ writeComment(property.value.atomics)(
292
+ property.description,
293
+ property.jsDocTags,
294
+ ),
295
+ ),
296
+ ]);
297
+
298
+ const writeAlias =
299
+ (project: INestiaProject) =>
300
+ (importer: ImportDictionary) =>
301
+ (meta: MetadataAliasType | MetadataObjectType): ts.TypeNode => {
302
+ importInternalFile(project)(importer)(meta.name);
303
+ return ts.factory.createTypeReferenceNode(meta.name);
304
+ };
305
+
306
+ const write_native = (name: string): ts.TypeNode =>
307
+ ts.factory.createTypeReferenceNode(name);
308
+
309
+ /* -----------------------------------------------------------
310
+ MISCELLANEOUS
311
+ ----------------------------------------------------------- */
312
+ const write_type_tag_matrix =
313
+ (importer: ImportDictionary) =>
314
+ (
315
+ from: "array" | "boolean" | "number" | "bigint" | "string" | "object",
316
+ base: ts.TypeNode,
317
+ matrix: IMetadataTypeTag[][],
318
+ ): ts.TypeNode => {
319
+ matrix = matrix.filter((row) => row.length !== 0);
320
+ if (matrix.length === 0) return base;
321
+ else if (matrix.length === 1)
322
+ return ts.factory.createIntersectionTypeNode([
323
+ base,
324
+ ...matrix[0]!.map((tag) =>
325
+ SdkTypeTagProgrammer.write(importer, from, tag),
326
+ ),
327
+ ]);
328
+ return ts.factory.createIntersectionTypeNode([
329
+ base,
330
+ ts.factory.createUnionTypeNode(
331
+ matrix.map((row) =>
332
+ row.length === 1
333
+ ? SdkTypeTagProgrammer.write(importer, from, row[0]!)
334
+ : ts.factory.createIntersectionTypeNode(
335
+ row.map((tag) =>
336
+ SdkTypeTagProgrammer.write(importer, from, tag),
337
+ ),
338
+ ),
339
+ ),
340
+ ),
341
+ ]);
342
+ };
343
+ }
344
+
345
+ const writeNode = (text: string) => ts.factory.createTypeReferenceNode(text);
346
+ const writeComment =
347
+ (atomics: MetadataAtomic[]) =>
348
+ (description: string | null, jsDocTags: IJsDocTagInfo[]): string => {
349
+ const lines: string[] = [];
350
+ if (description?.length)
351
+ lines.push(...description.split("\n").map((s) => `${s}`));
352
+
353
+ const filtered: IJsDocTagInfo[] =
354
+ !!atomics.length && !!jsDocTags?.length
355
+ ? jsDocTags.filter(
356
+ (tag) =>
357
+ !atomics.some((a) =>
358
+ a.tags.some((r) => r.some((t) => t.kind === tag.name)),
359
+ ),
360
+ )
361
+ : (jsDocTags ?? []);
362
+
363
+ if (description?.length && filtered.length) lines.push("");
364
+ if (filtered.length)
365
+ lines.push(
366
+ ...filtered.map((t) =>
367
+ t.text?.length
368
+ ? `@${t.name} ${t.text.map((e) => e.text).join("")}`
369
+ : `@${t.name}`,
370
+ ),
371
+ );
372
+ return lines.join("\n");
373
+ };
374
+
375
+ const importInternalFile =
376
+ (project: INestiaProject) =>
377
+ (importer: ImportDictionary) =>
378
+ (name: string) => {
379
+ const top: string = name.split(".")[0]!;
380
+ if (importer.file === `${project.config.output}/structures/${top}.ts`)
381
+ return;
382
+ importer.internal({
383
+ declaration: true,
384
+ file: `${project.config.output}/structures/${name.split(".")[0]}`,
385
+ type: "element",
386
+ name: top,
387
+ });
388
+ };