@nestia/sdk 0.2.0 → 1.0.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 (38) hide show
  1. package/assets/config/nestia.config.ts +79 -70
  2. package/lib/INestiaConfig.d.ts +18 -14
  3. package/lib/executable/sdk.js +16 -16
  4. package/lib/generates/FunctionGenerator.js +9 -9
  5. package/lib/generates/FunctionGenerator.js.map +1 -1
  6. package/lib/generates/SwaggerGenerator.js +9 -9
  7. package/package.json +3 -3
  8. package/src/INestiaConfig.ts +124 -120
  9. package/src/NestiaSdkApplication.ts +183 -183
  10. package/src/analyses/ControllerAnalyzer.ts +203 -203
  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 +279 -279
  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/NestiaSdkConfig.ts +35 -35
  20. package/src/executable/internal/nestia.config.getter.ts +12 -12
  21. package/src/executable/sdk.ts +74 -74
  22. package/src/generates/FileGenerator.ts +156 -156
  23. package/src/generates/FunctionGenerator.ts +284 -287
  24. package/src/generates/SdkGenerator.ts +50 -50
  25. package/src/generates/SwaggerGenerator.ts +393 -393
  26. package/src/index.ts +3 -3
  27. package/src/module.ts +2 -2
  28. package/src/structures/IController.ts +27 -27
  29. package/src/structures/IRoute.ts +29 -29
  30. package/src/structures/ISwagger.ts +55 -55
  31. package/src/structures/ITypeTuple.ts +6 -6
  32. package/src/structures/MethodType.ts +11 -11
  33. package/src/structures/ParamCategory.ts +1 -1
  34. package/src/structures/TypeEntry.ts +22 -22
  35. package/src/utils/ArrayUtil.ts +26 -26
  36. package/src/utils/ImportDictionary.ts +56 -56
  37. package/src/utils/MapUtil.ts +14 -14
  38. package/src/utils/StripEnums.ts +10 -10
@@ -1,279 +1,279 @@
1
- import { equal } from "tstl/ranges/module";
2
-
3
- import { IController } from "../structures/IController";
4
- import { ParamCategory } from "../structures/ParamCategory";
5
- import { ArrayUtil } from "../utils/ArrayUtil";
6
- import { PathAnalyzer } from "./PathAnalyzer";
7
-
8
- type IModule = {
9
- [key: string]: any;
10
- };
11
-
12
- export namespace ReflectAnalyzer {
13
- export async function analyze(
14
- unique: WeakSet<any>,
15
- file: string,
16
- ): Promise<IController[]> {
17
- const module: IModule = await import(file);
18
- const ret: IController[] = [];
19
-
20
- for (const tuple of Object.entries(module)) {
21
- if (unique.has(tuple[1])) continue;
22
- else unique.add(tuple[1]);
23
-
24
- const controller: IController | null = _Analyze_controller(
25
- file,
26
- ...tuple,
27
- );
28
- if (controller !== null) ret.push(controller);
29
- }
30
- return ret;
31
- }
32
-
33
- /* ---------------------------------------------------------
34
- CONTROLLER
35
- --------------------------------------------------------- */
36
- function _Analyze_controller(
37
- file: string,
38
- name: string,
39
- creator: any,
40
- ): IController | null {
41
- //----
42
- // VALIDATIONS
43
- //----
44
- // MUST BE TYPE OF A CREATOR WHO HAS THE CONSTRUCTOR
45
- if (
46
- !(
47
- creator instanceof Function &&
48
- creator.constructor instanceof Function
49
- )
50
- )
51
- return null;
52
- // MUST HAVE THOSE MATADATA
53
- else if (
54
- ArrayUtil.has(
55
- Reflect.getMetadataKeys(creator),
56
- "path",
57
- "host",
58
- "scope:options",
59
- ) === false
60
- )
61
- return null;
62
-
63
- //----
64
- // CONSTRUCTION
65
- //----
66
- // BASIC INFO
67
- const paths: string[] = _Get_paths(
68
- Reflect.getMetadata("path", creator),
69
- );
70
- const meta: IController = {
71
- file,
72
- name,
73
- paths,
74
- functions: [],
75
- };
76
-
77
- // PARSE CHILDREN DATA
78
- for (const tuple of _Get_prototype_entries(creator)) {
79
- const child: IController.IFunction | null = _Analyze_function(
80
- creator.prototype,
81
- meta,
82
- ...tuple,
83
- );
84
- if (child !== null) meta.functions.push(child);
85
- }
86
-
87
- // RETURNS
88
- return meta;
89
- }
90
-
91
- function _Get_prototype_entries(creator: any): Array<[string, unknown]> {
92
- const keyList = Object.getOwnPropertyNames(creator.prototype);
93
- const entries: Array<[string, unknown]> = keyList.map((key) => [
94
- key,
95
- creator.prototype[key],
96
- ]);
97
-
98
- const parent = Object.getPrototypeOf(creator);
99
- if (parent.prototype !== undefined)
100
- entries.push(..._Get_prototype_entries(parent));
101
-
102
- return entries;
103
- }
104
-
105
- function _Get_paths(value: string | string[]): string[] {
106
- if (typeof value === "string") return [value];
107
- else if (value.length === 0) return [""];
108
- else return value;
109
- }
110
-
111
- /* ---------------------------------------------------------
112
- FUNCTION
113
- --------------------------------------------------------- */
114
- function _Analyze_function(
115
- classProto: any,
116
- controller: IController,
117
- name: string,
118
- proto: any,
119
- ): IController.IFunction | null {
120
- //----
121
- // VALIDATIONS
122
- //----
123
- // MUST BE TYPE OF A FUNCTION
124
- if (!(proto instanceof Function)) return null;
125
- // MUST HAVE THOSE METADATE
126
- else if (
127
- ArrayUtil.has(Reflect.getMetadataKeys(proto), "path", "method") ===
128
- false
129
- )
130
- return null;
131
-
132
- //----
133
- // CONSTRUCTION
134
- //----
135
- // BASIC INFO
136
- const meta: IController.IFunction = {
137
- name,
138
- method: METHODS[Reflect.getMetadata("method", proto)],
139
- paths: _Get_paths(Reflect.getMetadata("path", proto)),
140
- parameters: [],
141
- encrypted:
142
- Reflect.hasMetadata("__interceptors__", proto) &&
143
- Reflect.getMetadata("__interceptors__", proto)[0]?.constructor
144
- ?.name === "EncryptedRouteInterceptor",
145
- };
146
-
147
- // PARSE CHILDREN DATA
148
- const nestParameters: NestParameters | undefined = Reflect.getMetadata(
149
- "__routeArguments__",
150
- classProto.constructor,
151
- name,
152
- );
153
- if (nestParameters === undefined) meta.parameters = [];
154
- else {
155
- for (const tuple of Object.entries(nestParameters)) {
156
- const child: IController.IParameter | null = _Analyze_parameter(
157
- ...tuple,
158
- );
159
- if (child !== null) meta.parameters.push(child);
160
- }
161
- meta.parameters = meta.parameters.sort((x, y) => x.index - y.index);
162
- }
163
-
164
- // VALIDATE PATH ARGUMENTS
165
- for (const controllerLocation of controller.paths)
166
- for (const metaLocation of meta.paths) {
167
- // NORMALIZE LOCATION
168
- const location: string = PathAnalyzer.join(
169
- controllerLocation,
170
- metaLocation,
171
- );
172
-
173
- // LIST UP PARAMETERS
174
- const binded: string[] = PathAnalyzer.parameters(
175
- location,
176
- () => `${controller.name}.${name}()`,
177
- ).sort();
178
-
179
- const parameters: string[] = meta.parameters
180
- .filter((param) => param.category === "param")
181
- .map((param) => param.field!)
182
- .sort();
183
-
184
- // DO VALIDATE
185
- if (equal(binded, parameters) === false)
186
- throw new Error(
187
- `Error on ${
188
- controller.name
189
- }.${name}(): binded arguments in the "path" between function's decorator and parameters' decorators are different (function: [${binded.join(
190
- ", ",
191
- )}], parameters: [${parameters.join(", ")}])`,
192
- );
193
- }
194
-
195
- // RETURNS
196
- return meta;
197
- }
198
-
199
- const METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH"];
200
-
201
- /* ---------------------------------------------------------
202
- PARAMETER
203
- --------------------------------------------------------- */
204
- function _Analyze_parameter(
205
- key: string,
206
- param: INestParam,
207
- ): IController.IParameter | null {
208
- const symbol: string = key.split(":")[0];
209
- if (symbol.indexOf("__custom") !== -1)
210
- return _Analyze_custom_parameter(param);
211
-
212
- const typeIndex: number = Number(symbol[0]);
213
- if (isNaN(typeIndex) === true) return null;
214
-
215
- const type: ParamCategory | undefined = NEST_PARAMETER_TYPES[typeIndex];
216
- if (type === undefined) return null;
217
-
218
- return {
219
- name: key,
220
- category: type,
221
- index: param.index,
222
- field: param.data,
223
- encrypted: false,
224
- };
225
- }
226
-
227
- function _Analyze_custom_parameter(
228
- param: INestParam,
229
- ): IController.IParameter | null {
230
- if (param.factory === undefined) return null;
231
- else if (
232
- param.factory.name === "TypedBody" ||
233
- param.factory.name === "EncryptedBody" ||
234
- param.factory.name === "PlainBody"
235
- ) {
236
- return {
237
- category: "body",
238
- index: param.index,
239
- name: param.name,
240
- field: param.data,
241
- encrypted: param.factory.name === "EncryptedBody",
242
- };
243
- } else if (param.factory.name === "TypedParam")
244
- return {
245
- name: param.name,
246
- category: "param",
247
- index: param.index,
248
- field: param.data,
249
- encrypted: false,
250
- };
251
- else return null;
252
- }
253
-
254
- type NestParameters = {
255
- [key: string]: INestParam;
256
- };
257
-
258
- interface INestParam {
259
- name: string;
260
- index: number;
261
- factory?: (...args: any) => any;
262
- data: string | undefined;
263
- }
264
-
265
- const NEST_PARAMETER_TYPES = [
266
- undefined,
267
- undefined,
268
- undefined,
269
- "body",
270
- "query",
271
- "param",
272
- undefined,
273
- undefined,
274
- undefined,
275
- undefined,
276
- undefined,
277
- undefined,
278
- ] as const;
279
- }
1
+ import { equal } from "tstl/ranges/module";
2
+
3
+ import { IController } from "../structures/IController";
4
+ import { ParamCategory } from "../structures/ParamCategory";
5
+ import { ArrayUtil } from "../utils/ArrayUtil";
6
+ import { PathAnalyzer } from "./PathAnalyzer";
7
+
8
+ type IModule = {
9
+ [key: string]: any;
10
+ };
11
+
12
+ export namespace ReflectAnalyzer {
13
+ export async function analyze(
14
+ unique: WeakSet<any>,
15
+ file: string,
16
+ ): Promise<IController[]> {
17
+ const module: IModule = await import(file);
18
+ const ret: IController[] = [];
19
+
20
+ for (const tuple of Object.entries(module)) {
21
+ if (unique.has(tuple[1])) continue;
22
+ else unique.add(tuple[1]);
23
+
24
+ const controller: IController | null = _Analyze_controller(
25
+ file,
26
+ ...tuple,
27
+ );
28
+ if (controller !== null) ret.push(controller);
29
+ }
30
+ return ret;
31
+ }
32
+
33
+ /* ---------------------------------------------------------
34
+ CONTROLLER
35
+ --------------------------------------------------------- */
36
+ function _Analyze_controller(
37
+ file: string,
38
+ name: string,
39
+ creator: any,
40
+ ): IController | null {
41
+ //----
42
+ // VALIDATIONS
43
+ //----
44
+ // MUST BE TYPE OF A CREATOR WHO HAS THE CONSTRUCTOR
45
+ if (
46
+ !(
47
+ creator instanceof Function &&
48
+ creator.constructor instanceof Function
49
+ )
50
+ )
51
+ return null;
52
+ // MUST HAVE THOSE MATADATA
53
+ else if (
54
+ ArrayUtil.has(
55
+ Reflect.getMetadataKeys(creator),
56
+ "path",
57
+ "host",
58
+ "scope:options",
59
+ ) === false
60
+ )
61
+ return null;
62
+
63
+ //----
64
+ // CONSTRUCTION
65
+ //----
66
+ // BASIC INFO
67
+ const paths: string[] = _Get_paths(
68
+ Reflect.getMetadata("path", creator),
69
+ );
70
+ const meta: IController = {
71
+ file,
72
+ name,
73
+ paths,
74
+ functions: [],
75
+ };
76
+
77
+ // PARSE CHILDREN DATA
78
+ for (const tuple of _Get_prototype_entries(creator)) {
79
+ const child: IController.IFunction | null = _Analyze_function(
80
+ creator.prototype,
81
+ meta,
82
+ ...tuple,
83
+ );
84
+ if (child !== null) meta.functions.push(child);
85
+ }
86
+
87
+ // RETURNS
88
+ return meta;
89
+ }
90
+
91
+ function _Get_prototype_entries(creator: any): Array<[string, unknown]> {
92
+ const keyList = Object.getOwnPropertyNames(creator.prototype);
93
+ const entries: Array<[string, unknown]> = keyList.map((key) => [
94
+ key,
95
+ creator.prototype[key],
96
+ ]);
97
+
98
+ const parent = Object.getPrototypeOf(creator);
99
+ if (parent.prototype !== undefined)
100
+ entries.push(..._Get_prototype_entries(parent));
101
+
102
+ return entries;
103
+ }
104
+
105
+ function _Get_paths(value: string | string[]): string[] {
106
+ if (typeof value === "string") return [value];
107
+ else if (value.length === 0) return [""];
108
+ else return value;
109
+ }
110
+
111
+ /* ---------------------------------------------------------
112
+ FUNCTION
113
+ --------------------------------------------------------- */
114
+ function _Analyze_function(
115
+ classProto: any,
116
+ controller: IController,
117
+ name: string,
118
+ proto: any,
119
+ ): IController.IFunction | null {
120
+ //----
121
+ // VALIDATIONS
122
+ //----
123
+ // MUST BE TYPE OF A FUNCTION
124
+ if (!(proto instanceof Function)) return null;
125
+ // MUST HAVE THOSE METADATE
126
+ else if (
127
+ ArrayUtil.has(Reflect.getMetadataKeys(proto), "path", "method") ===
128
+ false
129
+ )
130
+ return null;
131
+
132
+ //----
133
+ // CONSTRUCTION
134
+ //----
135
+ // BASIC INFO
136
+ const meta: IController.IFunction = {
137
+ name,
138
+ method: METHODS[Reflect.getMetadata("method", proto)],
139
+ paths: _Get_paths(Reflect.getMetadata("path", proto)),
140
+ parameters: [],
141
+ encrypted:
142
+ Reflect.hasMetadata("__interceptors__", proto) &&
143
+ Reflect.getMetadata("__interceptors__", proto)[0]?.constructor
144
+ ?.name === "EncryptedRouteInterceptor",
145
+ };
146
+
147
+ // PARSE CHILDREN DATA
148
+ const nestParameters: NestParameters | undefined = Reflect.getMetadata(
149
+ "__routeArguments__",
150
+ classProto.constructor,
151
+ name,
152
+ );
153
+ if (nestParameters === undefined) meta.parameters = [];
154
+ else {
155
+ for (const tuple of Object.entries(nestParameters)) {
156
+ const child: IController.IParameter | null = _Analyze_parameter(
157
+ ...tuple,
158
+ );
159
+ if (child !== null) meta.parameters.push(child);
160
+ }
161
+ meta.parameters = meta.parameters.sort((x, y) => x.index - y.index);
162
+ }
163
+
164
+ // VALIDATE PATH ARGUMENTS
165
+ for (const controllerLocation of controller.paths)
166
+ for (const metaLocation of meta.paths) {
167
+ // NORMALIZE LOCATION
168
+ const location: string = PathAnalyzer.join(
169
+ controllerLocation,
170
+ metaLocation,
171
+ );
172
+
173
+ // LIST UP PARAMETERS
174
+ const binded: string[] = PathAnalyzer.parameters(
175
+ location,
176
+ () => `${controller.name}.${name}()`,
177
+ ).sort();
178
+
179
+ const parameters: string[] = meta.parameters
180
+ .filter((param) => param.category === "param")
181
+ .map((param) => param.field!)
182
+ .sort();
183
+
184
+ // DO VALIDATE
185
+ if (equal(binded, parameters) === false)
186
+ throw new Error(
187
+ `Error on ${
188
+ controller.name
189
+ }.${name}(): binded arguments in the "path" between function's decorator and parameters' decorators are different (function: [${binded.join(
190
+ ", ",
191
+ )}], parameters: [${parameters.join(", ")}])`,
192
+ );
193
+ }
194
+
195
+ // RETURNS
196
+ return meta;
197
+ }
198
+
199
+ const METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH"];
200
+
201
+ /* ---------------------------------------------------------
202
+ PARAMETER
203
+ --------------------------------------------------------- */
204
+ function _Analyze_parameter(
205
+ key: string,
206
+ param: INestParam,
207
+ ): IController.IParameter | null {
208
+ const symbol: string = key.split(":")[0];
209
+ if (symbol.indexOf("__custom") !== -1)
210
+ return _Analyze_custom_parameter(param);
211
+
212
+ const typeIndex: number = Number(symbol[0]);
213
+ if (isNaN(typeIndex) === true) return null;
214
+
215
+ const type: ParamCategory | undefined = NEST_PARAMETER_TYPES[typeIndex];
216
+ if (type === undefined) return null;
217
+
218
+ return {
219
+ name: key,
220
+ category: type,
221
+ index: param.index,
222
+ field: param.data,
223
+ encrypted: false,
224
+ };
225
+ }
226
+
227
+ function _Analyze_custom_parameter(
228
+ param: INestParam,
229
+ ): IController.IParameter | null {
230
+ if (param.factory === undefined) return null;
231
+ else if (
232
+ param.factory.name === "TypedBody" ||
233
+ param.factory.name === "EncryptedBody" ||
234
+ param.factory.name === "PlainBody"
235
+ ) {
236
+ return {
237
+ category: "body",
238
+ index: param.index,
239
+ name: param.name,
240
+ field: param.data,
241
+ encrypted: param.factory.name === "EncryptedBody",
242
+ };
243
+ } else if (param.factory.name === "TypedParam")
244
+ return {
245
+ name: param.name,
246
+ category: "param",
247
+ index: param.index,
248
+ field: param.data,
249
+ encrypted: false,
250
+ };
251
+ else return null;
252
+ }
253
+
254
+ type NestParameters = {
255
+ [key: string]: INestParam;
256
+ };
257
+
258
+ interface INestParam {
259
+ name: string;
260
+ index: number;
261
+ factory?: (...args: any) => any;
262
+ data: string | undefined;
263
+ }
264
+
265
+ const NEST_PARAMETER_TYPES = [
266
+ undefined,
267
+ undefined,
268
+ undefined,
269
+ "body",
270
+ "query",
271
+ "param",
272
+ undefined,
273
+ undefined,
274
+ undefined,
275
+ undefined,
276
+ undefined,
277
+ undefined,
278
+ ] as const;
279
+ }
@@ -1,59 +1,59 @@
1
- import fs from "fs";
2
- import glob from "glob";
3
- import path from "path";
4
-
5
- import { INestiaConfig } from "../INestiaConfig";
6
-
7
- export namespace SourceFinder {
8
- export async function find(input: INestiaConfig.IInput): Promise<string[]> {
9
- const dict: Set<string> = new Set();
10
-
11
- await decode(input.include, (str) => dict.add(str));
12
- if (input.exclude)
13
- await decode(input.exclude, (str) => dict.delete(str));
14
-
15
- return [...dict];
16
- }
17
-
18
- async function decode(
19
- input: string[],
20
- closure: (location: string) => void,
21
- ): Promise<void> {
22
- for (const pattern of input) {
23
- for (const location of await _Glob(path.resolve(pattern))) {
24
- const stats: fs.Stats = await fs.promises.stat(location);
25
- if (stats.isDirectory() === true)
26
- await iterate(closure, location);
27
- else if (stats.isFile() && _Is_ts_file(location))
28
- closure(location);
29
- }
30
- }
31
- }
32
-
33
- async function iterate(
34
- closure: (location: string) => void,
35
- location: string,
36
- ): Promise<void> {
37
- const directory: string[] = await fs.promises.readdir(location);
38
- for (const file of directory) {
39
- const next: string = path.resolve(`${location}/${file}`);
40
- const stats: fs.Stats = await fs.promises.stat(next);
41
-
42
- if (stats.isDirectory() === true) await iterate(closure, next);
43
- else if (stats.isFile() && _Is_ts_file(file)) closure(next);
44
- }
45
- }
46
-
47
- function _Glob(pattern: string): Promise<string[]> {
48
- return new Promise((resolve, reject) => {
49
- glob(pattern, (err, matches) => {
50
- if (err) reject(err);
51
- else resolve(matches.map((str) => path.resolve(str)));
52
- });
53
- });
54
- }
55
-
56
- function _Is_ts_file(file: string): boolean {
57
- return file.substr(-3) === ".ts" && file.substr(-5) !== ".d.ts";
58
- }
59
- }
1
+ import fs from "fs";
2
+ import glob from "glob";
3
+ import path from "path";
4
+
5
+ import { INestiaConfig } from "../INestiaConfig";
6
+
7
+ export namespace SourceFinder {
8
+ export async function find(input: INestiaConfig.IInput): Promise<string[]> {
9
+ const dict: Set<string> = new Set();
10
+
11
+ await decode(input.include, (str) => dict.add(str));
12
+ if (input.exclude)
13
+ await decode(input.exclude, (str) => dict.delete(str));
14
+
15
+ return [...dict];
16
+ }
17
+
18
+ async function decode(
19
+ input: string[],
20
+ closure: (location: string) => void,
21
+ ): Promise<void> {
22
+ for (const pattern of input) {
23
+ for (const location of await _Glob(path.resolve(pattern))) {
24
+ const stats: fs.Stats = await fs.promises.stat(location);
25
+ if (stats.isDirectory() === true)
26
+ await iterate(closure, location);
27
+ else if (stats.isFile() && _Is_ts_file(location))
28
+ closure(location);
29
+ }
30
+ }
31
+ }
32
+
33
+ async function iterate(
34
+ closure: (location: string) => void,
35
+ location: string,
36
+ ): Promise<void> {
37
+ const directory: string[] = await fs.promises.readdir(location);
38
+ for (const file of directory) {
39
+ const next: string = path.resolve(`${location}/${file}`);
40
+ const stats: fs.Stats = await fs.promises.stat(next);
41
+
42
+ if (stats.isDirectory() === true) await iterate(closure, next);
43
+ else if (stats.isFile() && _Is_ts_file(file)) closure(next);
44
+ }
45
+ }
46
+
47
+ function _Glob(pattern: string): Promise<string[]> {
48
+ return new Promise((resolve, reject) => {
49
+ glob(pattern, (err, matches) => {
50
+ if (err) reject(err);
51
+ else resolve(matches.map((str) => path.resolve(str)));
52
+ });
53
+ });
54
+ }
55
+
56
+ function _Is_ts_file(file: string): boolean {
57
+ return file.substr(-3) === ".ts" && file.substr(-5) !== ".d.ts";
58
+ }
59
+ }