@nestia/sdk 1.1.1 → 1.2.0-dev.20230504

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 (79) hide show
  1. package/assets/bundle/api/index.ts +4 -0
  2. package/assets/bundle/api/module.ts +5 -0
  3. package/assets/bundle/e2e/index.ts +41 -0
  4. package/lib/INestiaConfig.d.ts +6 -0
  5. package/lib/NestiaSdkApplication.d.ts +1 -0
  6. package/lib/NestiaSdkApplication.js +35 -14
  7. package/lib/NestiaSdkApplication.js.map +1 -1
  8. package/lib/analyses/ControllerAnalyzer.js +1 -0
  9. package/lib/analyses/ControllerAnalyzer.js.map +1 -1
  10. package/lib/analyses/ReflectAnalyzer.js +12 -1
  11. package/lib/analyses/ReflectAnalyzer.js.map +1 -1
  12. package/lib/executable/internal/NestiaSdkCommand.d.ts +3 -2
  13. package/lib/executable/internal/NestiaSdkCommand.js +52 -56
  14. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  15. package/lib/executable/internal/NestiaSdkConfig.js +5 -1
  16. package/lib/executable/internal/NestiaSdkConfig.js.map +1 -1
  17. package/lib/executable/sdk.js +5 -8
  18. package/lib/executable/sdk.js.map +1 -1
  19. package/lib/generates/E2eGenerator.d.ts +5 -0
  20. package/lib/generates/E2eGenerator.js +52 -0
  21. package/lib/generates/E2eGenerator.js.map +1 -0
  22. package/lib/generates/SdkGenerator.d.ts +1 -2
  23. package/lib/generates/SdkGenerator.js +20 -22
  24. package/lib/generates/SdkGenerator.js.map +1 -1
  25. package/lib/generates/SwaggerGenerator.d.ts +1 -1
  26. package/lib/generates/SwaggerGenerator.js +40 -43
  27. package/lib/generates/SwaggerGenerator.js.map +1 -1
  28. package/lib/generates/internal/E2eFileProgrammer.d.ts +8 -0
  29. package/lib/generates/internal/E2eFileProgrammer.js +101 -0
  30. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -0
  31. package/lib/generates/internal/SdkFileProgrammer.d.ts +5 -0
  32. package/lib/generates/internal/SdkFileProgrammer.js +121 -0
  33. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -0
  34. package/lib/generates/internal/SdkFunctionProgrammer.d.ts +5 -0
  35. package/lib/generates/{FunctionGenerator.js → internal/SdkFunctionProgrammer.js} +58 -57
  36. package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -0
  37. package/lib/generates/internal/SdkRouteDirectory.d.ts +10 -0
  38. package/lib/generates/internal/SdkRouteDirectory.js +18 -0
  39. package/lib/generates/internal/SdkRouteDirectory.js.map +1 -0
  40. package/lib/structures/IController.d.ts +4 -0
  41. package/lib/structures/IRoute.d.ts +4 -0
  42. package/lib/utils/NestiaConfigUtil.d.ts +4 -0
  43. package/lib/utils/NestiaConfigUtil.js +24 -0
  44. package/lib/utils/NestiaConfigUtil.js.map +1 -0
  45. package/lib/utils/SourceFinder.d.ts +9 -0
  46. package/lib/utils/SourceFinder.js +60 -0
  47. package/lib/utils/SourceFinder.js.map +1 -0
  48. package/package.json +2 -3
  49. package/src/INestiaConfig.ts +7 -0
  50. package/src/NestiaSdkApplication.ts +54 -17
  51. package/src/analyses/ControllerAnalyzer.ts +1 -0
  52. package/src/analyses/ReflectAnalyzer.ts +12 -2
  53. package/src/executable/internal/NestiaSdkCommand.ts +87 -105
  54. package/src/executable/sdk.ts +4 -8
  55. package/src/generates/E2eGenerator.ts +65 -0
  56. package/src/generates/SdkGenerator.ts +29 -30
  57. package/src/generates/SwaggerGenerator.ts +66 -64
  58. package/src/generates/internal/E2eFileProgrammer.ts +119 -0
  59. package/src/generates/internal/SdkFileProgrammer.ts +144 -0
  60. package/src/generates/internal/SdkFunctionProgrammer.ts +371 -0
  61. package/src/generates/internal/SdkRouteDirectory.ts +21 -0
  62. package/src/structures/IController.ts +4 -0
  63. package/src/structures/IRoute.ts +4 -0
  64. package/src/utils/NestiaConfigUtil.ts +21 -0
  65. package/src/utils/SourceFinder.ts +60 -0
  66. package/lib/analyses/SourceFinder.d.ts +0 -4
  67. package/lib/analyses/SourceFinder.js +0 -71
  68. package/lib/analyses/SourceFinder.js.map +0 -1
  69. package/lib/generates/FileGenerator.d.ts +0 -5
  70. package/lib/generates/FileGenerator.js +0 -138
  71. package/lib/generates/FileGenerator.js.map +0 -1
  72. package/lib/generates/FunctionGenerator.d.ts +0 -5
  73. package/lib/generates/FunctionGenerator.js.map +0 -1
  74. package/src/analyses/SourceFinder.ts +0 -59
  75. package/src/generates/FileGenerator.ts +0 -156
  76. package/src/generates/FunctionGenerator.ts +0 -348
  77. /package/assets/bundle/{HttpError.ts → api/HttpError.ts} +0 -0
  78. /package/assets/bundle/{IConnection.ts → api/IConnection.ts} +0 -0
  79. /package/assets/bundle/{Primitive.ts → api/Primitive.ts} +0 -0
@@ -11,99 +11,83 @@ import { NestiaSdkConfig } from "./NestiaSdkConfig";
11
11
  interface ICommand {
12
12
  exclude: string | null;
13
13
  out: string | null;
14
+ e2e: string | null;
14
15
  }
15
16
 
16
- interface IOutput {
17
+ interface IProps {
17
18
  assign: (config: INestiaConfig, output: string) => void;
18
19
  validate: (config: INestiaConfig) => boolean;
19
20
  location: (config: INestiaConfig) => string;
20
21
  }
21
22
 
22
23
  export namespace NestiaSdkCommand {
23
- export function sdk(
24
- elements: string[],
25
- pure: boolean = true,
26
- ): Promise<void> {
27
- return main(
28
- (app) => app.sdk(),
29
- {
30
- assign: (config, output) => (config.output = output),
31
- validate: (config) => !!config.output,
32
- location: (config) => config.output!,
24
+ export const sdk = (argv: string[]) =>
25
+ main({
26
+ assign: (config, output) => (config.output = output),
27
+ validate: (config) => !!config.output,
28
+ location: (config) => config.output!,
29
+ })(argv)((app) => app.sdk());
30
+
31
+ export const swagger = (argv: string[]) =>
32
+ main({
33
+ assign: (config, output) => {
34
+ if (!config.swagger) config.swagger = { output };
35
+ else config.swagger.output = output;
33
36
  },
34
- elements,
35
- pure,
36
- );
37
- }
38
-
39
- export function swagger(
40
- elements: string[],
41
- pure: boolean = true,
42
- ): Promise<void> {
43
- return main(
44
- (app) => app.swagger(),
45
- {
46
- assign: (config, output) => {
47
- if (!config.swagger) config.swagger = { output };
48
- else config.swagger.output = output;
49
- },
50
- validate: (config) =>
51
- !!config.swagger && !!config.swagger.output,
52
- location: (config) => config.swagger!.output!,
53
- },
54
- elements,
55
- pure,
56
- );
57
- }
58
-
59
- async function main(
60
- task: (app: NestiaSdkApplication) => Promise<void>,
61
- output: IOutput,
62
- elements: string[],
63
- pure: boolean,
64
- ): Promise<void> {
65
- if (pure === false)
66
- cli.setArgv([
67
- process.argv[0],
68
- process.argv[1],
69
- "nestia",
70
- ...elements,
71
- ]);
72
- const command: ICommand = cli.parse({
73
- exclude: ["e", "Something to exclude", "string", null],
74
- out: ["o", "Output path of the SDK files", "string", null],
75
- });
76
-
77
- const inputs: string[] = [];
78
- for (const arg of elements) {
79
- if (arg[0] === "-") break;
80
- inputs.push(arg);
81
- }
82
- await generate(task, inputs, command, output);
83
- }
84
-
85
- async function generate(
86
- task: (app: NestiaSdkApplication) => Promise<void>,
87
- include: string[],
88
- command: ICommand,
89
- output: IOutput,
90
- ): Promise<void> {
91
- // CONFIGURATION
92
- const config: INestiaConfig =
93
- (await get_nestia_config(output.validate)) ??
94
- parse_cli(include, command, output);
95
-
96
- const options = await get_typescript_options();
97
-
98
- config.compilerOptions = {
99
- ...options,
100
- ...(config.compilerOptions || {}),
37
+ validate: (config) => !!config.swagger && !!config.swagger.output,
38
+ location: (config) => config.swagger!.output!,
39
+ })(argv)((app) => app.swagger());
40
+
41
+ export const e2e = (argv: string[]) =>
42
+ main({
43
+ assign: (config, output) => (config.output = output),
44
+ validate: (config) => !!config.output,
45
+ location: (config) => config.output!,
46
+ })(argv)((app) => app.sdk());
47
+
48
+ const main =
49
+ (props: IProps) =>
50
+ (argv: string[]) =>
51
+ async (task: (app: NestiaSdkApplication) => Promise<void>) => {
52
+ const command: ICommand = cli.parse({
53
+ exclude: ["e", "Something to exclude", "string", null],
54
+ out: ["o", "Output path of the SDK files", "string", null],
55
+ e2e: [
56
+ "e",
57
+ "Output path of e2e test function files",
58
+ "string",
59
+ null,
60
+ ],
61
+ });
62
+
63
+ const inputs: string[] = [];
64
+ for (const r of argv) {
65
+ if (r[0] === "-") break;
66
+ inputs.push(r);
67
+ }
68
+ await generate(props)(command)(inputs)(task);
101
69
  };
102
70
 
103
- // CALL THE APP.GENERATE()
104
- const app: NestiaSdkApplication = new NestiaSdkApplication(config);
105
- await task(app);
106
- }
71
+ const generate =
72
+ (props: IProps) =>
73
+ (command: ICommand) =>
74
+ (include: string[]) =>
75
+ async (task: (app: NestiaSdkApplication) => Promise<void>) => {
76
+ // CONFIGURATION
77
+ const config: INestiaConfig =
78
+ (await get_nestia_config(props.validate)) ??
79
+ parse_cli(props)(command)(include);
80
+
81
+ const options = await get_typescript_options();
82
+ config.compilerOptions = {
83
+ ...options,
84
+ ...(config.compilerOptions || {}),
85
+ };
86
+
87
+ // CALL THE APP.GENERATE()
88
+ const app: NestiaSdkApplication = new NestiaSdkApplication(config);
89
+ await task(app);
90
+ };
107
91
 
108
92
  async function get_typescript_options(): Promise<ts.CompilerOptions | null> {
109
93
  const configFileName = ts.findConfigFile(
@@ -111,18 +95,14 @@ export namespace NestiaSdkCommand {
111
95
  ts.sys.fileExists,
112
96
  "tsconfig.json",
113
97
  );
114
-
115
98
  if (!configFileName) return null;
116
99
 
117
100
  const { tsconfig } = await parseNative(configFileName);
118
-
119
101
  const configFileText = JSON.stringify(tsconfig);
120
-
121
102
  const { config } = ts.parseConfigFileTextToJson(
122
103
  configFileName,
123
104
  configFileText,
124
105
  );
125
-
126
106
  const configParseResult = ts.parseJsonConfigFileContent(
127
107
  config,
128
108
  ts.sys,
@@ -138,7 +118,9 @@ export namespace NestiaSdkCommand {
138
118
  validate: (config: INestiaConfig) => boolean,
139
119
  ): Promise<INestiaConfig | null> {
140
120
  const connector = new WorkerConnector(null, null, "process");
141
- await connector.connect(`${__dirname}/nestia.config.getter.${__filename.substr(-2)}`);
121
+ await connector.connect(
122
+ `${__dirname}/nestia.config.getter.${__filename.substr(-2)}`,
123
+ );
142
124
 
143
125
  const driver = await connector.getDriver<typeof NestiaSdkConfig>();
144
126
  const config: INestiaConfig | null = await driver.get();
@@ -152,23 +134,23 @@ export namespace NestiaSdkCommand {
152
134
  return config;
153
135
  }
154
136
 
155
- function parse_cli(
156
- include: string[],
157
- command: ICommand,
158
- output: IOutput,
159
- ): INestiaConfig {
160
- if (command.out === null)
161
- throw new Error(
162
- `Error on NestiaCommand.main(): output directory is not specified. Add the "--out <output_directory>" option.`,
163
- );
164
-
165
- const config: INestiaConfig = {
166
- input: {
167
- include,
168
- exclude: command.exclude ? [command.exclude] : undefined,
169
- },
137
+ const parse_cli =
138
+ (props: IProps) =>
139
+ (command: ICommand) =>
140
+ (include: string[]): INestiaConfig => {
141
+ if (command.out === null)
142
+ throw new Error(
143
+ `Error on NestiaCommand.main(): output directory is not specified. Add the "--out <output_directory>" option.`,
144
+ );
145
+
146
+ const config: INestiaConfig = {
147
+ input: {
148
+ include,
149
+ exclude: command.exclude ? [command.exclude] : undefined,
150
+ },
151
+ e2e: command.e2e ?? undefined,
152
+ };
153
+ props.assign(config, command.out);
154
+ return config;
170
155
  };
171
- output.assign(config, command.out);
172
- return config;
173
- }
174
156
  }
@@ -14,14 +14,9 @@ npx @nestia/sdk [command] [options?]
14
14
  - npx @nestia/sdk dependencies
15
15
  - npx @nestia/sdk dependencies --manager pnpm
16
16
  2. npx @nestia/sdk init
17
- 3. npx @nestia/sdk sdk <input> --out <output>
18
- - npx @nestia/sdk sdk # when "nestia.config.ts" be configured
19
- - npx @nestia/sdk sdk src/controllers --out src/api
20
- - npx @nestia/sdk sdk src/**/*.controller.ts --out src/api
21
- 4. npx @nestia/sdk swagger <input> --out <output>
22
- - npx @nestia/sdk swagger # when "nestia.config.ts" be configured
23
- - npx @nestia/sdk swagger src/controllers --out src/api
24
- - npx @nestia/sdk swagger src/**/*.controller.ts --out src/api
17
+ 3. npx @nestia/sdk sdk
18
+ 4. npx @nestia/sdk swagger
19
+ 5. npx @nestia/sdk e2e
25
20
  `;
26
21
 
27
22
  function halt(desc: string): never {
@@ -66,6 +61,7 @@ async function main() {
66
61
  else if (type === "init") await initialize();
67
62
  else if (type === "sdk") await execute((c) => c.sdk(argv));
68
63
  else if (type === "swagger") await execute((c) => c.swagger(argv));
64
+ else if (type === "e2e") await execute((c) => c.e2e(argv));
69
65
  else halt(USAGE);
70
66
  }
71
67
  main().catch((exp) => {
@@ -0,0 +1,65 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ import { INestiaConfig } from "../INestiaConfig";
5
+ import { IRoute } from "../structures/IRoute";
6
+ import { NestiaConfigUtil } from "../utils/NestiaConfigUtil";
7
+ import { E2eFileProgrammer } from "./internal/E2eFileProgrammer";
8
+
9
+ export namespace E2eGenerator {
10
+ export const generate =
11
+ (config: INestiaConfig) =>
12
+ async (routeList: IRoute[]): Promise<void> => {
13
+ // PREPARE DIRECTORIES
14
+ const output: string = path.resolve(config.e2e!);
15
+ await mkdir(output);
16
+ await mkdir(path.join(output, "features"));
17
+ await mkdir(path.join(output, "features", "api"));
18
+ await mkdir(path.join(output, "features", "api", "automated"));
19
+
20
+ // GENERATE TEST INDEX FILE
21
+ await index(config)(path.join(config.e2e!, "index.ts"));
22
+
23
+ // GENERATE EACH TEST FILES
24
+ for (const route of routeList)
25
+ await E2eFileProgrammer.generate(config)({
26
+ api: path.resolve(config.output!),
27
+ current: path.join(output, "features", "api", "automated"),
28
+ })(route);
29
+ };
30
+
31
+ const index =
32
+ (config: INestiaConfig) =>
33
+ async (output: string): Promise<void> => {
34
+ if (fs.existsSync(output)) return;
35
+
36
+ const location: string = path.join(
37
+ __dirname,
38
+ "..",
39
+ "..",
40
+ "assets",
41
+ "bundle",
42
+ "e2e",
43
+ "index.ts",
44
+ );
45
+ const content: string = await fs.promises.readFile(
46
+ location,
47
+ "utf8",
48
+ );
49
+
50
+ await fs.promises.writeFile(
51
+ output,
52
+ content.replace(
53
+ "${input}",
54
+ JSON.stringify(NestiaConfigUtil.input(config.input)),
55
+ ),
56
+ "utf8",
57
+ );
58
+ };
59
+ }
60
+
61
+ const mkdir = async (location: string): Promise<void> => {
62
+ try {
63
+ await fs.promises.mkdir(location);
64
+ } catch {}
65
+ };
@@ -1,44 +1,42 @@
1
1
  import fs from "fs";
2
2
  import NodePath from "path";
3
- import ts from "typescript";
4
3
 
5
4
  import { INestiaConfig } from "../INestiaConfig";
6
5
  import { IRoute } from "../structures/IRoute";
7
- import { FileGenerator } from "./FileGenerator";
6
+ import { SdkFileProgrammer } from "./internal/SdkFileProgrammer";
8
7
 
9
8
  export namespace SdkGenerator {
10
- export async function generate(
11
- _checker: ts.TypeChecker,
12
- config: INestiaConfig,
13
- routeList: IRoute[],
14
- ): Promise<void> {
15
- // PREPARE NEW DIRECTORIES
16
- try {
17
- await fs.promises.mkdir(config.output!);
18
- } catch {}
9
+ export const generate =
10
+ (config: INestiaConfig) =>
11
+ async (routes: IRoute[]): Promise<void> => {
12
+ // PREPARE NEW DIRECTORIES
13
+ try {
14
+ await fs.promises.mkdir(config.output!);
15
+ } catch {}
19
16
 
20
- // BUNDLING
21
- const bundle: string[] = await fs.promises.readdir(BUNDLE_PATH);
22
- for (const file of bundle) {
23
- const current: string = `${BUNDLE_PATH}/${file}`;
24
- const stats: fs.Stats = await fs.promises.stat(current);
17
+ // BUNDLING
18
+ const bundle: string[] = await fs.promises.readdir(BUNDLE_PATH);
19
+ for (const file of bundle) {
20
+ const current: string = `${BUNDLE_PATH}/${file}`;
21
+ const stats: fs.Stats = await fs.promises.stat(current);
25
22
 
26
- if (stats.isFile() === true) {
27
- const content: string = await fs.promises.readFile(
28
- current,
29
- "utf8",
30
- );
31
- await fs.promises.writeFile(
32
- `${config.output}/${file}`,
33
- content,
34
- "utf8",
35
- );
23
+ if (stats.isFile() === true) {
24
+ const content: string = await fs.promises.readFile(
25
+ current,
26
+ "utf8",
27
+ );
28
+ if (fs.existsSync(`${config.output}/${file}`) === false)
29
+ await fs.promises.writeFile(
30
+ `${config.output}/${file}`,
31
+ content,
32
+ "utf8",
33
+ );
34
+ }
36
35
  }
37
- }
38
36
 
39
- // FUNCTIONAL
40
- await FileGenerator.generate(config, routeList);
41
- }
37
+ // FUNCTIONAL
38
+ await SdkFileProgrammer.generate(config)(routes);
39
+ };
42
40
 
43
41
  export const BUNDLE_PATH = NodePath.join(
44
42
  __dirname,
@@ -46,5 +44,6 @@ export namespace SdkGenerator {
46
44
  "..",
47
45
  "assets",
48
46
  "bundle",
47
+ "api",
49
48
  );
50
49
  }
@@ -17,72 +17,74 @@ import { ISwaggerDocument } from "../structures/ISwaggerDocument";
17
17
  import { MapUtil } from "../utils/MapUtil";
18
18
 
19
19
  export namespace SwaggerGenerator {
20
- export async function generate(
21
- checker: ts.TypeChecker,
22
- config: INestiaConfig.ISwaggerConfig,
23
- routeList: IRoute[],
24
- ): Promise<void> {
25
- // PREPARE ASSETS
26
- const parsed: NodePath.ParsedPath = NodePath.parse(config.output);
27
- const location: string = !!parsed.ext
28
- ? NodePath.resolve(config.output)
29
- : NodePath.join(NodePath.resolve(config.output), "swagger.json");
30
-
31
- const collection: MetadataCollection = new MetadataCollection({
32
- replace: MetadataCollection.replace,
33
- });
34
-
35
- // CONSTRUCT SWAGGER DOCUMENTS
36
- const tupleList: Array<ISchemaTuple> = [];
37
- const swagger: ISwaggerDocument = await initialize(location);
38
- const pathDict: Map<string, ISwaggerDocument.IPath> = new Map();
39
-
40
- for (const route of routeList) {
41
- if (route.tags.find((tag) => tag.name === "internal")) continue;
42
-
43
- const path: ISwaggerDocument.IPath = MapUtil.take(
44
- pathDict,
45
- get_path(route.path, route.parameters),
46
- () => ({}),
47
- );
48
- path[route.method.toLowerCase()] = generate_route(
49
- checker,
50
- collection,
51
- tupleList,
52
- route,
20
+ export const generate =
21
+ (checker: ts.TypeChecker) =>
22
+ (config: INestiaConfig.ISwaggerConfig) =>
23
+ async (routeList: IRoute[]): Promise<void> => {
24
+ // PREPARE ASSETS
25
+ const parsed: NodePath.ParsedPath = NodePath.parse(config.output);
26
+ const location: string = !!parsed.ext
27
+ ? NodePath.resolve(config.output)
28
+ : NodePath.join(
29
+ NodePath.resolve(config.output),
30
+ "swagger.json",
31
+ );
32
+
33
+ const collection: MetadataCollection = new MetadataCollection({
34
+ replace: MetadataCollection.replace,
35
+ });
36
+
37
+ // CONSTRUCT SWAGGER DOCUMENTS
38
+ const tupleList: Array<ISchemaTuple> = [];
39
+ const swagger: ISwaggerDocument = await initialize(location);
40
+ const pathDict: Map<string, ISwaggerDocument.IPath> = new Map();
41
+
42
+ for (const route of routeList) {
43
+ if (route.tags.find((tag) => tag.name === "internal")) continue;
44
+
45
+ const path: ISwaggerDocument.IPath = MapUtil.take(
46
+ pathDict,
47
+ get_path(route.path, route.parameters),
48
+ () => ({}),
49
+ );
50
+ path[route.method.toLowerCase()] = generate_route(
51
+ checker,
52
+ collection,
53
+ tupleList,
54
+ route,
55
+ );
56
+ }
57
+ swagger.paths = {};
58
+ for (const [path, routes] of pathDict) {
59
+ swagger.paths[path] = routes;
60
+ }
61
+
62
+ // FILL JSON-SCHEMAS
63
+ const application: IJsonApplication = ApplicationProgrammer.write({
64
+ purpose: "swagger",
65
+ })(tupleList.map(({ metadata }) => metadata));
66
+ swagger.components = {
67
+ ...(swagger.components ?? {}),
68
+ schemas: application.components.schemas,
69
+ };
70
+ tupleList.forEach(({ schema }, index) => {
71
+ Object.assign(schema, application.schemas[index]!);
72
+ });
73
+
74
+ // CONFIGURE SECURITY
75
+ if (config.security) fill_security(config.security, swagger);
76
+
77
+ // ERASE IJsonComponents.IObject.$id
78
+ for (const obj of Object.values(swagger.components.schemas))
79
+ if (obj.$id) delete obj.$id;
80
+
81
+ // DO GENERATE
82
+ await fs.promises.writeFile(
83
+ location,
84
+ JSON.stringify(swagger, null, 2),
85
+ "utf8",
53
86
  );
54
- }
55
- swagger.paths = {};
56
- for (const [path, routes] of pathDict) {
57
- swagger.paths[path] = routes;
58
- }
59
-
60
- // FILL JSON-SCHEMAS
61
- const application: IJsonApplication = ApplicationProgrammer.write({
62
- purpose: "swagger",
63
- })(tupleList.map(({ metadata }) => metadata));
64
- swagger.components = {
65
- ...(swagger.components ?? {}),
66
- schemas: application.components.schemas,
67
87
  };
68
- tupleList.forEach(({ schema }, index) => {
69
- Object.assign(schema, application.schemas[index]!);
70
- });
71
-
72
- // CONFIGURE SECURITY
73
- if (config.security) fill_security(config.security, swagger);
74
-
75
- // ERASE IJsonComponents.IObject.$id
76
- for (const obj of Object.values(swagger.components.schemas))
77
- if (obj.$id) delete obj.$id;
78
-
79
- // DO GENERATE
80
- await fs.promises.writeFile(
81
- location,
82
- JSON.stringify(swagger, null, 2),
83
- "utf8",
84
- );
85
- }
86
88
 
87
89
  /* ---------------------------------------------------------
88
90
  INITIALIZERS
@@ -0,0 +1,119 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ import { INestiaConfig } from "../../INestiaConfig";
5
+ import { IRoute } from "../../structures/IRoute";
6
+ import { ImportDictionary } from "../../utils/ImportDictionary";
7
+
8
+ export namespace E2eFileProgrammer {
9
+ export const generate =
10
+ (config: INestiaConfig) =>
11
+ (props: { api: string; current: string }) =>
12
+ async (route: IRoute): Promise<void> => {
13
+ const importDict: ImportDictionary = new ImportDictionary();
14
+ for (const tuple of route.imports)
15
+ for (const instance of tuple[1])
16
+ importDict.emplace(tuple[0], false, instance);
17
+
18
+ const uuid: boolean = route.parameters.some(
19
+ (p) => p.category === "param" && p.meta?.type === "uuid",
20
+ );
21
+ const content: string = [
22
+ config.primitive === false
23
+ ? `import typia from "typia";`
24
+ : `import typia, { Primitive } from "typia";`,
25
+ "",
26
+ `import api from "./${path
27
+ .relative(props.current, props.api)
28
+ .split("\\")
29
+ .join("/")}";`,
30
+ ...(importDict.empty()
31
+ ? []
32
+ : [importDict.toScript(props.current)]),
33
+ "",
34
+ arrow(config)(route),
35
+ ...(uuid ? ["", UUID] : []),
36
+ ].join("\n");
37
+
38
+ await fs.promises.writeFile(
39
+ `${props.current}/${name(route)}.ts`,
40
+ content,
41
+ "utf8",
42
+ );
43
+ };
44
+
45
+ const arrow =
46
+ (config: INestiaConfig) =>
47
+ (route: IRoute): string => {
48
+ const tab: number = route.output.name === "void" ? 2 : 3;
49
+ const output = [
50
+ `await ${accessor(route)}(`,
51
+ `${" ".repeat(tab * 4)}connection,`,
52
+ ...route.parameters.map(parameter(config)(tab)),
53
+ `${" ".repeat((tab - 1) * 4)});`,
54
+ ].join("\n");
55
+ return [
56
+ `export const ${name(route)} = async (`,
57
+ ` connection: api.IConnection`,
58
+ `): Promise<void> => {`,
59
+ ...(route.output.name === "void"
60
+ ? [` ${output}`]
61
+ : [
62
+ ` const output: ${primitive(config)(
63
+ route.output.name,
64
+ )} = `,
65
+ ` ${output}`,
66
+ ` typia.assert(output);`,
67
+ ]),
68
+ `};`,
69
+ ].join("\n");
70
+ };
71
+
72
+ const parameter =
73
+ (config: INestiaConfig) =>
74
+ (tab: number) =>
75
+ (param: IRoute.IParameter): string => {
76
+ const middle: string =
77
+ param.category === "param" && param.meta?.type === "uuid"
78
+ ? param.meta.nullable
79
+ ? `Math.random() < .2 ? null : uuid()`
80
+ : `uuid()`
81
+ : `typia.random<${primitive(config)(param.type.name)}>()`;
82
+ return `${" ".repeat(4 * tab)}${middle},`;
83
+ };
84
+
85
+ const name = (route: IRoute): string =>
86
+ [
87
+ "test_api",
88
+ ...route.path
89
+ .split("/")
90
+ .filter((str) => str.length && str[0] !== ":")
91
+ .map(normalize),
92
+ route.name,
93
+ ].join("_");
94
+
95
+ const accessor = (route: IRoute): string =>
96
+ [
97
+ "api.functional",
98
+ ...route.path
99
+ .split("/")
100
+ .filter((str) => str.length && str[0] !== ":")
101
+ .map(normalize),
102
+ route.name,
103
+ ].join(".");
104
+
105
+ const normalize = (str: string) =>
106
+ str.split("-").join("_").split(".").join("_");
107
+
108
+ const primitive =
109
+ (config: INestiaConfig) =>
110
+ (name: string): string =>
111
+ config.primitive !== false ? `Primitive<${name}>` : name;
112
+ }
113
+
114
+ const UUID = `const uuid = (): string =>
115
+ "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
116
+ const r = (Math.random() * 16) | 0;
117
+ const v = c === "x" ? r : (r & 0x3) | 0x8;
118
+ return v.toString(16);
119
+ });`;