@nestia/migrate 4.6.1-dev.20250117 → 4.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 (49) hide show
  1. package/README.md +87 -87
  2. package/lib/bundles/NEST_TEMPLATE.js +66 -66
  3. package/lib/bundles/NEST_TEMPLATE.js.map +1 -1
  4. package/lib/bundles/SDK_TEMPLATE.js +30 -30
  5. package/lib/bundles/SDK_TEMPLATE.js.map +1 -1
  6. package/lib/index.mjs +92 -92
  7. package/lib/utils/openapi-down-convert/converter.js +2 -2
  8. package/package.json +6 -6
  9. package/src/MigrateApplication.ts +107 -107
  10. package/src/analyzers/MigrateApplicationAnalyzer.ts +18 -18
  11. package/src/analyzers/MigrateControllerAnalyzer.ts +51 -51
  12. package/src/archivers/MigrateFileArchiver.ts +38 -38
  13. package/src/bundles/NEST_TEMPLATE.ts +66 -66
  14. package/src/bundles/SDK_TEMPLATE.ts +30 -30
  15. package/src/executable/bundle.js +125 -125
  16. package/src/executable/migrate.ts +7 -7
  17. package/src/factories/TypeLiteralFactory.ts +57 -57
  18. package/src/index.ts +4 -4
  19. package/src/internal/MigrateCommander.ts +86 -86
  20. package/src/internal/MigrateInquirer.ts +89 -89
  21. package/src/module.ts +8 -8
  22. package/src/programmers/MigrateApiFileProgrammer.ts +49 -49
  23. package/src/programmers/MigrateApiFunctionProgrammer.ts +210 -210
  24. package/src/programmers/MigrateApiNamespaceProgrammer.ts +417 -417
  25. package/src/programmers/MigrateApiProgrammer.ts +103 -103
  26. package/src/programmers/MigrateApiSimulatationProgrammer.ts +324 -324
  27. package/src/programmers/MigrateApiStartProgrammer.ts +194 -194
  28. package/src/programmers/MigrateDtoProgrammer.ts +87 -87
  29. package/src/programmers/MigrateE2eFileProgrammer.ts +117 -117
  30. package/src/programmers/MigrateE2eProgrammer.ts +34 -34
  31. package/src/programmers/MigrateImportProgrammer.ts +118 -118
  32. package/src/programmers/MigrateNestControllerProgrammer.ts +50 -50
  33. package/src/programmers/MigrateNestMethodProgrammer.ts +393 -393
  34. package/src/programmers/MigrateNestModuleProgrammer.ts +65 -65
  35. package/src/programmers/MigrateNestProgrammer.ts +81 -81
  36. package/src/programmers/MigrateSchemaProgrammer.ts +373 -373
  37. package/src/structures/IHttpMigrateController.ts +8 -8
  38. package/src/structures/IHttpMigrateDto.ts +8 -8
  39. package/src/structures/IHttpMigrateFile.ts +5 -5
  40. package/src/structures/IHttpMigrateProgram.ts +27 -27
  41. package/src/structures/IHttpMigrateRoute.ts +1 -1
  42. package/src/structures/IHttpMigrateSchema.ts +4 -4
  43. package/src/utils/FilePrinter.ts +36 -36
  44. package/src/utils/MapUtil.ts +13 -13
  45. package/src/utils/OpenApiTypeChecker.ts +73 -73
  46. package/src/utils/SetupWizard.ts +12 -12
  47. package/src/utils/StringUtil.ts +113 -113
  48. package/src/utils/openapi-down-convert/RefVisitor.ts +139 -139
  49. package/src/utils/openapi-down-convert/converter.ts +527 -527
@@ -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
+ }