@nestia/sdk 1.1.0 → 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 +14 -2
  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 +53 -57
  14. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  15. package/lib/executable/internal/NestiaSdkConfig.js +23 -50
  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 +6 -10
  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 +14 -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
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.SourceFinder = void 0;
16
+ const fs_1 = __importDefault(require("fs"));
17
+ const glob_1 = __importDefault(require("glob"));
18
+ const path_1 = __importDefault(require("path"));
19
+ var SourceFinder;
20
+ (function (SourceFinder) {
21
+ SourceFinder.find = (props) => __awaiter(this, void 0, void 0, function* () {
22
+ var _a;
23
+ const dict = new Set();
24
+ yield emplace(props.filter)(props.include)((str) => dict.add(str));
25
+ if ((_a = props.exclude) === null || _a === void 0 ? void 0 : _a.length)
26
+ yield emplace(props.filter)(props.exclude)((str) => dict.delete(str));
27
+ return [...dict];
28
+ });
29
+ const emplace = (filter) => (input) => (closure) => __awaiter(this, void 0, void 0, function* () {
30
+ for (const pattern of input) {
31
+ for (const file of yield _Glob(path_1.default.resolve(pattern))) {
32
+ const stats = yield fs_1.default.promises.stat(file);
33
+ if (stats.isDirectory() === true)
34
+ yield iterate(filter)(closure)(file);
35
+ else if (stats.isFile() && filter(file))
36
+ closure(file);
37
+ }
38
+ }
39
+ });
40
+ const iterate = (filter) => (closure) => (location) => __awaiter(this, void 0, void 0, function* () {
41
+ const directory = yield fs_1.default.promises.readdir(location);
42
+ for (const file of directory) {
43
+ const next = path_1.default.resolve(`${location}/${file}`);
44
+ const stats = yield fs_1.default.promises.stat(next);
45
+ if (stats.isDirectory() === true)
46
+ yield iterate(filter)(closure)(next);
47
+ else if (stats.isFile() && filter(next))
48
+ closure(next);
49
+ }
50
+ });
51
+ const _Glob = (pattern) => new Promise((resolve, reject) => {
52
+ (0, glob_1.default)(pattern, (err, matches) => {
53
+ if (err)
54
+ reject(err);
55
+ else
56
+ resolve(matches.map((str) => path_1.default.resolve(str)));
57
+ });
58
+ });
59
+ })(SourceFinder = exports.SourceFinder || (exports.SourceFinder = {}));
60
+ //# sourceMappingURL=SourceFinder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SourceFinder.js","sourceRoot":"","sources":["../../src/utils/SourceFinder.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nestia/sdk",
3
- "version": "1.1.0",
3
+ "version": "1.2.0-dev.20230504",
4
4
  "description": "Nestia SDK and Swagger generator",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
@@ -11,11 +11,10 @@
11
11
  "build": "rimraf lib && tsc",
12
12
  "dev": "rimraf lib && tsc --watch",
13
13
  "eslint": "eslint ./**/*.ts",
14
- "package:latest": "npm run build && npm run test && npm publish --access public",
14
+ "package:latest": "npm run build && npm publish --access public",
15
15
  "package:next": "npm run package:latest -- --tag next",
16
16
  "prepare": "ts-patch install",
17
- "prettier": "prettier --write ./**/*.ts",
18
- "test": "node lib/test"
17
+ "prettier": "prettier --write ./**/*.ts"
19
18
  },
20
19
  "repository": {
21
20
  "type": "git",
@@ -43,7 +42,7 @@
43
42
  "tsconfck": "^2.0.1",
44
43
  "tsconfig-paths": "^4.1.1",
45
44
  "tstl": "^2.5.13",
46
- "typia": "^3.8.1"
45
+ "typia": "^3.8.4"
47
46
  },
48
47
  "peerDependencies": {
49
48
  "@nestjs/common": ">= 7.0.1",
@@ -53,7 +52,6 @@
53
52
  "typescript": ">= 4.5.2"
54
53
  },
55
54
  "devDependencies": {
56
- "@nestia/core": "^1.1.0",
57
55
  "@nestia/fetcher": "^1.1.2",
58
56
  "@trivago/prettier-plugin-sort-imports": "^4.0.0",
59
57
  "@types/cli": "^0.11.21",
@@ -69,8 +67,8 @@
69
67
  "prettier": "^2.8.1",
70
68
  "rimraf": "^3.0.2",
71
69
  "ts-node": "^10.9.1",
72
- "ts-patch": "3.0.0-beta3",
73
- "typescript": "^5.0.4",
70
+ "ts-patch": "v2.1.0",
71
+ "typescript": "^4.9.5",
74
72
  "typescript-transform-paths": "^3.4.4",
75
73
  "uuid": "^9.0.0"
76
74
  },
@@ -78,8 +76,6 @@
78
76
  "assets",
79
77
  "lib",
80
78
  "src",
81
- "!lib/test",
82
- "!src/test",
83
79
  "README.md",
84
80
  "LICENSE",
85
81
  "package.json"
@@ -21,6 +21,13 @@ export interface INestiaConfig {
21
21
  */
22
22
  output?: string;
23
23
 
24
+ /**
25
+ * Otput directory that e2e test codes would be placed in.
26
+ *
27
+ * If not configured, you can't generate e2e test functions.
28
+ */
29
+ e2e?: string;
30
+
24
31
  /**
25
32
  * Compiler options for the TypeScript.
26
33
  *
@@ -1,20 +1,21 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import * as runner from "ts-node";
4
- import { Singleton } from "tstl/thread/Singleton";
5
- import { Pair } from "tstl/utility/Pair";
4
+ import { Pair, Singleton } from "tstl";
6
5
  import ts from "typescript";
7
6
 
8
7
  import { INestiaConfig } from "./INestiaConfig";
9
8
  import { ControllerAnalyzer } from "./analyses/ControllerAnalyzer";
10
9
  import { ReflectAnalyzer } from "./analyses/ReflectAnalyzer";
11
- import { SourceFinder } from "./analyses/SourceFinder";
12
10
  import { NestiaConfigCompilerOptions } from "./executable/internal/NestiaConfigCompilerOptions";
11
+ import { E2eGenerator } from "./generates/E2eGenerator";
13
12
  import { SdkGenerator } from "./generates/SdkGenerator";
14
13
  import { SwaggerGenerator } from "./generates/SwaggerGenerator";
15
14
  import { IController } from "./structures/IController";
16
15
  import { IRoute } from "./structures/IRoute";
17
16
  import { ArrayUtil } from "./utils/ArrayUtil";
17
+ import { NestiaConfigUtil } from "./utils/NestiaConfigUtil";
18
+ import { SourceFinder } from "./utils/SourceFinder";
18
19
 
19
20
  export class NestiaSdkApplication {
20
21
  private readonly config_: INestiaConfig;
@@ -57,6 +58,39 @@ export class NestiaSdkApplication {
57
58
  });
58
59
  }
59
60
 
61
+ public async e2e(): Promise<void> {
62
+ if (!this.config_.output)
63
+ throw new Error(
64
+ "Error on NestiaApplication.e2e(): output path of SDK is not specified.",
65
+ );
66
+ else if (!this.config_.e2e)
67
+ throw new Error(
68
+ "Error on NestiaApplication.e2e(): output path of e2e test files is not specified.",
69
+ );
70
+
71
+ const validate =
72
+ (title: string) =>
73
+ async (location: string): Promise<void> => {
74
+ const parent: string = path.resolve(location + "/..");
75
+ const stats: fs.Stats = await fs.promises.lstat(parent);
76
+ if (stats.isDirectory() === false)
77
+ throw new Error(
78
+ `Error on NestiaApplication.e2e(): output directory of ${title} does not exists.`,
79
+ );
80
+ };
81
+ await validate("sdk")(this.config_.output);
82
+ await validate("e2e")(this.config_.e2e);
83
+
84
+ await this.generate(
85
+ (config) => config,
86
+ () => SdkGenerator.generate,
87
+ );
88
+ await this.generate(
89
+ (config) => config,
90
+ () => E2eGenerator.generate,
91
+ );
92
+ }
93
+
60
94
  public async sdk(): Promise<void> {
61
95
  if (!this.config_.output)
62
96
  throw new Error(
@@ -69,12 +103,14 @@ export class NestiaSdkApplication {
69
103
  throw new Error(
70
104
  "Error on NestiaApplication.sdk(): output directory does not exists.",
71
105
  );
72
-
73
- await this.generate((config) => config, SdkGenerator.generate);
106
+ await this.generate(
107
+ (config) => config,
108
+ () => SdkGenerator.generate,
109
+ );
74
110
  }
75
111
 
76
112
  public async swagger(): Promise<void> {
77
- if (!this.config_.swagger || !this.config_.swagger.output)
113
+ if (!this.config_.swagger?.output)
78
114
  throw new Error(
79
115
  `Error on NestiaApplication.swagger(): output path of the "swagger.json" is not specified.`,
80
116
  );
@@ -99,22 +135,23 @@ export class NestiaSdkApplication {
99
135
  config: (entire: INestiaConfig) => Config,
100
136
  archiver: (
101
137
  checker: ts.TypeChecker,
102
- config: Config,
103
- routes: IRoute[],
104
- ) => Promise<void>,
138
+ ) => (config: Config) => (routes: IRoute[]) => Promise<void>,
105
139
  ): Promise<void> {
106
140
  // MOUNT TS-NODE
107
141
  this.prepare();
108
142
 
109
143
  // LOAD CONTROLLER FILES
110
- const input: INestiaConfig.IInput =
111
- this.config_.input instanceof Array
112
- ? { include: this.config_.input }
113
- : typeof this.config_.input === "string"
114
- ? { include: [this.config_.input] }
115
- : this.config_.input;
144
+ const input: INestiaConfig.IInput = NestiaConfigUtil.input(
145
+ this.config_.input,
146
+ );
116
147
  const fileList: string[] = await ArrayUtil.asyncFilter(
117
- await SourceFinder.find(input),
148
+ await SourceFinder.find({
149
+ include: input.include,
150
+ exclude: input.exclude,
151
+ filter: (file) =>
152
+ file.substring(file.length - 3) === ".ts" &&
153
+ file.substring(file.length - 5) !== ".d.ts",
154
+ }),
118
155
  (file) => this.is_not_excluded(file),
119
156
  );
120
157
 
@@ -147,7 +184,7 @@ export class NestiaSdkApplication {
147
184
  }
148
185
 
149
186
  // DO GENERATE
150
- await archiver(checker, config(this.config_), routeList);
187
+ await archiver(checker)(config(this.config_))(routeList);
151
188
  }
152
189
 
153
190
  private prepare(): void {
@@ -253,6 +253,7 @@ export namespace ControllerAnalyzer {
253
253
  encrypted: param.encrypted,
254
254
  type: tuple,
255
255
  optional,
256
+ meta: param.meta,
256
257
  };
257
258
  }
258
259
  }
@@ -6,6 +6,8 @@ import { ParamCategory } from "../structures/ParamCategory";
6
6
  import { ArrayUtil } from "../utils/ArrayUtil";
7
7
  import { PathAnalyzer } from "./PathAnalyzer";
8
8
 
9
+ declare const Reflect: any;
10
+
9
11
  type IModule = {
10
12
  [key: string]: any;
11
13
  };
@@ -248,15 +250,25 @@ export namespace ReflectAnalyzer {
248
250
  field: param.data,
249
251
  encrypted: param.factory.name === "EncryptedBody",
250
252
  };
251
- } else if (param.factory.name === "TypedParam")
253
+ } else if (param.factory.name === "TypedParam") {
252
254
  return {
253
255
  name: param.name,
254
256
  category: "param",
255
257
  index: param.index,
256
258
  field: param.data,
257
259
  encrypted: false,
260
+ meta: (() => {
261
+ const type = (param.factory as any).type;
262
+ const nullable = (param.factory as any).nullable;
263
+ if (type !== undefined && nullable !== undefined)
264
+ return {
265
+ type,
266
+ nullable,
267
+ };
268
+ return undefined;
269
+ })(),
258
270
  };
259
- else if (param.factory.name === "TypedQuery")
271
+ } else if (param.factory.name === "TypedQuery")
260
272
  return {
261
273
  name: param.name,
262
274
  category: "query",
@@ -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.js`);
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
+ };