@nestia/sdk 2.6.2 → 2.6.3

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