@nestia/sdk 3.0.5-dev.20240418 → 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 +9 -7
  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
@@ -5,15 +5,16 @@ import ts from "typescript";
5
5
  import { INestiaConfig } from "./INestiaConfig";
6
6
  import { AccessorAnalyzer } from "./analyses/AccessorAnalyzer";
7
7
  import { ConfigAnalyzer } from "./analyses/ConfigAnalyzer";
8
- import { ControllerAnalyzer } from "./analyses/ControllerAnalyzer";
9
- import { ReflectAnalyzer } from "./analyses/ReflectAnalyzer";
8
+ import { ReflectControllerAnalyzer } from "./analyses/ReflectControllerAnalyzer";
9
+ import { TypedControllerAnalyzer } from "./analyses/TypedControllerAnalyzer";
10
10
  import { E2eGenerator } from "./generates/E2eGenerator";
11
11
  import { SdkGenerator } from "./generates/SdkGenerator";
12
12
  import { SwaggerGenerator } from "./generates/SwaggerGenerator";
13
- import { IController } from "./structures/IController";
14
13
  import { IErrorReport } from "./structures/IErrorReport";
15
14
  import { INestiaProject } from "./structures/INestiaProject";
16
- import { IRoute } from "./structures/IRoute";
15
+ import { IReflectController } from "./structures/IReflectController";
16
+ import { ITypedHttpRoute } from "./structures/ITypedHttpRoute";
17
+ import { ITypedWebSocketRoute } from "./structures/ITypedWebSocketRoute";
17
18
  import { MapUtil } from "./utils/MapUtil";
18
19
 
19
20
  export class NestiaSdkApplication {
@@ -46,14 +47,12 @@ export class NestiaSdkApplication {
46
47
  await validate("e2e")(this.config.e2e);
47
48
 
48
49
  print_title("Nestia E2E Generator");
49
- await this.generate(
50
- "e2e",
51
- (config) => config,
52
- (checker) => (config) => async (routes) => {
53
- await SdkGenerator.generate(checker)(config)(routes);
54
- await E2eGenerator.generate(checker)(config)(routes);
55
- },
56
- );
50
+ await this.generate("e2e", (project) => async (routes) => {
51
+ await SdkGenerator.generate(project)(routes);
52
+ await E2eGenerator.generate(project)(
53
+ routes.filter((r) => r.protocol === "http") as ITypedHttpRoute[],
54
+ );
55
+ });
57
56
  }
58
57
 
59
58
  public async sdk(): Promise<void> {
@@ -70,7 +69,7 @@ export class NestiaSdkApplication {
70
69
  );
71
70
 
72
71
  print_title("Nestia SDK Generator");
73
- await this.generate("sdk", (config) => config, SdkGenerator.generate);
72
+ await this.generate("sdk", SdkGenerator.generate);
74
73
  }
75
74
 
76
75
  public async swagger(): Promise<void> {
@@ -90,25 +89,22 @@ export class NestiaSdkApplication {
90
89
  );
91
90
 
92
91
  print_title("Nestia Swagger Generator");
93
- await this.generate(
94
- "swagger",
95
- (config) => config.swagger!,
96
- SwaggerGenerator.generate,
97
- );
92
+ await this.generate("swagger", SwaggerGenerator.generate);
98
93
  }
99
94
 
100
- private async generate<Config>(
95
+ private async generate(
101
96
  method: string,
102
- config: (entire: INestiaConfig) => Config,
103
97
  archiver: (
104
- checker: ts.TypeChecker,
105
- ) => (config: Config) => (routes: IRoute[]) => Promise<void>,
98
+ project: INestiaProject,
99
+ ) => (
100
+ routes: Array<ITypedHttpRoute | ITypedWebSocketRoute>,
101
+ ) => Promise<void>,
106
102
  ): Promise<void> {
107
103
  //----
108
104
  // ANALYZE REFLECTS
109
105
  //----
110
106
  const unique: WeakSet<any> = new WeakSet();
111
- const controllers: IController[] = [];
107
+ const controllers: IReflectController[] = [];
112
108
  const project: INestiaProject = {
113
109
  config: this.config,
114
110
  input: await ConfigAnalyzer.input(this.config),
@@ -120,7 +116,7 @@ export class NestiaSdkApplication {
120
116
  console.log("Analyzing reflections");
121
117
  for (const include of (await ConfigAnalyzer.input(this.config)).include)
122
118
  controllers.push(
123
- ...(await ReflectAnalyzer.analyze(project)(
119
+ ...(await ReflectControllerAnalyzer.analyze(project)(
124
120
  unique,
125
121
  include.file,
126
122
  include.paths,
@@ -132,9 +128,11 @@ export class NestiaSdkApplication {
132
128
  const set: Set<string> = new Set();
133
129
  for (const c of controllers)
134
130
  for (const cPath of c.paths)
135
- for (const f of c.functions)
136
- for (const fPath of f.paths)
137
- set.add(`${f.method}::${cPath}/${fPath}`);
131
+ for (const op of c.operations)
132
+ for (const fPath of op.paths)
133
+ set.add(
134
+ `${op.protocol === "http" ? `${op.method}::` : ""}${cPath}/${fPath}`,
135
+ );
138
136
  return set.size;
139
137
  })();
140
138
 
@@ -145,7 +143,7 @@ export class NestiaSdkApplication {
145
143
  .map(
146
144
  (c) =>
147
145
  c.paths.length *
148
- c.functions.map((f) => f.paths.length).reduce((a, b) => a + b, 0),
146
+ c.operations.map((f) => f.paths.length).reduce((a, b) => a + b, 0),
149
147
  )
150
148
  .reduce((a, b) => a + b, 0)}`,
151
149
  );
@@ -161,11 +159,13 @@ export class NestiaSdkApplication {
161
159
  );
162
160
  project.checker = program.getTypeChecker();
163
161
 
164
- const routeList: IRoute[] = [];
162
+ const routeList: Array<ITypedHttpRoute | ITypedWebSocketRoute> = [];
165
163
  for (const c of controllers) {
166
164
  const file: ts.SourceFile | undefined = program.getSourceFile(c.file);
167
165
  if (file === undefined) continue;
168
- routeList.push(...(await ControllerAnalyzer.analyze(project)(file, c)));
166
+ routeList.push(
167
+ ...(await TypedControllerAnalyzer.analyze(project)(file, c)),
168
+ );
169
169
  }
170
170
 
171
171
  // REPORT ERRORS
@@ -177,7 +177,9 @@ export class NestiaSdkApplication {
177
177
 
178
178
  // FIND IMPLICIT TYPES
179
179
  if (this.config.clone !== true) {
180
- const implicit: IRoute[] = routeList.filter(is_implicit_return_typed);
180
+ const implicit: ITypedHttpRoute[] = routeList.filter(
181
+ (r) => r.protocol === "http" && is_implicit_return_typed(r),
182
+ ) as ITypedHttpRoute[];
181
183
  if (implicit.length > 0)
182
184
  throw new Error(
183
185
  `NestiaApplication.${method}(): implicit return type is not allowed.\n` +
@@ -186,7 +188,7 @@ export class NestiaSdkApplication {
186
188
  implicit
187
189
  .map(
188
190
  (it) =>
189
- ` - ${it.target.class.name}.${it.target.function.name} at "${it.location}"`,
191
+ ` - ${it.controller.name}.${it.name} at "${it.location}"`,
190
192
  )
191
193
  .join("\n"),
192
194
  );
@@ -194,7 +196,7 @@ export class NestiaSdkApplication {
194
196
 
195
197
  // DO GENERATE
196
198
  AccessorAnalyzer.analyze(routeList);
197
- await archiver(project.checker)(config(this.config))(routeList);
199
+ await archiver(project)(routeList);
198
200
  }
199
201
  }
200
202
 
@@ -204,7 +206,7 @@ const print_title = (str: string): void => {
204
206
  console.log("-----------------------------------------------------------");
205
207
  };
206
208
 
207
- const is_implicit_return_typed = (route: IRoute): boolean => {
209
+ const is_implicit_return_typed = (route: ITypedHttpRoute): boolean => {
208
210
  const name: string = route.output.typeName;
209
211
  if (name === "void") return false;
210
212
  else if (name.indexOf("readonly [") !== -1) return true;
@@ -1,16 +1,21 @@
1
1
  import { Escaper } from "typia/lib/utils/Escaper";
2
2
 
3
- import { IRoute } from "../structures/IRoute";
3
+ import { ITypedHttpRoute } from "../structures/ITypedHttpRoute";
4
+ import { ITypedWebSocketRoute } from "../structures/ITypedWebSocketRoute";
4
5
 
5
6
  export namespace AccessorAnalyzer {
6
- export const analyze = (routes: IRoute[]) => {
7
+ export const analyze = (
8
+ routes: Array<ITypedHttpRoute | ITypedWebSocketRoute>,
9
+ ) => {
7
10
  shrink(routes);
8
11
  variable(routes);
9
12
  shrink(routes);
10
13
  for (const r of routes) r.name = r.accessors.at(-1) ?? r.name;
11
14
  };
12
15
 
13
- const prepare = (routeList: IRoute[]): Map<string, number> => {
16
+ const prepare = (
17
+ routeList: Array<ITypedHttpRoute | ITypedWebSocketRoute>,
18
+ ): Map<string, number> => {
14
19
  const dict: Map<string, number> = new Map();
15
20
  for (const route of routeList)
16
21
  route.accessors.forEach((_a, i) => {
@@ -20,7 +25,9 @@ export namespace AccessorAnalyzer {
20
25
  return dict;
21
26
  };
22
27
 
23
- const variable = (routeList: IRoute[]) => {
28
+ const variable = (
29
+ routeList: Array<ITypedHttpRoute | ITypedWebSocketRoute>,
30
+ ) => {
24
31
  const dict: Map<string, number> = prepare(routeList);
25
32
  for (const route of routeList) {
26
33
  const emended: string[] = route.accessors.slice();
@@ -42,7 +49,7 @@ export namespace AccessorAnalyzer {
42
49
  }
43
50
  };
44
51
 
45
- const shrink = (routeList: IRoute[]) => {
52
+ const shrink = (routeList: Array<ITypedHttpRoute | ITypedWebSocketRoute>) => {
46
53
  const dict: Map<string, number> = prepare(routeList);
47
54
  for (const route of routeList) {
48
55
  if (
@@ -4,53 +4,62 @@ import { MetadataCollection } from "typia/lib/factories/MetadataCollection";
4
4
  import { MetadataFactory } from "typia/lib/factories/MetadataFactory";
5
5
  import { Metadata } from "typia/lib/schemas/metadata/Metadata";
6
6
 
7
- import { IController } from "../structures/IController";
8
7
  import { INestiaProject } from "../structures/INestiaProject";
9
- import { IRoute } from "../structures/IRoute";
8
+ import { IReflectController } from "../structures/IReflectController";
9
+ import { IReflectHttpOperation } from "../structures/IReflectHttpOperation";
10
10
  import { ITypeTuple } from "../structures/ITypeTuple";
11
+ import { ITypedHttpRoute } from "../structures/ITypedHttpRoute";
11
12
  import { GenericAnalyzer } from "./GenericAnalyzer";
12
13
  import { ImportAnalyzer } from "./ImportAnalyzer";
13
14
 
14
15
  export namespace ExceptionAnalyzer {
15
16
  export const analyze =
16
17
  (project: INestiaProject) =>
17
- (
18
- genericDict: GenericAnalyzer.Dictionary,
19
- importDict: ImportAnalyzer.Dictionary,
20
- ) =>
21
- (controller: IController, func: IController.IFunction) =>
22
- (
23
- declaration: ts.MethodDeclaration,
24
- ): Record<number | "2XX" | "3XX" | "4XX" | "5XX", IRoute.IOutput> => {
18
+ (props: {
19
+ generics: GenericAnalyzer.Dictionary;
20
+ imports: ImportAnalyzer.Dictionary;
21
+ controller: IReflectController;
22
+ operation: IReflectHttpOperation;
23
+ declaration: ts.MethodDeclaration;
24
+ }): Record<
25
+ number | "2XX" | "3XX" | "4XX" | "5XX",
26
+ ITypedHttpRoute.IOutput
27
+ > => {
25
28
  const output: Record<
26
29
  number | "2XX" | "3XX" | "4XX" | "5XX",
27
- IRoute.IOutput
30
+ ITypedHttpRoute.IOutput
28
31
  > = {} as any;
29
- for (const decorator of declaration.modifiers ?? [])
32
+ for (const decorator of props.declaration.modifiers ?? [])
30
33
  if (ts.isDecorator(decorator))
31
- analyzeTyped(project)(genericDict, importDict)(controller, func)(
34
+ analyzeTyped(project)({
35
+ ...props,
32
36
  output,
33
- )(decorator);
37
+ decorator,
38
+ });
34
39
  return output;
35
40
  };
36
41
 
37
42
  const analyzeTyped =
38
43
  (project: INestiaProject) =>
39
- (
40
- genericDict: GenericAnalyzer.Dictionary,
41
- importDict: ImportAnalyzer.Dictionary,
42
- ) =>
43
- (controller: IController, func: IController.IFunction) =>
44
- (output: Record<number | "2XX" | "3XX" | "4XX" | "5XX", IRoute.IOutput>) =>
45
- (decorator: ts.Decorator): boolean => {
44
+ (props: {
45
+ generics: GenericAnalyzer.Dictionary;
46
+ imports: ImportAnalyzer.Dictionary;
47
+ controller: IReflectController;
48
+ operation: IReflectHttpOperation;
49
+ output: Record<
50
+ number | "2XX" | "3XX" | "4XX" | "5XX",
51
+ ITypedHttpRoute.IOutput
52
+ >;
53
+ decorator: ts.Decorator;
54
+ }): boolean => {
46
55
  // CHECK DECORATOR
47
- if (!ts.isCallExpression(decorator.expression)) return false;
48
- else if ((decorator.expression.typeArguments ?? []).length !== 1)
56
+ if (!ts.isCallExpression(props.decorator.expression)) return false;
57
+ else if ((props.decorator.expression.typeArguments ?? []).length !== 1)
49
58
  return false;
50
59
 
51
60
  // CHECK SIGNATURE
52
61
  const signature: ts.Signature | undefined =
53
- project.checker.getResolvedSignature(decorator.expression);
62
+ project.checker.getResolvedSignature(props.decorator.expression);
54
63
  if (!signature || !signature.declaration) return false;
55
64
  else if (
56
65
  path
@@ -61,48 +70,49 @@ export namespace ExceptionAnalyzer {
61
70
 
62
71
  // GET TYPE INFO
63
72
  const status: string | null = getStatus(project.checker)(
64
- decorator.expression.arguments[0] ?? null,
73
+ props.decorator.expression.arguments[0] ?? null,
65
74
  );
66
75
  if (status === null) return false;
67
76
 
68
- const node: ts.TypeNode = decorator.expression.typeArguments![0];
77
+ const node: ts.TypeNode = props.decorator.expression.typeArguments![0];
69
78
  const type: ts.Type = project.checker.getTypeFromTypeNode(node);
70
79
  if (type.isTypeParameter()) {
71
80
  project.errors.push({
72
- file: controller.file,
73
- controller: controller.name,
74
- function: func.name,
81
+ file: props.controller.file,
82
+ controller: props.controller.name,
83
+ function: props.operation.name,
75
84
  message: "TypedException() without generic argument specification.",
76
85
  });
77
86
  return false;
78
87
  }
79
88
 
80
- const tuple: ITypeTuple | null = ImportAnalyzer.analyze(
81
- project.checker,
82
- genericDict,
83
- importDict,
89
+ const tuple: ITypeTuple | null = ImportAnalyzer.analyze(project.checker)({
90
+ generics: props.generics,
91
+ imports: props.imports,
84
92
  type,
85
- );
93
+ });
86
94
  if (
87
95
  tuple === null ||
88
96
  (project.config.clone !== true &&
89
97
  (tuple.typeName === "__type" || tuple.typeName === "__object"))
90
98
  ) {
91
99
  project.errors.push({
92
- file: controller.file,
93
- controller: controller.name,
94
- function: func.name,
100
+ file: props.controller.file,
101
+ controller: props.controller.name,
102
+ function: props.operation.name,
95
103
  message: "TypeException() with implicit (unnamed) type.",
96
104
  });
97
105
  return false;
98
106
  }
99
107
 
100
108
  // DO ASSIGN
101
- const matched: IController.IException[] = Object.entries(func.exceptions)
109
+ const matched: IReflectHttpOperation.IException[] = Object.entries(
110
+ props.operation.exceptions,
111
+ )
102
112
  .filter(([key]) => status === key)
103
113
  .map(([_key, value]) => value);
104
114
  for (const m of matched)
105
- output[m.status] = {
115
+ props.output[m.status] = {
106
116
  type: tuple.type,
107
117
  typeName: tuple.typeName,
108
118
  contentType: "application/json",
@@ -12,126 +12,145 @@ export namespace ImportAnalyzer {
12
12
 
13
13
  export type Dictionary = HashMap<string, HashSet<string>>;
14
14
 
15
- export function analyze(
16
- checker: ts.TypeChecker,
17
- genericDict: GenericAnalyzer.Dictionary,
18
- importDict: Dictionary,
19
- type: ts.Type,
20
- ): ITypeTuple | null {
21
- type = get_type(checker, type);
22
- explore_escaped_name(checker, genericDict, importDict, type);
23
-
24
- try {
25
- return {
15
+ export const analyze =
16
+ (checker: ts.TypeChecker) =>
17
+ (props: {
18
+ generics: GenericAnalyzer.Dictionary;
19
+ imports: Dictionary;
20
+ type: ts.Type;
21
+ }): ITypeTuple | null => {
22
+ const type: ts.Type = get_type(checker)(props.type);
23
+ explore_escaped_name(checker)({
24
+ ...props,
26
25
  type,
27
- typeName: explore_escaped_name(checker, genericDict, importDict, type),
28
- };
29
- } catch {
30
- return null;
31
- }
32
- }
26
+ });
27
+ try {
28
+ return {
29
+ type,
30
+ typeName: explore_escaped_name(checker)({
31
+ ...props,
32
+ type,
33
+ }),
34
+ };
35
+ } catch {
36
+ return null;
37
+ }
38
+ };
33
39
 
34
40
  /* ---------------------------------------------------------
35
41
  TYPE
36
42
  --------------------------------------------------------- */
37
- function get_type(checker: ts.TypeChecker, type: ts.Type): ts.Type {
38
- const symbol: ts.Symbol | undefined = type.getSymbol();
39
- return symbol && get_name(symbol) === "Promise"
40
- ? escape_promise(checker, type)
41
- : type;
42
- }
43
-
44
- function escape_promise(checker: ts.TypeChecker, type: ts.Type): ts.Type {
45
- const generic: readonly ts.Type[] = checker.getTypeArguments(
46
- type as ts.TypeReference,
47
- );
48
- if (generic.length !== 1)
49
- throw new Error(
50
- "Error on ImportAnalyzer.analyze(): invalid promise type.",
43
+ const get_type =
44
+ (checker: ts.TypeChecker) =>
45
+ (type: ts.Type): ts.Type => {
46
+ const symbol: ts.Symbol | undefined = type.getSymbol();
47
+ return symbol && get_name(symbol) === "Promise"
48
+ ? escape_promise(checker)(type)
49
+ : type;
50
+ };
51
+
52
+ const escape_promise =
53
+ (checker: ts.TypeChecker) =>
54
+ (type: ts.Type): ts.Type => {
55
+ const generic: readonly ts.Type[] = checker.getTypeArguments(
56
+ type as ts.TypeReference,
51
57
  );
52
- return generic[0];
53
- }
54
-
55
- function get_name(symbol: ts.Symbol): string {
56
- return explore_name(
58
+ if (generic.length !== 1)
59
+ throw new Error(
60
+ "Error on ImportAnalyzer.analyze(): invalid promise type.",
61
+ );
62
+ return generic[0];
63
+ };
64
+
65
+ const get_name = (symbol: ts.Symbol): string =>
66
+ explore_name(
57
67
  symbol.escapedName.toString(),
58
68
  symbol.getDeclarations()?.[0]?.parent,
59
69
  );
60
- }
61
70
 
62
71
  /* ---------------------------------------------------------
63
72
  ESCAPED TEXT WITH IMPORT STATEMENTS
64
73
  --------------------------------------------------------- */
65
- function explore_escaped_name(
66
- checker: ts.TypeChecker,
67
- genericDict: GenericAnalyzer.Dictionary,
68
- importDict: Dictionary,
69
- type: ts.Type,
70
- ): string {
71
- //----
72
- // CONDITIONAL BRANCHES
73
- //----
74
- // DECOMPOSE GENERIC ARGUMENT
75
- while (genericDict.has(type) === true) type = genericDict.get(type)!;
76
-
77
- // PRIMITIVE
78
- const symbol: ts.Symbol | undefined = type.aliasSymbol ?? type.getSymbol();
79
-
80
- // UNION OR INTERSECT
81
- if (type.aliasSymbol === undefined && type.isUnionOrIntersection()) {
82
- const joiner: string = type.isIntersection() ? " & " : " | ";
83
- return type.types
84
- .map((child) =>
85
- explore_escaped_name(checker, genericDict, importDict, child),
86
- )
87
- .join(joiner);
88
- }
89
-
90
- // NO SYMBOL
91
- else if (symbol === undefined)
92
- return checker.typeToString(
93
- type,
94
- undefined,
95
- ts.TypeFormatFlags.NoTruncation,
96
- );
97
-
98
- //----
99
- // SPECIALIZATION
100
- //----
101
- const name: string = get_name(symbol);
102
- const sourceFile: ts.SourceFile | undefined =
103
- symbol.declarations?.[0]?.getSourceFile();
104
- if (sourceFile === undefined) return name;
105
-
106
- if (sourceFile.fileName.indexOf("typescript/lib") === -1) {
107
- const set: HashSet<string> = importDict.take(
108
- sourceFile.fileName,
109
- () => new HashSet(),
110
- );
111
- set.insert(name.split(".")[0]);
112
- }
113
-
114
- // CHECK GENERIC
115
- const generic: readonly ts.Type[] = type.aliasSymbol
116
- ? type.aliasTypeArguments || []
117
- : checker.getTypeArguments(type as ts.TypeReference);
118
- return generic.length
119
- ? name === "Promise"
120
- ? explore_escaped_name(checker, genericDict, importDict, generic[0])
121
- : `${name}<${generic
122
- .map((child) =>
123
- explore_escaped_name(checker, genericDict, importDict, child),
124
- )
125
- .join(", ")}>`
126
- : name;
127
- }
128
-
129
- function explore_name(name: string, decl?: ts.Node): string {
130
- return decl && ts.isModuleBlock(decl)
74
+ const explore_escaped_name =
75
+ (checker: ts.TypeChecker) =>
76
+ (props: {
77
+ generics: GenericAnalyzer.Dictionary;
78
+ imports: Dictionary;
79
+ type: ts.Type;
80
+ }): string => {
81
+ //----
82
+ // CONDITIONAL BRANCHES
83
+ //----
84
+ // DECOMPOSE GENERIC ARGUMENT
85
+ let type: ts.Type = props.type;
86
+ while (props.generics.has(type) === true)
87
+ type = props.generics.get(type)!;
88
+
89
+ // PRIMITIVE
90
+ const symbol: ts.Symbol | undefined =
91
+ type.aliasSymbol ?? type.getSymbol();
92
+
93
+ // UNION OR INTERSECT
94
+ if (type.aliasSymbol === undefined && type.isUnionOrIntersection()) {
95
+ const joiner: string = type.isIntersection() ? " & " : " | ";
96
+ return type.types
97
+ .map((child) =>
98
+ explore_escaped_name(checker)({
99
+ ...props,
100
+ type: child,
101
+ }),
102
+ )
103
+ .join(joiner);
104
+ }
105
+ // NO SYMBOL
106
+ else if (symbol === undefined)
107
+ return checker.typeToString(
108
+ type,
109
+ undefined,
110
+ ts.TypeFormatFlags.NoTruncation,
111
+ );
112
+
113
+ //----
114
+ // SPECIALIZATION
115
+ //----
116
+ const name: string = get_name(symbol);
117
+ const sourceFile: ts.SourceFile | undefined =
118
+ symbol.declarations?.[0]?.getSourceFile();
119
+ if (sourceFile === undefined) return name;
120
+ else if (sourceFile.fileName.indexOf("typescript/lib") === -1) {
121
+ const set: HashSet<string> = props.imports.take(
122
+ sourceFile.fileName,
123
+ () => new HashSet(),
124
+ );
125
+ set.insert(name.split(".")[0]);
126
+ }
127
+
128
+ // CHECK GENERIC
129
+ const generic: readonly ts.Type[] = type.aliasSymbol
130
+ ? type.aliasTypeArguments ?? []
131
+ : checker.getTypeArguments(type as ts.TypeReference);
132
+ return generic.length
133
+ ? name === "Promise"
134
+ ? explore_escaped_name(checker)({
135
+ ...props,
136
+ type: generic[0],
137
+ })
138
+ : `${name}<${generic
139
+ .map((child) =>
140
+ explore_escaped_name(checker)({
141
+ ...props,
142
+ type: child,
143
+ }),
144
+ )
145
+ .join(", ")}>`
146
+ : name;
147
+ };
148
+
149
+ const explore_name = (name: string, decl?: ts.Node): string =>
150
+ decl && ts.isModuleBlock(decl)
131
151
  ? explore_name(
132
152
  `${decl.parent.name.getFullText().trim()}.${name}`,
133
153
  decl.parent.parent,
134
154
  )
135
155
  : name;
136
- }
137
156
  }
@@ -1,29 +1,7 @@
1
- import { RequestMethod } from "@nestjs/common";
2
1
  import path from "path";
3
2
  import { Token, parse } from "path-to-regexp";
4
3
 
5
- import { INormalizedInput } from "../structures/INormalizedInput";
6
-
7
4
  export namespace PathAnalyzer {
8
- export const combinate =
9
- (globalPrefix: INormalizedInput["globalPrefix"]) =>
10
- (versions: Array<string | null>) =>
11
- (props: { path: string; method: string }): string[] => {
12
- const out = (str: string) =>
13
- versions.map((v) => (v === null ? str : join(v, str)));
14
- if (!globalPrefix?.prefix.length) return out(props.path);
15
- else if (!globalPrefix.exclude?.length)
16
- return out(props.path).map((str) => join(globalPrefix.prefix, str));
17
- return globalPrefix.exclude.some((exclude) =>
18
- typeof exclude === "string"
19
- ? RegExp(exclude).test(props.path)
20
- : METHOD(exclude.method) === props.method &&
21
- RegExp(exclude.path).test(props.path),
22
- )
23
- ? out(props.path)
24
- : out(props.path).map((str) => join(globalPrefix.prefix, str));
25
- };
26
-
27
5
  export const join = (...args: string[]) =>
28
6
  "/" +
29
7
  _Trim(
@@ -89,22 +67,3 @@ export namespace PathAnalyzer {
89
67
  value: string;
90
68
  }
91
69
  }
92
-
93
- const METHOD = (value: RequestMethod) =>
94
- value === RequestMethod.ALL
95
- ? "all"
96
- : value === RequestMethod.DELETE
97
- ? "delete"
98
- : value === RequestMethod.GET
99
- ? "get"
100
- : value === RequestMethod.HEAD
101
- ? "head"
102
- : value === RequestMethod.OPTIONS
103
- ? "options"
104
- : value === RequestMethod.PATCH
105
- ? "patch"
106
- : value === RequestMethod.POST
107
- ? "post"
108
- : value === RequestMethod.PUT
109
- ? "put"
110
- : "unknown";