@nestia/sdk 2.3.0-dev.20231018-4 → 2.3.0-dev.20231019

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 (43) hide show
  1. package/assets/config/nestia.config.ts +13 -7
  2. package/lib/INestiaConfig.d.ts +8 -8
  3. package/lib/NestiaSdkApplication.d.ts +0 -2
  4. package/lib/NestiaSdkApplication.js +3 -42
  5. package/lib/NestiaSdkApplication.js.map +1 -1
  6. package/lib/analyses/ConfigAnalyzer.d.ts +2 -1
  7. package/lib/analyses/ConfigAnalyzer.js +97 -42
  8. package/lib/analyses/ConfigAnalyzer.js.map +1 -1
  9. package/lib/analyses/ControllerAnalyzer.d.ts +1 -1
  10. package/lib/analyses/ControllerAnalyzer.js +39 -24
  11. package/lib/analyses/ControllerAnalyzer.js.map +1 -1
  12. package/lib/analyses/PathAnalyzer.d.ts +2 -2
  13. package/lib/analyses/PathAnalyzer.js +19 -1
  14. package/lib/analyses/PathAnalyzer.js.map +1 -1
  15. package/lib/analyses/ReflectAnalyzer.d.ts +1 -1
  16. package/lib/analyses/ReflectAnalyzer.js +8 -5
  17. package/lib/analyses/ReflectAnalyzer.js.map +1 -1
  18. package/lib/executable/internal/NestiaConfigLoader.js +97 -97
  19. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  20. package/lib/generates/E2eGenerator.js +1 -1
  21. package/lib/generates/E2eGenerator.js.map +1 -1
  22. package/lib/generates/SwaggerGenerator.js +1 -2
  23. package/lib/generates/SwaggerGenerator.js.map +1 -1
  24. package/lib/structures/IController.d.ts +1 -0
  25. package/lib/structures/INormalizedInput.d.ts +19 -0
  26. package/lib/structures/INormalizedInput.js +3 -0
  27. package/lib/structures/INormalizedInput.js.map +1 -0
  28. package/lib/utils/SourceFinder.d.ts +7 -7
  29. package/lib/utils/SourceFinder.js +2 -2
  30. package/lib/utils/SourceFinder.js.map +1 -1
  31. package/package.json +4 -4
  32. package/src/INestiaConfig.ts +17 -36
  33. package/src/NestiaSdkApplication.ts +15 -67
  34. package/src/analyses/ConfigAnalyzer.ts +131 -46
  35. package/src/analyses/ControllerAnalyzer.ts +32 -19
  36. package/src/analyses/PathAnalyzer.ts +22 -3
  37. package/src/analyses/ReflectAnalyzer.ts +8 -2
  38. package/src/executable/internal/NestiaConfigLoader.ts +3 -1
  39. package/src/generates/E2eGenerator.ts +1 -1
  40. package/src/generates/SwaggerGenerator.ts +4 -8
  41. package/src/structures/IController.ts +1 -0
  42. package/src/structures/INormalizedInput.ts +20 -0
  43. package/src/utils/SourceFinder.ts +11 -10
@@ -7,9 +7,11 @@ import { CommentFactory } from "typia/lib/factories/CommentFactory";
7
7
 
8
8
  import { INestiaConfig } from "../INestiaConfig";
9
9
  import { IController } from "../structures/IController";
10
+ import { INormalizedInput } from "../structures/INormalizedInput";
10
11
  import { IRoute } from "../structures/IRoute";
11
12
  import { ITypeTuple } from "../structures/ITypeTuple";
12
13
  import { PathUtil } from "../utils/PathUtil";
14
+ import { ConfigAnalyzer } from "./ConfigAnalyzer";
13
15
  import { ExceptionAnalyzer } from "./ExceptionAnalyzer";
14
16
  import { GenericAnalyzer } from "./GenericAnalyzer";
15
17
  import { ImportAnalyzer } from "./ImportAnalyzer";
@@ -17,14 +19,16 @@ import { PathAnalyzer } from "./PathAnalyzer";
17
19
  import { SecurityAnalyzer } from "./SecurityAnalyzer";
18
20
 
19
21
  export namespace ControllerAnalyzer {
20
- export function analyze(
22
+ export async function analyze(
21
23
  config: INestiaConfig,
22
24
  checker: ts.TypeChecker,
23
25
  sourceFile: ts.SourceFile,
24
26
  controller: IController,
25
- ): IRoute[] {
27
+ ): Promise<IRoute[]> {
26
28
  // FIND CONTROLLER CLASS
29
+ const input: INormalizedInput = await ConfigAnalyzer.input(config);
27
30
  const ret: IRoute[] = [];
31
+
28
32
  ts.forEachChild(sourceFile, (node) => {
29
33
  if (
30
34
  ts.isClassDeclaration(node) &&
@@ -32,7 +36,13 @@ export namespace ControllerAnalyzer {
32
36
  ) {
33
37
  // ANALYZE THE CONTROLLER
34
38
  ret.push(
35
- ..._Analyze_controller(config, checker, controller, node),
39
+ ..._Analyze_controller(
40
+ config,
41
+ input,
42
+ checker,
43
+ controller,
44
+ node,
45
+ ),
36
46
  );
37
47
  return;
38
48
  }
@@ -45,6 +55,7 @@ export namespace ControllerAnalyzer {
45
55
  --------------------------------------------------------- */
46
56
  function _Analyze_controller(
47
57
  config: INestiaConfig,
58
+ input: INormalizedInput,
48
59
  checker: ts.TypeChecker,
49
60
  controller: IController,
50
61
  classNode: ts.ClassDeclaration,
@@ -77,6 +88,7 @@ export namespace ControllerAnalyzer {
77
88
 
78
89
  const routes: IRoute[] = _Analyze_function(
79
90
  config,
91
+ input,
80
92
  checker,
81
93
  controller,
82
94
  genericDict,
@@ -94,6 +106,7 @@ export namespace ControllerAnalyzer {
94
106
  --------------------------------------------------------- */
95
107
  function _Analyze_function(
96
108
  config: INestiaConfig,
109
+ input: INormalizedInput,
97
110
  checker: ts.TypeChecker,
98
111
  controller: IController,
99
112
  genericDict: GenericAnalyzer.Dictionary,
@@ -115,9 +128,8 @@ export namespace ControllerAnalyzer {
115
128
  `Error on ControllerAnalyzer.analyze(): unable to get the signature from the ${controller.name}.${func.name}().`,
116
129
  );
117
130
 
118
- const importDict: ImportAnalyzer.Dictionary = new HashMap();
119
-
120
131
  // EXPLORE CHILDREN TYPES
132
+ const importDict: ImportAnalyzer.Dictionary = new HashMap();
121
133
  const parameters: IRoute.IParameter[] = func.parameters.map((param) =>
122
134
  _Analyze_parameter(
123
135
  checker,
@@ -205,7 +217,7 @@ export namespace ControllerAnalyzer {
205
217
  description: CommentFactory.description(symbol),
206
218
  operationId: jsDocTags
207
219
  .find(({ name }) => name === "operationId")
208
- ?.text!?.[0].text.split(" ")[0]
220
+ ?.text?.[0].text.split(" ")[0]
209
221
  .trim(),
210
222
  jsDocTags: jsDocTags,
211
223
  setHeaders: jsDocTags
@@ -232,22 +244,23 @@ export namespace ControllerAnalyzer {
232
244
  };
233
245
 
234
246
  // CONFIGURE PATHS
235
- const input: INestiaConfig.IInput =
236
- config.input as INestiaConfig.IInput;
237
247
  const pathList: Set<string> = new Set();
238
248
  const versions: Array<string | null> = _Analyze_versions(
239
- func.versions ??
240
- controller.versions ??
241
- (input.versioning?.defaultVersion !== undefined
242
- ? Array.isArray(input.versioning?.defaultVersion)
243
- ? input.versioning?.defaultVersion
244
- : [input.versioning?.defaultVersion]
245
- : undefined) ??
246
- undefined,
249
+ input.versioning === undefined
250
+ ? undefined
251
+ : func.versions ??
252
+ controller.versions ??
253
+ (input.versioning?.defaultVersion !== undefined
254
+ ? Array.isArray(input.versioning?.defaultVersion)
255
+ ? input.versioning?.defaultVersion
256
+ : [input.versioning?.defaultVersion]
257
+ : undefined) ??
258
+ undefined,
247
259
  );
248
- for (const cPath of controller.paths)
249
- for (const filePath of func.paths)
250
- pathList.add(PathAnalyzer.join(cPath, filePath));
260
+ for (const prefix of controller.prefixes)
261
+ for (const cPath of controller.paths)
262
+ for (const filePath of func.paths)
263
+ pathList.add(PathAnalyzer.join(prefix, cPath, filePath));
251
264
 
252
265
  return [...pathList]
253
266
  .map((individual) =>
@@ -1,11 +1,12 @@
1
+ import { RequestMethod } from "@nestjs/common";
1
2
  import path from "path";
2
3
  import { Token, parse } from "path-to-regexp";
3
4
 
4
- import { INestiaConfig } from "../INestiaConfig";
5
+ import { INormalizedInput } from "../structures/INormalizedInput";
5
6
 
6
7
  export namespace PathAnalyzer {
7
8
  export const combinate =
8
- (globalPrefix: INestiaConfig.IInput["globalPrefix"]) =>
9
+ (globalPrefix: INormalizedInput["globalPrefix"]) =>
9
10
  (versions: Array<string | null>) =>
10
11
  (props: { path: string; method: string }): string[] => {
11
12
  const out = (str: string) =>
@@ -18,7 +19,7 @@ export namespace PathAnalyzer {
18
19
  return globalPrefix.exclude.some((exclude) =>
19
20
  typeof exclude === "string"
20
21
  ? RegExp(exclude).test(props.path)
21
- : (exclude.method as string) === props.method &&
22
+ : METHOD(exclude.method) === props.method &&
22
23
  RegExp(exclude.path).test(props.path),
23
24
  )
24
25
  ? out(props.path)
@@ -79,3 +80,21 @@ export namespace PathAnalyzer {
79
80
  }
80
81
 
81
82
  const ERROR_MESSAGE = "nestia supports only string typed parameter on path";
83
+ const METHOD = (value: RequestMethod) =>
84
+ value === RequestMethod.ALL
85
+ ? "all"
86
+ : value === RequestMethod.DELETE
87
+ ? "delete"
88
+ : value === RequestMethod.GET
89
+ ? "get"
90
+ : value === RequestMethod.HEAD
91
+ ? "head"
92
+ : value === RequestMethod.OPTIONS
93
+ ? "options"
94
+ : value === RequestMethod.PATCH
95
+ ? "patch"
96
+ : value === RequestMethod.POST
97
+ ? "post"
98
+ : value === RequestMethod.PUT
99
+ ? "put"
100
+ : "unknown";
@@ -17,6 +17,8 @@ export namespace ReflectAnalyzer {
17
17
  export async function analyze(
18
18
  unique: WeakSet<any>,
19
19
  file: string,
20
+ prefixes: string[],
21
+ target?: Function,
20
22
  ): Promise<IController[]> {
21
23
  const module: IModule = await (async () => {
22
24
  try {
@@ -37,14 +39,16 @@ export namespace ReflectAnalyzer {
37
39
 
38
40
  for (const [key, value] of Object.entries(module)) {
39
41
  if (typeof value !== "function" || unique.has(value)) continue;
42
+ else if ((target ?? value) !== value) continue;
40
43
  else unique.add(value);
41
44
 
42
- const controller: IController | null = _Analyze_controller(
45
+ const result: IController | null = _Analyze_controller(
43
46
  file,
44
47
  key,
45
48
  value,
49
+ prefixes,
46
50
  );
47
- if (controller !== null) ret.push(controller);
51
+ if (result !== null) ret.push(result);
48
52
  }
49
53
  return ret;
50
54
  }
@@ -56,6 +60,7 @@ export namespace ReflectAnalyzer {
56
60
  file: string,
57
61
  name: string,
58
62
  creator: any,
63
+ prefixes: string[],
59
64
  ): IController | null {
60
65
  //----
61
66
  // VALIDATIONS
@@ -87,6 +92,7 @@ export namespace ReflectAnalyzer {
87
92
  file,
88
93
  name,
89
94
  functions: [],
95
+ prefixes,
90
96
  paths: _Get_paths(creator),
91
97
  versions: _Get_versions(creator),
92
98
  security: _Get_securities(creator),
@@ -71,7 +71,9 @@ export namespace NestiaConfigLoader {
71
71
  export const project = async (file: string): Promise<string> => {
72
72
  const connector = new WorkerConnector(null, null, "process");
73
73
  await connector.connect(
74
- `${__dirname}/nestia.project.getter.${__filename.substr(-2)}`,
74
+ `${__dirname}/nestia.project.getter.${__filename.substring(
75
+ __filename.length - 2,
76
+ )}`,
75
77
  );
76
78
 
77
79
  const driver = await connector.getDriver<typeof NestiaProjectGetter>();
@@ -53,7 +53,7 @@ export namespace E2eGenerator {
53
53
  output,
54
54
  content.replace(
55
55
  "${input}",
56
- JSON.stringify(await ConfigAnalyzer.input(config.input)),
56
+ JSON.stringify(await ConfigAnalyzer.input(config)),
57
57
  ),
58
58
  "utf8",
59
59
  );
@@ -1,5 +1,4 @@
1
1
  import fs from "fs";
2
- import NodePath from "path";
3
2
  import path from "path";
4
3
  import { Singleton } from "tstl/thread/Singleton";
5
4
  import ts from "typescript";
@@ -41,8 +40,8 @@ export namespace SwaggerGenerator {
41
40
  validate_security(config)(routeList);
42
41
 
43
42
  // PREPARE ASSETS
44
- const parsed: NodePath.ParsedPath = NodePath.parse(config.output);
45
- const directory: string = NodePath.dirname(parsed.dir);
43
+ const parsed: path.ParsedPath = path.parse(config.output);
44
+ const directory: string = path.dirname(parsed.dir);
46
45
  if (fs.existsSync(directory) === false)
47
46
  try {
48
47
  await fs.promises.mkdir(directory);
@@ -53,11 +52,8 @@ export namespace SwaggerGenerator {
53
52
  );
54
53
 
55
54
  const location: string = !!parsed.ext
56
- ? NodePath.resolve(config.output)
57
- : NodePath.join(
58
- NodePath.resolve(config.output),
59
- "swagger.json",
60
- );
55
+ ? path.resolve(config.output)
56
+ : path.join(path.resolve(config.output), "swagger.json");
61
57
 
62
58
  const collection: MetadataCollection = new MetadataCollection({
63
59
  replace: MetadataCollection.replace,
@@ -5,6 +5,7 @@ import type { ParamCategory } from "./ParamCategory";
5
5
  export interface IController {
6
6
  file: string;
7
7
  name: string;
8
+ prefixes: string[];
8
9
  paths: string[];
9
10
  versions:
10
11
  | Array<Exclude<VersionValue, Array<string | typeof VERSION_NEUTRAL>>>
@@ -0,0 +1,20 @@
1
+ import { RouteInfo, VersionValue } from "@nestjs/common/interfaces";
2
+
3
+ export interface INormalizedInput {
4
+ include: INormalizedInput.IInput[];
5
+ globalPrefix?: {
6
+ prefix: string;
7
+ exclude?: Array<string | RouteInfo>;
8
+ };
9
+ versioning?: {
10
+ prefix: string;
11
+ defaultVersion?: VersionValue;
12
+ };
13
+ }
14
+ export namespace INormalizedInput {
15
+ export interface IInput {
16
+ paths: string[];
17
+ file: string;
18
+ controller?: Function;
19
+ }
20
+ }
@@ -3,6 +3,12 @@ import glob from "glob";
3
3
  import path from "path";
4
4
 
5
5
  export namespace SourceFinder {
6
+ interface IProps {
7
+ exclude?: string[];
8
+ include: string[];
9
+ filter: (location: string) => Promise<boolean>;
10
+ }
11
+
6
12
  export const find = async (props: IProps): Promise<string[]> => {
7
13
  const dict: Set<string> = new Set();
8
14
 
@@ -16,7 +22,7 @@ export namespace SourceFinder {
16
22
  };
17
23
 
18
24
  const emplace =
19
- (filter: (file: string) => boolean) =>
25
+ (filter: (file: string) => Promise<boolean>) =>
20
26
  (input: string[]) =>
21
27
  async (closure: (location: string) => void): Promise<void> => {
22
28
  for (const pattern of input) {
@@ -28,13 +34,14 @@ export namespace SourceFinder {
28
34
  const stats: fs.Stats = await fs.promises.stat(file);
29
35
  if (stats.isDirectory() === true)
30
36
  await iterate(filter)(closure)(file);
31
- else if (stats.isFile() && filter(file)) closure(file);
37
+ else if (stats.isFile() && (await filter(file)))
38
+ closure(file);
32
39
  }
33
40
  }
34
41
  };
35
42
 
36
43
  const iterate =
37
- (filter: (location: string) => boolean) =>
44
+ (filter: (location: string) => Promise<boolean>) =>
38
45
  (closure: (location: string) => void) =>
39
46
  async (location: string): Promise<void> => {
40
47
  const directory: string[] = await fs.promises.readdir(location);
@@ -44,7 +51,7 @@ export namespace SourceFinder {
44
51
 
45
52
  if (stats.isDirectory() === true)
46
53
  await iterate(filter)(closure)(next);
47
- else if (stats.isFile() && filter(next)) closure(next);
54
+ else if (stats.isFile() && (await filter(next))) closure(next);
48
55
  }
49
56
  };
50
57
 
@@ -61,9 +68,3 @@ export namespace SourceFinder {
61
68
  !pattern.endsWith(".d.ts") &&
62
69
  fs.existsSync(pattern);
63
70
  }
64
-
65
- interface IProps {
66
- exclude?: string[];
67
- include: string[];
68
- filter: (location: string) => boolean;
69
- }