@nestia/migrate 0.5.1 → 0.6.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 (103) hide show
  1. package/lib/{NestiaMigrateApplication.d.ts → MigrateApplication.d.ts} +1 -1
  2. package/lib/{NestiaMigrateApplication.js → MigrateApplication.js} +38 -32
  3. package/lib/MigrateApplication.js.map +1 -0
  4. package/lib/analyzers/ControllerAnalyzer.d.ts +5 -0
  5. package/lib/{programmers/ControllerProgrammer.js → analyzers/ControllerAnalyzer.js} +8 -32
  6. package/lib/analyzers/ControllerAnalyzer.js.map +1 -0
  7. package/lib/analyzers/MethodAnalyzer.d.ts +9 -0
  8. package/lib/{programmers/RouteProgrammer.js → analyzers/MethodAnalyzer.js} +30 -134
  9. package/lib/analyzers/MethodAnalyzer.js.map +1 -0
  10. package/lib/analyzers/MigrateAnalyzer.d.ts +4 -0
  11. package/lib/analyzers/MigrateAnalyzer.js +12 -0
  12. package/lib/analyzers/MigrateAnalyzer.js.map +1 -0
  13. package/lib/analyzers/RouteAnalyzer.d.ts +0 -0
  14. package/lib/analyzers/RouteAnalyzer.js +2 -0
  15. package/lib/analyzers/RouteAnalyzer.js.map +1 -0
  16. package/lib/archivers/FileArchiver.js.map +1 -1
  17. package/lib/bundles/TEMPLATE.js +10 -10
  18. package/lib/bundles/TEMPLATE.js.map +1 -1
  19. package/lib/executable/bundle.js.map +1 -1
  20. package/lib/executable/migrate.js +7 -7
  21. package/lib/executable/migrate.js.map +1 -1
  22. package/lib/module.d.ts +1 -1
  23. package/lib/module.js +1 -1
  24. package/lib/module.js.map +1 -1
  25. package/lib/programmers/DtoProgrammer.d.ts +8 -4
  26. package/lib/programmers/DtoProgrammer.js +36 -77
  27. package/lib/programmers/DtoProgrammer.js.map +1 -1
  28. package/lib/programmers/ImportProgrammer.d.ts +5 -5
  29. package/lib/programmers/ImportProgrammer.js +27 -19
  30. package/lib/programmers/ImportProgrammer.js.map +1 -1
  31. package/lib/programmers/{ControllerProgrammer.d.ts → NestControllerProgrammer.d.ts} +3 -4
  32. package/lib/programmers/NestControllerProgrammer.js +30 -0
  33. package/lib/programmers/NestControllerProgrammer.js.map +1 -0
  34. package/lib/programmers/NestMethodProgrammer.d.ts +7 -0
  35. package/lib/programmers/NestMethodProgrammer.js +103 -0
  36. package/lib/programmers/NestMethodProgrammer.js.map +1 -0
  37. package/lib/programmers/NestModuleProgrammer.d.ts +5 -0
  38. package/lib/programmers/NestModuleProgrammer.js +29 -0
  39. package/lib/programmers/NestModuleProgrammer.js.map +1 -0
  40. package/lib/programmers/NestProgrammer.d.ts +5 -0
  41. package/lib/programmers/NestProgrammer.js +60 -0
  42. package/lib/programmers/NestProgrammer.js.map +1 -0
  43. package/lib/programmers/SchemaProgrammer.d.ts +2 -1
  44. package/lib/programmers/SchemaProgrammer.js +122 -189
  45. package/lib/programmers/SchemaProgrammer.js.map +1 -1
  46. package/lib/structures/IMigrateProgram.d.ts +2 -2
  47. package/lib/structures/ISwaggerInfo.d.ts +3 -3
  48. package/lib/utils/FilePrinter.d.ts +9 -0
  49. package/lib/utils/FilePrinter.js +25 -0
  50. package/lib/utils/FilePrinter.js.map +1 -0
  51. package/lib/utils/JsonTypeChecker.d.ts +3 -1
  52. package/lib/utils/JsonTypeChecker.js +31 -18
  53. package/lib/utils/JsonTypeChecker.js.map +1 -1
  54. package/lib/utils/MapUtil.js.map +1 -1
  55. package/lib/utils/SetupWizard.js.map +1 -1
  56. package/lib/utils/StringUtil.js.map +1 -1
  57. package/package.json +8 -6
  58. package/src/MigrateApplication.ts +73 -0
  59. package/src/analyzers/ControllerAnalyzer.ts +107 -0
  60. package/src/analyzers/MethodAnalyzer.ts +315 -0
  61. package/src/analyzers/MigrateAnalyzer.ts +9 -0
  62. package/src/analyzers/RouteAnalyzer.ts +0 -0
  63. package/src/archivers/FileArchiver.ts +35 -38
  64. package/src/bundles/TEMPLATE.ts +10 -10
  65. package/src/executable/bundle.ts +72 -78
  66. package/src/executable/migrate.ts +59 -60
  67. package/src/index.ts +4 -4
  68. package/src/module.ts +4 -4
  69. package/src/programmers/DtoProgrammer.ts +74 -118
  70. package/src/programmers/ImportProgrammer.ts +98 -60
  71. package/src/programmers/NestControllerProgrammer.ts +47 -0
  72. package/src/programmers/NestMethodProgrammer.ts +211 -0
  73. package/src/programmers/NestModuleProgrammer.ts +62 -0
  74. package/src/programmers/NestProgrammer.ts +74 -0
  75. package/src/programmers/SchemaProgrammer.ts +247 -339
  76. package/src/structures/IMigrateController.ts +8 -8
  77. package/src/structures/IMigrateDto.ts +8 -8
  78. package/src/structures/IMigrateFile.ts +5 -5
  79. package/src/structures/IMigrateProgram.ts +7 -7
  80. package/src/structures/IMigrateRoute.ts +36 -36
  81. package/src/structures/IMigrateSchema.ts +4 -4
  82. package/src/structures/ISwaggeSchema.ts +82 -82
  83. package/src/structures/ISwagger.ts +20 -20
  84. package/src/structures/ISwaggerComponents.ts +7 -7
  85. package/src/structures/ISwaggerInfo.ts +57 -57
  86. package/src/structures/ISwaggerRoute.ts +52 -52
  87. package/src/structures/ISwaggerSecurity.ts +47 -47
  88. package/src/utils/FilePrinter.ts +36 -0
  89. package/src/utils/JsonTypeChecker.ts +67 -52
  90. package/src/utils/MapUtil.ts +13 -13
  91. package/src/utils/SetupWizard.ts +15 -15
  92. package/src/utils/StringUtil.ts +51 -51
  93. package/lib/NestiaMigrateApplication.js.map +0 -1
  94. package/lib/programmers/ControllerProgrammer.js.map +0 -1
  95. package/lib/programmers/MigrateProgrammer.d.ts +0 -8
  96. package/lib/programmers/MigrateProgrammer.js +0 -48
  97. package/lib/programmers/MigrateProgrammer.js.map +0 -1
  98. package/lib/programmers/RouteProgrammer.d.ts +0 -13
  99. package/lib/programmers/RouteProgrammer.js.map +0 -1
  100. package/src/NestiaMigrateApplication.ts +0 -73
  101. package/src/programmers/ControllerProgrammer.ts +0 -157
  102. package/src/programmers/MigrateProgrammer.ts +0 -62
  103. package/src/programmers/RouteProgrammer.ts +0 -506
@@ -1,506 +0,0 @@
1
- import { Escaper } from "typia/lib/utils/Escaper";
2
-
3
- import { IMigrateRoute } from "../structures/IMigrateRoute";
4
- import { ISwaggerSchema } from "../structures/ISwaggeSchema";
5
- import { ISwagger } from "../structures/ISwagger";
6
- import { ISwaggerComponents } from "../structures/ISwaggerComponents";
7
- import { ISwaggerRoute } from "../structures/ISwaggerRoute";
8
- import { JsonTypeChecker } from "../utils/JsonTypeChecker";
9
- import { StringUtil } from "../utils/StringUtil";
10
- import { ImportProgrammer } from "./ImportProgrammer";
11
- import { SchemaProgrammer } from "./SchemaProgrammer";
12
-
13
- export namespace RouteProgrammer {
14
- export const analyze =
15
- (swagger: ISwagger) =>
16
- (props: { path: string; method: string }) =>
17
- (route: ISwaggerRoute): IMigrateRoute | null => {
18
- const body = emplaceBodySchema(emplaceReference(swagger)("body"))(
19
- route.requestBody,
20
- );
21
- const success = emplaceBodySchema(
22
- emplaceReference(swagger)("response"),
23
- )(route.responses?.["201"] ?? route.responses?.["200"]);
24
- if (body === false || success === false) {
25
- console.log(
26
- `Failed to migrate ${props.method.toUpperCase()} ${
27
- props.path
28
- }: @nestia/migrate supports only application/json, application/x-www-form-urlencoded or text/plain format yet.`,
29
- );
30
- return null;
31
- } else if (
32
- SUPPORTED_METHODS.has(props.method.toUpperCase()) === false
33
- ) {
34
- console.log(
35
- `Failed to migrate ${props.method.toUpperCase()} ${
36
- props.path
37
- }: @nestia/migrate does not support ${props.method.toUpperCase()} method.`,
38
- );
39
- return null;
40
- }
41
-
42
- const [headers, query] = ["header", "query"].map((type) => {
43
- const parameters = (route.parameters ?? []).filter(
44
- (p) => p.in === type,
45
- );
46
- if (parameters.length === 0) return null;
47
-
48
- const objects = parameters
49
- .map((p) =>
50
- JsonTypeChecker.isObject(p.schema)
51
- ? p.schema
52
- : JsonTypeChecker.isReference(p.schema) &&
53
- JsonTypeChecker.isObject(
54
- (swagger.components.schemas ?? {})[
55
- p.schema.$ref.replace(
56
- `#/components/schemas/`,
57
- ``,
58
- )
59
- ] ?? {},
60
- )
61
- ? p.schema
62
- : null!,
63
- )
64
- .filter((s) => !!s);
65
- const primitives = parameters.filter(
66
- (p) =>
67
- JsonTypeChecker.isBoolean(p.schema) ||
68
- JsonTypeChecker.isNumber(p.schema) ||
69
- JsonTypeChecker.isInteger(p.schema) ||
70
- JsonTypeChecker.isString(p.schema) ||
71
- JsonTypeChecker.isArray(p.schema),
72
- );
73
- if (objects.length === 1 && primitives.length === 0)
74
- return objects[0];
75
- else if (objects.length > 1)
76
- throw new Error(
77
- `Error on nestia.migrate.RouteProgrammer.analze(): ${type} typed parameters must be only one object type - ${StringUtil.capitalize(
78
- props.method,
79
- )} "${props.path}".`,
80
- );
81
-
82
- const dto: ISwaggerSchema.IObject | null = objects[0]
83
- ? JsonTypeChecker.isObject(objects[0])
84
- ? objects[0]
85
- : ((swagger.components.schemas ?? {})[
86
- (
87
- objects[0] as ISwaggerSchema.IReference
88
- ).$ref.replace(`#/components/schemas/`, ``)
89
- ] as ISwaggerSchema.IObject)
90
- : null;
91
- const entire: ISwaggerSchema.IObject[] = [
92
- ...objects.map((o) =>
93
- JsonTypeChecker.isObject(o)
94
- ? o
95
- : (swagger.components.schemas?.[
96
- o.$ref.replace(`#/components/schemas/`, ``)
97
- ]! as ISwaggerSchema.IObject),
98
- ),
99
- {
100
- type: "object",
101
- properties: Object.fromEntries([
102
- ...primitives.map((p) => [
103
- p.name,
104
- {
105
- ...p.schema,
106
- description:
107
- p.schema.description ?? p.description,
108
- },
109
- ]),
110
- ...(dto
111
- ? Object.entries(dto.properties ?? {})
112
- : []),
113
- ]),
114
- required: [
115
- ...primitives
116
- .filter((p) => p.required)
117
- .map((p) => p.name!),
118
- ...(dto ? dto.required ?? [] : []),
119
- ],
120
- },
121
- ];
122
- return parameters.length === 0
123
- ? null
124
- : emplaceReference(swagger)(
125
- StringUtil.pascal(`I/Api/${props.path}`) +
126
- "." +
127
- StringUtil.pascal(`${props.method}/${type}`),
128
- )({
129
- type: "object",
130
- properties: Object.fromEntries([
131
- ...new Map<string, ISwaggerSchema>(
132
- entire
133
- .map((o) =>
134
- Object.entries(
135
- o.properties ?? {},
136
- ).map(
137
- ([name, schema]) =>
138
- [
139
- name,
140
- {
141
- ...schema,
142
- description:
143
- schema.description ??
144
- schema.description,
145
- } as ISwaggerSchema,
146
- ] as const,
147
- ),
148
- )
149
- .flat(),
150
- ),
151
- ]),
152
- required: [
153
- ...new Set(
154
- entire.map((o) => o.required ?? []).flat(),
155
- ),
156
- ],
157
- });
158
- });
159
-
160
- const parameterNames: string[] = StringUtil.splitWithNormalization(
161
- props.path,
162
- )
163
- .filter((str) => str[0] === "{" || str[0] === ":")
164
- .map((str) =>
165
- str[0] === "{"
166
- ? str.substring(1, str.length - 1)
167
- : str.substring(1),
168
- );
169
- if (
170
- parameterNames.length !==
171
- (route.parameters ?? []).filter((p) => p.in === "path").length
172
- ) {
173
- console.log(
174
- `Failed to migrate ${props.method.toUpperCase()} ${
175
- props.path
176
- }: number of path parameters are not matched with its full path.`,
177
- );
178
- return null;
179
- }
180
- return {
181
- name: "@lazy",
182
- path: props.path,
183
- method: props.method,
184
- headers,
185
- parameters: (route.parameters ?? [])
186
- .filter((p) => p.in === "path")
187
- .map((p, i) => ({
188
- key: (() => {
189
- let key: string = StringUtil.normalize(
190
- parameterNames[i],
191
- );
192
- if (Escaper.variable(key)) return key;
193
-
194
- while (true) {
195
- key = "_" + key;
196
- if (!parameterNames.some((s) => s === key))
197
- return key;
198
- }
199
- })(),
200
- schema: {
201
- ...p.schema,
202
- description: p.schema.description ?? p.description,
203
- },
204
- })),
205
- query,
206
- body,
207
- success,
208
- exceptions: Object.fromEntries(
209
- Object.entries(route.responses ?? {})
210
- .filter(
211
- ([key, value]) =>
212
- key !== "200" &&
213
- key !== "201" &&
214
- !!value.content?.["application/json"],
215
- )
216
- .map(([key, value]) => [
217
- key,
218
- {
219
- description: value.description,
220
- schema:
221
- value.content?.["application/json"]
222
- ?.schema ?? {},
223
- },
224
- ]),
225
- ),
226
- description: describe(route),
227
- "x-nestia-jsDocTags": route["x-nestia-jsDocTags"],
228
- };
229
- };
230
-
231
- const describe = (route: ISwaggerRoute): string | undefined => {
232
- const commentTags: string[] = [];
233
- const add = (text: string) => {
234
- if (commentTags.every((line) => line !== text))
235
- commentTags.push(text);
236
- };
237
-
238
- let description: string | undefined = route.description;
239
- if (route.summary) {
240
- const emended: string = route.summary.endsWith(".")
241
- ? route.summary
242
- : route.summary + ".";
243
- if (
244
- description !== undefined &&
245
- !description?.startsWith(route.summary) &&
246
- !route["x-nestia-jsDocTags"]?.some((t) => t.name === "summary")
247
- )
248
- description = `${emended}\n${description}`;
249
- }
250
- if (route.tags) route.tags.forEach((name) => add(`@tag ${name}`));
251
- if (route.deprecated) add("@deprecated");
252
- for (const security of route.security ?? [])
253
- for (const [name, scopes] of Object.entries(security))
254
- add(`@security ${[name, ...scopes].join("")}`);
255
- for (const jsDocTag of route["x-nestia-jsDocTags"] ?? [])
256
- if (jsDocTag.text?.length)
257
- add(
258
- `@${jsDocTag.name} ${jsDocTag.text
259
- .map((text) => text.text)
260
- .join("")}`,
261
- );
262
- else add(`@${jsDocTag.name}`);
263
- return description?.length
264
- ? commentTags.length
265
- ? `${description}\n\n${commentTags.join("\n")}`
266
- : description
267
- : commentTags.join("\n");
268
- };
269
-
270
- const isNotObjectLiteral = (schema: ISwaggerSchema): boolean =>
271
- JsonTypeChecker.isReference(schema) ||
272
- JsonTypeChecker.isBoolean(schema) ||
273
- JsonTypeChecker.isNumber(schema) ||
274
- JsonTypeChecker.isString(schema) ||
275
- JsonTypeChecker.isUnknown(schema) ||
276
- (JsonTypeChecker.isAnyOf(schema) &&
277
- schema.anyOf.every(isNotObjectLiteral)) ||
278
- (JsonTypeChecker.isOneOf(schema) &&
279
- schema.oneOf.every(isNotObjectLiteral)) ||
280
- (JsonTypeChecker.isArray(schema) && isNotObjectLiteral(schema.items));
281
-
282
- const emplaceBodySchema =
283
- (emplacer: (schema: ISwaggerSchema) => ISwaggerSchema.IReference) =>
284
- (meta?: {
285
- description?: string;
286
- content?: ISwaggerRoute.IContent;
287
- "x-nestia-encrypted"?: boolean;
288
- }): false | null | IMigrateRoute.IBody => {
289
- if (!meta?.content) return null;
290
-
291
- const entries: [string, { schema: ISwaggerSchema }][] =
292
- Object.entries(meta.content);
293
- const json = entries.find((e) =>
294
- meta["x-nestia-encrypted"] === true
295
- ? e[0].includes("text/plain") ||
296
- e[0].includes("application/json")
297
- : e[0].includes("application/json") || e[0].includes("*/*"),
298
- );
299
- if (json) {
300
- const { schema } = json[1];
301
- return {
302
- type: "application/json",
303
- schema: isNotObjectLiteral(schema)
304
- ? schema
305
- : emplacer(schema),
306
- "x-nestia-encrypted": meta["x-nestia-encrypted"],
307
- };
308
- }
309
-
310
- const query = entries.find((e) =>
311
- e[0].includes("application/x-www-form-urlencoded"),
312
- );
313
- if (query) {
314
- const { schema } = query[1];
315
- return {
316
- type: "application/x-www-form-urlencoded",
317
- schema: isNotObjectLiteral(schema)
318
- ? schema
319
- : emplacer(schema),
320
- };
321
- }
322
-
323
- const text = entries.find((e) => e[0].includes("text/plain"));
324
- if (text) return { type: "text/plain", schema: { type: "string" } };
325
- return false;
326
- };
327
-
328
- const emplaceReference =
329
- (swagger: ISwagger) =>
330
- (name: string) =>
331
- (schema: ISwaggerSchema): ISwaggerSchema.IReference => {
332
- swagger.components.schemas ??= {};
333
- swagger.components.schemas[name] = schema;
334
- return { $ref: `#/components/schemas/${name}` };
335
- };
336
-
337
- export const write =
338
- (components: ISwaggerComponents) =>
339
- (references: ISwaggerSchema.IReference[]) =>
340
- (importer: ImportProgrammer) =>
341
- (route: IMigrateRoute): string => {
342
- const output: string = route.success
343
- ? SchemaProgrammer.write(components)(references)(importer)(
344
- route.success.schema,
345
- )
346
- : "void";
347
-
348
- const methoder = (composer: (name: string) => string) =>
349
- `${composer(
350
- StringUtil.capitalize(route.method),
351
- )}(${JSON.stringify(route.path)})`;
352
- const external = (lib: string) => (instance: string) =>
353
- importer.external({ library: lib, instance });
354
-
355
- const decorator: string[] =
356
- route.success?.["x-nestia-encrypted"] === true
357
- ? [
358
- `@${external("@nestia/core")(
359
- "EncryptedRoute",
360
- )}.${methoder((str) => str)}`,
361
- ]
362
- : route.success?.type === "text/plain"
363
- ? [
364
- `@${external("@nestjs/common")(
365
- "Header",
366
- )}("Content-Type", "text/plain")`,
367
- `@${methoder((str) =>
368
- external("@nestjs/common")(str),
369
- )}`,
370
- ]
371
- : route.success?.type ===
372
- "application/x-www-form-urlencoded"
373
- ? [
374
- `@${external("@nestia/core")(
375
- "TypedQuery",
376
- )}.${methoder((str) => str)}`,
377
- ]
378
- : route.method === "head"
379
- ? [
380
- `@${external("@nestjs/common")("Head")}${methoder(
381
- () => "",
382
- )}`,
383
- ]
384
- : [
385
- `@${external("@nestia/core")(
386
- "TypedRoute",
387
- )}.${methoder((str) => str)}`,
388
- ];
389
- for (const [key, value] of Object.entries(route.exceptions ?? {}))
390
- decorator.push(
391
- `@${external("@nestia/core")(
392
- "TypedException",
393
- )}<${SchemaProgrammer.write(components)(references)(
394
- importer,
395
- )(value.schema)}>(${
396
- isNaN(Number(key)) ? JSON.stringify(key) : key
397
- }, ${JSON.stringify(value.description)})`,
398
- );
399
-
400
- const content: string[] = [
401
- ...(route.description
402
- ? [
403
- "/**",
404
- ...route.description
405
- .split("\n")
406
- .map((line) => ` * ${line}`),
407
- " */",
408
- ]
409
- : []),
410
- ...decorator,
411
- `public async ${route.name}(`,
412
- ...route.parameters.map(
413
- (param) =>
414
- ` ${writeParameter(components)(importer)(param)},`,
415
- ),
416
- ...(route.headers
417
- ? [
418
- ` @${external("@nestia/core")(
419
- "TypedHeaders",
420
- )}() headers: ${SchemaProgrammer.write(components)(
421
- references,
422
- )(importer)(route.headers)},`,
423
- ]
424
- : []),
425
- ...(route.query
426
- ? [
427
- ` @${external("@nestia/core")(
428
- "TypedQuery",
429
- )}() query: ${SchemaProgrammer.write(components)(
430
- references,
431
- )(importer)(route.query)},`,
432
- ]
433
- : []),
434
- ...(route.body
435
- ? route.body["x-nestia-encrypted"] === true
436
- ? [
437
- ` @${external("@nestia/core")(
438
- "EncryptedBody",
439
- )}() body: ${SchemaProgrammer.write(components)(
440
- references,
441
- )(importer)(route.body.schema)},`,
442
- ]
443
- : route.body.type === "application/json"
444
- ? [
445
- ` @${external("@nestia/core")(
446
- "TypedBody",
447
- )}() body: ${SchemaProgrammer.write(components)(
448
- references,
449
- )(importer)(route.body.schema)},`,
450
- ]
451
- : route.body.type ===
452
- "application/x-www-form-urlencoded"
453
- ? [
454
- ` @${external("@nestia/core")(
455
- "TypedQuery",
456
- )}.Body() body: ${SchemaProgrammer.write(
457
- components,
458
- )(references)(importer)(route.body.schema)},`,
459
- ]
460
- : [
461
- ` @${external("@nestia/core")(
462
- "PlainBody",
463
- )}() body: string,`,
464
- ]
465
- : []),
466
- `): Promise<${output}> {`,
467
- ...route.parameters.map(
468
- (p) => ` ${StringUtil.normalize(p.key)};`,
469
- ),
470
- ...(route.headers ? [" headers;"] : []),
471
- ...(route.query ? [" query;"] : []),
472
- ...(route.body ? [" body;"] : []),
473
- ...(output !== "void"
474
- ? [
475
- ` return ${external("typia")(
476
- "random",
477
- )}<${output}>();`,
478
- ]
479
- : []),
480
- `}`,
481
- ];
482
- return content.join("\n");
483
- };
484
-
485
- const writeParameter =
486
- (components: ISwaggerComponents) =>
487
- (importer: ImportProgrammer) =>
488
- ({ key, schema }: IMigrateRoute.IParameter): string => {
489
- const variable = StringUtil.normalize(key);
490
- return `@${importer.external({
491
- library: "@nestia/core",
492
- instance: "TypedParam",
493
- })}(${JSON.stringify(key)}) ${variable}: ${SchemaProgrammer.write(
494
- components,
495
- )([])(importer)(schema)}`;
496
- };
497
- }
498
-
499
- const SUPPORTED_METHODS: Set<string> = new Set([
500
- "GET",
501
- "POST",
502
- "PUT",
503
- "PATCH",
504
- "DELETE",
505
- "HEAD",
506
- ]);