@nestia/sdk 1.0.6 → 1.0.8

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 (35) hide show
  1. package/LICENSE +21 -0
  2. package/assets/config/nestia.config.ts +70 -70
  3. package/lib/executable/sdk.js +16 -16
  4. package/lib/generates/SwaggerGenerator.js +2 -2
  5. package/lib/generates/SwaggerGenerator.js.map +1 -1
  6. package/lib/structures/ISwaggerDocument.d.ts +1 -1
  7. package/package.json +3 -3
  8. package/src/INestiaConfig.ts +147 -147
  9. package/src/NestiaSdkApplication.ts +183 -183
  10. package/src/analyses/ControllerAnalyzer.ts +223 -223
  11. package/src/analyses/GenericAnalyzer.ts +53 -53
  12. package/src/analyses/ImportAnalyzer.ts +143 -143
  13. package/src/analyses/PathAnalyzer.ts +58 -58
  14. package/src/analyses/ReflectAnalyzer.ts +287 -287
  15. package/src/analyses/SourceFinder.ts +59 -59
  16. package/src/executable/internal/CommandParser.ts +15 -15
  17. package/src/executable/internal/NestiaConfigCompilerOptions.ts +18 -18
  18. package/src/executable/internal/NestiaSdkCommand.ts +174 -174
  19. package/src/executable/internal/nestia.config.getter.ts +12 -12
  20. package/src/executable/sdk.ts +74 -74
  21. package/src/generates/FileGenerator.ts +156 -156
  22. package/src/generates/SdkGenerator.ts +50 -50
  23. package/src/generates/SwaggerGenerator.ts +2 -2
  24. package/src/module.ts +2 -2
  25. package/src/structures/IController.ts +27 -27
  26. package/src/structures/IRoute.ts +33 -33
  27. package/src/structures/ISwaggerDocument.ts +119 -119
  28. package/src/structures/ITypeTuple.ts +6 -6
  29. package/src/structures/MethodType.ts +11 -11
  30. package/src/structures/ParamCategory.ts +1 -1
  31. package/src/structures/TypeEntry.ts +22 -22
  32. package/src/utils/ArrayUtil.ts +26 -26
  33. package/src/utils/ImportDictionary.ts +56 -56
  34. package/src/utils/MapUtil.ts +14 -14
  35. package/src/utils/StripEnums.ts +10 -10
@@ -1,183 +1,183 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import * as runner from "ts-node";
4
- import { Singleton } from "tstl/thread/Singleton";
5
- import { Pair } from "tstl/utility/Pair";
6
- import ts from "typescript";
7
-
8
- import { INestiaConfig } from "./INestiaConfig";
9
- import { ControllerAnalyzer } from "./analyses/ControllerAnalyzer";
10
- import { ReflectAnalyzer } from "./analyses/ReflectAnalyzer";
11
- import { SourceFinder } from "./analyses/SourceFinder";
12
- import { NestiaConfigCompilerOptions } from "./executable/internal/NestiaConfigCompilerOptions";
13
- import { SdkGenerator } from "./generates/SdkGenerator";
14
- import { SwaggerGenerator } from "./generates/SwaggerGenerator";
15
- import { IController } from "./structures/IController";
16
- import { IRoute } from "./structures/IRoute";
17
- import { ArrayUtil } from "./utils/ArrayUtil";
18
-
19
- export class NestiaSdkApplication {
20
- private readonly config_: INestiaConfig;
21
- private readonly bundle_checker_: Singleton<
22
- Promise<(str: string) => boolean>
23
- >;
24
-
25
- public constructor(config: INestiaConfig) {
26
- this.config_ = config;
27
- this.bundle_checker_ = new Singleton(async () => {
28
- if (!this.config_.output) return () => false;
29
-
30
- const bundles: string[] = await fs.promises.readdir(
31
- SdkGenerator.BUNDLE_PATH,
32
- );
33
- const tuples: Pair<string, boolean>[] = await ArrayUtil.asyncMap(
34
- bundles,
35
- async (file) => {
36
- const relative: string = path.join(
37
- this.config_.output!,
38
- file,
39
- );
40
- const location: string = path.join(
41
- SdkGenerator.BUNDLE_PATH,
42
- file,
43
- );
44
- const stats: fs.Stats = await fs.promises.stat(location);
45
-
46
- return new Pair(relative, stats.isDirectory());
47
- },
48
- );
49
-
50
- return (file: string): boolean => {
51
- for (const it of tuples)
52
- if (it.second === false && file === it.first) return true;
53
- else if (it.second === true && file.indexOf(it.first) === 0)
54
- return true;
55
- return false;
56
- };
57
- });
58
- }
59
-
60
- public async sdk(): Promise<void> {
61
- if (!this.config_.output)
62
- throw new Error(
63
- "Error on NestiaApplication.sdk(): output path is not specified.",
64
- );
65
-
66
- const parent: string = path.resolve(this.config_.output + "/..");
67
- const stats: fs.Stats = await fs.promises.lstat(parent);
68
- if (stats.isDirectory() === false)
69
- throw new Error(
70
- "Error on NestiaApplication.sdk(): output directory does not exists.",
71
- );
72
-
73
- await this.generate((config) => config, SdkGenerator.generate);
74
- }
75
-
76
- public async swagger(): Promise<void> {
77
- if (!this.config_.swagger || !this.config_.swagger.output)
78
- throw new Error(
79
- `Error on NestiaApplication.swagger(): output path of the "swagger.json" is not specified.`,
80
- );
81
-
82
- const parsed: path.ParsedPath = path.parse(this.config_.swagger.output);
83
- const directory: string = !!parsed.ext
84
- ? path.resolve(parsed.dir)
85
- : this.config_.swagger.output;
86
- const stats: fs.Stats = await fs.promises.lstat(directory);
87
- if (stats.isDirectory() === false)
88
- throw new Error(
89
- "Error on NestiaApplication.swagger(): output directory does not exists.",
90
- );
91
-
92
- await this.generate(
93
- (config) => config.swagger!,
94
- SwaggerGenerator.generate,
95
- );
96
- }
97
-
98
- private async generate<Config>(
99
- config: (entire: INestiaConfig) => Config,
100
- archiver: (
101
- checker: ts.TypeChecker,
102
- config: Config,
103
- routes: IRoute[],
104
- ) => Promise<void>,
105
- ): Promise<void> {
106
- // MOUNT TS-NODE
107
- this.prepare();
108
-
109
- // 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;
116
- const fileList: string[] = await ArrayUtil.asyncFilter(
117
- await SourceFinder.find(input),
118
- (file) => this.is_not_excluded(file),
119
- );
120
-
121
- // ANALYZE REFLECTS
122
- const unique: WeakSet<any> = new WeakSet();
123
- const controllerList: IController[] = [];
124
-
125
- for (const file of fileList)
126
- controllerList.push(
127
- ...(await ReflectAnalyzer.analyze(unique, file)),
128
- );
129
-
130
- // ANALYZE TYPESCRIPT CODE
131
- const program: ts.Program = ts.createProgram(
132
- controllerList.map((c) => c.file),
133
- this.config_.compilerOptions || { noEmit: true },
134
- );
135
- const checker: ts.TypeChecker = program.getTypeChecker();
136
-
137
- const routeList: IRoute[] = [];
138
- for (const controller of controllerList) {
139
- const sourceFile: ts.SourceFile | undefined = program.getSourceFile(
140
- controller.file,
141
- );
142
- if (sourceFile === undefined) continue;
143
-
144
- routeList.push(
145
- ...ControllerAnalyzer.analyze(checker, sourceFile, controller),
146
- );
147
- }
148
-
149
- // DO GENERATE
150
- await archiver(checker, config(this.config_), routeList);
151
- }
152
-
153
- private prepare(): void {
154
- // CONSTRUCT OPTIONS
155
- if (!this.config_.compilerOptions)
156
- this.config_.compilerOptions =
157
- NestiaConfigCompilerOptions.DEFAULT_OPTIONS as any;
158
- const absoluted: boolean = !!this.config_.compilerOptions?.baseUrl;
159
-
160
- // MOUNT TS-NODE
161
- runner.register({
162
- emit: false,
163
- compiler: "ttypescript",
164
- compilerOptions: this.config_.compilerOptions,
165
- require: absoluted ? ["tsconfig-paths/register"] : undefined,
166
- });
167
- }
168
-
169
- private async is_not_excluded(file: string): Promise<boolean> {
170
- if (this.config_.output)
171
- return (
172
- file.indexOf(path.join(this.config_.output, "functional")) ===
173
- -1 && (await this.bundle_checker_.get())(file) === false
174
- );
175
-
176
- const content: string = await fs.promises.readFile(file, "utf8");
177
- return (
178
- content.indexOf(
179
- " * @nestia Generated by Nestia - https://github.com/samchon/nestia",
180
- ) === -1
181
- );
182
- }
183
- }
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import * as runner from "ts-node";
4
+ import { Singleton } from "tstl/thread/Singleton";
5
+ import { Pair } from "tstl/utility/Pair";
6
+ import ts from "typescript";
7
+
8
+ import { INestiaConfig } from "./INestiaConfig";
9
+ import { ControllerAnalyzer } from "./analyses/ControllerAnalyzer";
10
+ import { ReflectAnalyzer } from "./analyses/ReflectAnalyzer";
11
+ import { SourceFinder } from "./analyses/SourceFinder";
12
+ import { NestiaConfigCompilerOptions } from "./executable/internal/NestiaConfigCompilerOptions";
13
+ import { SdkGenerator } from "./generates/SdkGenerator";
14
+ import { SwaggerGenerator } from "./generates/SwaggerGenerator";
15
+ import { IController } from "./structures/IController";
16
+ import { IRoute } from "./structures/IRoute";
17
+ import { ArrayUtil } from "./utils/ArrayUtil";
18
+
19
+ export class NestiaSdkApplication {
20
+ private readonly config_: INestiaConfig;
21
+ private readonly bundle_checker_: Singleton<
22
+ Promise<(str: string) => boolean>
23
+ >;
24
+
25
+ public constructor(config: INestiaConfig) {
26
+ this.config_ = config;
27
+ this.bundle_checker_ = new Singleton(async () => {
28
+ if (!this.config_.output) return () => false;
29
+
30
+ const bundles: string[] = await fs.promises.readdir(
31
+ SdkGenerator.BUNDLE_PATH,
32
+ );
33
+ const tuples: Pair<string, boolean>[] = await ArrayUtil.asyncMap(
34
+ bundles,
35
+ async (file) => {
36
+ const relative: string = path.join(
37
+ this.config_.output!,
38
+ file,
39
+ );
40
+ const location: string = path.join(
41
+ SdkGenerator.BUNDLE_PATH,
42
+ file,
43
+ );
44
+ const stats: fs.Stats = await fs.promises.stat(location);
45
+
46
+ return new Pair(relative, stats.isDirectory());
47
+ },
48
+ );
49
+
50
+ return (file: string): boolean => {
51
+ for (const it of tuples)
52
+ if (it.second === false && file === it.first) return true;
53
+ else if (it.second === true && file.indexOf(it.first) === 0)
54
+ return true;
55
+ return false;
56
+ };
57
+ });
58
+ }
59
+
60
+ public async sdk(): Promise<void> {
61
+ if (!this.config_.output)
62
+ throw new Error(
63
+ "Error on NestiaApplication.sdk(): output path is not specified.",
64
+ );
65
+
66
+ const parent: string = path.resolve(this.config_.output + "/..");
67
+ const stats: fs.Stats = await fs.promises.lstat(parent);
68
+ if (stats.isDirectory() === false)
69
+ throw new Error(
70
+ "Error on NestiaApplication.sdk(): output directory does not exists.",
71
+ );
72
+
73
+ await this.generate((config) => config, SdkGenerator.generate);
74
+ }
75
+
76
+ public async swagger(): Promise<void> {
77
+ if (!this.config_.swagger || !this.config_.swagger.output)
78
+ throw new Error(
79
+ `Error on NestiaApplication.swagger(): output path of the "swagger.json" is not specified.`,
80
+ );
81
+
82
+ const parsed: path.ParsedPath = path.parse(this.config_.swagger.output);
83
+ const directory: string = !!parsed.ext
84
+ ? path.resolve(parsed.dir)
85
+ : this.config_.swagger.output;
86
+ const stats: fs.Stats = await fs.promises.lstat(directory);
87
+ if (stats.isDirectory() === false)
88
+ throw new Error(
89
+ "Error on NestiaApplication.swagger(): output directory does not exists.",
90
+ );
91
+
92
+ await this.generate(
93
+ (config) => config.swagger!,
94
+ SwaggerGenerator.generate,
95
+ );
96
+ }
97
+
98
+ private async generate<Config>(
99
+ config: (entire: INestiaConfig) => Config,
100
+ archiver: (
101
+ checker: ts.TypeChecker,
102
+ config: Config,
103
+ routes: IRoute[],
104
+ ) => Promise<void>,
105
+ ): Promise<void> {
106
+ // MOUNT TS-NODE
107
+ this.prepare();
108
+
109
+ // 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;
116
+ const fileList: string[] = await ArrayUtil.asyncFilter(
117
+ await SourceFinder.find(input),
118
+ (file) => this.is_not_excluded(file),
119
+ );
120
+
121
+ // ANALYZE REFLECTS
122
+ const unique: WeakSet<any> = new WeakSet();
123
+ const controllerList: IController[] = [];
124
+
125
+ for (const file of fileList)
126
+ controllerList.push(
127
+ ...(await ReflectAnalyzer.analyze(unique, file)),
128
+ );
129
+
130
+ // ANALYZE TYPESCRIPT CODE
131
+ const program: ts.Program = ts.createProgram(
132
+ controllerList.map((c) => c.file),
133
+ this.config_.compilerOptions || { noEmit: true },
134
+ );
135
+ const checker: ts.TypeChecker = program.getTypeChecker();
136
+
137
+ const routeList: IRoute[] = [];
138
+ for (const controller of controllerList) {
139
+ const sourceFile: ts.SourceFile | undefined = program.getSourceFile(
140
+ controller.file,
141
+ );
142
+ if (sourceFile === undefined) continue;
143
+
144
+ routeList.push(
145
+ ...ControllerAnalyzer.analyze(checker, sourceFile, controller),
146
+ );
147
+ }
148
+
149
+ // DO GENERATE
150
+ await archiver(checker, config(this.config_), routeList);
151
+ }
152
+
153
+ private prepare(): void {
154
+ // CONSTRUCT OPTIONS
155
+ if (!this.config_.compilerOptions)
156
+ this.config_.compilerOptions =
157
+ NestiaConfigCompilerOptions.DEFAULT_OPTIONS as any;
158
+ const absoluted: boolean = !!this.config_.compilerOptions?.baseUrl;
159
+
160
+ // MOUNT TS-NODE
161
+ runner.register({
162
+ emit: false,
163
+ compiler: "ttypescript",
164
+ compilerOptions: this.config_.compilerOptions,
165
+ require: absoluted ? ["tsconfig-paths/register"] : undefined,
166
+ });
167
+ }
168
+
169
+ private async is_not_excluded(file: string): Promise<boolean> {
170
+ if (this.config_.output)
171
+ return (
172
+ file.indexOf(path.join(this.config_.output, "functional")) ===
173
+ -1 && (await this.bundle_checker_.get())(file) === false
174
+ );
175
+
176
+ const content: string = await fs.promises.readFile(file, "utf8");
177
+ return (
178
+ content.indexOf(
179
+ " * @nestia Generated by Nestia - https://github.com/samchon/nestia",
180
+ ) === -1
181
+ );
182
+ }
183
+ }