@nestia/migrate 0.2.0 → 0.2.1-dev.20230803

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 (30) hide show
  1. package/lib/NestiaMigrateApplication.js +2 -2
  2. package/lib/NestiaMigrateApplication.js.map +1 -1
  3. package/lib/bundles/TEMPLATE.js +2 -2
  4. package/lib/programmers/ControllerProgrammer.d.ts +2 -1
  5. package/lib/programmers/ControllerProgrammer.js +12 -17
  6. package/lib/programmers/ControllerProgrammer.js.map +1 -1
  7. package/lib/programmers/DtoProgrammer.d.ts +2 -1
  8. package/lib/programmers/DtoProgrammer.js +5 -5
  9. package/lib/programmers/DtoProgrammer.js.map +1 -1
  10. package/lib/programmers/ImportProgrammer.d.ts +11 -0
  11. package/lib/programmers/ImportProgrammer.js +20 -0
  12. package/lib/programmers/ImportProgrammer.js.map +1 -0
  13. package/lib/programmers/MigrateProgrammer.d.ts +2 -1
  14. package/lib/programmers/MigrateProgrammer.js +3 -3
  15. package/lib/programmers/MigrateProgrammer.js.map +1 -1
  16. package/lib/programmers/RouteProgrammer.d.ts +2 -1
  17. package/lib/programmers/RouteProgrammer.js +45 -17
  18. package/lib/programmers/RouteProgrammer.js.map +1 -1
  19. package/lib/programmers/SchemaProgrammer.d.ts +2 -1
  20. package/lib/programmers/SchemaProgrammer.js +64 -42
  21. package/lib/programmers/SchemaProgrammer.js.map +1 -1
  22. package/package.json +4 -4
  23. package/src/NestiaMigrateApplication.ts +6 -2
  24. package/src/bundles/TEMPLATE.ts +2 -2
  25. package/src/programmers/ControllerProgrammer.ts +50 -54
  26. package/src/programmers/DtoProgrammer.ts +29 -25
  27. package/src/programmers/ImportProgrammer.ts +29 -0
  28. package/src/programmers/MigrateProgrammer.ts +17 -14
  29. package/src/programmers/RouteProgrammer.ts +99 -31
  30. package/src/programmers/SchemaProgrammer.ts +82 -40
@@ -3,6 +3,7 @@ import { Escaper } from "typia/lib/utils/Escaper";
3
3
  import { IMigrateRoute } from "../structures/IMigrateRoute";
4
4
  import { ISwaggerSchema } from "../structures/ISwaggeSchema";
5
5
  import { ISwagger } from "../structures/ISwagger";
6
+ import { ISwaggerComponents } from "../structures/ISwaggerComponents";
6
7
  import { ISwaggerRoute } from "../structures/ISwaggerRoute";
7
8
  import { JsonTypeChecker } from "../utils/JsonTypeChecker";
8
9
  import { StringUtil } from "../utils/StringUtil";
@@ -26,6 +27,15 @@ export namespace RouteProgrammer {
26
27
  }: @nestia/migrate supports only application/json or text/plain format yet.`,
27
28
  );
28
29
  return null;
30
+ } else if (
31
+ SUPPORTED_METHODS.has(props.method.toUpperCase()) === false
32
+ ) {
33
+ console.log(
34
+ `Failed to migrate ${props.method.toUpperCase()} ${
35
+ props.path
36
+ }: @nestia/migrate does not support ${props.method.toUpperCase()} method.`,
37
+ );
38
+ return null;
29
39
  }
30
40
 
31
41
  const [headers, query] = ["header", "query"].map((type) => {
@@ -292,17 +302,47 @@ export namespace RouteProgrammer {
292
302
  };
293
303
 
294
304
  export const write =
305
+ (importer: (module: string) => (instance: string) => string) =>
306
+ (components: ISwaggerComponents) =>
295
307
  (references: ISwaggerSchema.IReference[]) =>
296
308
  (route: IMigrateRoute): string => {
297
309
  const output: string = route.response
298
- ? SchemaProgrammer.write(references)(route.response.schema)
310
+ ? SchemaProgrammer.write(components)(references)(
311
+ route.response.schema,
312
+ )
299
313
  : "void";
300
- const decorator: string =
301
- route.body?.["x-nestia-encrypted"] === true
302
- ? "@core.EncryptedRoute."
303
- : route.body?.type === "text/plain"
304
- ? [`@Header("Content-Type", "text/plain")`, `@`].join("\n")
305
- : "@core.TypedRoute.";
314
+
315
+ const methoder = (composer: (name: string) => string) =>
316
+ `${composer(
317
+ StringUtil.capitalize(route.method),
318
+ )}(${JSON.stringify(route.path)})`;
319
+ const decorator: string[] =
320
+ route.response?.["x-nestia-encrypted"] === true
321
+ ? [
322
+ `@${importer("@nestia/core")(
323
+ "EncryptedRoute",
324
+ )}.${methoder((str) => str)}`,
325
+ ]
326
+ : route.response?.type === "text/plain"
327
+ ? [
328
+ `@${importer("@nestjs/common")(
329
+ "Header",
330
+ )}("Content-Type", "text/plain")`,
331
+ `@${methoder((str) =>
332
+ importer("@nestjs/common")(str),
333
+ )}`,
334
+ ]
335
+ : route.method === "head"
336
+ ? [
337
+ `@${importer("@nestjs/common")("Head")}${methoder(
338
+ () => "",
339
+ )}`,
340
+ ]
341
+ : [
342
+ `@${importer("@nestia/core")(
343
+ "TypedRoute",
344
+ )}.${methoder((str) => str)}`,
345
+ ];
306
346
  const content: string[] = [
307
347
  ...(route.description
308
348
  ? [
@@ -313,21 +353,26 @@ export namespace RouteProgrammer {
313
353
  " */",
314
354
  ]
315
355
  : []),
316
- `${decorator}${StringUtil.capitalize(route.method)}${
317
- route.path.length ? `(${JSON.stringify(route.path)})` : "()"
318
- }`,
356
+ ...decorator,
319
357
  `public async ${route.name}(`,
320
- ...route.parameters.map((p) => ` ${writeParameter(p)},`),
358
+ ...route.parameters.map(
359
+ (param) =>
360
+ ` ${writeParameter(components)(importer)(param)},`,
361
+ ),
321
362
  ...(route.headers
322
363
  ? [
323
- ` @core.TypedHeaders() headers: ${SchemaProgrammer.write(
364
+ ` @${importer("@nestia/core")(
365
+ "TypedHeaders",
366
+ )}() headers: ${SchemaProgrammer.write(components)(
324
367
  references,
325
368
  )(route.headers)},`,
326
369
  ]
327
370
  : []),
328
371
  ...(route.query
329
372
  ? [
330
- ` @core.TypedQuery() query: ${SchemaProgrammer.write(
373
+ ` @${importer("@nestia/core")(
374
+ "TypedQuery",
375
+ )}() query: ${SchemaProgrammer.write(components)(
331
376
  references,
332
377
  )(route.query)},`,
333
378
  ]
@@ -335,17 +380,25 @@ export namespace RouteProgrammer {
335
380
  ...(route.body
336
381
  ? route.body["x-nestia-encrypted"] === true
337
382
  ? [
338
- ` @core.EncryptedBody() body: ${SchemaProgrammer.write(
383
+ ` @${importer("@nestia/core")(
384
+ "EncryptedBody",
385
+ )}() body: ${SchemaProgrammer.write(components)(
339
386
  references,
340
387
  )(route.body.schema)},`,
341
388
  ]
342
389
  : route.body.type === "application/json"
343
390
  ? [
344
- ` @core.TypedBody() body: ${SchemaProgrammer.write(
391
+ ` @${importer("@nestia/core")(
392
+ "TypedBody",
393
+ )}() body: ${SchemaProgrammer.write(components)(
345
394
  references,
346
395
  )(route.body.schema)},`,
347
396
  ]
348
- : [` @core.PlainBody() body: string,`]
397
+ : [
398
+ ` @${importer("@nestia/core")(
399
+ "PlainBody",
400
+ )}() body: string,`,
401
+ ]
349
402
  : []),
350
403
  `): Promise<${output}> {`,
351
404
  ...route.parameters.map(
@@ -355,25 +408,40 @@ export namespace RouteProgrammer {
355
408
  ...(route.query ? [" query;"] : []),
356
409
  ...(route.body ? [" body;"] : []),
357
410
  ...(output !== "void"
358
- ? [` return typia.random<${output}>();`]
411
+ ? [
412
+ ` return ${importer("typia")(
413
+ "random",
414
+ )}<${output}>();`,
415
+ ]
359
416
  : []),
360
417
  `}`,
361
418
  ];
362
419
  return content.join("\n");
363
420
  };
364
421
 
365
- const writeParameter = ({
366
- key,
367
- schema,
368
- }: IMigrateRoute.IParameter): string => {
369
- const variable = StringUtil.normalize(key);
370
- const format =
371
- JsonTypeChecker.isString(schema) &&
372
- (schema.format === "uuid" || schema.format === "date")
373
- ? schema.format
374
- : null;
375
- return `@core.TypedParam(${JSON.stringify(key)}${
376
- format ? `, ${JSON.stringify(format)}` : ""
377
- }) ${variable}: ${SchemaProgrammer.write([])(schema)}`;
378
- };
422
+ const writeParameter =
423
+ (components: ISwaggerComponents) =>
424
+ (importer: (library: string) => (instance: string) => string) =>
425
+ ({ key, schema }: IMigrateRoute.IParameter): string => {
426
+ const variable = StringUtil.normalize(key);
427
+ const format =
428
+ JsonTypeChecker.isString(schema) &&
429
+ (schema.format === "uuid" || schema.format === "date")
430
+ ? schema.format
431
+ : null;
432
+ return `@${importer("@nestia/core")("TypedParam")}(${JSON.stringify(
433
+ key,
434
+ )}${
435
+ format ? `, ${JSON.stringify(format)}` : ""
436
+ }) ${variable}: ${SchemaProgrammer.write(components)([])(schema)}`;
437
+ };
379
438
  }
439
+
440
+ const SUPPORTED_METHODS: Set<string> = new Set([
441
+ "GET",
442
+ "POST",
443
+ "PUT",
444
+ "PATCH",
445
+ "DELETE",
446
+ "HEAD",
447
+ ]);
@@ -1,49 +1,81 @@
1
1
  import { Escaper } from "typia/lib/utils/Escaper";
2
2
 
3
3
  import { ISwaggerSchema } from "../structures/ISwaggeSchema";
4
+ import { ISwaggerComponents } from "../structures/ISwaggerComponents";
4
5
  import { JsonTypeChecker } from "../utils/JsonTypeChecker";
5
6
 
6
7
  export namespace SchemaProgrammer {
7
8
  export const write =
9
+ (components: ISwaggerComponents) =>
8
10
  (references: ISwaggerSchema.IReference[]) =>
9
11
  (schema: ISwaggerSchema): string =>
10
- writeSchema(references)(() => () => {})(schema);
12
+ writeSchema(components)(references)(() => () => {})(true)(schema);
11
13
 
12
14
  type Tagger = (tag: string) => (value?: string) => void;
13
15
  const writeSchema =
16
+ (components: ISwaggerComponents) =>
14
17
  (references: ISwaggerSchema.IReference[]) =>
15
18
  (tagger: Tagger) =>
19
+ (final: boolean) =>
16
20
  (schema: ISwaggerSchema): string => {
17
21
  // SPECIAL TYPES
18
22
  if (JsonTypeChecker.isUnknown(schema)) return "any";
19
- else if (JsonTypeChecker.isAnyOf(schema))
20
- return schema.anyOf
21
- .map(writeSchema(references)(tagger))
22
- .join(" | ");
23
+
24
+ const type: string = (() => {
25
+ if (JsonTypeChecker.isAnyOf(schema))
26
+ return (
27
+ "(" +
28
+ schema.anyOf
29
+ .map(
30
+ writeSchema(components)(references)(tagger)(
31
+ false,
32
+ ),
33
+ )
34
+ .join(" | ") +
35
+ ")"
36
+ );
37
+ else if (JsonTypeChecker.isOneOf(schema))
38
+ return schema.oneOf
39
+ .map(writeSchema(components)(references)(tagger)(false))
40
+ .join(" | ");
41
+ // ATOMIC TYPES
42
+ else if (JsonTypeChecker.isBoolean(schema))
43
+ return writeBoolean(tagger)(schema);
44
+ else if (JsonTypeChecker.isInteger(schema))
45
+ return writeInteger(tagger)(schema);
46
+ else if (JsonTypeChecker.isNumber(schema))
47
+ return writeNumber(tagger)(schema);
48
+ else if (JsonTypeChecker.isString(schema))
49
+ return writeString(tagger)(schema);
50
+ // INSTANCE TYPES
51
+ else if (JsonTypeChecker.isArray(schema))
52
+ return writeArray(components)(references)(tagger)(schema);
53
+ else if (JsonTypeChecker.isObject(schema))
54
+ return writeObject(components)(references)(schema);
55
+ else if (JsonTypeChecker.isReference(schema)) {
56
+ references.push(schema);
57
+ return schema.$ref.replace(`#/components/schemas/`, ``);
58
+ } else return "any";
59
+ })();
60
+ if (type === "any" || final === false) return type;
61
+ return isNullable(components)(schema) ? `${type} | null` : type;
62
+ };
63
+
64
+ const isNullable =
65
+ (components: ISwaggerComponents) =>
66
+ (schema: ISwaggerSchema): boolean => {
67
+ if (JsonTypeChecker.isAnyOf(schema))
68
+ return schema.anyOf.some(isNullable(components));
23
69
  else if (JsonTypeChecker.isOneOf(schema))
24
- return schema.oneOf
25
- .map(writeSchema(references)(tagger))
26
- .join(" | ");
27
- // ATOMIC TYPES
28
- else if (JsonTypeChecker.isBoolean(schema))
29
- return writeBoolean(tagger)(schema);
30
- else if (JsonTypeChecker.isInteger(schema))
31
- return writeInteger(tagger)(schema);
32
- else if (JsonTypeChecker.isNumber(schema))
33
- return writeNumber(tagger)(schema);
34
- else if (JsonTypeChecker.isString(schema))
35
- return writeString(tagger)(schema);
36
- // INSTANCE TYPES
37
- else if (JsonTypeChecker.isArray(schema))
38
- return writeArray(references)(tagger)(schema);
39
- else if (JsonTypeChecker.isObject(schema))
40
- return writeObject(references)(schema);
70
+ return schema.oneOf.some(isNullable(components));
41
71
  else if (JsonTypeChecker.isReference(schema)) {
42
- references.push(schema);
43
- return schema.$ref.replace(`#/components/schemas/`, ``);
72
+ const $id = schema.$ref.replace("#/components/schemas/", "");
73
+ const target = (components.schemas ?? {})[$id];
74
+ return target === undefined
75
+ ? false
76
+ : isNullable(components)(target);
44
77
  }
45
- // NOTHING
46
- return "any";
78
+ return (schema as ISwaggerSchema.IString).nullable === true;
47
79
  };
48
80
 
49
81
  const writeBoolean =
@@ -94,20 +126,24 @@ export namespace SchemaProgrammer {
94
126
  };
95
127
 
96
128
  const writeArray =
129
+ (components: ISwaggerComponents) =>
97
130
  (references: ISwaggerSchema.IReference[]) =>
98
131
  (tagger: Tagger) =>
99
132
  (schema: ISwaggerSchema.IArray): string =>
100
133
  schema["x-typia-tuple"]
101
134
  ? `[${schema["x-typia-tuple"].items
102
- .map(writeTupleElement(references))
135
+ .map(writeTupleElement(components)(references))
103
136
  .join(", ")}]`
104
- : `Array<${writeSchema(references)(tagger)(schema.items)}>`;
137
+ : `Array<${writeSchema(components)(references)(tagger)(true)(
138
+ schema.items,
139
+ )}>`;
105
140
  const writeTupleElement =
141
+ (components: ISwaggerComponents) =>
106
142
  (references: ISwaggerSchema.IReference[]) =>
107
143
  (schema: ISwaggerSchema): string => {
108
- const name: string = writeSchema(references)(() => () => {})(
109
- schema,
110
- );
144
+ const name: string = writeSchema(components)(references)(
145
+ () => () => {},
146
+ )(true)(schema);
111
147
  return schema["x-typia-optional"]
112
148
  ? `${name}?`
113
149
  : schema["x-typia-rest"]
@@ -116,29 +152,31 @@ export namespace SchemaProgrammer {
116
152
  };
117
153
 
118
154
  const writeObject =
155
+ (components: ISwaggerComponents) =>
119
156
  (references: ISwaggerSchema.IReference[]) =>
120
157
  (schema: ISwaggerSchema.IObject): string => {
121
158
  const entries = Object.entries(schema.properties ?? {});
122
159
  return typeof schema.additionalProperties === "object"
123
160
  ? entries.length
124
- ? `${writeStaticObject(references)(
161
+ ? `${writeStaticObject(components)(references)(
125
162
  schema,
126
- )} & ${writeDynamicObject(references)(
163
+ )} & ${writeDynamicObject(components)(references)(
127
164
  schema.additionalProperties,
128
165
  )}`
129
- : writeDynamicObject(references)(
166
+ : writeDynamicObject(components)(references)(
130
167
  schema.additionalProperties,
131
168
  )
132
- : writeStaticObject(references)(schema);
169
+ : writeStaticObject(components)(references)(schema);
133
170
  };
134
171
  const writeStaticObject =
172
+ (components: ISwaggerComponents) =>
135
173
  (references: ISwaggerSchema.IReference[]) =>
136
174
  (schema: ISwaggerSchema.IObject): string =>
137
175
  [
138
176
  "{",
139
177
  ...Object.entries(schema.properties ?? {})
140
178
  .map(([key, value]) =>
141
- writeProperty(references)(key)(
179
+ writeProperty(components)(references)(key)(
142
180
  (schema.required ?? []).some((r) => r === key),
143
181
  )(value),
144
182
  )
@@ -146,20 +184,23 @@ export namespace SchemaProgrammer {
146
184
  "}",
147
185
  ].join("\n");
148
186
  const writeDynamicObject =
187
+ (components: ISwaggerComponents) =>
149
188
  (references: ISwaggerSchema.IReference[]) =>
150
189
  (additional: ISwaggerSchema): string => {
151
190
  return [
152
191
  "{",
153
192
  tab(4)(
154
- writeProperty(references)("[key: string]", true)(true)(
155
- additional,
156
- ),
193
+ writeProperty(components)(references)(
194
+ "[key: string]",
195
+ true,
196
+ )(true)(additional),
157
197
  ),
158
198
  "}",
159
199
  ].join("\n");
160
200
  };
161
201
 
162
202
  const writeProperty =
203
+ (components: ISwaggerComponents) =>
163
204
  (references: ISwaggerSchema.IReference[]) =>
164
205
  (key: string, ensureVariable: boolean = false) =>
165
206
  (required: boolean) =>
@@ -184,7 +225,8 @@ export namespace SchemaProgrammer {
184
225
  if (schema.title) tagger("@title")(schema.title);
185
226
 
186
227
  // GET TYPE WITH SPECIAL TAGS
187
- const type: string = writeSchema(references)(tagger)(schema);
228
+ const type: string =
229
+ writeSchema(components)(references)(tagger)(true)(schema);
188
230
 
189
231
  // ENDS WITH DEPRECATED TAG
190
232
  if (schema.deprecated) tagger("@deprecated")();