@nestia/migrate 4.6.0 → 4.6.1-dev.20250117
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.
- package/README.md +87 -87
- package/lib/bundles/NEST_TEMPLATE.js +66 -66
- package/lib/bundles/NEST_TEMPLATE.js.map +1 -1
- package/lib/bundles/SDK_TEMPLATE.js +30 -30
- package/lib/bundles/SDK_TEMPLATE.js.map +1 -1
- package/lib/index.mjs +92 -92
- package/lib/utils/openapi-down-convert/converter.js +2 -2
- package/package.json +6 -6
- package/src/MigrateApplication.ts +107 -107
- package/src/analyzers/MigrateApplicationAnalyzer.ts +18 -18
- package/src/analyzers/MigrateControllerAnalyzer.ts +51 -51
- package/src/archivers/MigrateFileArchiver.ts +38 -38
- package/src/bundles/NEST_TEMPLATE.ts +66 -66
- package/src/bundles/SDK_TEMPLATE.ts +30 -30
- package/src/executable/bundle.js +125 -125
- package/src/executable/migrate.ts +7 -7
- package/src/factories/TypeLiteralFactory.ts +57 -57
- package/src/index.ts +4 -4
- package/src/internal/MigrateCommander.ts +86 -86
- package/src/internal/MigrateInquirer.ts +89 -89
- package/src/module.ts +8 -8
- package/src/programmers/MigrateApiFileProgrammer.ts +49 -49
- package/src/programmers/MigrateApiFunctionProgrammer.ts +210 -210
- package/src/programmers/MigrateApiNamespaceProgrammer.ts +417 -417
- package/src/programmers/MigrateApiProgrammer.ts +103 -103
- package/src/programmers/MigrateApiSimulatationProgrammer.ts +324 -324
- package/src/programmers/MigrateApiStartProgrammer.ts +194 -194
- package/src/programmers/MigrateDtoProgrammer.ts +87 -87
- package/src/programmers/MigrateE2eFileProgrammer.ts +117 -117
- package/src/programmers/MigrateE2eProgrammer.ts +34 -34
- package/src/programmers/MigrateImportProgrammer.ts +118 -118
- package/src/programmers/MigrateNestControllerProgrammer.ts +50 -50
- package/src/programmers/MigrateNestMethodProgrammer.ts +393 -393
- package/src/programmers/MigrateNestModuleProgrammer.ts +65 -65
- package/src/programmers/MigrateNestProgrammer.ts +81 -81
- package/src/programmers/MigrateSchemaProgrammer.ts +373 -373
- package/src/structures/IHttpMigrateController.ts +8 -8
- package/src/structures/IHttpMigrateDto.ts +8 -8
- package/src/structures/IHttpMigrateFile.ts +5 -5
- package/src/structures/IHttpMigrateProgram.ts +27 -27
- package/src/structures/IHttpMigrateRoute.ts +1 -1
- package/src/structures/IHttpMigrateSchema.ts +4 -4
- package/src/utils/FilePrinter.ts +36 -36
- package/src/utils/MapUtil.ts +13 -13
- package/src/utils/OpenApiTypeChecker.ts +73 -73
- package/src/utils/SetupWizard.ts +12 -12
- package/src/utils/StringUtil.ts +113 -113
- package/src/utils/openapi-down-convert/RefVisitor.ts +139 -139
- package/src/utils/openapi-down-convert/converter.ts +527 -527
package/src/executable/bundle.js
CHANGED
@@ -1,125 +1,125 @@
|
|
1
|
-
const { version } = require("../../../../package.json");
|
2
|
-
const cp = require("child_process");
|
3
|
-
const fs = require("fs");
|
4
|
-
|
5
|
-
const ROOT = `${__dirname}/../..`;
|
6
|
-
const ASSETS = `${ROOT}/assets`;
|
7
|
-
|
8
|
-
const update = (content) => {
|
9
|
-
const parsed = JSON.parse(content);
|
10
|
-
for (const record of [
|
11
|
-
parsed.dependencies ?? {},
|
12
|
-
parsed.devDependencies ?? {},
|
13
|
-
])
|
14
|
-
for (const key of Object.keys(record))
|
15
|
-
if (
|
16
|
-
key === "@nestia/core" ||
|
17
|
-
key === "@nestia/fetcher" ||
|
18
|
-
key === "@nestia/sdk"
|
19
|
-
)
|
20
|
-
record[key] = `^${version}`;
|
21
|
-
return JSON.stringify(parsed, null, 2);
|
22
|
-
};
|
23
|
-
|
24
|
-
const bundle = async ({ mode, repository, exceptions, transform }) => {
|
25
|
-
const root = `${__dirname}/../..`;
|
26
|
-
const assets = `${root}/assets`;
|
27
|
-
const template = `${assets}/${mode}`;
|
28
|
-
|
29
|
-
const clone = async () => {
|
30
|
-
// CLONE REPOSITORY
|
31
|
-
if (fs.existsSync(template))
|
32
|
-
await fs.promises.rm(template, { recursive: true });
|
33
|
-
else
|
34
|
-
try {
|
35
|
-
await fs.promises.mkdir(ASSETS);
|
36
|
-
} catch {}
|
37
|
-
|
38
|
-
cp.execSync(`git clone https://github.com/samchon/${repository} ${mode}`, {
|
39
|
-
cwd: ASSETS,
|
40
|
-
});
|
41
|
-
|
42
|
-
// REMOVE VUNLERABLE FILES
|
43
|
-
for (const location of exceptions ?? [])
|
44
|
-
await fs.promises.rm(`${template}/${location}`, { recursive: true });
|
45
|
-
};
|
46
|
-
|
47
|
-
const iterate = (collection) => async (location) => {
|
48
|
-
const directory = await fs.promises.readdir(location);
|
49
|
-
for (const file of directory) {
|
50
|
-
const absolute = location + "/" + file;
|
51
|
-
const stats = await fs.promises.stat(absolute);
|
52
|
-
if (stats.isDirectory()) await iterate(collection)(absolute);
|
53
|
-
else {
|
54
|
-
const content = await fs.promises.readFile(absolute, "utf-8");
|
55
|
-
collection.push({
|
56
|
-
location: (() => {
|
57
|
-
const str = location.replace(template, "");
|
58
|
-
return str[0] === "/" ? str.substring(1) : str;
|
59
|
-
})(),
|
60
|
-
file,
|
61
|
-
content,
|
62
|
-
});
|
63
|
-
}
|
64
|
-
}
|
65
|
-
};
|
66
|
-
|
67
|
-
const archive = async (collection) => {
|
68
|
-
const name = `${mode.toUpperCase()}_TEMPLATE`;
|
69
|
-
const body = JSON.stringify(collection, null, 2);
|
70
|
-
const content = `export const ${name} = ${body}`;
|
71
|
-
|
72
|
-
try {
|
73
|
-
await fs.promises.mkdir(`${ROOT}/src/bundles`);
|
74
|
-
} catch {}
|
75
|
-
await fs.promises.writeFile(
|
76
|
-
`${ROOT}/src/bundles/${name}.ts`,
|
77
|
-
content,
|
78
|
-
"utf8",
|
79
|
-
);
|
80
|
-
};
|
81
|
-
|
82
|
-
const collection = [];
|
83
|
-
await clone();
|
84
|
-
await iterate(collection)(template);
|
85
|
-
if (transform) for (const it of collection) transform(it);
|
86
|
-
await archive(collection);
|
87
|
-
};
|
88
|
-
|
89
|
-
const main = async () => {
|
90
|
-
await bundle({
|
91
|
-
mode: "nest",
|
92
|
-
repository: "nestia-start",
|
93
|
-
exceptions: [
|
94
|
-
".git",
|
95
|
-
".github/dependabot.yml",
|
96
|
-
"src/api/functional",
|
97
|
-
"src/controllers",
|
98
|
-
"src/MyModule.ts",
|
99
|
-
"src/providers",
|
100
|
-
"test/features",
|
101
|
-
],
|
102
|
-
transform: (it) => {
|
103
|
-
if (it.file === "package.json") it.content = update(it.content);
|
104
|
-
},
|
105
|
-
});
|
106
|
-
await bundle({
|
107
|
-
mode: "sdk",
|
108
|
-
repository: "nestia-sdk-template",
|
109
|
-
exceptions: [
|
110
|
-
".git",
|
111
|
-
".github/dependabot.yml",
|
112
|
-
".github/workflows/build.yml",
|
113
|
-
"src/functional",
|
114
|
-
"src/structures",
|
115
|
-
"test/features",
|
116
|
-
],
|
117
|
-
transform: (it) => {
|
118
|
-
if (it.file === "package.json") it.content = update(it.content);
|
119
|
-
},
|
120
|
-
});
|
121
|
-
};
|
122
|
-
main().catch((exp) => {
|
123
|
-
console.error(exp);
|
124
|
-
process.exit(-1);
|
125
|
-
});
|
1
|
+
const { version } = require("../../../../package.json");
|
2
|
+
const cp = require("child_process");
|
3
|
+
const fs = require("fs");
|
4
|
+
|
5
|
+
const ROOT = `${__dirname}/../..`;
|
6
|
+
const ASSETS = `${ROOT}/assets`;
|
7
|
+
|
8
|
+
const update = (content) => {
|
9
|
+
const parsed = JSON.parse(content);
|
10
|
+
for (const record of [
|
11
|
+
parsed.dependencies ?? {},
|
12
|
+
parsed.devDependencies ?? {},
|
13
|
+
])
|
14
|
+
for (const key of Object.keys(record))
|
15
|
+
if (
|
16
|
+
key === "@nestia/core" ||
|
17
|
+
key === "@nestia/fetcher" ||
|
18
|
+
key === "@nestia/sdk"
|
19
|
+
)
|
20
|
+
record[key] = `^${version}`;
|
21
|
+
return JSON.stringify(parsed, null, 2);
|
22
|
+
};
|
23
|
+
|
24
|
+
const bundle = async ({ mode, repository, exceptions, transform }) => {
|
25
|
+
const root = `${__dirname}/../..`;
|
26
|
+
const assets = `${root}/assets`;
|
27
|
+
const template = `${assets}/${mode}`;
|
28
|
+
|
29
|
+
const clone = async () => {
|
30
|
+
// CLONE REPOSITORY
|
31
|
+
if (fs.existsSync(template))
|
32
|
+
await fs.promises.rm(template, { recursive: true });
|
33
|
+
else
|
34
|
+
try {
|
35
|
+
await fs.promises.mkdir(ASSETS);
|
36
|
+
} catch {}
|
37
|
+
|
38
|
+
cp.execSync(`git clone https://github.com/samchon/${repository} ${mode}`, {
|
39
|
+
cwd: ASSETS,
|
40
|
+
});
|
41
|
+
|
42
|
+
// REMOVE VUNLERABLE FILES
|
43
|
+
for (const location of exceptions ?? [])
|
44
|
+
await fs.promises.rm(`${template}/${location}`, { recursive: true });
|
45
|
+
};
|
46
|
+
|
47
|
+
const iterate = (collection) => async (location) => {
|
48
|
+
const directory = await fs.promises.readdir(location);
|
49
|
+
for (const file of directory) {
|
50
|
+
const absolute = location + "/" + file;
|
51
|
+
const stats = await fs.promises.stat(absolute);
|
52
|
+
if (stats.isDirectory()) await iterate(collection)(absolute);
|
53
|
+
else {
|
54
|
+
const content = await fs.promises.readFile(absolute, "utf-8");
|
55
|
+
collection.push({
|
56
|
+
location: (() => {
|
57
|
+
const str = location.replace(template, "");
|
58
|
+
return str[0] === "/" ? str.substring(1) : str;
|
59
|
+
})(),
|
60
|
+
file,
|
61
|
+
content,
|
62
|
+
});
|
63
|
+
}
|
64
|
+
}
|
65
|
+
};
|
66
|
+
|
67
|
+
const archive = async (collection) => {
|
68
|
+
const name = `${mode.toUpperCase()}_TEMPLATE`;
|
69
|
+
const body = JSON.stringify(collection, null, 2);
|
70
|
+
const content = `export const ${name} = ${body}`;
|
71
|
+
|
72
|
+
try {
|
73
|
+
await fs.promises.mkdir(`${ROOT}/src/bundles`);
|
74
|
+
} catch {}
|
75
|
+
await fs.promises.writeFile(
|
76
|
+
`${ROOT}/src/bundles/${name}.ts`,
|
77
|
+
content,
|
78
|
+
"utf8",
|
79
|
+
);
|
80
|
+
};
|
81
|
+
|
82
|
+
const collection = [];
|
83
|
+
await clone();
|
84
|
+
await iterate(collection)(template);
|
85
|
+
if (transform) for (const it of collection) transform(it);
|
86
|
+
await archive(collection);
|
87
|
+
};
|
88
|
+
|
89
|
+
const main = async () => {
|
90
|
+
await bundle({
|
91
|
+
mode: "nest",
|
92
|
+
repository: "nestia-start",
|
93
|
+
exceptions: [
|
94
|
+
".git",
|
95
|
+
".github/dependabot.yml",
|
96
|
+
"src/api/functional",
|
97
|
+
"src/controllers",
|
98
|
+
"src/MyModule.ts",
|
99
|
+
"src/providers",
|
100
|
+
"test/features",
|
101
|
+
],
|
102
|
+
transform: (it) => {
|
103
|
+
if (it.file === "package.json") it.content = update(it.content);
|
104
|
+
},
|
105
|
+
});
|
106
|
+
await bundle({
|
107
|
+
mode: "sdk",
|
108
|
+
repository: "nestia-sdk-template",
|
109
|
+
exceptions: [
|
110
|
+
".git",
|
111
|
+
".github/dependabot.yml",
|
112
|
+
".github/workflows/build.yml",
|
113
|
+
"src/functional",
|
114
|
+
"src/structures",
|
115
|
+
"test/features",
|
116
|
+
],
|
117
|
+
transform: (it) => {
|
118
|
+
if (it.file === "package.json") it.content = update(it.content);
|
119
|
+
},
|
120
|
+
});
|
121
|
+
};
|
122
|
+
main().catch((exp) => {
|
123
|
+
console.error(exp);
|
124
|
+
process.exit(-1);
|
125
|
+
});
|
@@ -1,7 +1,7 @@
|
|
1
|
-
#!/usr/bin/env node
|
2
|
-
import { MigrateCommander } from "../internal/MigrateCommander";
|
3
|
-
|
4
|
-
MigrateCommander.main().catch((exp) => {
|
5
|
-
console.error(exp);
|
6
|
-
process.exit(-1);
|
7
|
-
});
|
1
|
+
#!/usr/bin/env node
|
2
|
+
import { MigrateCommander } from "../internal/MigrateCommander";
|
3
|
+
|
4
|
+
MigrateCommander.main().catch((exp) => {
|
5
|
+
console.error(exp);
|
6
|
+
process.exit(-1);
|
7
|
+
});
|
@@ -1,57 +1,57 @@
|
|
1
|
-
import ts from "typescript";
|
2
|
-
import { Escaper } from "typia/lib/utils/Escaper";
|
3
|
-
|
4
|
-
export namespace TypeLiteralFactory {
|
5
|
-
export const generate = (value: any): ts.TypeNode =>
|
6
|
-
typeof value === "boolean"
|
7
|
-
? generateBoolean(value)
|
8
|
-
: typeof value === "number"
|
9
|
-
? generateNumber(value)
|
10
|
-
: typeof value === "string"
|
11
|
-
? generatestring(value)
|
12
|
-
: typeof value === "object"
|
13
|
-
? value === null
|
14
|
-
? generateNull()
|
15
|
-
: Array.isArray(value)
|
16
|
-
? generateTuple(value)
|
17
|
-
: generateObject(value)
|
18
|
-
: ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
|
19
|
-
|
20
|
-
const generatestring = (str: string) =>
|
21
|
-
ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(str));
|
22
|
-
|
23
|
-
const generateNumber = (num: number) =>
|
24
|
-
ts.factory.createLiteralTypeNode(
|
25
|
-
num < 0
|
26
|
-
? ts.factory.createPrefixUnaryExpression(
|
27
|
-
ts.SyntaxKind.MinusToken,
|
28
|
-
ts.factory.createNumericLiteral(-num),
|
29
|
-
)
|
30
|
-
: ts.factory.createNumericLiteral(num),
|
31
|
-
);
|
32
|
-
|
33
|
-
const generateBoolean = (bool: boolean) =>
|
34
|
-
ts.factory.createLiteralTypeNode(
|
35
|
-
bool ? ts.factory.createTrue() : ts.factory.createFalse(),
|
36
|
-
);
|
37
|
-
|
38
|
-
const generateNull = () =>
|
39
|
-
ts.factory.createLiteralTypeNode(ts.factory.createNull());
|
40
|
-
|
41
|
-
const generateTuple = (items: any[]) =>
|
42
|
-
ts.factory.createTupleTypeNode(items.map(generate));
|
43
|
-
|
44
|
-
const generateObject = (obj: object) =>
|
45
|
-
ts.factory.createTypeLiteralNode(
|
46
|
-
Object.entries(obj).map(([key, value]) =>
|
47
|
-
ts.factory.createPropertySignature(
|
48
|
-
undefined,
|
49
|
-
Escaper.variable(key)
|
50
|
-
? ts.factory.createIdentifier(key)
|
51
|
-
: ts.factory.createStringLiteral(key),
|
52
|
-
undefined,
|
53
|
-
generate(value),
|
54
|
-
),
|
55
|
-
),
|
56
|
-
);
|
57
|
-
}
|
1
|
+
import ts from "typescript";
|
2
|
+
import { Escaper } from "typia/lib/utils/Escaper";
|
3
|
+
|
4
|
+
export namespace TypeLiteralFactory {
|
5
|
+
export const generate = (value: any): ts.TypeNode =>
|
6
|
+
typeof value === "boolean"
|
7
|
+
? generateBoolean(value)
|
8
|
+
: typeof value === "number"
|
9
|
+
? generateNumber(value)
|
10
|
+
: typeof value === "string"
|
11
|
+
? generatestring(value)
|
12
|
+
: typeof value === "object"
|
13
|
+
? value === null
|
14
|
+
? generateNull()
|
15
|
+
: Array.isArray(value)
|
16
|
+
? generateTuple(value)
|
17
|
+
: generateObject(value)
|
18
|
+
: ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
|
19
|
+
|
20
|
+
const generatestring = (str: string) =>
|
21
|
+
ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(str));
|
22
|
+
|
23
|
+
const generateNumber = (num: number) =>
|
24
|
+
ts.factory.createLiteralTypeNode(
|
25
|
+
num < 0
|
26
|
+
? ts.factory.createPrefixUnaryExpression(
|
27
|
+
ts.SyntaxKind.MinusToken,
|
28
|
+
ts.factory.createNumericLiteral(-num),
|
29
|
+
)
|
30
|
+
: ts.factory.createNumericLiteral(num),
|
31
|
+
);
|
32
|
+
|
33
|
+
const generateBoolean = (bool: boolean) =>
|
34
|
+
ts.factory.createLiteralTypeNode(
|
35
|
+
bool ? ts.factory.createTrue() : ts.factory.createFalse(),
|
36
|
+
);
|
37
|
+
|
38
|
+
const generateNull = () =>
|
39
|
+
ts.factory.createLiteralTypeNode(ts.factory.createNull());
|
40
|
+
|
41
|
+
const generateTuple = (items: any[]) =>
|
42
|
+
ts.factory.createTupleTypeNode(items.map(generate));
|
43
|
+
|
44
|
+
const generateObject = (obj: object) =>
|
45
|
+
ts.factory.createTypeLiteralNode(
|
46
|
+
Object.entries(obj).map(([key, value]) =>
|
47
|
+
ts.factory.createPropertySignature(
|
48
|
+
undefined,
|
49
|
+
Escaper.variable(key)
|
50
|
+
? ts.factory.createIdentifier(key)
|
51
|
+
: ts.factory.createStringLiteral(key),
|
52
|
+
undefined,
|
53
|
+
generate(value),
|
54
|
+
),
|
55
|
+
),
|
56
|
+
);
|
57
|
+
}
|
package/src/index.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import * as migrate from "./module";
|
2
|
-
|
3
|
-
export default migrate;
|
4
|
-
export * from "./module";
|
1
|
+
import * as migrate from "./module";
|
2
|
+
|
3
|
+
export default migrate;
|
4
|
+
export * from "./module";
|
@@ -1,86 +1,86 @@
|
|
1
|
-
import { OpenApiV3, OpenApiV3_1, SwaggerV2 } from "@samchon/openapi";
|
2
|
-
import fs from "fs";
|
3
|
-
import path from "path";
|
4
|
-
import { format } from "prettier";
|
5
|
-
import typia, { IValidation, tags } from "typia";
|
6
|
-
|
7
|
-
import { MigrateApplication } from "../MigrateApplication";
|
8
|
-
import { MigrateFileArchiver } from "../archivers/MigrateFileArchiver";
|
9
|
-
import { MigrateInquirer } from "./MigrateInquirer";
|
10
|
-
|
11
|
-
export namespace MigrateCommander {
|
12
|
-
export const main = async (): Promise<void> => {
|
13
|
-
const resolve = (str: string | undefined) =>
|
14
|
-
str ? path.resolve(str).split("\\").join("/") : undefined;
|
15
|
-
const options: MigrateInquirer.IOutput = await MigrateInquirer.parse();
|
16
|
-
|
17
|
-
// VALIDATE OUTPUT DIRECTORY
|
18
|
-
const parent: string = resolve(options.output + "/..")!;
|
19
|
-
if (fs.existsSync(options.output)) halt("Output directory already exists.");
|
20
|
-
else if (fs.existsSync(parent) === false)
|
21
|
-
halt("Output directory's parent directory does not exist.");
|
22
|
-
else if (fs.statSync(parent).isDirectory() === false)
|
23
|
-
halt("Output directory's parent is not a directory.");
|
24
|
-
|
25
|
-
// READ SWAGGER
|
26
|
-
const document:
|
27
|
-
| SwaggerV2.IDocument
|
28
|
-
| OpenApiV3.IDocument
|
29
|
-
| OpenApiV3_1.IDocument = await (async () => {
|
30
|
-
if (typia.is<string & tags.Format<"uri">>(options.input)) {
|
31
|
-
const response: Response = await fetch(options.input);
|
32
|
-
const content: string = await response.text();
|
33
|
-
return JSON.parse(content);
|
34
|
-
}
|
35
|
-
if (fs.existsSync(options.input) === false)
|
36
|
-
halt("Unable to find the input swagger.json file.");
|
37
|
-
const stats: fs.Stats = fs.statSync(options.input);
|
38
|
-
if (stats.isFile() === false)
|
39
|
-
halt("The input swagger.json is not a file.");
|
40
|
-
const content: string = await fs.promises.readFile(
|
41
|
-
options.input,
|
42
|
-
"utf-8",
|
43
|
-
);
|
44
|
-
return JSON.parse(content);
|
45
|
-
})();
|
46
|
-
|
47
|
-
const result: IValidation<MigrateApplication> =
|
48
|
-
MigrateApplication.create(document);
|
49
|
-
if (result.success === false) {
|
50
|
-
console.log(result.errors);
|
51
|
-
throw new Error(
|
52
|
-
`Invalid swagger file (must follow the OpenAPI 3.0 spec).`,
|
53
|
-
);
|
54
|
-
}
|
55
|
-
|
56
|
-
const app: MigrateApplication = result.data;
|
57
|
-
const program =
|
58
|
-
options.mode === "nest" ? app.nest(options) : app.sdk(options);
|
59
|
-
if (program.errors)
|
60
|
-
for (const error of program.errors)
|
61
|
-
console.error(
|
62
|
-
`Failed to migrate ${error.method} ${error.path}`,
|
63
|
-
...error.messages.map((msg) => ` - ${msg}`),
|
64
|
-
);
|
65
|
-
await MigrateFileArchiver.archive({
|
66
|
-
mkdir: fs.promises.mkdir,
|
67
|
-
writeFile: async (file, content) =>
|
68
|
-
fs.promises.writeFile(file, await beautify(content), "utf-8"),
|
69
|
-
})(options.output)(program.files);
|
70
|
-
};
|
71
|
-
|
72
|
-
const beautify = async (script: string): Promise<string> => {
|
73
|
-
try {
|
74
|
-
return await format(script, {
|
75
|
-
parser: "typescript",
|
76
|
-
});
|
77
|
-
} catch {
|
78
|
-
return script;
|
79
|
-
}
|
80
|
-
};
|
81
|
-
|
82
|
-
const halt = (desc: string): never => {
|
83
|
-
console.error(desc);
|
84
|
-
process.exit(-1);
|
85
|
-
};
|
86
|
-
}
|
1
|
+
import { OpenApiV3, OpenApiV3_1, SwaggerV2 } from "@samchon/openapi";
|
2
|
+
import fs from "fs";
|
3
|
+
import path from "path";
|
4
|
+
import { format } from "prettier";
|
5
|
+
import typia, { IValidation, tags } from "typia";
|
6
|
+
|
7
|
+
import { MigrateApplication } from "../MigrateApplication";
|
8
|
+
import { MigrateFileArchiver } from "../archivers/MigrateFileArchiver";
|
9
|
+
import { MigrateInquirer } from "./MigrateInquirer";
|
10
|
+
|
11
|
+
export namespace MigrateCommander {
|
12
|
+
export const main = async (): Promise<void> => {
|
13
|
+
const resolve = (str: string | undefined) =>
|
14
|
+
str ? path.resolve(str).split("\\").join("/") : undefined;
|
15
|
+
const options: MigrateInquirer.IOutput = await MigrateInquirer.parse();
|
16
|
+
|
17
|
+
// VALIDATE OUTPUT DIRECTORY
|
18
|
+
const parent: string = resolve(options.output + "/..")!;
|
19
|
+
if (fs.existsSync(options.output)) halt("Output directory already exists.");
|
20
|
+
else if (fs.existsSync(parent) === false)
|
21
|
+
halt("Output directory's parent directory does not exist.");
|
22
|
+
else if (fs.statSync(parent).isDirectory() === false)
|
23
|
+
halt("Output directory's parent is not a directory.");
|
24
|
+
|
25
|
+
// READ SWAGGER
|
26
|
+
const document:
|
27
|
+
| SwaggerV2.IDocument
|
28
|
+
| OpenApiV3.IDocument
|
29
|
+
| OpenApiV3_1.IDocument = await (async () => {
|
30
|
+
if (typia.is<string & tags.Format<"uri">>(options.input)) {
|
31
|
+
const response: Response = await fetch(options.input);
|
32
|
+
const content: string = await response.text();
|
33
|
+
return JSON.parse(content);
|
34
|
+
}
|
35
|
+
if (fs.existsSync(options.input) === false)
|
36
|
+
halt("Unable to find the input swagger.json file.");
|
37
|
+
const stats: fs.Stats = fs.statSync(options.input);
|
38
|
+
if (stats.isFile() === false)
|
39
|
+
halt("The input swagger.json is not a file.");
|
40
|
+
const content: string = await fs.promises.readFile(
|
41
|
+
options.input,
|
42
|
+
"utf-8",
|
43
|
+
);
|
44
|
+
return JSON.parse(content);
|
45
|
+
})();
|
46
|
+
|
47
|
+
const result: IValidation<MigrateApplication> =
|
48
|
+
MigrateApplication.create(document);
|
49
|
+
if (result.success === false) {
|
50
|
+
console.log(result.errors);
|
51
|
+
throw new Error(
|
52
|
+
`Invalid swagger file (must follow the OpenAPI 3.0 spec).`,
|
53
|
+
);
|
54
|
+
}
|
55
|
+
|
56
|
+
const app: MigrateApplication = result.data;
|
57
|
+
const program =
|
58
|
+
options.mode === "nest" ? app.nest(options) : app.sdk(options);
|
59
|
+
if (program.errors)
|
60
|
+
for (const error of program.errors)
|
61
|
+
console.error(
|
62
|
+
`Failed to migrate ${error.method} ${error.path}`,
|
63
|
+
...error.messages.map((msg) => ` - ${msg}`),
|
64
|
+
);
|
65
|
+
await MigrateFileArchiver.archive({
|
66
|
+
mkdir: fs.promises.mkdir,
|
67
|
+
writeFile: async (file, content) =>
|
68
|
+
fs.promises.writeFile(file, await beautify(content), "utf-8"),
|
69
|
+
})(options.output)(program.files);
|
70
|
+
};
|
71
|
+
|
72
|
+
const beautify = async (script: string): Promise<string> => {
|
73
|
+
try {
|
74
|
+
return await format(script, {
|
75
|
+
parser: "typescript",
|
76
|
+
});
|
77
|
+
} catch {
|
78
|
+
return script;
|
79
|
+
}
|
80
|
+
};
|
81
|
+
|
82
|
+
const halt = (desc: string): never => {
|
83
|
+
console.error(desc);
|
84
|
+
process.exit(-1);
|
85
|
+
};
|
86
|
+
}
|