nestia 2.0.5 → 2.0.7-dev.20220414

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 (121) hide show
  1. package/README.md +5 -0
  2. package/{src/IConfiguration.ts → bin/IConfiguration.d.ts} +5 -8
  3. package/bin/IConfiguration.d.ts.map +1 -0
  4. package/bin/IConfiguration.js +3 -0
  5. package/bin/NestiaApplication.d.ts +10 -0
  6. package/bin/NestiaApplication.d.ts.map +1 -0
  7. package/bin/NestiaApplication.js +281 -0
  8. package/bin/analyses/ControllerAnalyzer.d.ts +7 -0
  9. package/bin/analyses/ControllerAnalyzer.d.ts.map +1 -0
  10. package/bin/analyses/ControllerAnalyzer.js +186 -0
  11. package/bin/analyses/GenericAnalyzer.d.ts +6 -0
  12. package/bin/analyses/GenericAnalyzer.d.ts.map +1 -0
  13. package/bin/analyses/GenericAnalyzer.js +100 -0
  14. package/bin/analyses/ImportAnalyzer.d.ts +13 -0
  15. package/bin/analyses/ImportAnalyzer.d.ts.map +1 -0
  16. package/bin/analyses/ImportAnalyzer.js +82 -0
  17. package/bin/analyses/ReflectAnalyzer.d.ts +5 -0
  18. package/bin/analyses/ReflectAnalyzer.d.ts.map +1 -0
  19. package/bin/analyses/ReflectAnalyzer.js +307 -0
  20. package/bin/analyses/SourceFinder.d.ts +5 -0
  21. package/bin/analyses/SourceFinder.d.ts.map +1 -0
  22. package/bin/analyses/SourceFinder.js +260 -0
  23. package/bin/bundle/HttpError.d.ts +2 -0
  24. package/bin/bundle/HttpError.d.ts.map +1 -0
  25. package/bin/bundle/HttpError.js +6 -0
  26. package/bin/bundle/IConnection.d.ts +2 -0
  27. package/bin/bundle/IConnection.d.ts.map +1 -0
  28. package/bin/bundle/IConnection.js +3 -0
  29. package/bin/bundle/Primitive.d.ts +2 -0
  30. package/bin/bundle/Primitive.d.ts.map +1 -0
  31. package/bin/bundle/Primitive.js +6 -0
  32. package/bin/bundle/__internal/AesPkcs5.d.ts +2 -0
  33. package/bin/bundle/__internal/AesPkcs5.d.ts.map +1 -0
  34. package/bin/bundle/__internal/AesPkcs5.js +6 -0
  35. package/bin/bundle/__internal/Fetcher.d.ts +2 -0
  36. package/bin/bundle/__internal/Fetcher.d.ts.map +1 -0
  37. package/bin/bundle/__internal/Fetcher.js +6 -0
  38. package/bin/executable/internal/CompilerOptions.d.ts +13 -0
  39. package/bin/executable/internal/CompilerOptions.d.ts.map +1 -0
  40. package/bin/executable/internal/CompilerOptions.js +132 -0
  41. package/bin/executable/internal/NestiaConfig.d.ts +5 -0
  42. package/bin/executable/internal/NestiaConfig.d.ts.map +1 -0
  43. package/bin/executable/internal/NestiaConfig.js +196 -0
  44. package/bin/executable/internal/nestia.config.getter.d.ts +2 -0
  45. package/bin/executable/internal/nestia.config.getter.d.ts.map +1 -0
  46. package/bin/executable/internal/nestia.config.getter.js +60 -0
  47. package/bin/executable/nestia.d.ts +3 -0
  48. package/bin/executable/nestia.d.ts.map +1 -0
  49. package/bin/executable/nestia.js +136 -0
  50. package/bin/executable/sdk.d.ts +2 -0
  51. package/bin/executable/sdk.d.ts.map +1 -0
  52. package/bin/executable/sdk.js +206 -0
  53. package/bin/generates/FileGenerator.d.ts +6 -0
  54. package/bin/generates/FileGenerator.d.ts.map +1 -0
  55. package/bin/generates/FileGenerator.js +302 -0
  56. package/bin/generates/FunctionGenerator.d.ts +5 -0
  57. package/bin/generates/FunctionGenerator.d.ts.map +1 -0
  58. package/bin/generates/FunctionGenerator.js +207 -0
  59. package/bin/generates/SdkGenerator.d.ts +6 -0
  60. package/bin/generates/SdkGenerator.d.ts.map +1 -0
  61. package/bin/generates/SdkGenerator.js +147 -0
  62. package/bin/index.d.ts +3 -0
  63. package/bin/index.d.ts.map +1 -0
  64. package/bin/index.js +28 -0
  65. package/bin/module.d.ts +3 -0
  66. package/bin/module.d.ts.map +1 -0
  67. package/bin/module.js +19 -0
  68. package/{src/structures/IController.ts → bin/structures/IController.d.ts} +6 -13
  69. package/bin/structures/IController.d.ts.map +1 -0
  70. package/bin/structures/IController.js +3 -0
  71. package/{src/structures/IRoute.ts → bin/structures/IRoute.d.ts} +5 -11
  72. package/bin/structures/IRoute.d.ts.map +1 -0
  73. package/bin/structures/IRoute.js +3 -0
  74. package/bin/structures/MethodType.d.ts +5 -0
  75. package/bin/structures/MethodType.d.ts.map +1 -0
  76. package/bin/structures/MethodType.js +8 -0
  77. package/bin/structures/ParamCategory.d.ts +2 -0
  78. package/bin/structures/ParamCategory.d.ts.map +1 -0
  79. package/bin/structures/ParamCategory.js +3 -0
  80. package/bin/utils/ArrayUtil.d.ts +6 -0
  81. package/bin/utils/ArrayUtil.d.ts.map +1 -0
  82. package/bin/utils/ArrayUtil.js +144 -0
  83. package/bin/utils/DirectoryUtil.d.ts +6 -0
  84. package/bin/utils/DirectoryUtil.d.ts.map +1 -0
  85. package/bin/utils/DirectoryUtil.js +190 -0
  86. package/bin/utils/ImportDictionary.d.ts +7 -0
  87. package/bin/utils/ImportDictionary.d.ts.map +1 -0
  88. package/bin/utils/ImportDictionary.js +85 -0
  89. package/bin/utils/StringUtil.d.ts +4 -0
  90. package/bin/utils/StringUtil.d.ts.map +1 -0
  91. package/bin/utils/StringUtil.js +13 -0
  92. package/bin/utils/stripJsonComments.d.ts +4 -0
  93. package/bin/utils/stripJsonComments.d.ts.map +1 -0
  94. package/bin/utils/stripJsonComments.js +76 -0
  95. package/package.json +14 -10
  96. package/tsconfig.json +8 -7
  97. package/src/NestiaApplication.ts +0 -96
  98. package/src/analyses/ControllerAnalyzer.ts +0 -154
  99. package/src/analyses/GenericAnalyzer.ts +0 -52
  100. package/src/analyses/ImportAnalyzer.ts +0 -93
  101. package/src/analyses/ReflectAnalyzer.ts +0 -221
  102. package/src/analyses/SourceFinder.ts +0 -73
  103. package/src/bin/nestia.ts +0 -59
  104. package/src/bundle/HttpError.ts +0 -1
  105. package/src/bundle/IConnection.ts +0 -1
  106. package/src/bundle/Primitive.ts +0 -1
  107. package/src/bundle/__internal/AesPkcs5.ts +0 -1
  108. package/src/bundle/__internal/Fetcher.ts +0 -1
  109. package/src/executable/sdk.ts +0 -89
  110. package/src/generates/FileGenerator.ts +0 -150
  111. package/src/generates/FunctionGenerator.ts +0 -201
  112. package/src/generates/SdkGenerator.ts +0 -39
  113. package/src/internal/TsConfig.ts +0 -115
  114. package/src/internal/tsconfig.default.json +0 -81
  115. package/src/structures/MethodType.ts +0 -6
  116. package/src/structures/ParamCategory.ts +0 -1
  117. package/src/utils/ArrayUtil.ts +0 -26
  118. package/src/utils/DirectoryUtil.ts +0 -48
  119. package/src/utils/ImportDictionary.ts +0 -44
  120. package/src/utils/StringUtil.ts +0 -10
  121. package/src/utils/stripJsonComments.ts +0 -79
@@ -1,96 +0,0 @@
1
- import * as fs from "fs";
2
- import * as path from "path";
3
- import * as tsc from "typescript";
4
- import { Pair } from "tstl/utility/Pair";
5
- import { Singleton } from "tstl/thread/Singleton";
6
-
7
- import { ControllerAnalyzer } from "./analyses/ControllerAnalyzer";
8
- import { ReflectAnalyzer } from "./analyses/ReflectAnalyzer";
9
- import { SourceFinder } from "./analyses/SourceFinder";
10
- import { SdkGenerator } from "./generates/SdkGenerator";
11
-
12
- import { IConfiguration } from "./IConfiguration";
13
- import { IController } from "./structures/IController";
14
- import { IRoute } from "./structures/IRoute";
15
- import { ArrayUtil } from "./utils/ArrayUtil";
16
-
17
- export class NestiaApplication
18
- {
19
- private readonly config_: IConfiguration;
20
- private readonly bundle_checker_: Singleton<Promise<(str: string) => boolean>>;
21
-
22
- public constructor(config: IConfiguration)
23
- {
24
- this.config_ = config;
25
- this.bundle_checker_ = new Singleton(async () =>
26
- {
27
- const bundles: string[] = await fs.promises.readdir(`${__dirname}${path.sep}bundle`);
28
- const tuples: Pair<string, boolean>[] = await ArrayUtil.asyncMap(bundles, async file =>
29
- {
30
- const relative: string = `${this.config_.output}${path.sep}${file}`;
31
- const stats: fs.Stats = await fs.promises.stat(`${__dirname}${path.sep}bundle${path.sep}${file}`);
32
-
33
- return new Pair(relative, stats.isDirectory());
34
- });
35
-
36
- return (file: string): boolean =>
37
- {
38
- for (const it of tuples)
39
- if (it.second === false && file === it.first)
40
- return true;
41
- else if (it.second === true && file.indexOf(it.first) === 0)
42
- return true;
43
- return false;
44
- };
45
- });
46
- }
47
-
48
- public async generate(): Promise<void>
49
- {
50
- // LOAD CONTROLLER FILES
51
- const input: IConfiguration.IInput = this.config_.input instanceof Array
52
- ? { include: this.config_.input }
53
- : typeof this.config_.input === "string"
54
- ? { include: [ this.config_.input ] }
55
- : this.config_.input;
56
- const fileList: string[] = await ArrayUtil.asyncFilter
57
- (
58
- await SourceFinder.find(input),
59
- file => this.is_not_excluded(file)
60
- );
61
-
62
- // ANALYZE REFLECTS
63
- const unique: WeakSet<any> = new WeakSet();
64
- const controllerList: IController[] = [];
65
-
66
- for (const file of fileList)
67
- controllerList.push(...await ReflectAnalyzer.analyze(unique, file));
68
-
69
- // ANALYZE TYPESCRIPT CODE
70
- const program: tsc.Program = tsc.createProgram
71
- (
72
- controllerList.map(c => c.file),
73
- this.config_.compilerOptions || {}
74
- );
75
- const checker: tsc.TypeChecker = program.getTypeChecker();
76
-
77
- const routeList: IRoute[] = [];
78
- for (const controller of controllerList)
79
- {
80
- const sourceFile: tsc.SourceFile | undefined = program.getSourceFile(controller.file);
81
- if (sourceFile === undefined)
82
- continue;
83
-
84
- routeList.push(...ControllerAnalyzer.analyze(checker, sourceFile, controller));
85
- }
86
-
87
- // DO GENERATE
88
- await SdkGenerator.generate(this.config_, routeList);
89
- }
90
-
91
- private async is_not_excluded(file: string): Promise<boolean>
92
- {
93
- return file.indexOf(`${this.config_.output}${path.sep}functional`) === -1
94
- && (await this.bundle_checker_.get())(file) === false;
95
- }
96
- }
@@ -1,154 +0,0 @@
1
- import * as NodePath from "path";
2
- import * as tsc from "typescript";
3
- import { HashMap } from "tstl/container/HashMap";
4
-
5
- import { IController } from "../structures/IController";
6
- import { IRoute } from "../structures/IRoute";
7
-
8
- import { GenericAnalyzer } from "./GenericAnalyzer";
9
- import { ImportAnalyzer } from "./ImportAnalyzer";
10
-
11
- export namespace ControllerAnalyzer
12
- {
13
- export function analyze(checker: tsc.TypeChecker, sourceFile: tsc.SourceFile, controller: IController): IRoute[]
14
- {
15
- // FIND CONTROLLER CLASS
16
- const ret: IRoute[] = [];
17
- tsc.forEachChild(sourceFile, node =>
18
- {
19
- if (tsc.isClassDeclaration(node) && node.name?.escapedText === controller.name)
20
- {
21
- // ANALYZE THE CONTROLLER
22
- ret.push(..._Analyze_controller(checker, controller, node));
23
- return;
24
- }
25
- });
26
- return ret;
27
- }
28
-
29
- /* ---------------------------------------------------------
30
- CLASS
31
- --------------------------------------------------------- */
32
- function _Analyze_controller
33
- (
34
- checker: tsc.TypeChecker,
35
- controller: IController,
36
- classNode: tsc.ClassDeclaration
37
- ): IRoute[]
38
- {
39
- const ret: IRoute[] = [];
40
- const classType: tsc.InterfaceType = checker.getTypeAtLocation(classNode) as tsc.InterfaceType;
41
- const genericDict: GenericAnalyzer.Dictionary = GenericAnalyzer.analyze(checker, classNode);
42
-
43
- for (const property of classType.getProperties())
44
- if (property.declarations)
45
- for (const declaration of property.declarations)
46
- {
47
- // TARGET ONLY METHOD
48
- if (!tsc.isMethodDeclaration(declaration))
49
- continue;
50
-
51
- // IT MUST BE
52
- const identifier = declaration.name;
53
- if (!tsc.isIdentifier(identifier))
54
- continue;
55
-
56
- // ANALYZED WITH THE REFLECTED-FUNCTION
57
- const func: IController.IFunction | undefined = controller.functions.find(f => f.name === identifier.escapedText);
58
- if (func !== undefined)
59
- ret.push(_Analyze_function(checker, controller, genericDict, func, declaration));
60
- }
61
- return ret;
62
- }
63
-
64
- /* ---------------------------------------------------------
65
- FUNCTION
66
- --------------------------------------------------------- */
67
- function _Analyze_function
68
- (
69
- checker: tsc.TypeChecker,
70
- controller: IController,
71
- genericDict: GenericAnalyzer.Dictionary,
72
- func: IController.IFunction,
73
- declaration: tsc.MethodDeclaration
74
- ): IRoute
75
- {
76
- // PREPARE ASSETS
77
- const signature: tsc.Signature | undefined = checker.getSignatureFromDeclaration(declaration);
78
- if (signature === undefined)
79
- throw new Error(`Error on ControllerAnalyzer._Analyze_function(): unable to get the ignature from the ${controller.name}.${func.name}().`);
80
-
81
- const importDict: ImportAnalyzer.Dictionary = new HashMap();
82
-
83
- // EXPLORE CHILDREN TYPES
84
- const parameters: IRoute.IParameter[] = func.parameters.map(param => _Analyze_parameter
85
- (
86
- checker,
87
- genericDict,
88
- importDict,
89
- controller,
90
- func.name,
91
- param,
92
- declaration.parameters[param.index]
93
- ));
94
- const output: string = ImportAnalyzer.analyze
95
- (
96
- checker,
97
- genericDict,
98
- importDict,
99
- checker.getReturnTypeOfSignature(signature),
100
- );
101
- const imports: [string, string[]][] = importDict.toJSON().map(pair => [pair.first, pair.second.toJSON()]);
102
-
103
- // CONFIGURE PATH
104
- let path: string = NodePath.join(controller.path, func.path).split("\\").join("/");
105
- if (path[0] !== "/")
106
- path = "/" + path;
107
- if (path[path.length - 1] === "/" && path !== "/")
108
- path = path.substr(0, path.length - 1);
109
-
110
- // RETURNS
111
- return {
112
- ...func,
113
- path,
114
- parameters,
115
- output,
116
- imports,
117
-
118
- symbol: `${controller.name}.${func.name}()`,
119
- comments: signature.getDocumentationComment(undefined),
120
- tags: signature.getJsDocTags()
121
- };
122
- }
123
-
124
- /* ---------------------------------------------------------
125
- PARAMETER
126
- --------------------------------------------------------- */
127
- function _Analyze_parameter
128
- (
129
- checker: tsc.TypeChecker,
130
- genericDict: GenericAnalyzer.Dictionary,
131
- importDict: ImportAnalyzer.Dictionary,
132
- controller: IController,
133
- funcName: string,
134
- param: IController.IParameter,
135
- declaration: tsc.ParameterDeclaration
136
- ): IRoute.IParameter
137
- {
138
- const symbol: tsc.Symbol = checker.getSymbolAtLocation(declaration.name)!;
139
- const type: tsc.Type = checker.getTypeOfSymbolAtLocation(symbol, declaration);
140
- const name: string = symbol.getEscapedName().toString();
141
-
142
- // VALIDATE PARAMETERS
143
- if ((param.category === "query" || param.category === "body") && param.field !== undefined)
144
- throw new Error(`Error on ${controller.name}.${funcName}(): parameter ${name} is specifying a field ${param.field} of the request ${param.category} message, however, Nestia does not support the field specialization for the request ${param.category} message. Erase the ${controller.name}.${funcName}()#${name} parameter and re-define a new decorator accepting full structured message.`);
145
-
146
- return {
147
- name,
148
- category: param.category,
149
- field: param.field,
150
- encrypted: param.encrypted,
151
- type: ImportAnalyzer.analyze(checker, genericDict, importDict, type)
152
- };
153
- }
154
- }
@@ -1,52 +0,0 @@
1
- import * as tsc from "typescript";
2
-
3
- export namespace GenericAnalyzer
4
- {
5
- export type Dictionary = WeakMap<tsc.Type, tsc.Type>;
6
-
7
- export function analyze(checker: tsc.TypeChecker, classNode: tsc.ClassDeclaration): Dictionary
8
- {
9
- const dict: Dictionary = new WeakMap();
10
- explore(checker, dict, classNode);
11
- return dict;
12
- }
13
-
14
- function explore(checker: tsc.TypeChecker, dict: Dictionary, classNode: tsc.ClassDeclaration): void
15
- {
16
- if (classNode.heritageClauses === undefined)
17
- return;
18
-
19
- for (const heritage of classNode.heritageClauses)
20
- for (const hType of heritage.types)
21
- {
22
- // MUST BE CLASS
23
- const expression: tsc.Type = checker.getTypeAtLocation(hType.expression);
24
- const superNode: tsc.Declaration = expression.symbol.getDeclarations()![0];
25
-
26
- if (!tsc.isClassDeclaration(superNode))
27
- continue;
28
-
29
- // SPECIFY GENERICS
30
- const usages: ReadonlyArray<tsc.TypeNode> = if_undefined_array(hType.typeArguments);
31
- const parameters: ReadonlyArray<tsc.TypeParameterDeclaration> = if_undefined_array(superNode.typeParameters);
32
-
33
- parameters.forEach((param, index) =>
34
- {
35
- const paramType: tsc.Type = checker.getTypeAtLocation(param);
36
- const usageType: tsc.Type = (usages[index] !== undefined)
37
- ? checker.getTypeAtLocation(usages[index])
38
- : checker.getTypeAtLocation(param.default!);
39
-
40
- dict.set(paramType, usageType);
41
- });
42
-
43
- // RECUSRIVE EXPLORATION
44
- explore(checker, dict, superNode);
45
- }
46
- }
47
-
48
- function if_undefined_array<T>(array: ReadonlyArray<T> | undefined): ReadonlyArray<T>
49
- {
50
- return array !== undefined ? array : [];
51
- }
52
- }
@@ -1,93 +0,0 @@
1
- import * as tsc from "typescript";
2
-
3
- import { HashMap } from "tstl/container/HashMap";
4
- import { HashSet } from "tstl/container/HashSet";
5
- import { GenericAnalyzer } from "./GenericAnalyzer";
6
-
7
- export namespace ImportAnalyzer
8
- {
9
- export interface IOutput
10
- {
11
- features: [string, string[]][];
12
- alias: string;
13
- }
14
-
15
- export type Dictionary = HashMap<string, HashSet<string>>;
16
-
17
- export function analyze
18
- (
19
- checker: tsc.TypeChecker,
20
- genericDict: GenericAnalyzer.Dictionary,
21
- importDict: Dictionary,
22
- type: tsc.Type
23
- ): string
24
- {
25
- return explore(checker, genericDict, importDict, type);
26
- }
27
-
28
- function explore
29
- (
30
- checker: tsc.TypeChecker,
31
- genericDict: GenericAnalyzer.Dictionary,
32
- importDict: Dictionary,
33
- type: tsc.Type
34
- ): string
35
- {
36
- //----
37
- // CONDITIONAL BRANCHES
38
- //----
39
- // DECOMPOSE GENERIC ARGUMENT
40
- while (genericDict.has(type) === true)
41
- type = genericDict.get(type)!;
42
-
43
- // PRIMITIVE
44
- const symbol: tsc.Symbol | undefined = type.getSymbol() || type.aliasSymbol;
45
- if (symbol === undefined)
46
- return checker.typeToString(type, undefined, undefined);
47
-
48
- // UNION OR INTERSECT
49
- else if (type.aliasSymbol === undefined && type.isUnionOrIntersection())
50
- {
51
- const joiner: string = type.isIntersection() ? " & " : " | ";
52
- return type.types.map(child => explore(checker, genericDict, importDict, child)).join(joiner);
53
- }
54
-
55
- //----
56
- // SPECIALIZATION
57
- //----
58
- const name: string = get_name(symbol);
59
- const sourceFile: tsc.SourceFile = symbol.declarations![0].getSourceFile();
60
-
61
- if (sourceFile.fileName.indexOf("typescript/lib") === -1)
62
- {
63
- let it: HashMap.Iterator<string, HashSet<string>> = importDict.find(sourceFile.fileName);
64
- if (it.equals(importDict.end()) === true)
65
- it = importDict.emplace(sourceFile.fileName, new HashSet()).first;
66
- it.second.insert(name.split(".")[0]);
67
- }
68
-
69
- // CHECK GENERIC
70
- const generic: readonly tsc.Type[] = checker.getTypeArguments(type as tsc.TypeReference);
71
- if (generic.length)
72
- {
73
- return name === "Promise"
74
- ? explore(checker, genericDict, importDict, generic[0])
75
- : `${name}<${generic.map(child => explore(checker, genericDict, importDict, child)).join(", ")}>`;
76
- }
77
- else
78
- return name;
79
- }
80
-
81
- function get_name(symbol: tsc.Symbol): string
82
- {
83
- let name: string = symbol.escapedName.toString();
84
- let decl: tsc.Node = symbol.getDeclarations()![0].parent;
85
-
86
- while (tsc.isModuleBlock(decl))
87
- {
88
- name = `${decl.parent.name.getText()}.${name}`;
89
- decl = decl.parent.parent;
90
- }
91
- return name;
92
- }
93
- }
@@ -1,221 +0,0 @@
1
- import * as NodePath from "path";
2
- import { equal } from "tstl/ranges/module";
3
-
4
- import { ArrayUtil } from "../utils/ArrayUtil";
5
- import { StringUtil } from "../utils/StringUtil";
6
-
7
- import { IController } from "../structures/IController";
8
- import { ParamCategory } from "../structures/ParamCategory";
9
-
10
- type IModule =
11
- {
12
- [key: string]: any;
13
- }
14
-
15
- export namespace ReflectAnalyzer
16
- {
17
- export async function analyze(unique: WeakSet<any>, file: string): Promise<IController[]>
18
- {
19
- const module: IModule = await import(file);
20
- const ret: IController[] = [];
21
-
22
- for (const tuple of Object.entries(module))
23
- {
24
- if (unique.has(tuple[1]))
25
- continue;
26
- else
27
- unique.add(tuple[1]);
28
-
29
- const controller: IController | null = _Analyze_controller(file, ...tuple);
30
- if (controller !== null)
31
- ret.push(controller);
32
- }
33
- return ret;
34
- }
35
-
36
- /* ---------------------------------------------------------
37
- CONTROLLER
38
- --------------------------------------------------------- */
39
- function _Analyze_controller(file: string, name: string, creator: any): IController | null
40
- {
41
- //----
42
- // VALIDATIONS
43
- //----
44
- // MUST BE TYPE OF A CREATOR WHO HAS THE CONSTRUCTOR
45
- if (!(creator instanceof Function && creator.constructor instanceof Function))
46
- return null;
47
-
48
- // MUST HAVE THOSE MATADATA
49
- else if (ArrayUtil.has(Reflect.getMetadataKeys(creator), "path", "host", "scope:options") === false)
50
- return null;
51
-
52
- //----
53
- // CONSTRUCTION
54
- //----
55
- // BASIC INFO
56
- const meta: IController = {
57
- file,
58
- name,
59
- path: Reflect.getMetadata("path", creator),
60
- functions: []
61
- };
62
-
63
- // PARSE CHILDREN DATA
64
- for (const tuple of _Get_prototype_entries(creator))
65
- {
66
- const child: IController.IFunction | null = _Analyze_function(creator.prototype, meta, ...tuple);
67
- if (child !== null)
68
- meta.functions.push(child);
69
- }
70
-
71
- // RETURNS
72
- return meta;
73
- }
74
-
75
- function _Get_prototype_entries(creator: any): Array<[string, unknown]>
76
- {
77
- const tuple = Object.entries(creator.prototype);
78
- const parent = Object.getPrototypeOf(creator);
79
-
80
- if (parent.prototype !== undefined)
81
- tuple.push(..._Get_prototype_entries(parent));
82
-
83
- return tuple;
84
- }
85
-
86
- /* ---------------------------------------------------------
87
- FUNCTION
88
- --------------------------------------------------------- */
89
- function _Analyze_function(classProto: any, controller: IController, name: string, proto: any): IController.IFunction | null
90
- {
91
- //----
92
- // VALIDATIONS
93
- //----
94
- // MUST BE TYPE OF A FUNCTION
95
- if (!(proto instanceof Function))
96
- return null;
97
-
98
- // MUST HAVE THOSE METADATE
99
- else if (ArrayUtil.has(Reflect.getMetadataKeys(proto), "path", "method") === false)
100
- return null;
101
-
102
- //----
103
- // CONSTRUCTION
104
- //----
105
- // BASIC INFO
106
- const meta: IController.IFunction = {
107
- name,
108
- method: METHODS[Reflect.getMetadata("method", proto)],
109
- path: Reflect.getMetadata("path", proto),
110
- parameters: [],
111
- encrypted: Reflect.hasMetadata("__interceptors__", proto)
112
- && Reflect.getMetadata("__interceptors__", proto)[0]?.constructor?.name === "EncryptedRouteInterceptor"
113
- };
114
-
115
- // PARSE CHILDREN DATA
116
- const nestParameters: NestParameters | undefined = Reflect.getMetadata("__routeArguments__", classProto.constructor, name);
117
- if (nestParameters === undefined)
118
- meta.parameters = [];
119
- else
120
- {
121
- for (const tuple of Object.entries(nestParameters))
122
- {
123
- const child: IController.IParameter | null = _Analyze_parameter(...tuple);
124
- if (child !== null)
125
- meta.parameters.push(child);
126
- }
127
- meta.parameters = meta.parameters.sort((x, y) => x.index - y.index);
128
- }
129
-
130
- // VALIDATE PATH ARGUMENTS
131
- const funcPathArguments: string[] = StringUtil.betweens(NodePath.join(controller.path, meta.path).split("\\").join("/"), ":", "/").sort();
132
- const paramPathArguments: string[] = meta.parameters.filter(param => param.category === "param").map(param => param.field!).sort();
133
-
134
- if (equal(funcPathArguments, paramPathArguments) === false)
135
- throw new Error(`Error on ${controller.name}.${name}(): binded arguments in the "path" between function's decorator and parameters' decorators are different (function: [${funcPathArguments.join(", ")}], parameters: [${paramPathArguments.join(", ")}])`);
136
-
137
- // RETURNS
138
- return meta;
139
- }
140
-
141
- const METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH"];
142
-
143
- /* ---------------------------------------------------------
144
- PARAMETER
145
- --------------------------------------------------------- */
146
- function _Analyze_parameter(key: string, param: INestParam): IController.IParameter | null
147
- {
148
- const symbol: string = key.split(":")[0];
149
- if (symbol.indexOf("__custom") !== -1)
150
- return _Analyze_custom_parameter(param);
151
-
152
- const typeIndex: number = Number(symbol[0]);
153
- if (isNaN(typeIndex) === true)
154
- return null;
155
-
156
- const type: ParamCategory | undefined = NEST_PARAMETER_TYPES[typeIndex];
157
- if (type === undefined)
158
- return null;
159
-
160
- return {
161
- name: key,
162
- category: type,
163
- index: param.index,
164
- field: param.data,
165
- encrypted: false
166
- }
167
- }
168
-
169
- function _Analyze_custom_parameter(param: INestParam): IController.IParameter | null
170
- {
171
- if (param.factory === undefined)
172
- return null;
173
- else if (param.factory.name === "EncryptedBody" || param.factory.name === "PlainBody")
174
- {
175
- return {
176
- category: "body",
177
- index: param.index,
178
- name: param.name,
179
- field: param.data,
180
- encrypted: param.factory.name === "EncryptedBody"
181
- };
182
- }
183
- else if (param.factory.name === "TypedParam")
184
- return {
185
- name: param.name,
186
- category: "param",
187
- index: param.index,
188
- field: param.data,
189
- encrypted: false
190
- };
191
- else
192
- return null;
193
- }
194
-
195
- type NestParameters = {
196
- [key: string]: INestParam;
197
- }
198
-
199
- interface INestParam
200
- {
201
- name: string;
202
- index: number;
203
- factory?: Function;
204
- data: string | undefined;
205
- }
206
-
207
- const NEST_PARAMETER_TYPES = [
208
- undefined,
209
- undefined,
210
- undefined,
211
- "body",
212
- "query",
213
- "param",
214
- undefined,
215
- undefined,
216
- undefined,
217
- undefined,
218
- undefined,
219
- undefined
220
- ] as const;
221
- }
@@ -1,73 +0,0 @@
1
- import * as fs from "fs";
2
- import glob from "glob";
3
- import * as path from "path";
4
-
5
- import { IConfiguration } from "../IConfiguration";
6
-
7
- export namespace SourceFinder
8
- {
9
- export async function find(input: IConfiguration.IInput): Promise<string[]>
10
- {
11
- const dict: Set<string> = new Set();
12
- await decode(input.include, str => dict.add(str));
13
- if (input.exclude)
14
- await decode(input.exclude, str => dict.delete(str));
15
-
16
- return [...dict];
17
- }
18
-
19
- async function decode
20
- (
21
- input: string[],
22
- closure: (location: string) => void,
23
- ): Promise<void>
24
- {
25
- for (const pattern of input)
26
- for (const location of await _Glob(path.resolve(pattern)))
27
- {
28
- const stats: fs.Stats = await fs.promises.stat(location);
29
- if (stats.isDirectory() === true)
30
- await iterate(closure, location);
31
- else if (stats.isFile() && _Is_ts_file(location))
32
- closure(location);
33
- }
34
- }
35
-
36
- async function iterate
37
- (
38
- closure: (location: string) => void,
39
- location: string
40
- ): Promise<void>
41
- {
42
- const directory: string[] = await fs.promises.readdir(location);
43
- for (const file of directory)
44
- {
45
- const next: string = path.resolve(`${location}/${file}`);
46
- const stats: fs.Stats = await fs.promises.stat(next);
47
-
48
- if (stats.isDirectory() === true)
49
- await iterate(closure, next);
50
- else if (stats.isFile() && _Is_ts_file(file))
51
- closure(next);
52
- }
53
- }
54
-
55
- function _Glob(pattern: string): Promise<string[]>
56
- {
57
- return new Promise((resolve, reject) =>
58
- {
59
- glob(pattern, (err, matches) =>
60
- {
61
- if (err)
62
- reject(err);
63
- else
64
- resolve(matches.map(str => path.resolve(str)));
65
- });
66
- });
67
- }
68
-
69
- function _Is_ts_file(file: string): boolean
70
- {
71
- return file.substr(-3) === ".ts" && file.substr(-5) !== ".d.ts";
72
- }
73
- }