@nestia/sdk 11.0.0-dev.20260316 → 11.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) 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/executable/internal/NestiaConfigLoader.js +5 -5
  15. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  16. package/package.json +8 -8
  17. package/src/INestiaConfig.ts +267 -267
  18. package/src/NestiaSdkApplication.ts +307 -307
  19. package/src/NestiaSwaggerComposer.ts +143 -143
  20. package/src/analyses/AccessorAnalyzer.ts +67 -67
  21. package/src/analyses/DtoAnalyzer.ts +260 -260
  22. package/src/analyses/ImportAnalyzer.ts +126 -126
  23. package/src/analyses/ReflectHttpOperationAnalyzer.ts +183 -183
  24. package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +72 -72
  25. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +350 -350
  26. package/src/analyses/ReflectHttpOperationResponseAnalyzer.ts +126 -126
  27. package/src/analyses/TypedHttpRouteAnalyzer.ts +208 -208
  28. package/src/executable/internal/NestiaConfigLoader.ts +85 -85
  29. package/src/executable/internal/NestiaSdkCommand.ts +107 -107
  30. package/src/generates/SwaggerGenerator.ts +291 -291
  31. package/src/generates/internal/E2eFileProgrammer.ts +196 -196
  32. package/src/generates/internal/FilePrinter.ts +64 -64
  33. package/src/generates/internal/ImportDictionary.ts +192 -192
  34. package/src/generates/internal/SdkAliasCollection.ts +260 -260
  35. package/src/generates/internal/SdkFileProgrammer.ts +110 -110
  36. package/src/generates/internal/SdkHttpCloneProgrammer.ts +126 -126
  37. package/src/generates/internal/SdkHttpCloneReferencer.ts +77 -77
  38. package/src/generates/internal/SdkHttpFunctionProgrammer.ts +278 -278
  39. package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +502 -502
  40. package/src/generates/internal/SdkHttpRouteProgrammer.ts +109 -109
  41. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +312 -312
  42. package/src/generates/internal/SdkImportWizard.ts +62 -62
  43. package/src/generates/internal/SdkTypeProgrammer.ts +388 -388
  44. package/src/generates/internal/SdkTypeTagProgrammer.ts +114 -114
  45. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +379 -379
  46. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +302 -302
  47. package/src/generates/internal/SwaggerOperationComposer.ts +119 -119
  48. package/src/generates/internal/SwaggerOperationParameterComposer.ts +161 -161
  49. package/src/generates/internal/SwaggerOperationResponseComposer.ts +110 -110
  50. package/src/module.ts +4 -4
  51. package/src/structures/IReflectHttpOperationException.ts +18 -18
  52. package/src/structures/IReflectHttpOperationParameter.ts +79 -79
  53. package/src/structures/IReflectHttpOperationSuccess.ts +21 -21
  54. package/src/structures/ITypedApplication.ts +11 -11
  55. package/src/structures/ITypedHttpRouteException.ts +15 -15
  56. package/src/structures/ITypedHttpRouteParameter.ts +41 -41
  57. package/src/structures/ITypedHttpRouteSuccess.ts +22 -22
  58. package/src/transformers/IOperationMetadata.ts +46 -46
  59. package/src/transformers/ISdkOperationTransformerContext.ts +8 -8
  60. package/src/transformers/SdkOperationProgrammer.ts +240 -240
  61. package/src/transformers/SdkOperationTransformer.ts +248 -248
  62. package/src/transformers/TextPlainValidator.ts +17 -17
  63. package/src/utils/MetadataUtil.ts +26 -26
  64. package/src/validators/HttpHeadersValidator.ts +40 -40
  65. package/src/validators/HttpQueryValidator.ts +40 -40
@@ -1,388 +1,388 @@
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
- };
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
+ };