@nestia/migrate 4.6.1-dev.20250117 → 4.6.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 (57) hide show
  1. package/README.md +92 -87
  2. package/lib/MigrateApplication.js +3 -3
  3. package/lib/bundles/NEST_TEMPLATE.js +84 -64
  4. package/lib/bundles/NEST_TEMPLATE.js.map +1 -1
  5. package/lib/bundles/SDK_TEMPLATE.js +30 -30
  6. package/lib/bundles/SDK_TEMPLATE.js.map +1 -1
  7. package/lib/index.mjs +118 -102
  8. package/lib/index.mjs.map +1 -1
  9. package/lib/programmers/MigrateApiNamespaceProgrammer.js +6 -6
  10. package/lib/programmers/MigrateApiNamespaceProgrammer.js.map +1 -1
  11. package/lib/programmers/{MigrateApiSimulatationProgrammer.d.ts → MigrateApiSimulationProgrammer.d.ts} +1 -1
  12. package/lib/programmers/{MigrateApiSimulatationProgrammer.js → MigrateApiSimulationProgrammer.js} +7 -7
  13. package/lib/programmers/MigrateApiSimulationProgrammer.js.map +1 -0
  14. package/lib/utils/openapi-down-convert/converter.js +2 -2
  15. package/package.json +6 -6
  16. package/src/MigrateApplication.ts +107 -107
  17. package/src/analyzers/MigrateApplicationAnalyzer.ts +18 -18
  18. package/src/analyzers/MigrateControllerAnalyzer.ts +51 -51
  19. package/src/archivers/MigrateFileArchiver.ts +38 -38
  20. package/src/bundles/NEST_TEMPLATE.ts +84 -64
  21. package/src/bundles/SDK_TEMPLATE.ts +30 -30
  22. package/src/executable/bundle.js +125 -125
  23. package/src/executable/migrate.ts +7 -7
  24. package/src/factories/TypeLiteralFactory.ts +57 -57
  25. package/src/index.ts +4 -4
  26. package/src/internal/MigrateCommander.ts +86 -86
  27. package/src/internal/MigrateInquirer.ts +89 -89
  28. package/src/module.ts +8 -8
  29. package/src/programmers/MigrateApiFileProgrammer.ts +49 -49
  30. package/src/programmers/MigrateApiFunctionProgrammer.ts +210 -210
  31. package/src/programmers/MigrateApiNamespaceProgrammer.ts +417 -417
  32. package/src/programmers/MigrateApiProgrammer.ts +103 -103
  33. package/src/programmers/{MigrateApiSimulatationProgrammer.ts → MigrateApiSimulationProgrammer.ts} +324 -324
  34. package/src/programmers/MigrateApiStartProgrammer.ts +194 -194
  35. package/src/programmers/MigrateDtoProgrammer.ts +87 -87
  36. package/src/programmers/MigrateE2eFileProgrammer.ts +117 -117
  37. package/src/programmers/MigrateE2eProgrammer.ts +34 -34
  38. package/src/programmers/MigrateImportProgrammer.ts +118 -118
  39. package/src/programmers/MigrateNestControllerProgrammer.ts +50 -50
  40. package/src/programmers/MigrateNestMethodProgrammer.ts +393 -393
  41. package/src/programmers/MigrateNestModuleProgrammer.ts +65 -65
  42. package/src/programmers/MigrateNestProgrammer.ts +81 -81
  43. package/src/programmers/MigrateSchemaProgrammer.ts +373 -373
  44. package/src/structures/IHttpMigrateController.ts +8 -8
  45. package/src/structures/IHttpMigrateDto.ts +8 -8
  46. package/src/structures/IHttpMigrateFile.ts +5 -5
  47. package/src/structures/IHttpMigrateProgram.ts +27 -27
  48. package/src/structures/IHttpMigrateRoute.ts +1 -1
  49. package/src/structures/IHttpMigrateSchema.ts +4 -4
  50. package/src/utils/FilePrinter.ts +36 -36
  51. package/src/utils/MapUtil.ts +13 -13
  52. package/src/utils/OpenApiTypeChecker.ts +73 -73
  53. package/src/utils/SetupWizard.ts +12 -12
  54. package/src/utils/StringUtil.ts +113 -113
  55. package/src/utils/openapi-down-convert/RefVisitor.ts +139 -139
  56. package/src/utils/openapi-down-convert/converter.ts +527 -527
  57. package/lib/programmers/MigrateApiSimulatationProgrammer.js.map +0 -1
@@ -1,373 +1,373 @@
1
- import { OpenApi } from "@samchon/openapi";
2
- import ts from "typescript";
3
- import typia from "typia";
4
- import { TypeFactory } from "typia/lib/factories/TypeFactory";
5
- import { FormatCheatSheet } from "typia/lib/tags/internal/FormatCheatSheet";
6
- import { Escaper } from "typia/lib/utils/Escaper";
7
-
8
- import { FilePrinter } from "../utils/FilePrinter";
9
- import { OpenApiTypeChecker } from "../utils/OpenApiTypeChecker";
10
- import { StringUtil } from "../utils/StringUtil";
11
- import { MigrateImportProgrammer } from "./MigrateImportProgrammer";
12
-
13
- export namespace MigrateSchemaProgrammer {
14
- /* -----------------------------------------------------------
15
- FACADE
16
- ----------------------------------------------------------- */
17
- export const write =
18
- (components: OpenApi.IComponents) =>
19
- (importer: MigrateImportProgrammer) =>
20
- (schema: OpenApi.IJsonSchema): ts.TypeNode => {
21
- // CONSIDER ANY TYPE CASE
22
- const union: ts.TypeNode[] = [];
23
- if (OpenApiTypeChecker.isUnknown(schema))
24
- return TypeFactory.keyword("any");
25
-
26
- // ITERATION
27
- const type: ts.TypeNode = (() => {
28
- // ATOMIC
29
- if (OpenApiTypeChecker.isConstant(schema))
30
- return writeConstant(importer)(schema);
31
- else if (OpenApiTypeChecker.isBoolean(schema))
32
- return writeBoolean(importer)(schema);
33
- else if (OpenApiTypeChecker.isInteger(schema))
34
- return writeInteger(importer)(schema);
35
- else if (OpenApiTypeChecker.isNumber(schema))
36
- return writeNumber(importer)(schema);
37
- else if (OpenApiTypeChecker.isString(schema))
38
- return writeString(importer)(schema);
39
- // INSTANCES
40
- else if (OpenApiTypeChecker.isArray(schema))
41
- return writeArray(components)(importer)(schema);
42
- else if (OpenApiTypeChecker.isTuple(schema))
43
- return writeTuple(components)(importer)(schema);
44
- else if (OpenApiTypeChecker.isObject(schema))
45
- return writeObject(components)(importer)(schema);
46
- else if (OpenApiTypeChecker.isReference(schema))
47
- return writeReference(importer)(schema);
48
- // UNION
49
- else if (OpenApiTypeChecker.isOneOf(schema))
50
- return writeUnion(components)(importer)(schema.oneOf);
51
- else if (OpenApiTypeChecker.isNull(schema)) return createNode("null");
52
- else return TypeFactory.keyword("any");
53
- })();
54
- union.push(type);
55
-
56
- // DETERMINE
57
- if (union.length === 0) return TypeFactory.keyword("any");
58
- else if (union.length === 1) return union[0];
59
- return ts.factory.createUnionTypeNode(union);
60
- };
61
-
62
- /* -----------------------------------------------------------
63
- ATOMICS
64
- ----------------------------------------------------------- */
65
- const writeConstant =
66
- (importer: MigrateImportProgrammer) =>
67
- (schema: OpenApi.IJsonSchema.IConstant): ts.TypeNode => {
68
- const intersection: ts.TypeNode[] = [
69
- ts.factory.createLiteralTypeNode(
70
- typeof schema.const === "boolean"
71
- ? schema.const === true
72
- ? ts.factory.createTrue()
73
- : ts.factory.createFalse()
74
- : typeof schema.const === "number"
75
- ? schema.const < 0
76
- ? ts.factory.createPrefixUnaryExpression(
77
- ts.SyntaxKind.MinusToken,
78
- ts.factory.createNumericLiteral(-schema.const),
79
- )
80
- : ts.factory.createNumericLiteral(schema.const)
81
- : ts.factory.createStringLiteral(schema.const),
82
- ),
83
- ];
84
- writePlugin({
85
- importer,
86
- regular: typia.misc.literals<keyof OpenApi.IJsonSchema.IConstant>(),
87
- intersection,
88
- })(schema);
89
- return intersection.length === 1
90
- ? intersection[0]
91
- : ts.factory.createIntersectionTypeNode(intersection);
92
- };
93
-
94
- const writeBoolean =
95
- (importer: MigrateImportProgrammer) =>
96
- (schema: OpenApi.IJsonSchema.IBoolean): ts.TypeNode => {
97
- const intersection: ts.TypeNode[] = [TypeFactory.keyword("boolean")];
98
- writePlugin({
99
- importer,
100
- regular: typia.misc.literals<keyof OpenApi.IJsonSchema.IBoolean>(),
101
- intersection,
102
- })(schema);
103
- return intersection.length === 1
104
- ? intersection[0]
105
- : ts.factory.createIntersectionTypeNode(intersection);
106
- };
107
-
108
- const writeInteger =
109
- (importer: MigrateImportProgrammer) =>
110
- (schema: OpenApi.IJsonSchema.IInteger): ts.TypeNode =>
111
- writeNumeric(() => [
112
- TypeFactory.keyword("number"),
113
- importer.tag("Type", "int32"),
114
- ])(importer)(schema);
115
-
116
- const writeNumber =
117
- (importer: MigrateImportProgrammer) =>
118
- (schema: OpenApi.IJsonSchema.INumber): ts.TypeNode =>
119
- writeNumeric(() => [TypeFactory.keyword("number")])(importer)(schema);
120
-
121
- const writeNumeric =
122
- (factory: () => ts.TypeNode[]) =>
123
- (importer: MigrateImportProgrammer) =>
124
- (
125
- schema: OpenApi.IJsonSchema.IInteger | OpenApi.IJsonSchema.INumber,
126
- ): ts.TypeNode => {
127
- const intersection: ts.TypeNode[] = factory();
128
- if (schema.default !== undefined)
129
- intersection.push(importer.tag("Default", schema.default));
130
- if (schema.minimum !== undefined)
131
- intersection.push(
132
- importer.tag(
133
- schema.exclusiveMinimum ? "ExclusiveMinimum" : "Minimum",
134
- schema.minimum,
135
- ),
136
- );
137
- if (schema.maximum !== undefined)
138
- intersection.push(
139
- importer.tag(
140
- schema.exclusiveMaximum ? "ExclusiveMaximum" : "Maximum",
141
- schema.maximum,
142
- ),
143
- );
144
- if (schema.multipleOf !== undefined)
145
- intersection.push(importer.tag("MultipleOf", schema.multipleOf));
146
- writePlugin({
147
- importer,
148
- regular: typia.misc.literals<keyof OpenApi.IJsonSchema.INumber>(),
149
- intersection,
150
- })(schema);
151
- return intersection.length === 1
152
- ? intersection[0]
153
- : ts.factory.createIntersectionTypeNode(intersection);
154
- };
155
-
156
- const writeString =
157
- (importer: MigrateImportProgrammer) =>
158
- (schema: OpenApi.IJsonSchema.IString): ts.TypeNode => {
159
- if (schema.format === "binary")
160
- return ts.factory.createTypeReferenceNode("File");
161
-
162
- const intersection: ts.TypeNode[] = [TypeFactory.keyword("string")];
163
- if (schema.default !== undefined)
164
- intersection.push(importer.tag("Default", schema.default));
165
- if (schema.minLength !== undefined)
166
- intersection.push(importer.tag("MinLength", schema.minLength));
167
- if (schema.maxLength !== undefined)
168
- intersection.push(importer.tag("MaxLength", schema.maxLength));
169
- if (schema.pattern !== undefined)
170
- intersection.push(importer.tag("Pattern", schema.pattern));
171
- if (
172
- schema.format !== undefined &&
173
- (FormatCheatSheet as Record<string, string>)[schema.format] !==
174
- undefined
175
- )
176
- intersection.push(importer.tag("Format", schema.format));
177
- if (schema.contentMediaType !== undefined)
178
- intersection.push(
179
- importer.tag("ContentMediaType", schema.contentMediaType),
180
- );
181
- writePlugin({
182
- importer,
183
- regular: typia.misc.literals<keyof OpenApi.IJsonSchema.IString>(),
184
- intersection,
185
- })(schema);
186
- return intersection.length === 1
187
- ? intersection[0]
188
- : ts.factory.createIntersectionTypeNode(intersection);
189
- };
190
-
191
- /* -----------------------------------------------------------
192
- INSTANCES
193
- ----------------------------------------------------------- */
194
- const writeArray =
195
- (components: OpenApi.IComponents) =>
196
- (importer: MigrateImportProgrammer) =>
197
- (schema: OpenApi.IJsonSchema.IArray): ts.TypeNode => {
198
- const intersection: ts.TypeNode[] = [
199
- ts.factory.createArrayTypeNode(
200
- write(components)(importer)(schema.items),
201
- ),
202
- ];
203
- if (schema.minItems !== undefined)
204
- intersection.push(importer.tag("MinItems", schema.minItems));
205
- if (schema.maxItems !== undefined)
206
- intersection.push(importer.tag("MaxItems", schema.maxItems));
207
- if (schema.uniqueItems === true)
208
- intersection.push(importer.tag("UniqueItems"));
209
- writePlugin({
210
- importer,
211
- regular: typia.misc.literals<keyof OpenApi.IJsonSchema.IArray>(),
212
- intersection,
213
- })(schema);
214
- return intersection.length === 1
215
- ? intersection[0]
216
- : ts.factory.createIntersectionTypeNode(intersection);
217
- };
218
-
219
- const writeTuple =
220
- (components: OpenApi.IComponents) =>
221
- (importer: MigrateImportProgrammer) =>
222
- (schema: OpenApi.IJsonSchema.ITuple): ts.TypeNode => {
223
- const tuple: ts.TypeNode = ts.factory.createTupleTypeNode([
224
- ...schema.prefixItems.map(write(components)(importer)),
225
- ...(typeof schema.additionalItems === "object" &&
226
- schema.additionalItems !== null
227
- ? [
228
- ts.factory.createRestTypeNode(
229
- write(components)(importer)(schema.additionalItems),
230
- ),
231
- ]
232
- : schema.additionalItems === true
233
- ? [
234
- ts.factory.createRestTypeNode(
235
- ts.factory.createArrayTypeNode(
236
- ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
237
- ),
238
- ),
239
- ]
240
- : []),
241
- ]);
242
- const intersection: ts.TypeNode[] = [tuple];
243
- writePlugin({
244
- importer,
245
- regular: typia.misc.literals<keyof OpenApi.IJsonSchema.ITuple>(),
246
- intersection,
247
- })(schema);
248
- return intersection.length === 1
249
- ? intersection[0]
250
- : ts.factory.createIntersectionTypeNode(intersection);
251
- };
252
-
253
- const writeObject =
254
- (components: OpenApi.IComponents) =>
255
- (importer: MigrateImportProgrammer) =>
256
- (schema: OpenApi.IJsonSchema.IObject): ts.TypeNode => {
257
- const regular = () =>
258
- ts.factory.createTypeLiteralNode(
259
- Object.entries(schema.properties ?? []).map(([key, value]) =>
260
- writeRegularProperty(components)(importer)(schema.required ?? [])(
261
- key,
262
- value,
263
- ),
264
- ),
265
- );
266
- const dynamic = () =>
267
- ts.factory.createTypeLiteralNode([
268
- writeDynamicProperty(components)(importer)(
269
- schema.additionalProperties as OpenApi.IJsonSchema,
270
- ),
271
- ]);
272
- return !!schema.properties?.length &&
273
- typeof schema.additionalProperties === "object"
274
- ? ts.factory.createIntersectionTypeNode([regular(), dynamic()])
275
- : typeof schema.additionalProperties === "object"
276
- ? dynamic()
277
- : regular();
278
- };
279
-
280
- const writeRegularProperty =
281
- (components: OpenApi.IComponents) =>
282
- (importer: MigrateImportProgrammer) =>
283
- (required: string[]) =>
284
- (key: string, value: OpenApi.IJsonSchema) =>
285
- FilePrinter.description(
286
- ts.factory.createPropertySignature(
287
- undefined,
288
- Escaper.variable(key)
289
- ? ts.factory.createIdentifier(key)
290
- : ts.factory.createStringLiteral(key),
291
- required.includes(key)
292
- ? undefined
293
- : ts.factory.createToken(ts.SyntaxKind.QuestionToken),
294
- write(components)(importer)(value),
295
- ),
296
- writeComment(value),
297
- );
298
-
299
- const writeDynamicProperty =
300
- (components: OpenApi.IComponents) =>
301
- (importer: MigrateImportProgrammer) =>
302
- (value: OpenApi.IJsonSchema) =>
303
- FilePrinter.description(
304
- ts.factory.createIndexSignature(
305
- undefined,
306
- [
307
- ts.factory.createParameterDeclaration(
308
- undefined,
309
- undefined,
310
- ts.factory.createIdentifier("key"),
311
- undefined,
312
- TypeFactory.keyword("string"),
313
- ),
314
- ],
315
- write(components)(importer)(value),
316
- ),
317
- writeComment(value),
318
- );
319
-
320
- const writeReference =
321
- (importer: MigrateImportProgrammer) =>
322
- (
323
- schema: OpenApi.IJsonSchema.IReference,
324
- ): ts.TypeReferenceNode | ts.KeywordTypeNode => {
325
- if (schema.$ref.startsWith("#/components/schemas") === false)
326
- return TypeFactory.keyword("any");
327
- const name: string = schema.$ref
328
- .split("/")
329
- .slice(3)
330
- .filter((str) => str.length !== 0)
331
- .map(StringUtil.escapeNonVariable)
332
- .join("");
333
- if (name === "") return TypeFactory.keyword("any");
334
- return importer.dto(name);
335
- };
336
-
337
- /* -----------------------------------------------------------
338
- UNIONS
339
- ----------------------------------------------------------- */
340
- const writeUnion =
341
- (components: OpenApi.IComponents) =>
342
- (importer: MigrateImportProgrammer) =>
343
- (elements: OpenApi.IJsonSchema[]): ts.UnionTypeNode =>
344
- ts.factory.createUnionTypeNode(elements.map(write(components)(importer)));
345
- }
346
- const createNode = (text: string) => ts.factory.createTypeReferenceNode(text);
347
- const writeComment = (schema: OpenApi.IJsonSchema): string =>
348
- [
349
- ...(schema.description?.length ? [schema.description] : []),
350
- ...(schema.description?.length &&
351
- (schema.title !== undefined || schema.deprecated === true)
352
- ? [""]
353
- : []),
354
- ...(schema.title !== undefined ? [`@title ${schema.title}`] : []),
355
- ...(schema.deprecated === true ? [`@deprecated`] : []),
356
- ]
357
- .join("\n")
358
- .split("*/")
359
- .join("*\\/");
360
- const writePlugin =
361
- (props: {
362
- importer: MigrateImportProgrammer;
363
- regular: string[];
364
- intersection: ts.TypeNode[];
365
- }) =>
366
- (schema: any) => {
367
- const extra: any = {};
368
- for (const [key, value] of Object.entries(schema))
369
- if (value !== undefined && false === props.regular.includes(key))
370
- extra[key] = value;
371
- if (Object.keys(extra).length !== 0)
372
- props.intersection.push(props.importer.tag("JsonSchemaPlugin", extra));
373
- };
1
+ import { OpenApi } from "@samchon/openapi";
2
+ import ts from "typescript";
3
+ import typia from "typia";
4
+ import { TypeFactory } from "typia/lib/factories/TypeFactory";
5
+ import { FormatCheatSheet } from "typia/lib/tags/internal/FormatCheatSheet";
6
+ import { Escaper } from "typia/lib/utils/Escaper";
7
+
8
+ import { FilePrinter } from "../utils/FilePrinter";
9
+ import { OpenApiTypeChecker } from "../utils/OpenApiTypeChecker";
10
+ import { StringUtil } from "../utils/StringUtil";
11
+ import { MigrateImportProgrammer } from "./MigrateImportProgrammer";
12
+
13
+ export namespace MigrateSchemaProgrammer {
14
+ /* -----------------------------------------------------------
15
+ FACADE
16
+ ----------------------------------------------------------- */
17
+ export const write =
18
+ (components: OpenApi.IComponents) =>
19
+ (importer: MigrateImportProgrammer) =>
20
+ (schema: OpenApi.IJsonSchema): ts.TypeNode => {
21
+ // CONSIDER ANY TYPE CASE
22
+ const union: ts.TypeNode[] = [];
23
+ if (OpenApiTypeChecker.isUnknown(schema))
24
+ return TypeFactory.keyword("any");
25
+
26
+ // ITERATION
27
+ const type: ts.TypeNode = (() => {
28
+ // ATOMIC
29
+ if (OpenApiTypeChecker.isConstant(schema))
30
+ return writeConstant(importer)(schema);
31
+ else if (OpenApiTypeChecker.isBoolean(schema))
32
+ return writeBoolean(importer)(schema);
33
+ else if (OpenApiTypeChecker.isInteger(schema))
34
+ return writeInteger(importer)(schema);
35
+ else if (OpenApiTypeChecker.isNumber(schema))
36
+ return writeNumber(importer)(schema);
37
+ else if (OpenApiTypeChecker.isString(schema))
38
+ return writeString(importer)(schema);
39
+ // INSTANCES
40
+ else if (OpenApiTypeChecker.isArray(schema))
41
+ return writeArray(components)(importer)(schema);
42
+ else if (OpenApiTypeChecker.isTuple(schema))
43
+ return writeTuple(components)(importer)(schema);
44
+ else if (OpenApiTypeChecker.isObject(schema))
45
+ return writeObject(components)(importer)(schema);
46
+ else if (OpenApiTypeChecker.isReference(schema))
47
+ return writeReference(importer)(schema);
48
+ // UNION
49
+ else if (OpenApiTypeChecker.isOneOf(schema))
50
+ return writeUnion(components)(importer)(schema.oneOf);
51
+ else if (OpenApiTypeChecker.isNull(schema)) return createNode("null");
52
+ else return TypeFactory.keyword("any");
53
+ })();
54
+ union.push(type);
55
+
56
+ // DETERMINE
57
+ if (union.length === 0) return TypeFactory.keyword("any");
58
+ else if (union.length === 1) return union[0];
59
+ return ts.factory.createUnionTypeNode(union);
60
+ };
61
+
62
+ /* -----------------------------------------------------------
63
+ ATOMICS
64
+ ----------------------------------------------------------- */
65
+ const writeConstant =
66
+ (importer: MigrateImportProgrammer) =>
67
+ (schema: OpenApi.IJsonSchema.IConstant): ts.TypeNode => {
68
+ const intersection: ts.TypeNode[] = [
69
+ ts.factory.createLiteralTypeNode(
70
+ typeof schema.const === "boolean"
71
+ ? schema.const === true
72
+ ? ts.factory.createTrue()
73
+ : ts.factory.createFalse()
74
+ : typeof schema.const === "number"
75
+ ? schema.const < 0
76
+ ? ts.factory.createPrefixUnaryExpression(
77
+ ts.SyntaxKind.MinusToken,
78
+ ts.factory.createNumericLiteral(-schema.const),
79
+ )
80
+ : ts.factory.createNumericLiteral(schema.const)
81
+ : ts.factory.createStringLiteral(schema.const),
82
+ ),
83
+ ];
84
+ writePlugin({
85
+ importer,
86
+ regular: typia.misc.literals<keyof OpenApi.IJsonSchema.IConstant>(),
87
+ intersection,
88
+ })(schema);
89
+ return intersection.length === 1
90
+ ? intersection[0]
91
+ : ts.factory.createIntersectionTypeNode(intersection);
92
+ };
93
+
94
+ const writeBoolean =
95
+ (importer: MigrateImportProgrammer) =>
96
+ (schema: OpenApi.IJsonSchema.IBoolean): ts.TypeNode => {
97
+ const intersection: ts.TypeNode[] = [TypeFactory.keyword("boolean")];
98
+ writePlugin({
99
+ importer,
100
+ regular: typia.misc.literals<keyof OpenApi.IJsonSchema.IBoolean>(),
101
+ intersection,
102
+ })(schema);
103
+ return intersection.length === 1
104
+ ? intersection[0]
105
+ : ts.factory.createIntersectionTypeNode(intersection);
106
+ };
107
+
108
+ const writeInteger =
109
+ (importer: MigrateImportProgrammer) =>
110
+ (schema: OpenApi.IJsonSchema.IInteger): ts.TypeNode =>
111
+ writeNumeric(() => [
112
+ TypeFactory.keyword("number"),
113
+ importer.tag("Type", "int32"),
114
+ ])(importer)(schema);
115
+
116
+ const writeNumber =
117
+ (importer: MigrateImportProgrammer) =>
118
+ (schema: OpenApi.IJsonSchema.INumber): ts.TypeNode =>
119
+ writeNumeric(() => [TypeFactory.keyword("number")])(importer)(schema);
120
+
121
+ const writeNumeric =
122
+ (factory: () => ts.TypeNode[]) =>
123
+ (importer: MigrateImportProgrammer) =>
124
+ (
125
+ schema: OpenApi.IJsonSchema.IInteger | OpenApi.IJsonSchema.INumber,
126
+ ): ts.TypeNode => {
127
+ const intersection: ts.TypeNode[] = factory();
128
+ if (schema.default !== undefined)
129
+ intersection.push(importer.tag("Default", schema.default));
130
+ if (schema.minimum !== undefined)
131
+ intersection.push(
132
+ importer.tag(
133
+ schema.exclusiveMinimum ? "ExclusiveMinimum" : "Minimum",
134
+ schema.minimum,
135
+ ),
136
+ );
137
+ if (schema.maximum !== undefined)
138
+ intersection.push(
139
+ importer.tag(
140
+ schema.exclusiveMaximum ? "ExclusiveMaximum" : "Maximum",
141
+ schema.maximum,
142
+ ),
143
+ );
144
+ if (schema.multipleOf !== undefined)
145
+ intersection.push(importer.tag("MultipleOf", schema.multipleOf));
146
+ writePlugin({
147
+ importer,
148
+ regular: typia.misc.literals<keyof OpenApi.IJsonSchema.INumber>(),
149
+ intersection,
150
+ })(schema);
151
+ return intersection.length === 1
152
+ ? intersection[0]
153
+ : ts.factory.createIntersectionTypeNode(intersection);
154
+ };
155
+
156
+ const writeString =
157
+ (importer: MigrateImportProgrammer) =>
158
+ (schema: OpenApi.IJsonSchema.IString): ts.TypeNode => {
159
+ if (schema.format === "binary")
160
+ return ts.factory.createTypeReferenceNode("File");
161
+
162
+ const intersection: ts.TypeNode[] = [TypeFactory.keyword("string")];
163
+ if (schema.default !== undefined)
164
+ intersection.push(importer.tag("Default", schema.default));
165
+ if (schema.minLength !== undefined)
166
+ intersection.push(importer.tag("MinLength", schema.minLength));
167
+ if (schema.maxLength !== undefined)
168
+ intersection.push(importer.tag("MaxLength", schema.maxLength));
169
+ if (schema.pattern !== undefined)
170
+ intersection.push(importer.tag("Pattern", schema.pattern));
171
+ if (
172
+ schema.format !== undefined &&
173
+ (FormatCheatSheet as Record<string, string>)[schema.format] !==
174
+ undefined
175
+ )
176
+ intersection.push(importer.tag("Format", schema.format));
177
+ if (schema.contentMediaType !== undefined)
178
+ intersection.push(
179
+ importer.tag("ContentMediaType", schema.contentMediaType),
180
+ );
181
+ writePlugin({
182
+ importer,
183
+ regular: typia.misc.literals<keyof OpenApi.IJsonSchema.IString>(),
184
+ intersection,
185
+ })(schema);
186
+ return intersection.length === 1
187
+ ? intersection[0]
188
+ : ts.factory.createIntersectionTypeNode(intersection);
189
+ };
190
+
191
+ /* -----------------------------------------------------------
192
+ INSTANCES
193
+ ----------------------------------------------------------- */
194
+ const writeArray =
195
+ (components: OpenApi.IComponents) =>
196
+ (importer: MigrateImportProgrammer) =>
197
+ (schema: OpenApi.IJsonSchema.IArray): ts.TypeNode => {
198
+ const intersection: ts.TypeNode[] = [
199
+ ts.factory.createArrayTypeNode(
200
+ write(components)(importer)(schema.items),
201
+ ),
202
+ ];
203
+ if (schema.minItems !== undefined)
204
+ intersection.push(importer.tag("MinItems", schema.minItems));
205
+ if (schema.maxItems !== undefined)
206
+ intersection.push(importer.tag("MaxItems", schema.maxItems));
207
+ if (schema.uniqueItems === true)
208
+ intersection.push(importer.tag("UniqueItems"));
209
+ writePlugin({
210
+ importer,
211
+ regular: typia.misc.literals<keyof OpenApi.IJsonSchema.IArray>(),
212
+ intersection,
213
+ })(schema);
214
+ return intersection.length === 1
215
+ ? intersection[0]
216
+ : ts.factory.createIntersectionTypeNode(intersection);
217
+ };
218
+
219
+ const writeTuple =
220
+ (components: OpenApi.IComponents) =>
221
+ (importer: MigrateImportProgrammer) =>
222
+ (schema: OpenApi.IJsonSchema.ITuple): ts.TypeNode => {
223
+ const tuple: ts.TypeNode = ts.factory.createTupleTypeNode([
224
+ ...schema.prefixItems.map(write(components)(importer)),
225
+ ...(typeof schema.additionalItems === "object" &&
226
+ schema.additionalItems !== null
227
+ ? [
228
+ ts.factory.createRestTypeNode(
229
+ write(components)(importer)(schema.additionalItems),
230
+ ),
231
+ ]
232
+ : schema.additionalItems === true
233
+ ? [
234
+ ts.factory.createRestTypeNode(
235
+ ts.factory.createArrayTypeNode(
236
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
237
+ ),
238
+ ),
239
+ ]
240
+ : []),
241
+ ]);
242
+ const intersection: ts.TypeNode[] = [tuple];
243
+ writePlugin({
244
+ importer,
245
+ regular: typia.misc.literals<keyof OpenApi.IJsonSchema.ITuple>(),
246
+ intersection,
247
+ })(schema);
248
+ return intersection.length === 1
249
+ ? intersection[0]
250
+ : ts.factory.createIntersectionTypeNode(intersection);
251
+ };
252
+
253
+ const writeObject =
254
+ (components: OpenApi.IComponents) =>
255
+ (importer: MigrateImportProgrammer) =>
256
+ (schema: OpenApi.IJsonSchema.IObject): ts.TypeNode => {
257
+ const regular = () =>
258
+ ts.factory.createTypeLiteralNode(
259
+ Object.entries(schema.properties ?? []).map(([key, value]) =>
260
+ writeRegularProperty(components)(importer)(schema.required ?? [])(
261
+ key,
262
+ value,
263
+ ),
264
+ ),
265
+ );
266
+ const dynamic = () =>
267
+ ts.factory.createTypeLiteralNode([
268
+ writeDynamicProperty(components)(importer)(
269
+ schema.additionalProperties as OpenApi.IJsonSchema,
270
+ ),
271
+ ]);
272
+ return !!schema.properties?.length &&
273
+ typeof schema.additionalProperties === "object"
274
+ ? ts.factory.createIntersectionTypeNode([regular(), dynamic()])
275
+ : typeof schema.additionalProperties === "object"
276
+ ? dynamic()
277
+ : regular();
278
+ };
279
+
280
+ const writeRegularProperty =
281
+ (components: OpenApi.IComponents) =>
282
+ (importer: MigrateImportProgrammer) =>
283
+ (required: string[]) =>
284
+ (key: string, value: OpenApi.IJsonSchema) =>
285
+ FilePrinter.description(
286
+ ts.factory.createPropertySignature(
287
+ undefined,
288
+ Escaper.variable(key)
289
+ ? ts.factory.createIdentifier(key)
290
+ : ts.factory.createStringLiteral(key),
291
+ required.includes(key)
292
+ ? undefined
293
+ : ts.factory.createToken(ts.SyntaxKind.QuestionToken),
294
+ write(components)(importer)(value),
295
+ ),
296
+ writeComment(value),
297
+ );
298
+
299
+ const writeDynamicProperty =
300
+ (components: OpenApi.IComponents) =>
301
+ (importer: MigrateImportProgrammer) =>
302
+ (value: OpenApi.IJsonSchema) =>
303
+ FilePrinter.description(
304
+ ts.factory.createIndexSignature(
305
+ undefined,
306
+ [
307
+ ts.factory.createParameterDeclaration(
308
+ undefined,
309
+ undefined,
310
+ ts.factory.createIdentifier("key"),
311
+ undefined,
312
+ TypeFactory.keyword("string"),
313
+ ),
314
+ ],
315
+ write(components)(importer)(value),
316
+ ),
317
+ writeComment(value),
318
+ );
319
+
320
+ const writeReference =
321
+ (importer: MigrateImportProgrammer) =>
322
+ (
323
+ schema: OpenApi.IJsonSchema.IReference,
324
+ ): ts.TypeReferenceNode | ts.KeywordTypeNode => {
325
+ if (schema.$ref.startsWith("#/components/schemas") === false)
326
+ return TypeFactory.keyword("any");
327
+ const name: string = schema.$ref
328
+ .split("/")
329
+ .slice(3)
330
+ .filter((str) => str.length !== 0)
331
+ .map(StringUtil.escapeNonVariable)
332
+ .join("");
333
+ if (name === "") return TypeFactory.keyword("any");
334
+ return importer.dto(name);
335
+ };
336
+
337
+ /* -----------------------------------------------------------
338
+ UNIONS
339
+ ----------------------------------------------------------- */
340
+ const writeUnion =
341
+ (components: OpenApi.IComponents) =>
342
+ (importer: MigrateImportProgrammer) =>
343
+ (elements: OpenApi.IJsonSchema[]): ts.UnionTypeNode =>
344
+ ts.factory.createUnionTypeNode(elements.map(write(components)(importer)));
345
+ }
346
+ const createNode = (text: string) => ts.factory.createTypeReferenceNode(text);
347
+ const writeComment = (schema: OpenApi.IJsonSchema): string =>
348
+ [
349
+ ...(schema.description?.length ? [schema.description] : []),
350
+ ...(schema.description?.length &&
351
+ (schema.title !== undefined || schema.deprecated === true)
352
+ ? [""]
353
+ : []),
354
+ ...(schema.title !== undefined ? [`@title ${schema.title}`] : []),
355
+ ...(schema.deprecated === true ? [`@deprecated`] : []),
356
+ ]
357
+ .join("\n")
358
+ .split("*/")
359
+ .join("*\\/");
360
+ const writePlugin =
361
+ (props: {
362
+ importer: MigrateImportProgrammer;
363
+ regular: string[];
364
+ intersection: ts.TypeNode[];
365
+ }) =>
366
+ (schema: any) => {
367
+ const extra: any = {};
368
+ for (const [key, value] of Object.entries(schema))
369
+ if (value !== undefined && false === props.regular.includes(key))
370
+ extra[key] = value;
371
+ if (Object.keys(extra).length !== 0)
372
+ props.intersection.push(props.importer.tag("JsonSchemaPlugin", extra));
373
+ };