@nestia/migrate 0.13.17 → 0.14.0

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 (67) hide show
  1. package/lib/MigrateApplication.d.ts +1 -0
  2. package/lib/MigrateApplication.js +823 -873
  3. package/lib/MigrateApplication.js.map +1 -1
  4. package/lib/analyzers/MigrateAnalyzer.js +5 -2
  5. package/lib/analyzers/MigrateAnalyzer.js.map +1 -1
  6. package/lib/analyzers/MigrateControllerAnalyzer.d.ts +2 -2
  7. package/lib/analyzers/MigrateControllerAnalyzer.js +14 -88
  8. package/lib/analyzers/MigrateControllerAnalyzer.js.map +1 -1
  9. package/lib/bundles/NEST_TEMPLATE.js +3 -3
  10. package/lib/bundles/SDK_TEMPLATE.js +1 -1
  11. package/lib/executable/bundle.js +1 -1
  12. package/lib/internal/MigrateCommander.js +5 -2
  13. package/lib/internal/MigrateCommander.js.map +1 -1
  14. package/lib/programmers/MigrateApiFileProgrammer.d.ts +2 -9
  15. package/lib/programmers/MigrateApiFileProgrammer.js +4 -4
  16. package/lib/programmers/MigrateApiFileProgrammer.js.map +1 -1
  17. package/lib/programmers/MigrateApiFunctionProgrammer.d.ts +2 -8
  18. package/lib/programmers/MigrateApiFunctionProgrammer.js +33 -30
  19. package/lib/programmers/MigrateApiFunctionProgrammer.js.map +1 -1
  20. package/lib/programmers/MigrateApiNamespaceProgrammer.d.ts +2 -8
  21. package/lib/programmers/MigrateApiNamespaceProgrammer.js +31 -37
  22. package/lib/programmers/MigrateApiNamespaceProgrammer.js.map +1 -1
  23. package/lib/programmers/MigrateApiProgrammer.js +19 -70
  24. package/lib/programmers/MigrateApiProgrammer.js.map +1 -1
  25. package/lib/programmers/MigrateApiSimulatationProgrammer.d.ts +2 -8
  26. package/lib/programmers/MigrateApiSimulatationProgrammer.js +16 -16
  27. package/lib/programmers/MigrateApiSimulatationProgrammer.js.map +1 -1
  28. package/lib/programmers/MigrateApiStartProgrammer.js +1 -1
  29. package/lib/programmers/MigrateApiStartProgrammer.js.map +1 -1
  30. package/lib/programmers/MigrateE2eProgrammer.js +1 -3
  31. package/lib/programmers/MigrateE2eProgrammer.js.map +1 -1
  32. package/lib/programmers/MigrateNestMethodProgrammer.js +4 -4
  33. package/lib/programmers/MigrateNestMethodProgrammer.js.map +1 -1
  34. package/lib/programmers/MigrateNestProgrammer.js +27 -23
  35. package/lib/programmers/MigrateNestProgrammer.js.map +1 -1
  36. package/lib/programmers/MigrateSchemaProgrammer.js +22 -22
  37. package/lib/structures/IMigrateProgram.d.ts +8 -8
  38. package/lib/structures/IMigrateRoute.d.ts +1 -46
  39. package/lib/utils/OpenApiTypeChecker.d.ts +1 -1
  40. package/lib/utils/StringUtil.d.ts +0 -4
  41. package/lib/utils/StringUtil.js +0 -31
  42. package/lib/utils/StringUtil.js.map +1 -1
  43. package/lib/utils/openapi-down-convert/RefVisitor.js +4 -5
  44. package/lib/utils/openapi-down-convert/RefVisitor.js.map +1 -1
  45. package/package.json +8 -8
  46. package/src/MigrateApplication.ts +3 -2
  47. package/src/analyzers/MigrateAnalyzer.ts +10 -5
  48. package/src/analyzers/MigrateControllerAnalyzer.ts +17 -122
  49. package/src/bundles/NEST_TEMPLATE.ts +3 -3
  50. package/src/bundles/SDK_TEMPLATE.ts +1 -1
  51. package/src/internal/MigrateCommander.ts +8 -2
  52. package/src/programmers/MigrateApiFileProgrammer.ts +10 -14
  53. package/src/programmers/MigrateApiFunctionProgrammer.ts +43 -41
  54. package/src/programmers/MigrateApiNamespaceProgrammer.ts +33 -51
  55. package/src/programmers/MigrateApiProgrammer.ts +26 -95
  56. package/src/programmers/MigrateApiSimulatationProgrammer.ts +17 -25
  57. package/src/programmers/MigrateApiStartProgrammer.ts +1 -1
  58. package/src/programmers/MigrateE2eProgrammer.ts +1 -3
  59. package/src/programmers/MigrateNestMethodProgrammer.ts +4 -4
  60. package/src/programmers/MigrateNestProgrammer.ts +10 -4
  61. package/src/structures/IMigrateProgram.ts +8 -8
  62. package/src/structures/IMigrateRoute.ts +1 -51
  63. package/src/utils/StringUtil.ts +0 -42
  64. package/lib/analyzers/MigrateMethodAnalyzer.d.ts +0 -9
  65. package/lib/analyzers/MigrateMethodAnalyzer.js +0 -304
  66. package/lib/analyzers/MigrateMethodAnalyzer.js.map +0 -1
  67. package/src/analyzers/MigrateMethodAnalyzer.ts +0 -387
@@ -1,387 +0,0 @@
1
- import { OpenApi } from "@samchon/openapi";
2
- import { Escaper } from "typia/lib/utils/Escaper";
3
-
4
- import { IMigrateProgram } from "../structures/IMigrateProgram";
5
- import { IMigrateRoute } from "../structures/IMigrateRoute";
6
- import { OpenApiTypeChecker } from "../utils/OpenApiTypeChecker";
7
- import { StringUtil } from "../utils/StringUtil";
8
-
9
- export namespace MigrateMethodAnalzyer {
10
- export const analyze =
11
- (props: Omit<IMigrateProgram.IProps, "dictionary">) =>
12
- (endpoint: { path: string; method: string }) =>
13
- (route: OpenApi.IOperation): IMigrateRoute | null => {
14
- const body = emplaceBodySchema("request")(
15
- emplaceReference(props.document)("body"),
16
- )(route.requestBody);
17
- const success = emplaceBodySchema("response")(
18
- emplaceReference(props.document)("response"),
19
- )(
20
- route.responses?.["201"] ??
21
- route.responses?.["200"] ??
22
- route.responses?.default,
23
- );
24
-
25
- const failures: string[] = [];
26
- if (body === false)
27
- failures.push(
28
- `supports only "application/json", "application/x-www-form-urlencoded", "multipart/form-data" and "text/plain" content type in the request body.`,
29
- );
30
- if (success === false)
31
- failures.push(
32
- `supports only "application/json", "application/x-www-form-urlencoded" and "text/plain" content type in the response body.`,
33
- );
34
- if (SUPPORTED_METHODS.has(endpoint.method.toUpperCase()) === false)
35
- failures.push(
36
- `does not support ${endpoint.method.toUpperCase()} method.`,
37
- );
38
-
39
- const [headers, query] = ["header", "query"].map((type) => {
40
- const parameters: OpenApi.IOperation.IParameter[] = (
41
- route.parameters ?? []
42
- ).filter((p) => p.in === type);
43
- if (parameters.length === 0) return null;
44
-
45
- const objects = parameters
46
- .map((p) =>
47
- OpenApiTypeChecker.isObject(p.schema)
48
- ? p.schema
49
- : OpenApiTypeChecker.isReference(p.schema) &&
50
- OpenApiTypeChecker.isObject(
51
- props.document.components.schemas?.[
52
- p.schema.$ref.replace(`#/components/schemas/`, ``)
53
- ] ?? {},
54
- )
55
- ? p.schema
56
- : null!,
57
- )
58
- .filter((s) => !!s);
59
- const primitives = parameters.filter(
60
- (p) =>
61
- OpenApiTypeChecker.isBoolean(p.schema) ||
62
- OpenApiTypeChecker.isInteger(p.schema) ||
63
- OpenApiTypeChecker.isNumber(p.schema) ||
64
- OpenApiTypeChecker.isString(p.schema) ||
65
- OpenApiTypeChecker.isArray(p.schema),
66
- );
67
- if (objects.length === 1 && primitives.length === 0) return objects[0];
68
- else if (objects.length > 1) {
69
- failures.push(
70
- `${type} typed parameters must be only one object type`,
71
- );
72
- return false;
73
- }
74
-
75
- const dto: OpenApi.IJsonSchema.IObject | null = objects[0]
76
- ? OpenApiTypeChecker.isObject(objects[0])
77
- ? objects[0]
78
- : ((props.document.components.schemas ?? {})[
79
- (objects[0] as OpenApi.IJsonSchema.IReference).$ref.replace(
80
- `#/components/schemas/`,
81
- ``,
82
- )
83
- ] as OpenApi.IJsonSchema.IObject)
84
- : null;
85
- const entire: OpenApi.IJsonSchema.IObject[] = [
86
- ...objects.map((o) =>
87
- OpenApiTypeChecker.isObject(o)
88
- ? o
89
- : (props.document.components.schemas?.[
90
- o.$ref.replace(`#/components/schemas/`, ``)
91
- ]! as OpenApi.IJsonSchema.IObject),
92
- ),
93
- {
94
- type: "object",
95
- properties: Object.fromEntries([
96
- ...primitives.map((p) => [
97
- p.name,
98
- {
99
- ...p.schema,
100
- description: p.schema.description ?? p.description,
101
- },
102
- ]),
103
- ...(dto ? Object.entries(dto.properties ?? {}) : []),
104
- ]),
105
- required: [
106
- ...primitives.filter((p) => p.required).map((p) => p.name!),
107
- ...(dto ? dto.required ?? [] : []),
108
- ],
109
- },
110
- ];
111
- return parameters.length === 0
112
- ? null
113
- : emplaceReference(props.document)(
114
- StringUtil.pascal(`I/Api/${endpoint.path}`) +
115
- "." +
116
- StringUtil.pascal(`${endpoint.method}/${type}`),
117
- )({
118
- type: "object",
119
- properties: Object.fromEntries([
120
- ...new Map<string, OpenApi.IJsonSchema>(
121
- entire
122
- .map((o) =>
123
- Object.entries(o.properties ?? {}).map(
124
- ([name, schema]) =>
125
- [
126
- name,
127
- {
128
- ...schema,
129
- description:
130
- schema.description ?? schema.description,
131
- } as OpenApi.IJsonSchema,
132
- ] as const,
133
- ),
134
- )
135
- .flat(),
136
- ),
137
- ]),
138
- required: [
139
- ...new Set(entire.map((o) => o.required ?? []).flat()),
140
- ],
141
- });
142
- });
143
-
144
- const parameterNames: string[] = StringUtil.splitWithNormalization(
145
- endpoint.path,
146
- )
147
- .filter((str) => str[0] === "{" || str[0] === ":")
148
- .map((str) =>
149
- str[0] === "{" ? str.substring(1, str.length - 1) : str.substring(1),
150
- );
151
- const pathParameters: OpenApi.IOperation.IParameter[] = (
152
- route.parameters ?? []
153
- ).filter((p) => p.in === "path");
154
- if (parameterNames.length !== pathParameters.length)
155
- if (
156
- pathParameters.length < parameterNames.length &&
157
- pathParameters.every(
158
- (p) => p.name !== undefined && parameterNames.includes(p.name),
159
- )
160
- ) {
161
- for (const name of parameterNames)
162
- if (pathParameters.find((p) => p.name === name) === undefined)
163
- pathParameters.push({
164
- name,
165
- in: "path",
166
- schema: { type: "string" },
167
- });
168
- pathParameters.sort(
169
- (a, b) =>
170
- parameterNames.indexOf(a.name!) - parameterNames.indexOf(b.name!),
171
- );
172
- route.parameters = [
173
- ...pathParameters,
174
- ...(route.parameters ?? []).filter((p) => p.in !== "path"),
175
- ];
176
- } else
177
- failures.push(
178
- "number of path parameters are not matched with its full path.",
179
- );
180
- if (failures.length) {
181
- console.log(
182
- `Failed to migrate ${endpoint.method.toUpperCase()} ${endpoint.path}`,
183
- ...failures.map((f) => ` - ${f}`),
184
- );
185
- return null;
186
- }
187
- return {
188
- name: "@lazy",
189
- originalPath: endpoint.path,
190
- path: endpoint.path,
191
- method: endpoint.method,
192
- accessor: ["@lazy"],
193
- headers: headers
194
- ? {
195
- name: "headers",
196
- key: "headers",
197
- schema: headers,
198
- }
199
- : null,
200
- parameters: (route.parameters ?? [])
201
- .filter((p) => p.in === "path")
202
- .map((p, i) => ({
203
- name: parameterNames[i],
204
- key: (() => {
205
- let key: string = StringUtil.normalize(parameterNames[i]);
206
- if (Escaper.variable(key)) return key;
207
- while (true) {
208
- key = "_" + key;
209
- if (!parameterNames.some((s) => s === key)) return key;
210
- }
211
- })(),
212
- schema: {
213
- ...p!.schema,
214
- description: p!.schema.description ?? p!.description,
215
- },
216
- })),
217
- query: query
218
- ? {
219
- name: "query",
220
- key: "query",
221
- schema: query,
222
- }
223
- : null,
224
- body: body as IMigrateRoute.IBody | null,
225
- success: success as IMigrateRoute.IBody | null,
226
- exceptions: Object.fromEntries(
227
- Object.entries(route.responses ?? {})
228
- .filter(
229
- ([key]) => key !== "200" && key !== "201" && key !== "default",
230
- )
231
- .map(([key, value]) => [
232
- key,
233
- {
234
- description: value.description,
235
- schema: value.content?.["application/json"]?.schema ?? {},
236
- },
237
- ]),
238
- ),
239
- deprecated: route.deprecated ?? false,
240
- comment: () => describe(route),
241
- tags: route.tags ?? [],
242
- };
243
- };
244
-
245
- const describe = (route: OpenApi.IOperation): string => {
246
- const commentTags: string[] = [];
247
- const add = (text: string) => {
248
- if (commentTags.every((line) => line !== text)) commentTags.push(text);
249
- };
250
-
251
- let description: string = route.description ?? "";
252
- if (route.summary) {
253
- const emended: string = route.summary.endsWith(".")
254
- ? route.summary
255
- : route.summary + ".";
256
- if (!!description.length && !description.startsWith(route.summary))
257
- description = `${emended}\n${description}`;
258
- }
259
- for (const p of route.parameters ?? [])
260
- if (p.description) add(`@param ${p.name} ${p.description}`);
261
- if (route.requestBody?.description)
262
- add(`@param body ${route.requestBody.description}`);
263
- for (const security of route.security ?? [])
264
- for (const [name, scopes] of Object.entries(security))
265
- add(`@security ${[name, ...scopes].join("")}`);
266
- if (route.tags) route.tags.forEach((name) => add(`@tag ${name}`));
267
- if (route.deprecated) add("@deprecated");
268
- return description.length
269
- ? commentTags.length
270
- ? `${description}\n\n${commentTags.join("\n")}`
271
- : description
272
- : commentTags.join("\n");
273
- };
274
-
275
- const isNotObjectLiteral = (schema: OpenApi.IJsonSchema): boolean =>
276
- OpenApiTypeChecker.isReference(schema) ||
277
- OpenApiTypeChecker.isBoolean(schema) ||
278
- OpenApiTypeChecker.isNumber(schema) ||
279
- OpenApiTypeChecker.isString(schema) ||
280
- OpenApiTypeChecker.isUnknown(schema) ||
281
- (OpenApiTypeChecker.isOneOf(schema) &&
282
- schema.oneOf.every(isNotObjectLiteral)) ||
283
- (OpenApiTypeChecker.isArray(schema) && isNotObjectLiteral(schema.items));
284
-
285
- const emplaceBodySchema =
286
- (from: "request" | "response") =>
287
- (
288
- emplacer: (schema: OpenApi.IJsonSchema) => OpenApi.IJsonSchema.IReference,
289
- ) =>
290
- (meta?: {
291
- description?: string;
292
- content?: Partial<Record<string, OpenApi.IOperation.IMediaType>>; // ISwaggerRouteBodyContent;
293
- "x-nestia-encrypted"?: boolean;
294
- }): false | null | IMigrateRoute.IBody => {
295
- if (!meta?.content) return null;
296
-
297
- const entries: [string, OpenApi.IOperation.IMediaType][] = Object.entries(
298
- meta.content,
299
- ).filter(([_, v]) => !!v?.schema) as [
300
- string,
301
- OpenApi.IOperation.IMediaType,
302
- ][];
303
- const json = entries.find((e) =>
304
- meta["x-nestia-encrypted"] === true
305
- ? e[0].includes("text/plain") || e[0].includes("application/json")
306
- : e[0].includes("application/json") || e[0].includes("*/*"),
307
- );
308
- if (json) {
309
- const { schema } = json[1];
310
- return {
311
- type: "application/json",
312
- name: "body",
313
- key: "body",
314
- schema: schema
315
- ? isNotObjectLiteral(schema)
316
- ? schema
317
- : emplacer(schema)
318
- : {},
319
- "x-nestia-encrypted": meta["x-nestia-encrypted"],
320
- };
321
- }
322
-
323
- const query = entries.find((e) =>
324
- e[0].includes("application/x-www-form-urlencoded"),
325
- );
326
- if (query) {
327
- const { schema } = query[1];
328
- return {
329
- type: "application/x-www-form-urlencoded",
330
- name: "body",
331
- key: "body",
332
- schema: schema
333
- ? isNotObjectLiteral(schema)
334
- ? schema
335
- : emplacer(schema)
336
- : {},
337
- };
338
- }
339
-
340
- const text = entries.find((e) => e[0].includes("text/plain"));
341
- if (text)
342
- return {
343
- type: "text/plain",
344
- name: "body",
345
- key: "body",
346
- schema: { type: "string" },
347
- };
348
-
349
- if (from === "request") {
350
- const multipart = entries.find((e) =>
351
- e[0].includes("multipart/form-data"),
352
- );
353
- if (multipart) {
354
- const { schema } = multipart[1];
355
- return {
356
- type: "multipart/form-data",
357
- name: "body",
358
- key: "body",
359
- schema: schema
360
- ? isNotObjectLiteral(schema)
361
- ? schema
362
- : emplacer(schema)
363
- : {},
364
- };
365
- }
366
- }
367
- return false;
368
- };
369
-
370
- const emplaceReference =
371
- (swagger: OpenApi.IDocument) =>
372
- (name: string) =>
373
- (schema: OpenApi.IJsonSchema): OpenApi.IJsonSchema.IReference => {
374
- swagger.components.schemas ??= {};
375
- swagger.components.schemas[name] = schema;
376
- return { $ref: `#/components/schemas/${name}` };
377
- };
378
- }
379
-
380
- const SUPPORTED_METHODS: Set<string> = new Set([
381
- "GET",
382
- "POST",
383
- "PUT",
384
- "PATCH",
385
- "DELETE",
386
- "HEAD",
387
- ]);