@nestia/sdk 4.4.2-dev.20241217 → 4.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +87 -87
  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 +271 -271
  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 +186 -186
  35. package/src/analyses/TypedWebSocketRouteAnalyzer.ts +18 -18
  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 +159 -159
  44. package/src/generates/SwaggerGenerator.ts +292 -292
  45. package/src/generates/internal/E2eFileProgrammer.ts +183 -183
  46. package/src/generates/internal/FilePrinter.ts +53 -53
  47. package/src/generates/internal/ImportDictionary.ts +147 -147
  48. package/src/generates/internal/SdkAliasCollection.ts +185 -185
  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 +71 -71
  53. package/src/generates/internal/SdkHttpFunctionProgrammer.ts +301 -301
  54. package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +529 -529
  55. package/src/generates/internal/SdkHttpRouteProgrammer.ts +117 -117
  56. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +362 -362
  57. package/src/generates/internal/SdkImportWizard.ts +55 -55
  58. package/src/generates/internal/SdkRouteDirectory.ts +18 -18
  59. package/src/generates/internal/SdkTypeProgrammer.ts +377 -377
  60. package/src/generates/internal/SdkTypeTagProgrammer.ts +120 -120
  61. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +363 -363
  62. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +265 -265
  63. package/src/generates/internal/SwaggerDescriptionComposer.ts +64 -64
  64. package/src/generates/internal/SwaggerOperationComposer.ts +117 -117
  65. package/src/generates/internal/SwaggerOperationParameterComposer.ts +177 -177
  66. package/src/generates/internal/SwaggerOperationResponseComposer.ts +110 -110
  67. package/src/index.ts +4 -4
  68. package/src/module.ts +3 -3
  69. package/src/structures/INestiaProject.ts +13 -13
  70. package/src/structures/INestiaSdkInput.ts +20 -20
  71. package/src/structures/IReflectApplication.ts +8 -8
  72. package/src/structures/IReflectController.ts +15 -15
  73. package/src/structures/IReflectHttpOperation.ts +26 -26
  74. package/src/structures/IReflectHttpOperationException.ts +19 -19
  75. package/src/structures/IReflectHttpOperationParameter.ts +81 -81
  76. package/src/structures/IReflectHttpOperationSuccess.ts +22 -22
  77. package/src/structures/IReflectOperationError.ts +26 -26
  78. package/src/structures/IReflectType.ts +4 -4
  79. package/src/structures/IReflectTypeImport.ts +4 -4
  80. package/src/structures/IReflectWebSocketOperation.ts +17 -17
  81. package/src/structures/IReflectWebSocketOperationParameter.ts +38 -38
  82. package/src/structures/ITypedApplication.ts +11 -11
  83. package/src/structures/ITypedHttpRoute.ts +30 -30
  84. package/src/structures/ITypedHttpRouteException.ts +15 -15
  85. package/src/structures/ITypedHttpRouteParameter.ts +41 -41
  86. package/src/structures/ITypedHttpRouteSuccess.ts +22 -22
  87. package/src/structures/ITypedWebSocketRoute.ts +20 -20
  88. package/src/structures/ITypedWebSocketRouteParameter.ts +3 -3
  89. package/src/structures/MethodType.ts +5 -5
  90. package/src/structures/ParamCategory.ts +1 -1
  91. package/src/structures/TypeEntry.ts +22 -22
  92. package/src/transform.ts +9 -9
  93. package/src/transformers/IOperationMetadata.ts +44 -44
  94. package/src/transformers/ISdkOperationTransformerContext.ts +8 -8
  95. package/src/transformers/SdkOperationProgrammer.ts +209 -209
  96. package/src/transformers/SdkOperationTransformer.ts +253 -253
  97. package/src/transformers/TextPlainValidator.ts +17 -17
  98. package/src/typings/get-function-location.d.ts +7 -7
  99. package/src/utils/ArrayUtil.ts +26 -26
  100. package/src/utils/FileRetriever.ts +22 -22
  101. package/src/utils/MapUtil.ts +14 -14
  102. package/src/utils/MetadataUtil.ts +26 -26
  103. package/src/utils/PathUtil.ts +10 -10
  104. package/src/utils/SourceFinder.ts +66 -66
  105. package/src/utils/StringUtil.ts +17 -17
  106. package/src/utils/StripEnums.ts +5 -5
  107. package/src/utils/VersioningStrategy.ts +28 -28
  108. package/src/validators/HttpHeadersValidator.ts +34 -34
  109. package/src/validators/HttpQueryValidator.ts +34 -34
@@ -1,377 +1,377 @@
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(write_alias(project)(importer)(object.type));
61
- for (const alias of meta.aliases)
62
- union.push(write_alias(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 FilePrinter.description(
79
- 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
- writeComment([])(object.description ?? null, object.jsDocTags),
90
- );
91
- };
92
-
93
- const write_escaped =
94
- (project: INestiaProject) =>
95
- (importer: ImportDictionary) =>
96
- (meta: MetadataEscaped): ts.TypeNode => {
97
- if (
98
- meta.original.size() === 1 &&
99
- meta.original.natives.length === 1 &&
100
- meta.original.natives[0].name === "Date"
101
- )
102
- return ts.factory.createIntersectionTypeNode([
103
- TypeFactory.keyword("string"),
104
- SdkTypeTagProgrammer.write(importer, "string", {
105
- name: "Format",
106
- value: "date-time",
107
- } as IMetadataTypeTag),
108
- ]);
109
- return write(project)(importer)(meta.returns, true);
110
- };
111
-
112
- /* -----------------------------------------------------------
113
- ATOMICS
114
- ----------------------------------------------------------- */
115
- const write_constant = (value: MetadataConstantValue) => {
116
- if (typeof value.value === "boolean")
117
- return ts.factory.createLiteralTypeNode(
118
- value ? ts.factory.createTrue() : ts.factory.createFalse(),
119
- );
120
- else if (typeof value.value === "bigint")
121
- return ts.factory.createLiteralTypeNode(
122
- value.value < BigInt(0)
123
- ? ts.factory.createPrefixUnaryExpression(
124
- ts.SyntaxKind.MinusToken,
125
- ts.factory.createBigIntLiteral((-value).toString()),
126
- )
127
- : ts.factory.createBigIntLiteral(value.toString()),
128
- );
129
- else if (typeof value.value === "number")
130
- return ts.factory.createLiteralTypeNode(
131
- ExpressionFactory.number(value.value),
132
- );
133
- return ts.factory.createLiteralTypeNode(
134
- ts.factory.createStringLiteral(value.value as string),
135
- );
136
- };
137
-
138
- const write_template =
139
- (project: INestiaProject) =>
140
- (importer: ImportDictionary) =>
141
- (meta: Metadata[]): ts.TypeNode => {
142
- const head: boolean = meta[0].isSoleLiteral();
143
- const spans: [ts.TypeNode | null, string | null][] = [];
144
- for (const elem of meta.slice(head ? 1 : 0)) {
145
- const last =
146
- spans.at(-1) ??
147
- (() => {
148
- const tuple = [null!, null!] as [ts.TypeNode | null, string | null];
149
- spans.push(tuple);
150
- return tuple;
151
- })();
152
- if (elem.isSoleLiteral())
153
- if (last[1] === null)
154
- last[1] = String(elem.constants[0].values[0].value);
155
- else
156
- spans.push([
157
- ts.factory.createLiteralTypeNode(
158
- ts.factory.createStringLiteral(
159
- String(elem.constants[0].values[0].value),
160
- ),
161
- ),
162
- null,
163
- ]);
164
- else if (last[0] === null) last[0] = write(project)(importer)(elem);
165
- else spans.push([write(project)(importer)(elem), null]);
166
- }
167
- return ts.factory.createTemplateLiteralType(
168
- ts.factory.createTemplateHead(
169
- head ? (meta[0].constants[0].values[0].value as string) : "",
170
- ),
171
- spans
172
- .filter(([node]) => node !== null)
173
- .map(([node, str], i, array) =>
174
- ts.factory.createTemplateLiteralTypeSpan(
175
- node!,
176
- (i !== array.length - 1
177
- ? ts.factory.createTemplateMiddle
178
- : ts.factory.createTemplateTail)(str ?? ""),
179
- ),
180
- ),
181
- );
182
- };
183
-
184
- const write_atomic =
185
- (importer: ImportDictionary) =>
186
- (meta: MetadataAtomic): ts.TypeNode =>
187
- write_type_tag_matrix(importer)(
188
- meta.type as "boolean" | "bigint" | "number" | "string",
189
- ts.factory.createKeywordTypeNode(
190
- meta.type === "boolean"
191
- ? ts.SyntaxKind.BooleanKeyword
192
- : meta.type === "bigint"
193
- ? ts.SyntaxKind.BigIntKeyword
194
- : meta.type === "number"
195
- ? ts.SyntaxKind.NumberKeyword
196
- : ts.SyntaxKind.StringKeyword,
197
- ),
198
- meta.tags,
199
- );
200
-
201
- /* -----------------------------------------------------------
202
- INSTANCES
203
- ----------------------------------------------------------- */
204
- const write_array =
205
- (project: INestiaProject) =>
206
- (importer: ImportDictionary) =>
207
- (meta: MetadataArray): ts.TypeNode =>
208
- write_type_tag_matrix(importer)(
209
- "array",
210
- ts.factory.createArrayTypeNode(
211
- write(project)(importer)(meta.type.value),
212
- ),
213
- meta.tags,
214
- );
215
-
216
- const write_tuple =
217
- (project: INestiaProject) =>
218
- (importer: ImportDictionary) =>
219
- (meta: MetadataTuple): ts.TypeNode =>
220
- ts.factory.createTupleTypeNode(
221
- meta.type.elements.map((elem) =>
222
- elem.rest
223
- ? ts.factory.createRestTypeNode(
224
- ts.factory.createArrayTypeNode(
225
- write(project)(importer)(elem.rest),
226
- ),
227
- )
228
- : elem.optional
229
- ? ts.factory.createOptionalTypeNode(
230
- write(project)(importer)(elem),
231
- )
232
- : write(project)(importer)(elem),
233
- ),
234
- );
235
-
236
- const write_regular_property =
237
- (project: INestiaProject) =>
238
- (importer: ImportDictionary) =>
239
- (properties: MetadataProperty[]): ts.TypeLiteralNode =>
240
- ts.factory.createTypeLiteralNode(
241
- properties.map((p) =>
242
- FilePrinter.description(
243
- ts.factory.createPropertySignature(
244
- undefined,
245
- Escaper.variable(String(p.key.constants[0].values[0].value))
246
- ? ts.factory.createIdentifier(
247
- String(p.key.constants[0].values[0].value),
248
- )
249
- : ts.factory.createStringLiteral(
250
- String(p.key.constants[0].values[0].value),
251
- ),
252
- p.value.isRequired() === false
253
- ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
254
- : undefined,
255
- SdkTypeProgrammer.write(project)(importer)(p.value),
256
- ),
257
- writeComment(p.value.atomics)(p.description, p.jsDocTags),
258
- ),
259
- ),
260
- );
261
-
262
- const write_dynamic_property =
263
- (project: INestiaProject) =>
264
- (importer: ImportDictionary) =>
265
- (property: MetadataProperty): ts.TypeLiteralNode =>
266
- ts.factory.createTypeLiteralNode([
267
- FilePrinter.description(
268
- ts.factory.createIndexSignature(
269
- undefined,
270
- [
271
- ts.factory.createParameterDeclaration(
272
- undefined,
273
- undefined,
274
- ts.factory.createIdentifier("key"),
275
- undefined,
276
- SdkTypeProgrammer.write(project)(importer)(property.key),
277
- ),
278
- ],
279
- SdkTypeProgrammer.write(project)(importer)(property.value),
280
- ),
281
- writeComment(property.value.atomics)(
282
- property.description,
283
- property.jsDocTags,
284
- ),
285
- ),
286
- ]);
287
-
288
- const write_alias =
289
- (project: INestiaProject) =>
290
- (importer: ImportDictionary) =>
291
- (meta: MetadataAliasType | MetadataObjectType): ts.TypeNode => {
292
- importInternalFile(project)(importer)(meta.name);
293
- return ts.factory.createTypeReferenceNode(meta.name);
294
- };
295
-
296
- const write_native = (name: string): ts.TypeNode =>
297
- ts.factory.createTypeReferenceNode(name);
298
-
299
- /* -----------------------------------------------------------
300
- MISCELLANEOUS
301
- ----------------------------------------------------------- */
302
- const write_type_tag_matrix =
303
- (importer: ImportDictionary) =>
304
- (
305
- from: "array" | "boolean" | "number" | "bigint" | "string" | "object",
306
- base: ts.TypeNode,
307
- matrix: IMetadataTypeTag[][],
308
- ): ts.TypeNode => {
309
- matrix = matrix.filter((row) => row.length !== 0);
310
- if (matrix.length === 0) return base;
311
- else if (matrix.length === 1)
312
- return ts.factory.createIntersectionTypeNode([
313
- base,
314
- ...matrix[0].map((tag) =>
315
- SdkTypeTagProgrammer.write(importer, from, tag),
316
- ),
317
- ]);
318
- return ts.factory.createIntersectionTypeNode([
319
- base,
320
- ts.factory.createUnionTypeNode(
321
- matrix.map((row) =>
322
- row.length === 1
323
- ? SdkTypeTagProgrammer.write(importer, from, row[0])
324
- : ts.factory.createIntersectionTypeNode(
325
- row.map((tag) =>
326
- SdkTypeTagProgrammer.write(importer, from, tag),
327
- ),
328
- ),
329
- ),
330
- ),
331
- ]);
332
- };
333
- }
334
-
335
- const writeNode = (text: string) => ts.factory.createTypeReferenceNode(text);
336
- const writeComment =
337
- (atomics: MetadataAtomic[]) =>
338
- (description: string | null, jsDocTags: IJsDocTagInfo[]): string => {
339
- const lines: string[] = [];
340
- if (description?.length)
341
- lines.push(...description.split("\n").map((s) => `${s}`));
342
-
343
- const filtered: IJsDocTagInfo[] =
344
- !!atomics.length && !!jsDocTags?.length
345
- ? jsDocTags.filter(
346
- (tag) =>
347
- !atomics.some((a) =>
348
- a.tags.some((r) => r.some((t) => t.kind === tag.name)),
349
- ),
350
- )
351
- : (jsDocTags ?? []);
352
-
353
- if (description?.length && filtered.length) lines.push("");
354
- if (filtered.length)
355
- lines.push(
356
- ...filtered.map((t) =>
357
- t.text?.length
358
- ? `@${t.name} ${t.text.map((e) => e.text).join("")}`
359
- : `@${t.name}`,
360
- ),
361
- );
362
- return lines.join("\n");
363
- };
364
-
365
- const importInternalFile =
366
- (project: INestiaProject) =>
367
- (importer: ImportDictionary) =>
368
- (name: string) => {
369
- const top = name.split(".")[0];
370
- if (importer.file === `${project.config.output}/structures/${top}.ts`)
371
- return;
372
- importer.internal({
373
- type: true,
374
- file: `${project.config.output}/structures/${name.split(".")[0]}`,
375
- instance: top,
376
- });
377
- };
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(write_alias(project)(importer)(object.type));
61
+ for (const alias of meta.aliases)
62
+ union.push(write_alias(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 FilePrinter.description(
79
+ 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
+ writeComment([])(object.description ?? null, object.jsDocTags),
90
+ );
91
+ };
92
+
93
+ const write_escaped =
94
+ (project: INestiaProject) =>
95
+ (importer: ImportDictionary) =>
96
+ (meta: MetadataEscaped): ts.TypeNode => {
97
+ if (
98
+ meta.original.size() === 1 &&
99
+ meta.original.natives.length === 1 &&
100
+ meta.original.natives[0].name === "Date"
101
+ )
102
+ return ts.factory.createIntersectionTypeNode([
103
+ TypeFactory.keyword("string"),
104
+ SdkTypeTagProgrammer.write(importer, "string", {
105
+ name: "Format",
106
+ value: "date-time",
107
+ } as IMetadataTypeTag),
108
+ ]);
109
+ return write(project)(importer)(meta.returns, true);
110
+ };
111
+
112
+ /* -----------------------------------------------------------
113
+ ATOMICS
114
+ ----------------------------------------------------------- */
115
+ const write_constant = (value: MetadataConstantValue) => {
116
+ if (typeof value.value === "boolean")
117
+ return ts.factory.createLiteralTypeNode(
118
+ value ? ts.factory.createTrue() : ts.factory.createFalse(),
119
+ );
120
+ else if (typeof value.value === "bigint")
121
+ return ts.factory.createLiteralTypeNode(
122
+ value.value < BigInt(0)
123
+ ? ts.factory.createPrefixUnaryExpression(
124
+ ts.SyntaxKind.MinusToken,
125
+ ts.factory.createBigIntLiteral((-value).toString()),
126
+ )
127
+ : ts.factory.createBigIntLiteral(value.toString()),
128
+ );
129
+ else if (typeof value.value === "number")
130
+ return ts.factory.createLiteralTypeNode(
131
+ ExpressionFactory.number(value.value),
132
+ );
133
+ return ts.factory.createLiteralTypeNode(
134
+ ts.factory.createStringLiteral(value.value as string),
135
+ );
136
+ };
137
+
138
+ const write_template =
139
+ (project: INestiaProject) =>
140
+ (importer: ImportDictionary) =>
141
+ (meta: Metadata[]): ts.TypeNode => {
142
+ const head: boolean = meta[0].isSoleLiteral();
143
+ const spans: [ts.TypeNode | null, string | null][] = [];
144
+ for (const elem of meta.slice(head ? 1 : 0)) {
145
+ const last =
146
+ spans.at(-1) ??
147
+ (() => {
148
+ const tuple = [null!, null!] as [ts.TypeNode | null, string | null];
149
+ spans.push(tuple);
150
+ return tuple;
151
+ })();
152
+ if (elem.isSoleLiteral())
153
+ if (last[1] === null)
154
+ last[1] = String(elem.constants[0].values[0].value);
155
+ else
156
+ spans.push([
157
+ ts.factory.createLiteralTypeNode(
158
+ ts.factory.createStringLiteral(
159
+ String(elem.constants[0].values[0].value),
160
+ ),
161
+ ),
162
+ null,
163
+ ]);
164
+ else if (last[0] === null) last[0] = write(project)(importer)(elem);
165
+ else spans.push([write(project)(importer)(elem), null]);
166
+ }
167
+ return ts.factory.createTemplateLiteralType(
168
+ ts.factory.createTemplateHead(
169
+ head ? (meta[0].constants[0].values[0].value as string) : "",
170
+ ),
171
+ spans
172
+ .filter(([node]) => node !== null)
173
+ .map(([node, str], i, array) =>
174
+ ts.factory.createTemplateLiteralTypeSpan(
175
+ node!,
176
+ (i !== array.length - 1
177
+ ? ts.factory.createTemplateMiddle
178
+ : ts.factory.createTemplateTail)(str ?? ""),
179
+ ),
180
+ ),
181
+ );
182
+ };
183
+
184
+ const write_atomic =
185
+ (importer: ImportDictionary) =>
186
+ (meta: MetadataAtomic): ts.TypeNode =>
187
+ write_type_tag_matrix(importer)(
188
+ meta.type as "boolean" | "bigint" | "number" | "string",
189
+ ts.factory.createKeywordTypeNode(
190
+ meta.type === "boolean"
191
+ ? ts.SyntaxKind.BooleanKeyword
192
+ : meta.type === "bigint"
193
+ ? ts.SyntaxKind.BigIntKeyword
194
+ : meta.type === "number"
195
+ ? ts.SyntaxKind.NumberKeyword
196
+ : ts.SyntaxKind.StringKeyword,
197
+ ),
198
+ meta.tags,
199
+ );
200
+
201
+ /* -----------------------------------------------------------
202
+ INSTANCES
203
+ ----------------------------------------------------------- */
204
+ const write_array =
205
+ (project: INestiaProject) =>
206
+ (importer: ImportDictionary) =>
207
+ (meta: MetadataArray): ts.TypeNode =>
208
+ write_type_tag_matrix(importer)(
209
+ "array",
210
+ ts.factory.createArrayTypeNode(
211
+ write(project)(importer)(meta.type.value),
212
+ ),
213
+ meta.tags,
214
+ );
215
+
216
+ const write_tuple =
217
+ (project: INestiaProject) =>
218
+ (importer: ImportDictionary) =>
219
+ (meta: MetadataTuple): ts.TypeNode =>
220
+ ts.factory.createTupleTypeNode(
221
+ meta.type.elements.map((elem) =>
222
+ elem.rest
223
+ ? ts.factory.createRestTypeNode(
224
+ ts.factory.createArrayTypeNode(
225
+ write(project)(importer)(elem.rest),
226
+ ),
227
+ )
228
+ : elem.optional
229
+ ? ts.factory.createOptionalTypeNode(
230
+ write(project)(importer)(elem),
231
+ )
232
+ : write(project)(importer)(elem),
233
+ ),
234
+ );
235
+
236
+ const write_regular_property =
237
+ (project: INestiaProject) =>
238
+ (importer: ImportDictionary) =>
239
+ (properties: MetadataProperty[]): ts.TypeLiteralNode =>
240
+ ts.factory.createTypeLiteralNode(
241
+ properties.map((p) =>
242
+ FilePrinter.description(
243
+ ts.factory.createPropertySignature(
244
+ undefined,
245
+ Escaper.variable(String(p.key.constants[0].values[0].value))
246
+ ? ts.factory.createIdentifier(
247
+ String(p.key.constants[0].values[0].value),
248
+ )
249
+ : ts.factory.createStringLiteral(
250
+ String(p.key.constants[0].values[0].value),
251
+ ),
252
+ p.value.isRequired() === false
253
+ ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
254
+ : undefined,
255
+ SdkTypeProgrammer.write(project)(importer)(p.value),
256
+ ),
257
+ writeComment(p.value.atomics)(p.description, p.jsDocTags),
258
+ ),
259
+ ),
260
+ );
261
+
262
+ const write_dynamic_property =
263
+ (project: INestiaProject) =>
264
+ (importer: ImportDictionary) =>
265
+ (property: MetadataProperty): ts.TypeLiteralNode =>
266
+ ts.factory.createTypeLiteralNode([
267
+ FilePrinter.description(
268
+ ts.factory.createIndexSignature(
269
+ undefined,
270
+ [
271
+ ts.factory.createParameterDeclaration(
272
+ undefined,
273
+ undefined,
274
+ ts.factory.createIdentifier("key"),
275
+ undefined,
276
+ SdkTypeProgrammer.write(project)(importer)(property.key),
277
+ ),
278
+ ],
279
+ SdkTypeProgrammer.write(project)(importer)(property.value),
280
+ ),
281
+ writeComment(property.value.atomics)(
282
+ property.description,
283
+ property.jsDocTags,
284
+ ),
285
+ ),
286
+ ]);
287
+
288
+ const write_alias =
289
+ (project: INestiaProject) =>
290
+ (importer: ImportDictionary) =>
291
+ (meta: MetadataAliasType | MetadataObjectType): ts.TypeNode => {
292
+ importInternalFile(project)(importer)(meta.name);
293
+ return ts.factory.createTypeReferenceNode(meta.name);
294
+ };
295
+
296
+ const write_native = (name: string): ts.TypeNode =>
297
+ ts.factory.createTypeReferenceNode(name);
298
+
299
+ /* -----------------------------------------------------------
300
+ MISCELLANEOUS
301
+ ----------------------------------------------------------- */
302
+ const write_type_tag_matrix =
303
+ (importer: ImportDictionary) =>
304
+ (
305
+ from: "array" | "boolean" | "number" | "bigint" | "string" | "object",
306
+ base: ts.TypeNode,
307
+ matrix: IMetadataTypeTag[][],
308
+ ): ts.TypeNode => {
309
+ matrix = matrix.filter((row) => row.length !== 0);
310
+ if (matrix.length === 0) return base;
311
+ else if (matrix.length === 1)
312
+ return ts.factory.createIntersectionTypeNode([
313
+ base,
314
+ ...matrix[0].map((tag) =>
315
+ SdkTypeTagProgrammer.write(importer, from, tag),
316
+ ),
317
+ ]);
318
+ return ts.factory.createIntersectionTypeNode([
319
+ base,
320
+ ts.factory.createUnionTypeNode(
321
+ matrix.map((row) =>
322
+ row.length === 1
323
+ ? SdkTypeTagProgrammer.write(importer, from, row[0])
324
+ : ts.factory.createIntersectionTypeNode(
325
+ row.map((tag) =>
326
+ SdkTypeTagProgrammer.write(importer, from, tag),
327
+ ),
328
+ ),
329
+ ),
330
+ ),
331
+ ]);
332
+ };
333
+ }
334
+
335
+ const writeNode = (text: string) => ts.factory.createTypeReferenceNode(text);
336
+ const writeComment =
337
+ (atomics: MetadataAtomic[]) =>
338
+ (description: string | null, jsDocTags: IJsDocTagInfo[]): string => {
339
+ const lines: string[] = [];
340
+ if (description?.length)
341
+ lines.push(...description.split("\n").map((s) => `${s}`));
342
+
343
+ const filtered: IJsDocTagInfo[] =
344
+ !!atomics.length && !!jsDocTags?.length
345
+ ? jsDocTags.filter(
346
+ (tag) =>
347
+ !atomics.some((a) =>
348
+ a.tags.some((r) => r.some((t) => t.kind === tag.name)),
349
+ ),
350
+ )
351
+ : (jsDocTags ?? []);
352
+
353
+ if (description?.length && filtered.length) lines.push("");
354
+ if (filtered.length)
355
+ lines.push(
356
+ ...filtered.map((t) =>
357
+ t.text?.length
358
+ ? `@${t.name} ${t.text.map((e) => e.text).join("")}`
359
+ : `@${t.name}`,
360
+ ),
361
+ );
362
+ return lines.join("\n");
363
+ };
364
+
365
+ const importInternalFile =
366
+ (project: INestiaProject) =>
367
+ (importer: ImportDictionary) =>
368
+ (name: string) => {
369
+ const top = name.split(".")[0];
370
+ if (importer.file === `${project.config.output}/structures/${top}.ts`)
371
+ return;
372
+ importer.internal({
373
+ type: true,
374
+ file: `${project.config.output}/structures/${name.split(".")[0]}`,
375
+ instance: top,
376
+ });
377
+ };