@nestia/sdk 3.0.5 → 3.1.0-dev.20240426

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 (174) hide show
  1. package/lib/NestiaSdkApplication.d.ts +1 -0
  2. package/lib/NestiaSdkApplication.js +17 -17
  3. package/lib/NestiaSdkApplication.js.map +1 -1
  4. package/lib/analyses/AccessorAnalyzer.d.ts +3 -2
  5. package/lib/analyses/AccessorAnalyzer.js.map +1 -1
  6. package/lib/analyses/ExceptionAnalyzer.d.ts +11 -3
  7. package/lib/analyses/ExceptionAnalyzer.js +23 -18
  8. package/lib/analyses/ExceptionAnalyzer.js.map +1 -1
  9. package/lib/analyses/GenericAnalyzer.d.ts +1 -0
  10. package/lib/analyses/ImportAnalyzer.d.ts +6 -1
  11. package/lib/analyses/ImportAnalyzer.js +27 -29
  12. package/lib/analyses/ImportAnalyzer.js.map +1 -1
  13. package/lib/analyses/PathAnalyzer.d.ts +0 -5
  14. package/lib/analyses/PathAnalyzer.js +0 -32
  15. package/lib/analyses/PathAnalyzer.js.map +1 -1
  16. package/lib/analyses/{ReflectAnalyzer.d.ts → ReflectControllerAnalyzer.d.ts} +3 -4
  17. package/lib/analyses/ReflectControllerAnalyzer.js +145 -0
  18. package/lib/analyses/ReflectControllerAnalyzer.js.map +1 -0
  19. package/lib/analyses/ReflectHttpOperationAnalyzer.d.ts +10 -0
  20. package/lib/analyses/ReflectHttpOperationAnalyzer.js +224 -0
  21. package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -0
  22. package/lib/analyses/ReflectMetadataAnalyzer.d.ts +8 -0
  23. package/lib/analyses/ReflectMetadataAnalyzer.js +34 -0
  24. package/lib/analyses/ReflectMetadataAnalyzer.js.map +1 -0
  25. package/lib/analyses/ReflectWebSocketOperationAnalyzer.d.ts +10 -0
  26. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js +78 -0
  27. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js.map +1 -0
  28. package/lib/analyses/SecurityAnalyzer.js +1 -1
  29. package/lib/analyses/SecurityAnalyzer.js.map +1 -1
  30. package/lib/analyses/TypedControllerAnalyzer.d.ts +9 -0
  31. package/lib/analyses/TypedControllerAnalyzer.js +77 -0
  32. package/lib/analyses/TypedControllerAnalyzer.js.map +1 -0
  33. package/lib/analyses/TypedHttpOperationAnalyzer.d.ts +16 -0
  34. package/lib/analyses/TypedHttpOperationAnalyzer.js +251 -0
  35. package/lib/analyses/TypedHttpOperationAnalyzer.js.map +1 -0
  36. package/lib/analyses/TypedWebSocketOperationAnalyzer.d.ts +16 -0
  37. package/lib/analyses/TypedWebSocketOperationAnalyzer.js +218 -0
  38. package/lib/analyses/TypedWebSocketOperationAnalyzer.js.map +1 -0
  39. package/lib/executable/internal/NestiaConfigLoader.d.ts +1 -0
  40. package/lib/generates/CloneGenerator.d.ts +3 -4
  41. package/lib/generates/CloneGenerator.js +8 -8
  42. package/lib/generates/CloneGenerator.js.map +1 -1
  43. package/lib/generates/E2eGenerator.d.ts +3 -4
  44. package/lib/generates/E2eGenerator.js +7 -7
  45. package/lib/generates/E2eGenerator.js.map +1 -1
  46. package/lib/generates/SdkGenerator.d.ts +4 -4
  47. package/lib/generates/SdkGenerator.js +8 -8
  48. package/lib/generates/SdkGenerator.js.map +1 -1
  49. package/lib/generates/SwaggerGenerator.d.ts +5 -2
  50. package/lib/generates/SwaggerGenerator.js +15 -13
  51. package/lib/generates/SwaggerGenerator.js.map +1 -1
  52. package/lib/generates/internal/E2eFileProgrammer.d.ts +4 -5
  53. package/lib/generates/internal/E2eFileProgrammer.js +13 -12
  54. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  55. package/lib/generates/internal/FilePrinter.d.ts +1 -0
  56. package/lib/generates/internal/ImportDictionary.d.ts +1 -0
  57. package/lib/generates/internal/SdkAliasCollection.d.ts +9 -8
  58. package/lib/generates/internal/SdkAliasCollection.js +20 -20
  59. package/lib/generates/internal/SdkAliasCollection.js.map +1 -1
  60. package/lib/generates/internal/SdkDistributionComposer.d.ts +1 -1
  61. package/lib/generates/internal/SdkDistributionComposer.js +36 -2
  62. package/lib/generates/internal/SdkDistributionComposer.js.map +1 -1
  63. package/lib/generates/internal/SdkFileProgrammer.d.ts +4 -4
  64. package/lib/generates/internal/SdkFileProgrammer.js +10 -7
  65. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  66. package/lib/generates/internal/SdkHttpCloneProgrammer.d.ts +13 -0
  67. package/lib/generates/internal/{SdkCloneProgrammer.js → SdkHttpCloneProgrammer.js} +14 -14
  68. package/lib/generates/internal/SdkHttpCloneProgrammer.js.map +1 -0
  69. package/lib/generates/internal/SdkHttpFunctionProgrammer.d.ts +12 -0
  70. package/lib/generates/internal/{SdkFunctionProgrammer.js → SdkHttpFunctionProgrammer.js} +12 -12
  71. package/lib/generates/internal/SdkHttpFunctionProgrammer.js.map +1 -0
  72. package/lib/generates/internal/SdkHttpNamespaceProgrammer.d.ts +12 -0
  73. package/lib/generates/internal/{SdkNamespaceProgrammer.js → SdkHttpNamespaceProgrammer.js} +26 -26
  74. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js.map +1 -0
  75. package/lib/generates/internal/SdkHttpRouteProgrammer.d.ts +8 -0
  76. package/lib/generates/internal/{SdkRouteProgrammer.js → SdkHttpRouteProgrammer.js} +11 -11
  77. package/lib/generates/internal/SdkHttpRouteProgrammer.js.map +1 -0
  78. package/lib/generates/internal/SdkHttpSimulationProgrammer.d.ts +13 -0
  79. package/lib/generates/internal/{SdkSimulationProgrammer.js → SdkHttpSimulationProgrammer.js} +18 -18
  80. package/lib/generates/internal/SdkHttpSimulationProgrammer.js.map +1 -0
  81. package/lib/generates/internal/SdkRouteDirectory.d.ts +3 -2
  82. package/lib/generates/internal/SdkRouteDirectory.js.map +1 -1
  83. package/lib/generates/internal/SdkTypeProgrammer.d.ts +4 -3
  84. package/lib/generates/internal/SdkTypeProgrammer.js +33 -33
  85. package/lib/generates/internal/SdkTypeProgrammer.js.map +1 -1
  86. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.d.ts +8 -0
  87. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js +115 -0
  88. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js.map +1 -0
  89. package/lib/generates/internal/SdkWebSocketRouteProgrammer.d.ts +8 -0
  90. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js +79 -0
  91. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js.map +1 -0
  92. package/lib/generates/internal/SwaggerSchemaGenerator.d.ts +6 -5
  93. package/lib/generates/internal/SwaggerSchemaGenerator.js +3 -1
  94. package/lib/generates/internal/SwaggerSchemaGenerator.js.map +1 -1
  95. package/lib/structures/INestiaProject.d.ts +1 -0
  96. package/lib/structures/IReflectController.d.ts +15 -0
  97. package/lib/structures/{IRoute.js → IReflectController.js} +1 -1
  98. package/lib/structures/IReflectController.js.map +1 -0
  99. package/lib/structures/{IController.d.ts → IReflectHttpOperation.d.ts} +15 -25
  100. package/lib/structures/IReflectHttpOperation.js +3 -0
  101. package/lib/structures/IReflectHttpOperation.js.map +1 -0
  102. package/lib/structures/IReflectWebSocketOperation.d.ts +16 -0
  103. package/lib/structures/IReflectWebSocketOperation.js +3 -0
  104. package/lib/structures/IReflectWebSocketOperation.js.map +1 -0
  105. package/lib/structures/ISwaggerError.d.ts +2 -2
  106. package/lib/structures/ITypeTuple.d.ts +1 -0
  107. package/lib/structures/{IRoute.d.ts → ITypedHttpRoute.d.ts} +12 -12
  108. package/lib/structures/{IController.js → ITypedHttpRoute.js} +1 -1
  109. package/lib/structures/ITypedHttpRoute.js.map +1 -0
  110. package/lib/structures/ITypedWebSocketRoute.d.ts +54 -0
  111. package/lib/structures/ITypedWebSocketRoute.js +3 -0
  112. package/lib/structures/ITypedWebSocketRoute.js.map +1 -0
  113. package/lib/structures/TypeEntry.d.ts +1 -0
  114. package/lib/utils/VersioningStrategy.d.ts +6 -0
  115. package/lib/utils/VersioningStrategy.js +22 -0
  116. package/lib/utils/VersioningStrategy.js.map +1 -0
  117. package/package.json +8 -6
  118. package/src/NestiaSdkApplication.ts +36 -34
  119. package/src/analyses/AccessorAnalyzer.ts +12 -5
  120. package/src/analyses/ExceptionAnalyzer.ts +49 -39
  121. package/src/analyses/ImportAnalyzer.ts +123 -104
  122. package/src/analyses/PathAnalyzer.ts +0 -41
  123. package/src/analyses/ReflectControllerAnalyzer.ts +155 -0
  124. package/src/analyses/ReflectHttpOperationAnalyzer.ts +290 -0
  125. package/src/analyses/ReflectMetadataAnalyzer.ts +53 -0
  126. package/src/analyses/ReflectWebSocketOperationAnalyzer.ts +96 -0
  127. package/src/analyses/SecurityAnalyzer.ts +2 -1
  128. package/src/analyses/TypedControllerAnalyzer.ts +92 -0
  129. package/src/analyses/TypedHttpOperationAnalyzer.ts +352 -0
  130. package/src/analyses/TypedWebSocketOperationAnalyzer.ts +368 -0
  131. package/src/generates/CloneGenerator.ts +17 -15
  132. package/src/generates/E2eGenerator.ts +10 -12
  133. package/src/generates/SdkGenerator.ts +19 -12
  134. package/src/generates/SwaggerGenerator.ts +31 -21
  135. package/src/generates/internal/E2eFileProgrammer.ts +20 -24
  136. package/src/generates/internal/SdkAliasCollection.ts +38 -33
  137. package/src/generates/internal/SdkDistributionComposer.ts +13 -4
  138. package/src/generates/internal/SdkFileProgrammer.ts +17 -13
  139. package/src/generates/internal/{SdkCloneProgrammer.ts → SdkHttpCloneProgrammer.ts} +14 -15
  140. package/src/generates/internal/{SdkFunctionProgrammer.ts → SdkHttpFunctionProgrammer.ts} +24 -23
  141. package/src/generates/internal/{SdkNamespaceProgrammer.ts → SdkHttpNamespaceProgrammer.ts} +44 -49
  142. package/src/generates/internal/{SdkRouteProgrammer.ts → SdkHttpRouteProgrammer.ts} +12 -13
  143. package/src/generates/internal/{SdkSimulationProgrammer.ts → SdkHttpSimulationProgrammer.ts} +23 -25
  144. package/src/generates/internal/SdkRouteDirectory.ts +3 -2
  145. package/src/generates/internal/SdkTypeProgrammer.ts +43 -37
  146. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +378 -0
  147. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +248 -0
  148. package/src/generates/internal/SwaggerSchemaGenerator.ts +26 -21
  149. package/src/structures/IReflectController.ts +17 -0
  150. package/src/structures/{IController.ts → IReflectHttpOperation.ts} +78 -94
  151. package/src/structures/IReflectWebSocketOperation.ts +17 -0
  152. package/src/structures/ISwaggerError.ts +2 -2
  153. package/src/structures/{IRoute.ts → ITypedHttpRoute.ts} +14 -12
  154. package/src/structures/ITypedWebSocketRoute.ts +67 -0
  155. package/src/utils/VersioningStrategy.ts +28 -0
  156. package/lib/analyses/ControllerAnalyzer.d.ts +0 -7
  157. package/lib/analyses/ControllerAnalyzer.js +0 -269
  158. package/lib/analyses/ControllerAnalyzer.js.map +0 -1
  159. package/lib/analyses/ReflectAnalyzer.js +0 -377
  160. package/lib/analyses/ReflectAnalyzer.js.map +0 -1
  161. package/lib/generates/internal/SdkCloneProgrammer.d.ts +0 -12
  162. package/lib/generates/internal/SdkCloneProgrammer.js.map +0 -1
  163. package/lib/generates/internal/SdkFunctionProgrammer.d.ts +0 -11
  164. package/lib/generates/internal/SdkFunctionProgrammer.js.map +0 -1
  165. package/lib/generates/internal/SdkNamespaceProgrammer.d.ts +0 -11
  166. package/lib/generates/internal/SdkNamespaceProgrammer.js.map +0 -1
  167. package/lib/generates/internal/SdkRouteProgrammer.d.ts +0 -7
  168. package/lib/generates/internal/SdkRouteProgrammer.js.map +0 -1
  169. package/lib/generates/internal/SdkSimulationProgrammer.d.ts +0 -12
  170. package/lib/generates/internal/SdkSimulationProgrammer.js.map +0 -1
  171. package/lib/structures/IController.js.map +0 -1
  172. package/lib/structures/IRoute.js.map +0 -1
  173. package/src/analyses/ControllerAnalyzer.ts +0 -402
  174. package/src/analyses/ReflectAnalyzer.ts +0 -471
@@ -0,0 +1,155 @@
1
+ import {
2
+ HOST_METADATA,
3
+ PATH_METADATA,
4
+ SCOPE_OPTIONS_METADATA,
5
+ } from "@nestjs/common/constants";
6
+
7
+ import { INestiaProject } from "../structures/INestiaProject";
8
+ import { IReflectController } from "../structures/IReflectController";
9
+ import { IReflectHttpOperation } from "../structures/IReflectHttpOperation";
10
+ import { IReflectWebSocketOperation } from "../structures/IReflectWebSocketOperation";
11
+ import { ArrayUtil } from "../utils/ArrayUtil";
12
+ import { ReflectHttpOperationAnalyzer } from "./ReflectHttpOperationAnalyzer";
13
+ import { ReflectMetadataAnalyzer } from "./ReflectMetadataAnalyzer";
14
+ import { ReflectWebSocketOperationAnalyzer } from "./ReflectWebSocketOperationAnalyzer";
15
+
16
+ type IModule = {
17
+ [key: string]: any;
18
+ };
19
+
20
+ export namespace ReflectControllerAnalyzer {
21
+ export const analyze =
22
+ (project: INestiaProject) =>
23
+ async (
24
+ unique: WeakSet<any>,
25
+ file: string,
26
+ prefixes: string[],
27
+ target?: Function,
28
+ ): Promise<IReflectController[]> => {
29
+ const module: IModule = await (async () => {
30
+ try {
31
+ return await import(file);
32
+ } catch (exp) {
33
+ console.log(
34
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
35
+ );
36
+ console.log(`Error on "${file}" file. Check your code.`);
37
+ console.log(exp);
38
+ console.log(
39
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
40
+ );
41
+ process.exit(-1);
42
+ }
43
+ })();
44
+ const ret: IReflectController[] = [];
45
+
46
+ for (const [key, value] of Object.entries(module)) {
47
+ if (typeof value !== "function" || unique.has(value)) continue;
48
+ else if ((target ?? value) !== value) continue;
49
+ else unique.add(value);
50
+
51
+ const result: IReflectController | null = _Analyze_controller(project)({
52
+ file,
53
+ name: key,
54
+ creator: value,
55
+ prefixes,
56
+ });
57
+ if (result !== null) ret.push(result);
58
+ }
59
+ return ret;
60
+ };
61
+
62
+ /* ---------------------------------------------------------
63
+ CONTROLLER
64
+ --------------------------------------------------------- */
65
+ const _Analyze_controller =
66
+ (project: INestiaProject) =>
67
+ (props: {
68
+ file: string;
69
+ name: string;
70
+ creator: any;
71
+ prefixes: string[];
72
+ }): IReflectController | null => {
73
+ //----
74
+ // VALIDATIONS
75
+ //----
76
+ // MUST BE TYPE OF A CREATOR WHO HAS THE CONSTRUCTOR
77
+ if (
78
+ !(
79
+ props.creator instanceof Function &&
80
+ props.creator.constructor instanceof Function
81
+ )
82
+ )
83
+ return null;
84
+ // MUST HAVE THOSE MATADATA
85
+ else if (
86
+ ArrayUtil.has(
87
+ Reflect.getMetadataKeys(props.creator),
88
+ PATH_METADATA,
89
+ HOST_METADATA,
90
+ SCOPE_OPTIONS_METADATA,
91
+ ) === false
92
+ )
93
+ return null;
94
+
95
+ //----
96
+ // CONSTRUCTION
97
+ //----
98
+ // BASIC INFO
99
+ const meta: IReflectController = {
100
+ constructor: props.creator,
101
+ prototype: props.creator.prototype,
102
+ file: props.file,
103
+ name: props.name,
104
+ operations: [],
105
+ prefixes: props.prefixes,
106
+ paths: ReflectMetadataAnalyzer.paths(props.creator).filter((str) => {
107
+ if (str.includes("*") === true) {
108
+ project.warnings.push({
109
+ file: props.file,
110
+ controller: props.name,
111
+ function: null,
112
+ message: "@nestia/sdk does not compose wildcard controller.",
113
+ });
114
+ return false;
115
+ }
116
+ return true;
117
+ }),
118
+ versions: ReflectMetadataAnalyzer.versions(props.creator),
119
+ security: ReflectMetadataAnalyzer.securities(props.creator),
120
+ swaggerTgas:
121
+ Reflect.getMetadata("swagger/apiUseTags", props.creator) ?? [],
122
+ };
123
+
124
+ // PARSE CHILDREN DATA
125
+ for (const [key, value] of _Get_prototype_entries(props.creator)) {
126
+ if (typeof value !== "function") continue;
127
+ const next = {
128
+ controller: meta,
129
+ name: key,
130
+ function: value,
131
+ };
132
+ const child: IReflectHttpOperation | IReflectWebSocketOperation | null =
133
+ ReflectWebSocketOperationAnalyzer.analyze(project)(next) ??
134
+ ReflectHttpOperationAnalyzer.analyze(project)(next);
135
+ if (child !== null) meta.operations.push(child);
136
+ }
137
+
138
+ // RETURNS
139
+ return meta;
140
+ };
141
+
142
+ function _Get_prototype_entries(creator: any): Array<[string, unknown]> {
143
+ const keyList = Object.getOwnPropertyNames(creator.prototype);
144
+ const entries: Array<[string, unknown]> = keyList.map((key) => [
145
+ key,
146
+ creator.prototype[key],
147
+ ]);
148
+
149
+ const parent = Object.getPrototypeOf(creator);
150
+ if (parent.prototype !== undefined)
151
+ entries.push(..._Get_prototype_entries(parent));
152
+
153
+ return entries;
154
+ }
155
+ }
@@ -0,0 +1,290 @@
1
+ import {
2
+ HEADERS_METADATA,
3
+ HTTP_CODE_METADATA,
4
+ INTERCEPTORS_METADATA,
5
+ METHOD_METADATA,
6
+ PATH_METADATA,
7
+ ROUTE_ARGS_METADATA,
8
+ } from "@nestjs/common/constants";
9
+ import { RouteParamtypes } from "@nestjs/common/enums/route-paramtypes.enum";
10
+ import { ranges } from "tstl";
11
+
12
+ import { IErrorReport } from "../structures/IErrorReport";
13
+ import { INestiaProject } from "../structures/INestiaProject";
14
+ import { IReflectController } from "../structures/IReflectController";
15
+ import { IReflectHttpOperation } from "../structures/IReflectHttpOperation";
16
+ import { ParamCategory } from "../structures/ParamCategory";
17
+ import { ArrayUtil } from "../utils/ArrayUtil";
18
+ import { PathAnalyzer } from "./PathAnalyzer";
19
+ import { ReflectMetadataAnalyzer } from "./ReflectMetadataAnalyzer";
20
+
21
+ export namespace ReflectHttpOperationAnalyzer {
22
+ export const analyze =
23
+ (project: INestiaProject) =>
24
+ (props: {
25
+ controller: IReflectController;
26
+ function: Function;
27
+ name: string;
28
+ }): IReflectHttpOperation | null => {
29
+ if (
30
+ ArrayUtil.has(
31
+ Reflect.getMetadataKeys(props.function),
32
+ PATH_METADATA,
33
+ METHOD_METADATA,
34
+ ) === false
35
+ )
36
+ return null;
37
+
38
+ const errors: IErrorReport[] = [];
39
+
40
+ //----
41
+ // CONSTRUCTION
42
+ //----
43
+ // BASIC INFO
44
+ const encrypted: boolean = hasInterceptor("EncryptedRouteInterceptor")(
45
+ props.function,
46
+ );
47
+ const query: boolean = hasInterceptor("TypedQueryRouteInterceptor")(
48
+ props.function,
49
+ );
50
+ const method: string =
51
+ METHODS[Reflect.getMetadata(METHOD_METADATA, props.function)];
52
+ if (method === undefined || method === "OPTIONS") return null;
53
+
54
+ const parameters: IReflectHttpOperation.IParameter[] = (() => {
55
+ const nestParameters: NestParameters | undefined = Reflect.getMetadata(
56
+ ROUTE_ARGS_METADATA,
57
+ props.controller.constructor,
58
+ props.name,
59
+ );
60
+ if (nestParameters === undefined) return [];
61
+
62
+ const output: IReflectHttpOperation.IParameter[] = [];
63
+ for (const tuple of Object.entries(nestParameters)) {
64
+ const child: IReflectHttpOperation.IParameter | null =
65
+ _Analyze_http_parameter(...tuple);
66
+ if (child !== null) output.push(child);
67
+ }
68
+ return output.sort((x, y) => x.index - y.index);
69
+ })();
70
+
71
+ // VALIDATE BODY
72
+ const body: IReflectHttpOperation.IParameter | undefined =
73
+ parameters.find((param) => param.category === "body");
74
+ if (body !== undefined && (method === "GET" || method === "HEAD")) {
75
+ project.errors.push({
76
+ file: props.controller.file,
77
+ controller: props.controller.name,
78
+ function: props.name,
79
+ message: `"body" parameter cannot be used in the "${method}" method.`,
80
+ });
81
+ return null;
82
+ }
83
+
84
+ // DO CONSTRUCT
85
+ const meta: IReflectHttpOperation = {
86
+ protocol: "http",
87
+ function: props.function,
88
+ name: props.name,
89
+ method: method === "ALL" ? "POST" : method,
90
+ paths: ReflectMetadataAnalyzer.paths(props.function).filter((str) => {
91
+ if (str.includes("*") === true) {
92
+ project.warnings.push({
93
+ file: props.controller.file,
94
+ controller: props.controller.name,
95
+ function: props.name,
96
+ message: "@nestia/sdk does not compose wildcard method.",
97
+ });
98
+ return false;
99
+ }
100
+ return true;
101
+ }),
102
+ versions: ReflectMetadataAnalyzer.versions(props.function),
103
+ parameters,
104
+ status: Reflect.getMetadata(HTTP_CODE_METADATA, props.function),
105
+ encrypted,
106
+ contentType: encrypted
107
+ ? "text/plain"
108
+ : query
109
+ ? "application/x-www-form-urlencoded"
110
+ : Reflect.getMetadata(HEADERS_METADATA, props.function)?.find(
111
+ (h: Record<string, string>) =>
112
+ typeof h?.name === "string" &&
113
+ typeof h?.value === "string" &&
114
+ h.name.toLowerCase() === "content-type",
115
+ )?.value ?? "application/json",
116
+ security: ReflectMetadataAnalyzer.securities(props.function),
117
+ exceptions: ReflectMetadataAnalyzer.exceptions(props.function),
118
+ swaggerTags: [
119
+ ...new Set([
120
+ ...props.controller.swaggerTgas,
121
+ ...(Reflect.getMetadata("swagger/apiUseTags", props.function) ??
122
+ []),
123
+ ]),
124
+ ],
125
+ };
126
+
127
+ // VALIDATE PATH ARGUMENTS
128
+ for (const controllerLocation of props.controller.paths)
129
+ for (const metaLocation of meta.paths) {
130
+ // NORMALIZE LOCATION
131
+ const location: string = PathAnalyzer.join(
132
+ controllerLocation,
133
+ metaLocation,
134
+ );
135
+ if (location.includes("*")) continue;
136
+
137
+ // LIST UP PARAMETERS
138
+ const binded: string[] | null = PathAnalyzer.parameters(location);
139
+ if (binded === null) {
140
+ project.errors.push({
141
+ file: props.controller.file,
142
+ controller: props.controller.name,
143
+ function: props.name,
144
+ message: `invalid path (${JSON.stringify(location)})`,
145
+ });
146
+ continue;
147
+ }
148
+ const parameters: string[] = meta.parameters
149
+ .filter((param) => param.category === "param")
150
+ .map((param) => param.field!)
151
+ .sort();
152
+
153
+ // DO VALIDATE
154
+ if (ranges.equal(binded.sort(), parameters) === false)
155
+ errors.push({
156
+ file: props.controller.file,
157
+ controller: props.controller.name,
158
+ function: props.name,
159
+ message: `binded arguments in the "path" between function's decorator and parameters' decorators are different (function: [${binded.join(
160
+ ", ",
161
+ )}], parameters: [${parameters.join(", ")}]).`,
162
+ });
163
+ }
164
+
165
+ // RETURNS
166
+ if (errors.length) {
167
+ project.errors.push(...errors);
168
+ return null;
169
+ }
170
+ return meta;
171
+ };
172
+
173
+ function _Analyze_http_parameter(
174
+ key: string,
175
+ param: INestParam,
176
+ ): IReflectHttpOperation.IParameter | null {
177
+ const symbol: string = key.split(":")[0];
178
+ if (symbol.indexOf("__custom") !== -1)
179
+ return _Analyze_http_custom_parameter(param);
180
+
181
+ const typeIndex: RouteParamtypes = Number(symbol[0]) as RouteParamtypes;
182
+ if (isNaN(typeIndex) === true) return null;
183
+
184
+ const type: ParamCategory | undefined = getNestParamType(typeIndex);
185
+ if (type === undefined) return null;
186
+
187
+ return {
188
+ custom: false,
189
+ name: key,
190
+ category: type,
191
+ index: param.index,
192
+ field: param.data,
193
+ };
194
+ }
195
+
196
+ function _Analyze_http_custom_parameter(
197
+ param: INestParam,
198
+ ): IReflectHttpOperation.IParameter | null {
199
+ if (param.factory === undefined) return null;
200
+ else if (
201
+ param.factory.name === "EncryptedBody" ||
202
+ param.factory.name === "PlainBody" ||
203
+ param.factory.name === "TypedQueryBody" ||
204
+ param.factory.name === "TypedBody" ||
205
+ param.factory.name === "TypedFormDataBody"
206
+ )
207
+ return {
208
+ custom: true,
209
+ category: "body",
210
+ index: param.index,
211
+ name: param.name,
212
+ field: param.data,
213
+ encrypted: param.factory.name === "EncryptedBody",
214
+ contentType:
215
+ param.factory.name === "PlainBody" ||
216
+ param.factory.name === "EncryptedBody"
217
+ ? "text/plain"
218
+ : param.factory.name === "TypedQueryBody"
219
+ ? "application/x-www-form-urlencoded"
220
+ : param.factory.name === "TypedFormDataBody"
221
+ ? "multipart/form-data"
222
+ : "application/json",
223
+ };
224
+ else if (param.factory.name === "TypedHeaders")
225
+ return {
226
+ custom: true,
227
+ category: "headers",
228
+ name: param.name,
229
+ index: param.index,
230
+ field: param.data,
231
+ };
232
+ else if (param.factory.name === "TypedParam")
233
+ return {
234
+ custom: true,
235
+ category: "param",
236
+ name: param.name,
237
+ index: param.index,
238
+ field: param.data,
239
+ };
240
+ else if (param.factory.name === "TypedQuery")
241
+ return {
242
+ custom: true,
243
+ name: param.name,
244
+ category: "query",
245
+ index: param.index,
246
+ field: undefined,
247
+ };
248
+ else return null;
249
+ }
250
+ }
251
+
252
+ interface INestParam {
253
+ name: string;
254
+ index: number;
255
+ factory?: (...args: any) => any;
256
+ data: string | undefined;
257
+ }
258
+
259
+ type NestParameters = {
260
+ [key: string]: INestParam;
261
+ };
262
+
263
+ const hasInterceptor =
264
+ (name: string) =>
265
+ (proto: any): boolean => {
266
+ const meta = Reflect.getMetadata(INTERCEPTORS_METADATA, proto);
267
+ if (Array.isArray(meta) === false) return false;
268
+ return meta.some((elem) => elem?.constructor?.name === name);
269
+ };
270
+
271
+ // https://github.com/nestjs/nest/blob/master/packages/common/enums/route-paramtypes.enum.ts
272
+ const getNestParamType = (value: RouteParamtypes) => {
273
+ if (value === RouteParamtypes.BODY) return "body";
274
+ else if (value === RouteParamtypes.HEADERS) return "headers";
275
+ else if (value === RouteParamtypes.QUERY) return "query";
276
+ else if (value === RouteParamtypes.PARAM) return "param";
277
+ return undefined;
278
+ };
279
+
280
+ // node_modules/@nestjs/common/lib/enums/request-method.enum.ts
281
+ const METHODS = [
282
+ "GET",
283
+ "POST",
284
+ "PUT",
285
+ "DELETE",
286
+ "PATCH",
287
+ "ALL",
288
+ "OPTIONS",
289
+ "HEAD",
290
+ ];
@@ -0,0 +1,53 @@
1
+ import { VERSION_NEUTRAL } from "@nestjs/common";
2
+ import { PATH_METADATA, VERSION_METADATA } from "@nestjs/common/constants";
3
+ import { VersionValue } from "@nestjs/common/interfaces";
4
+
5
+ import { IReflectHttpOperation } from "../structures/IReflectHttpOperation";
6
+ import { SecurityAnalyzer } from "./SecurityAnalyzer";
7
+
8
+ export namespace ReflectMetadataAnalyzer {
9
+ export const exceptions = (
10
+ value: any,
11
+ ): Record<
12
+ number | "2XX" | "3XX" | "4XX" | "5XX",
13
+ IReflectHttpOperation.IException
14
+ > => {
15
+ const entire: IReflectHttpOperation.IException[] | undefined =
16
+ Reflect.getMetadata("nestia/TypedException", value);
17
+ return Object.fromEntries(
18
+ (entire ?? []).map((exp) => [exp.status, exp]),
19
+ ) as Record<
20
+ number | "2XX" | "3XX" | "4XX" | "5XX",
21
+ IReflectHttpOperation.IException
22
+ >;
23
+ };
24
+
25
+ export const paths = (target: any): string[] => {
26
+ const value: string | string[] = Reflect.getMetadata(PATH_METADATA, target);
27
+ if (typeof value === "string") return [value];
28
+ else if (value.length === 0) return [""];
29
+ else return value;
30
+ };
31
+
32
+ export const securities = (value: any): Record<string, string[]>[] => {
33
+ const entire: Record<string, string[]>[] | undefined = Reflect.getMetadata(
34
+ "swagger/apiSecurity",
35
+ value,
36
+ );
37
+ return entire ? SecurityAnalyzer.merge(...entire) : [];
38
+ };
39
+
40
+ export const versions = (
41
+ target: any,
42
+ ): Array<string | typeof VERSION_NEUTRAL> | undefined => {
43
+ const value: VersionValue | undefined = Reflect.getMetadata(
44
+ VERSION_METADATA,
45
+ target,
46
+ );
47
+ return value === undefined
48
+ ? undefined
49
+ : Array.isArray(value)
50
+ ? value
51
+ : [value];
52
+ };
53
+ }
@@ -0,0 +1,96 @@
1
+ import { ranges } from "tstl";
2
+
3
+ import { IErrorReport } from "../structures/IErrorReport";
4
+ import { INestiaProject } from "../structures/INestiaProject";
5
+ import { IReflectController } from "../structures/IReflectController";
6
+ import { IReflectWebSocketOperation } from "../structures/IReflectWebSocketOperation";
7
+ import { PathAnalyzer } from "./PathAnalyzer";
8
+ import { ReflectMetadataAnalyzer } from "./ReflectMetadataAnalyzer";
9
+
10
+ export namespace ReflectWebSocketOperationAnalyzer {
11
+ export const analyze =
12
+ (project: INestiaProject) =>
13
+ (props: {
14
+ controller: IReflectController;
15
+ function: Function;
16
+ name: string;
17
+ }): IReflectWebSocketOperation | null => {
18
+ const route: { paths: string[] } | undefined = Reflect.getMetadata(
19
+ "nestia/WebSocketRoute",
20
+ props.function,
21
+ );
22
+ if (route === undefined) return null;
23
+
24
+ const errors: IErrorReport[] = [];
25
+ const parameters: IReflectWebSocketOperation.IParameter[] = (
26
+ (Reflect.getMetadata(
27
+ "nestia/WebSocketRoute/Parameters",
28
+ props.controller.prototype,
29
+ props.name,
30
+ ) ?? []) as IReflectWebSocketOperation.IParameter[]
31
+ ).sort((a, b) => a.index - b.index);
32
+ if (parameters.find((p) => (p.category === "acceptor") === undefined))
33
+ errors.push({
34
+ file: props.controller.file,
35
+ controller: props.controller.name,
36
+ function: props.name,
37
+ message: "@WebSocketRoute.Acceptor() is essentially required",
38
+ });
39
+ if (parameters.length !== props.function.length)
40
+ errors.push({
41
+ file: props.controller.file,
42
+ controller: props.controller.name,
43
+ function: props.name,
44
+ message: [
45
+ "Every parameters must be one of below:",
46
+ " - @WebSocketRoute.Acceptor()",
47
+ " - @WebSocketRoute.Driver()",
48
+ " - @WebSocketRoute.Header()",
49
+ " - @WebSocketRoute.Param()",
50
+ " - @WebSocketRoute.Query()",
51
+ ].join("\n"),
52
+ });
53
+
54
+ const fields: string[] = parameters
55
+ .filter((p) => p.category === "param")
56
+ .map((p) => p.field)
57
+ .sort();
58
+ for (const cLoc of props.controller.paths)
59
+ for (const mLoc of route.paths) {
60
+ const location: string = PathAnalyzer.join(cLoc, mLoc);
61
+ if (location.includes("*")) continue;
62
+
63
+ const binded: string[] | null = PathAnalyzer.parameters(location);
64
+ if (binded === null) {
65
+ errors.push({
66
+ file: props.controller.file,
67
+ controller: props.controller.name,
68
+ function: props.name,
69
+ message: `invalid path (${JSON.stringify(location)})`,
70
+ });
71
+ continue;
72
+ }
73
+ if (ranges.equal(binded.sort(), fields) === false)
74
+ errors.push({
75
+ file: props.controller.file,
76
+ controller: props.controller.name,
77
+ function: props.name,
78
+ message: `binded arguments in the "path" between function's decorator and parameters' decorators are different (function: [${binded.join(
79
+ ", ",
80
+ )}], parameters: [${fields.join(", ")}]).`,
81
+ });
82
+ }
83
+ if (errors.length) {
84
+ project.errors.push(...errors);
85
+ return null;
86
+ }
87
+ return {
88
+ protocol: "websocket",
89
+ target: props.function,
90
+ name: props.name,
91
+ paths: route.paths,
92
+ versions: ReflectMetadataAnalyzer.versions(props.function),
93
+ parameters,
94
+ };
95
+ };
96
+ }
@@ -1,7 +1,6 @@
1
1
  import { MapUtil } from "../utils/MapUtil";
2
2
 
3
3
  export namespace SecurityAnalyzer {
4
- const none = Symbol("none");
5
4
  export const merge = (...entire: Record<string, string[]>[]) => {
6
5
  const dict: Map<string | typeof none, Set<string>> = new Map();
7
6
  for (const obj of entire) {
@@ -21,4 +20,6 @@ export namespace SecurityAnalyzer {
21
20
  });
22
21
  return output;
23
22
  };
23
+
24
+ const none = Symbol("none");
24
25
  }
@@ -0,0 +1,92 @@
1
+ import ts from "typescript";
2
+
3
+ import { INestiaProject } from "../structures/INestiaProject";
4
+ import { IReflectController } from "../structures/IReflectController";
5
+ import { IReflectHttpOperation } from "../structures/IReflectHttpOperation";
6
+ import { IReflectWebSocketOperation } from "../structures/IReflectWebSocketOperation";
7
+ import { ITypedHttpRoute } from "../structures/ITypedHttpRoute";
8
+ import { ITypedWebSocketRoute } from "../structures/ITypedWebSocketRoute";
9
+ import { GenericAnalyzer } from "./GenericAnalyzer";
10
+ import { TypedHttpOperationAnalyzer } from "./TypedHttpOperationAnalyzer";
11
+ import { TypedWebSocketOperationAnalyzer } from "./TypedWebSocketOperationAnalyzer";
12
+
13
+ export namespace TypedControllerAnalyzer {
14
+ export const analyze =
15
+ (project: INestiaProject) =>
16
+ async (
17
+ sourceFile: ts.SourceFile,
18
+ controller: IReflectController,
19
+ ): Promise<Array<ITypedHttpRoute | ITypedWebSocketRoute>> => {
20
+ // FIND CONTROLLER CLASS
21
+ const ret: Array<ITypedHttpRoute | ITypedWebSocketRoute> = [];
22
+ ts.forEachChild(sourceFile, (node) => {
23
+ if (
24
+ ts.isClassDeclaration(node) &&
25
+ node.name?.escapedText === controller.name
26
+ ) {
27
+ // ANALYZE THE CONTROLLER
28
+ ret.push(..._Analyze_controller(project)(controller, node));
29
+ return;
30
+ }
31
+ });
32
+ return ret;
33
+ };
34
+
35
+ /* ---------------------------------------------------------
36
+ CLASS
37
+ --------------------------------------------------------- */
38
+ const _Analyze_controller =
39
+ (project: INestiaProject) =>
40
+ (
41
+ controller: IReflectController,
42
+ classNode: ts.ClassDeclaration,
43
+ ): Array<ITypedHttpRoute | ITypedWebSocketRoute> => {
44
+ const classType: ts.InterfaceType = project.checker.getTypeAtLocation(
45
+ classNode,
46
+ ) as ts.InterfaceType;
47
+ const generics: GenericAnalyzer.Dictionary = GenericAnalyzer.analyze(
48
+ project.checker,
49
+ classNode,
50
+ );
51
+
52
+ const ret: Array<ITypedHttpRoute | ITypedWebSocketRoute> = [];
53
+ for (const symbol of classType.getProperties()) {
54
+ // GET METHOD DECLARATION
55
+ const declaration: ts.Declaration | undefined = (symbol.declarations ||
56
+ [])[0];
57
+ if (!declaration || !ts.isMethodDeclaration(declaration)) continue;
58
+
59
+ // IDENTIFIER MUST BE
60
+ const identifier = declaration.name;
61
+ if (!ts.isIdentifier(identifier)) continue;
62
+
63
+ // ANALYZED WITH THE REFLECTED-FUNCTION
64
+ const operation:
65
+ | IReflectHttpOperation
66
+ | IReflectWebSocketOperation
67
+ | undefined = controller.operations.find(
68
+ (f) => f.name === identifier.escapedText,
69
+ );
70
+ if (operation === undefined) continue;
71
+
72
+ const routes: ITypedHttpRoute[] | ITypedWebSocketRoute[] =
73
+ operation.protocol === "http"
74
+ ? TypedHttpOperationAnalyzer.analyze(project)({
75
+ controller,
76
+ generics,
77
+ operation,
78
+ declaration,
79
+ symbol,
80
+ })
81
+ : TypedWebSocketOperationAnalyzer.analyze(project)({
82
+ controller,
83
+ operation,
84
+ declaration,
85
+ symbol,
86
+ generics,
87
+ });
88
+ ret.push(...routes);
89
+ }
90
+ return ret;
91
+ };
92
+ }