@nestia/sdk 3.0.0-dev.20231209 → 3.0.0-dev.20240412

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 (168) hide show
  1. package/README.md +12 -9
  2. package/assets/config/nestia.config.ts +82 -79
  3. package/lib/INestiaConfig.d.ts +28 -6
  4. package/lib/NestiaSdkApplication.js +12 -10
  5. package/lib/NestiaSdkApplication.js.map +1 -1
  6. package/lib/analyses/ConfigAnalyzer.js +1 -1
  7. package/lib/analyses/ConfigAnalyzer.js.map +1 -1
  8. package/lib/analyses/ControllerAnalyzer.js +30 -15
  9. package/lib/analyses/ControllerAnalyzer.js.map +1 -1
  10. package/lib/analyses/ExceptionAnalyzer.js +35 -6
  11. package/lib/analyses/ExceptionAnalyzer.js.map +1 -1
  12. package/lib/analyses/ImportAnalyzer.d.ts +1 -2
  13. package/lib/analyses/ImportAnalyzer.js +2 -2
  14. package/lib/analyses/ImportAnalyzer.js.map +1 -1
  15. package/lib/analyses/PathAnalyzer.d.ts +2 -4
  16. package/lib/analyses/PathAnalyzer.js +27 -11
  17. package/lib/analyses/PathAnalyzer.js.map +1 -1
  18. package/lib/analyses/ReflectAnalyzer.js +34 -22
  19. package/lib/analyses/ReflectAnalyzer.js.map +1 -1
  20. package/lib/analyses/SecurityAnalyzer.js +13 -8
  21. package/lib/analyses/SecurityAnalyzer.js.map +1 -1
  22. package/lib/executable/internal/NestiaConfigLoader.js +300 -220
  23. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  24. package/lib/executable/sdk.js +11 -11
  25. package/lib/generates/CloneGenerator.d.ts +6 -0
  26. package/lib/generates/CloneGenerator.js +62 -0
  27. package/lib/generates/CloneGenerator.js.map +1 -0
  28. package/lib/generates/E2eGenerator.d.ts +2 -1
  29. package/lib/generates/E2eGenerator.js +2 -2
  30. package/lib/generates/E2eGenerator.js.map +1 -1
  31. package/lib/generates/SdkGenerator.js +3 -11
  32. package/lib/generates/SdkGenerator.js.map +1 -1
  33. package/lib/generates/SwaggerGenerator.d.ts +2 -0
  34. package/lib/generates/SwaggerGenerator.js +119 -62
  35. package/lib/generates/SwaggerGenerator.js.map +1 -1
  36. package/lib/generates/internal/E2eFileProgrammer.d.ts +2 -1
  37. package/lib/generates/internal/E2eFileProgrammer.js +49 -53
  38. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  39. package/lib/generates/internal/FilePrinter.d.ts +10 -0
  40. package/lib/generates/internal/FilePrinter.js +46 -0
  41. package/lib/generates/internal/FilePrinter.js.map +1 -0
  42. package/lib/{utils → generates/internal}/ImportDictionary.d.ts +2 -1
  43. package/lib/{utils → generates/internal}/ImportDictionary.js +20 -14
  44. package/lib/generates/internal/ImportDictionary.js.map +1 -0
  45. package/lib/generates/internal/SdkAliasCollection.d.ts +12 -0
  46. package/lib/generates/internal/SdkAliasCollection.js +97 -0
  47. package/lib/generates/internal/SdkAliasCollection.js.map +1 -0
  48. package/lib/generates/internal/SdkCloneProgrammer.d.ts +12 -0
  49. package/lib/generates/internal/SdkCloneProgrammer.js +99 -0
  50. package/lib/generates/internal/SdkCloneProgrammer.js.map +1 -0
  51. package/lib/generates/internal/SdkFileProgrammer.d.ts +2 -1
  52. package/lib/generates/internal/SdkFileProgrammer.js +27 -28
  53. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  54. package/lib/generates/internal/SdkFunctionProgrammer.d.ts +7 -2
  55. package/lib/generates/internal/SdkFunctionProgrammer.js +115 -322
  56. package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -1
  57. package/lib/generates/internal/SdkImportWizard.d.ts +1 -1
  58. package/lib/generates/internal/SdkNamespaceProgrammer.d.ts +11 -0
  59. package/lib/generates/internal/SdkNamespaceProgrammer.js +180 -0
  60. package/lib/generates/internal/SdkNamespaceProgrammer.js.map +1 -0
  61. package/lib/generates/internal/SdkRouteProgrammer.d.ts +7 -0
  62. package/lib/generates/internal/SdkRouteProgrammer.js +55 -0
  63. package/lib/generates/internal/SdkRouteProgrammer.js.map +1 -0
  64. package/lib/generates/internal/SdkSimulationProgrammer.d.ts +8 -2
  65. package/lib/generates/internal/SdkSimulationProgrammer.js +103 -89
  66. package/lib/generates/internal/SdkSimulationProgrammer.js.map +1 -1
  67. package/lib/generates/internal/SdkTypeProgrammer.d.ts +9 -0
  68. package/lib/generates/internal/SdkTypeProgrammer.js +228 -0
  69. package/lib/generates/internal/SdkTypeProgrammer.js.map +1 -0
  70. package/lib/generates/internal/SwaggerSchemaGenerator.d.ts +4 -4
  71. package/lib/generates/internal/SwaggerSchemaGenerator.js +30 -28
  72. package/lib/generates/internal/SwaggerSchemaGenerator.js.map +1 -1
  73. package/lib/structures/IController.d.ts +4 -2
  74. package/lib/structures/IRoute.d.ts +5 -4
  75. package/lib/structures/ISwaggerLazyProperty.d.ts +2 -2
  76. package/lib/structures/ISwaggerLazySchema.d.ts +2 -2
  77. package/lib/structures/ParamCategory.d.ts +1 -1
  78. package/lib/structures/TypeEntry.js +2 -2
  79. package/lib/structures/TypeEntry.js.map +1 -1
  80. package/lib/utils/StringUtil.d.ts +3 -0
  81. package/lib/utils/StringUtil.js +8 -0
  82. package/lib/utils/StringUtil.js.map +1 -0
  83. package/package.json +12 -16
  84. package/src/INestiaConfig.ts +30 -6
  85. package/src/NestiaSdkApplication.ts +255 -253
  86. package/src/analyses/AccessorAnalyzer.ts +60 -60
  87. package/src/analyses/ConfigAnalyzer.ts +147 -147
  88. package/src/analyses/ControllerAnalyzer.ts +42 -19
  89. package/src/analyses/ExceptionAnalyzer.ts +148 -115
  90. package/src/analyses/GenericAnalyzer.ts +51 -51
  91. package/src/analyses/ImportAnalyzer.ts +1 -2
  92. package/src/analyses/PathAnalyzer.ts +110 -98
  93. package/src/analyses/ReflectAnalyzer.ts +39 -35
  94. package/src/analyses/SecurityAnalyzer.ts +24 -20
  95. package/src/executable/internal/CommandParser.ts +15 -15
  96. package/src/executable/internal/NestiaConfigLoader.ts +67 -67
  97. package/src/executable/internal/NestiaSdkCommand.ts +60 -60
  98. package/src/executable/sdk.ts +73 -73
  99. package/src/generates/CloneGenerator.ts +62 -0
  100. package/src/generates/E2eGenerator.ts +66 -64
  101. package/src/generates/SdkGenerator.ts +84 -96
  102. package/src/generates/SwaggerGenerator.ts +145 -53
  103. package/src/generates/internal/E2eFileProgrammer.ts +182 -123
  104. package/src/generates/internal/FilePrinter.ts +53 -0
  105. package/src/{utils → generates/internal}/ImportDictionary.ts +35 -13
  106. package/src/generates/internal/SdkAliasCollection.ts +152 -0
  107. package/src/generates/internal/SdkCloneProgrammer.ts +155 -0
  108. package/src/generates/internal/SdkDistributionComposer.ts +91 -91
  109. package/src/generates/internal/SdkFileProgrammer.ts +115 -106
  110. package/src/generates/internal/SdkFunctionProgrammer.ts +298 -518
  111. package/src/generates/internal/SdkImportWizard.ts +55 -55
  112. package/src/generates/internal/SdkNamespaceProgrammer.ts +510 -0
  113. package/src/generates/internal/SdkRouteDirectory.ts +17 -17
  114. package/src/generates/internal/SdkRouteProgrammer.ts +83 -0
  115. package/src/generates/internal/SdkSimulationProgrammer.ts +365 -133
  116. package/src/generates/internal/SdkTypeProgrammer.ts +386 -0
  117. package/src/generates/internal/SwaggerSchemaGenerator.ts +437 -427
  118. package/src/generates/internal/SwaggerSchemaValidator.ts +198 -198
  119. package/src/index.ts +4 -4
  120. package/src/module.ts +2 -2
  121. package/src/structures/IController.ts +94 -95
  122. package/src/structures/IErrorReport.ts +6 -6
  123. package/src/structures/INestiaProject.ts +13 -13
  124. package/src/structures/INormalizedInput.ts +20 -20
  125. package/src/structures/IRoute.ts +53 -53
  126. package/src/structures/ISwaggerLazyProperty.ts +2 -2
  127. package/src/structures/ISwaggerLazySchema.ts +2 -2
  128. package/src/structures/ITypeTuple.ts +6 -6
  129. package/src/structures/MethodType.ts +5 -5
  130. package/src/structures/ParamCategory.ts +1 -1
  131. package/src/structures/TypeEntry.ts +1 -1
  132. package/src/utils/ArrayUtil.ts +26 -26
  133. package/src/utils/FileRetriever.ts +22 -22
  134. package/src/utils/MapUtil.ts +14 -14
  135. package/src/utils/PathUtil.ts +10 -10
  136. package/src/utils/SourceFinder.ts +66 -66
  137. package/src/utils/StringUtil.ts +6 -0
  138. package/src/utils/StripEnums.ts +5 -5
  139. package/assets/bundle/api/utils/NestiaSimulator.ts +0 -70
  140. package/lib/generates/internal/SdkDtoGenerator.d.ts +0 -9
  141. package/lib/generates/internal/SdkDtoGenerator.js +0 -294
  142. package/lib/generates/internal/SdkDtoGenerator.js.map +0 -1
  143. package/lib/generates/internal/SdkTypeDefiner.d.ts +0 -11
  144. package/lib/generates/internal/SdkTypeDefiner.js +0 -82
  145. package/lib/generates/internal/SdkTypeDefiner.js.map +0 -1
  146. package/lib/structures/ISwagger.d.ts +0 -72
  147. package/lib/structures/ISwagger.js +0 -3
  148. package/lib/structures/ISwagger.js.map +0 -1
  149. package/lib/structures/ISwaggerComponents.d.ts +0 -26
  150. package/lib/structures/ISwaggerComponents.js +0 -3
  151. package/lib/structures/ISwaggerComponents.js.map +0 -1
  152. package/lib/structures/ISwaggerInfo.d.ts +0 -71
  153. package/lib/structures/ISwaggerInfo.js +0 -3
  154. package/lib/structures/ISwaggerInfo.js.map +0 -1
  155. package/lib/structures/ISwaggerRoute.d.ts +0 -47
  156. package/lib/structures/ISwaggerRoute.js +0 -3
  157. package/lib/structures/ISwaggerRoute.js.map +0 -1
  158. package/lib/structures/ISwaggerSecurityScheme.d.ts +0 -56
  159. package/lib/structures/ISwaggerSecurityScheme.js +0 -3
  160. package/lib/structures/ISwaggerSecurityScheme.js.map +0 -1
  161. package/lib/utils/ImportDictionary.js.map +0 -1
  162. package/src/generates/internal/SdkDtoGenerator.ts +0 -424
  163. package/src/generates/internal/SdkTypeDefiner.ts +0 -119
  164. package/src/structures/ISwagger.ts +0 -91
  165. package/src/structures/ISwaggerComponents.ts +0 -29
  166. package/src/structures/ISwaggerInfo.ts +0 -80
  167. package/src/structures/ISwaggerRoute.ts +0 -51
  168. package/src/structures/ISwaggerSecurityScheme.ts +0 -65
@@ -1,23 +1,20 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { Singleton } from "tstl/thread/Singleton";
3
+ import { Singleton } from "tstl";
4
4
  import ts from "typescript";
5
- import typia, { IJsonApplication, IJsonComponents } from "typia";
5
+ import typia, { IJsonApplication } from "typia";
6
6
  import { MetadataCollection } from "typia/lib/factories/MetadataCollection";
7
7
  import { JsonApplicationProgrammer } from "typia/lib/programmers/json/JsonApplicationProgrammer";
8
8
 
9
9
  import { INestiaConfig } from "../INestiaConfig";
10
10
  import { IRoute } from "../structures/IRoute";
11
- import { ISwagger } from "../structures/ISwagger";
12
- import { ISwaggerError } from "../structures/ISwaggerError";
13
- import { ISwaggerInfo } from "../structures/ISwaggerInfo";
14
- import { ISwaggerLazyProperty } from "../structures/ISwaggerLazyProperty";
15
- import { ISwaggerLazySchema } from "../structures/ISwaggerLazySchema";
16
- import { ISwaggerRoute } from "../structures/ISwaggerRoute";
17
- import { ISwaggerSecurityScheme } from "../structures/ISwaggerSecurityScheme";
18
11
  import { FileRetriever } from "../utils/FileRetriever";
19
12
  import { MapUtil } from "../utils/MapUtil";
20
13
  import { SwaggerSchemaGenerator } from "./internal/SwaggerSchemaGenerator";
14
+ import { OpenApi } from "@samchon/openapi";
15
+ import { ISwaggerError } from "../structures/ISwaggerError";
16
+ import { ISwaggerLazyProperty } from "../structures/ISwaggerLazyProperty";
17
+ import { ISwaggerLazySchema } from "../structures/ISwaggerLazySchema";
21
18
 
22
19
  export namespace SwaggerGenerator {
23
20
  export interface IProps {
@@ -27,6 +24,7 @@ export namespace SwaggerGenerator {
27
24
  lazySchemas: Array<ISwaggerLazySchema>;
28
25
  lazyProperties: Array<ISwaggerLazyProperty>;
29
26
  errors: ISwaggerError[];
27
+ swagger: OpenApi.IDocument;
30
28
  }
31
29
 
32
30
  export const generate =
@@ -62,13 +60,13 @@ export namespace SwaggerGenerator {
62
60
  const errors: ISwaggerError[] = [];
63
61
  const lazySchemas: Array<ISwaggerLazySchema> = [];
64
62
  const lazyProperties: Array<ISwaggerLazyProperty> = [];
65
- const swagger: ISwagger = await initialize(config);
66
- const pathDict: Map<string, Record<string, ISwaggerRoute>> = new Map();
63
+ const swagger: OpenApi.IDocument = await initialize(config);
64
+ const pathDict: Map<string, Record<string, OpenApi.IOperation>> = new Map();
67
65
 
68
66
  for (const route of routeList) {
69
67
  if (route.jsDocTags.find((tag) => tag.name === "internal")) continue;
70
68
 
71
- const path: Record<string, ISwaggerRoute> = MapUtil.take(
69
+ const path: Record<string, OpenApi.IOperation> = MapUtil.take(
72
70
  pathDict,
73
71
  get_path(route.path, route.parameters),
74
72
  () => ({}),
@@ -80,15 +78,14 @@ export namespace SwaggerGenerator {
80
78
  lazySchemas,
81
79
  lazyProperties,
82
80
  errors,
81
+ swagger,
83
82
  })(route);
84
83
  }
85
84
  swagger.paths = {};
86
85
  for (const [path, routes] of pathDict) swagger.paths[path] = routes;
87
86
 
88
87
  // FILL JSON-SCHEMAS
89
- const application: IJsonApplication = JsonApplicationProgrammer.write({
90
- purpose: "swagger",
91
- })(lazySchemas.map(({ metadata }) => metadata));
88
+ const application: IJsonApplication<"3.1"> = JsonApplicationProgrammer.write("3.1")(lazySchemas.map(({ metadata }) => metadata)) as IJsonApplication<"3.1">;
92
89
  swagger.components = {
93
90
  ...(swagger.components ?? {}),
94
91
  ...(application.components ?? {}),
@@ -102,8 +99,8 @@ export namespace SwaggerGenerator {
102
99
  (
103
100
  application.components.schemas?.[
104
101
  p.object
105
- ] as IJsonComponents.IObject
106
- )?.properties[p.property],
102
+ ] as OpenApi.IJsonSchema.IObject
103
+ )?.properties?.[p.property] ?? {},
107
104
  );
108
105
 
109
106
  // CONFIGURE SECURITY
@@ -114,8 +111,8 @@ export namespace SwaggerGenerator {
114
111
  for (const e of errors)
115
112
  console.error(
116
113
  `${path.relative(e.route.location, process.cwd())}:${
117
- e.route.symbol.class
118
- }.${e.route.symbol.function}:${
114
+ e.route.target.class.name
115
+ }.${e.route.target.function.name}:${
119
116
  e.from
120
117
  } - error TS(@nestia/sdk): invalid type detected.\n\n` +
121
118
  e.messages.map((m) => ` - ${m}`).join("\n"),
@@ -124,6 +121,66 @@ export namespace SwaggerGenerator {
124
121
  throw new TypeError("Invalid type detected");
125
122
  }
126
123
 
124
+ // SWAGGER CUSTOMIZER
125
+ const customizer = {
126
+ at: new Singleton(() => {
127
+ const functor: Map<Function, Endpoint> = new Map();
128
+ for (const route of routeList) {
129
+ const method: OpenApi.Method = route.method.toLowerCase() as OpenApi.Method;
130
+ const path: string = get_path(route.path, route.parameters);
131
+ functor.set(route.target.function, {
132
+ method,
133
+ path,
134
+ route: swagger.paths![path][method]!,
135
+ });
136
+ }
137
+ return functor;
138
+ }),
139
+ get: new Singleton(() => (key: Accessor): OpenApi.IOperation | undefined => {
140
+ const method: OpenApi.Method = key.method.toLowerCase() as OpenApi.Method;
141
+ const path: string =
142
+ "/" +
143
+ key.path
144
+ .split("/")
145
+ .filter((str) => !!str.length)
146
+ .map((str) =>
147
+ str.startsWith(":") ? `{${str.substring(1)}}` : str,
148
+ )
149
+ .join("/");
150
+ return swagger.paths?.[path]?.[method];
151
+ }),
152
+ };
153
+ for (const route of routeList) {
154
+ if (
155
+ false ===
156
+ Reflect.hasMetadata(
157
+ "nestia/SwaggerCustomizer",
158
+ route.controller.prototype,
159
+ route.target.function.name,
160
+ )
161
+ )
162
+ continue;
163
+
164
+ const path: string = get_path(route.path, route.parameters);
165
+ const method: OpenApi.Method = route.method.toLowerCase() as OpenApi.Method;
166
+ const target: OpenApi.IOperation = swagger.paths![path][method]!;
167
+ const closure: Function | Function[] = Reflect.getMetadata(
168
+ "nestia/SwaggerCustomizer",
169
+ route.controller.prototype,
170
+ route.target.function.name,
171
+ );
172
+ const array: Function[] = Array.isArray(closure) ? closure : [closure];
173
+ for (const fn of array)
174
+ fn({
175
+ route: target,
176
+ method,
177
+ path,
178
+ swagger,
179
+ at: (func: Function) => customizer.at.get().get(func),
180
+ get: (accessor: Accessor) => customizer.get.get()(accessor),
181
+ });
182
+ }
183
+
127
184
  // DO GENERATE
128
185
  await fs.promises.writeFile(
129
186
  location,
@@ -143,7 +200,7 @@ export namespace SwaggerGenerator {
143
200
  (routeList: IRoute[]): void | never => {
144
201
  const securityMap: Map<
145
202
  string,
146
- { scheme: ISwaggerSecurityScheme; scopes: Set<string> }
203
+ { scheme: OpenApi.ISecurityScheme; scopes: Set<string> }
147
204
  > = new Map();
148
205
  for (const [key, value] of Object.entries(config.security ?? {}))
149
206
  securityMap.set(key, {
@@ -183,7 +240,7 @@ export namespace SwaggerGenerator {
183
240
  for (const [key, scopes] of Object.entries(record))
184
241
  validate((str) =>
185
242
  violations.push(
186
- ` - ${str} (${route.symbol} at "${route.location}")`,
243
+ ` - ${str} (${route.target.class.name}.${route.target.function.name}() at "${route.location}")`,
187
244
  ),
188
245
  )(key, scopes);
189
246
 
@@ -201,9 +258,9 @@ export namespace SwaggerGenerator {
201
258
  --------------------------------------------------------- */
202
259
  const initialize = async (
203
260
  config: INestiaConfig.ISwaggerConfig,
204
- ): Promise<ISwagger> => {
261
+ ): Promise<OpenApi.IDocument> => {
205
262
  const pack = new Singleton(
206
- async (): Promise<Partial<ISwaggerInfo> | null> => {
263
+ async (): Promise<Partial<OpenApi.IDocument.IInfo> | null> => {
207
264
  const location: string | null = await FileRetriever.file(
208
265
  "package.json",
209
266
  )(process.cwd());
@@ -220,7 +277,7 @@ export namespace SwaggerGenerator {
220
277
  | {
221
278
  type: string;
222
279
  /**
223
- * @format url
280
+ * @format uri
224
281
  */
225
282
  url: string;
226
283
  };
@@ -233,11 +290,11 @@ export namespace SwaggerGenerator {
233
290
  ? typeof data.license === "string"
234
291
  ? { name: data.license }
235
292
  : typeof data.license === "object"
236
- ? {
237
- name: data.license.type,
238
- url: data.license.url,
239
- }
240
- : undefined
293
+ ? {
294
+ name: data.license.type,
295
+ url: data.license.url,
296
+ }
297
+ : undefined
241
298
  : undefined,
242
299
  };
243
300
  } catch {
@@ -247,7 +304,7 @@ export namespace SwaggerGenerator {
247
304
  );
248
305
 
249
306
  return {
250
- openapi: "3.0.1",
307
+ openapi: "3.1.0",
251
308
  servers: config.servers ?? [
252
309
  {
253
310
  url: "https://github.com/samchon/nestia",
@@ -268,7 +325,10 @@ export namespace SwaggerGenerator {
268
325
  license: config.info?.license ?? (await pack.get())?.license,
269
326
  },
270
327
  paths: {},
271
- components: {},
328
+ components: {
329
+ schemas: {},
330
+ },
331
+ tags: config.tags ?? [],
272
332
  };
273
333
  };
274
334
 
@@ -283,9 +343,12 @@ export namespace SwaggerGenerator {
283
343
 
284
344
  const generate_route =
285
345
  (props: IProps) =>
286
- (route: IRoute): ISwaggerRoute => {
346
+ (route: IRoute): OpenApi.IOperation => {
347
+ // FIND REQUEST BODY
287
348
  const body = route.parameters.find((param) => param.category === "body");
288
- const getJsDocTexts = (name: string) =>
349
+
350
+ // CONSTRUCT SUMMARY & DESCRIPTION
351
+ const getJsDocTexts = (name: string): string[] =>
289
352
  route.jsDocTags
290
353
  .filter(
291
354
  (tag) =>
@@ -296,7 +359,6 @@ export namespace SwaggerGenerator {
296
359
  ) !== undefined,
297
360
  )
298
361
  .map((tag) => tag.text!.find((elem) => elem.kind === "text")!.text);
299
-
300
362
  const description: string | undefined = route.description?.length
301
363
  ? route.description
302
364
  : undefined;
@@ -306,24 +368,40 @@ export namespace SwaggerGenerator {
306
368
  const [explicit] = getJsDocTexts("summary");
307
369
  if (explicit?.length) return explicit;
308
370
 
309
- const index: number = description.indexOf(".");
310
- if (index <= 0) return undefined;
311
-
312
- const content: string = description.substring(0, index).trim();
313
- return content.length ? content : undefined;
371
+ const index: number = description.indexOf("\n");
372
+ const top: string = (
373
+ index === -1 ? description : description.substring(0, index)
374
+ ).trim();
375
+ return top.endsWith(".") ? top.substring(0, top.length - 1) : undefined;
314
376
  })();
315
377
  const deprecated = route.jsDocTags.find(
316
378
  (tag) => tag.name === "deprecated",
317
379
  );
318
380
 
381
+ // CONSTRUCT TAGS
382
+ const tagSet: Set<string> = new Set([
383
+ ...route.swaggerTags,
384
+ ...getJsDocTexts("tag").map((tag) => tag.split(" ")[0]),
385
+ ]);
386
+ for (const tag of tagSet)
387
+ if (props.swagger.tags!.find((elem) => elem.name === tag) === undefined)
388
+ props.swagger.tags!.push({ name: tag });
389
+ for (const texts of getJsDocTexts("tag")) {
390
+ const [name, ...description] = texts.split(" ");
391
+ if (description.length)
392
+ props.swagger.tags!.find((elem) => elem.name === name)!.description ??=
393
+ description.join(" ");
394
+ }
395
+
396
+ // FINALIZE
319
397
  return {
320
398
  deprecated: deprecated ? true : undefined,
321
- tags: [...route.swaggerTags, ...new Set([...getJsDocTexts("tag")])],
399
+ tags: [...tagSet],
322
400
  operationId:
323
401
  route.operationId ??
324
402
  props.config.operationId?.({
325
- class: route.symbol.class,
326
- function: route.symbol.function,
403
+ class: route.target.class.name,
404
+ function: route.target.function.name,
327
405
  method: route.method as "GET",
328
406
  path: route.path,
329
407
  }),
@@ -338,20 +416,24 @@ export namespace SwaggerGenerator {
338
416
  summary,
339
417
  description,
340
418
  security: route.security.length ? route.security : undefined,
341
- "x-nestia-namespace": [
342
- ...route.path
343
- .split("/")
344
- .filter((str) => str.length && str[0] !== ":"),
345
- route.name,
346
- ].join("."),
347
- "x-nestia-jsDocTags": route.jsDocTags,
348
- "x-nestia-method": route.method,
419
+ ...(props.config.additional === true
420
+ ? {
421
+ "x-nestia-namespace": [
422
+ ...route.path
423
+ .split("/")
424
+ .filter((str) => str.length && str[0] !== ":"),
425
+ route.name,
426
+ ].join("."),
427
+ "x-nestia-jsDocTags": route.jsDocTags,
428
+ "x-nestia-method": route.method,
429
+ }
430
+ : {}),
349
431
  };
350
432
  };
351
433
 
352
434
  function fill_security(
353
435
  security: Required<INestiaConfig.ISwaggerConfig>["security"],
354
- swagger: ISwagger,
436
+ swagger: OpenApi.IDocument,
355
437
  ): void {
356
438
  swagger.components.securitySchemes = {};
357
439
  for (const [key, value] of Object.entries(security))
@@ -359,8 +441,8 @@ export namespace SwaggerGenerator {
359
441
  }
360
442
 
361
443
  function emend_security(
362
- input: ISwaggerSecurityScheme,
363
- ): ISwaggerSecurityScheme {
444
+ input: OpenApi.ISecurityScheme,
445
+ ): OpenApi.ISecurityScheme {
364
446
  if (input.type === "apiKey")
365
447
  return {
366
448
  ...input,
@@ -370,3 +452,13 @@ export namespace SwaggerGenerator {
370
452
  return input;
371
453
  }
372
454
  }
455
+
456
+ interface Accessor {
457
+ method: string;
458
+ path: string;
459
+ }
460
+ interface Endpoint {
461
+ method: string;
462
+ path: string;
463
+ route: OpenApi.IOperation;
464
+ }
@@ -1,123 +1,182 @@
1
- import fs from "fs";
2
-
3
- import { INestiaConfig } from "../../INestiaConfig";
4
- import { IRoute } from "../../structures/IRoute";
5
- import { ImportDictionary } from "../../utils/ImportDictionary";
6
- import { SdkDtoGenerator } from "./SdkDtoGenerator";
7
- import { SdkImportWizard } from "./SdkImportWizard";
8
- import { SdkTypeDefiner } from "./SdkTypeDefiner";
9
-
10
- export namespace E2eFileProgrammer {
11
- export const generate =
12
- (config: INestiaConfig) =>
13
- (props: { api: string; current: string }) =>
14
- async (route: IRoute): Promise<void> => {
15
- const importer: ImportDictionary = new ImportDictionary(
16
- `${props.current}/${name(route)}.ts`,
17
- );
18
- if (config.clone !== true)
19
- for (const tuple of route.imports)
20
- for (const instance of tuple[1])
21
- importer.internal({
22
- file: tuple[0],
23
- type: true,
24
- instance,
25
- });
26
- importer.internal({
27
- type: false,
28
- file: props.api,
29
- instance: null,
30
- name: "api",
31
- });
32
-
33
- const body: string = arrow(config)(importer)(route);
34
- const content: string = [importer.toScript(props.current), "", body].join(
35
- "\n",
36
- );
37
-
38
- await fs.promises.writeFile(importer.file, content, "utf8");
39
- };
40
-
41
- const arrow =
42
- (config: INestiaConfig) =>
43
- (importer: ImportDictionary) =>
44
- (route: IRoute): string => {
45
- const tab: number = 2;
46
- const headers = route.parameters.find(
47
- (p) => p.category === "headers" && p.field === undefined,
48
- );
49
- const output = [
50
- `await ${accessor(route)}(`,
51
- headers !== undefined
52
- ? [
53
- "{",
54
- " ...connection,",
55
- " headers: {",
56
- " ...(connection.headers ?? {}),",
57
- ` ...${SdkImportWizard.typia(
58
- importer,
59
- )}.random<${getTypeName(config)(importer)(headers)}>(),`,
60
- " },",
61
- "},",
62
- ]
63
- .map((line) => `${" ".repeat(tab * 4)}${line}`)
64
- .join("\n")
65
- : `${" ".repeat(tab * 4)}connection,`,
66
- ...route.parameters
67
- .filter((param) => param.category !== "headers")
68
- .map(parameter(config)(importer)(tab)),
69
- `${" ".repeat((tab - 1) * 4)});`,
70
- ].join("\n");
71
- return [
72
- `export const ${name(route)} = async (`,
73
- ` connection: api.IConnection`,
74
- `): Promise<void> => {`,
75
- ...(route.output.typeName === "void"
76
- ? [` ${output}`]
77
- : [
78
- ` const output: ${SdkTypeDefiner.output(config)(importer)(
79
- route,
80
- )} = ${output}`,
81
- ` ${SdkImportWizard.typia(importer)}.assert(output);`,
82
- ]),
83
- `};`,
84
- ].join("\n");
85
- };
86
-
87
- const parameter =
88
- (config: INestiaConfig) =>
89
- (importer: ImportDictionary) =>
90
- (tab: number) =>
91
- (param: IRoute.IParameter): string => {
92
- const middle: string = `${SdkImportWizard.typia(importer)}.random<${wrap(
93
- config,
94
- )(importer)(
95
- getTypeName(config)(importer)(param),
96
- param.category === "body",
97
- )}>()`;
98
- return `${" ".repeat(4 * tab)}${middle},`;
99
- };
100
-
101
- const name = (route: IRoute): string =>
102
- ["test", "api", ...route.accessors].join("_");
103
-
104
- const accessor = (route: IRoute): string =>
105
- ["api", "functional", ...route.accessors].join(".");
106
-
107
- const wrap =
108
- (config: INestiaConfig) =>
109
- (importer: ImportDictionary) =>
110
- (name: string, body: boolean): string =>
111
- config.primitive === false
112
- ? name
113
- : `${(body ? SdkImportWizard.Primitive : SdkImportWizard.Resolved)(
114
- importer,
115
- )}<${name}>`;
116
- }
117
- const getTypeName =
118
- (config: INestiaConfig) =>
119
- (importer: ImportDictionary) =>
120
- (p: IRoute.IParameter | IRoute.IOutput) =>
121
- p.metadata
122
- ? SdkDtoGenerator.decode(config)(importer)(p.metadata)
123
- : p.typeName;
1
+ import ts from "typescript";
2
+ import { IdentifierFactory } from "typia/lib/factories/IdentifierFactory";
3
+
4
+ import { INestiaConfig } from "../../INestiaConfig";
5
+ import { IRoute } from "../../structures/IRoute";
6
+ import { FilePrinter } from "./FilePrinter";
7
+ import { ImportDictionary } from "./ImportDictionary";
8
+ import { SdkAliasCollection } from "./SdkAliasCollection";
9
+ import { SdkImportWizard } from "./SdkImportWizard";
10
+ import { SdkTypeProgrammer } from "./SdkTypeProgrammer";
11
+
12
+ export namespace E2eFileProgrammer {
13
+ export const generate =
14
+ (checker: ts.TypeChecker) =>
15
+ (config: INestiaConfig) =>
16
+ (props: { api: string; current: string }) =>
17
+ async (route: IRoute): Promise<void> => {
18
+ const importer: ImportDictionary = new ImportDictionary(
19
+ `${props.current}/${getFunctionName(route)}.ts`,
20
+ );
21
+ if (config.clone !== true)
22
+ for (const tuple of route.imports)
23
+ for (const instance of tuple[1])
24
+ importer.internal({
25
+ file: tuple[0],
26
+ type: true,
27
+ instance,
28
+ });
29
+ importer.internal({
30
+ type: false,
31
+ file: props.api,
32
+ instance: null,
33
+ name: "api",
34
+ });
35
+
36
+ const functor = generate_function(checker)(config)(importer)(route);
37
+ await FilePrinter.write({
38
+ location: importer.file,
39
+ statements: [
40
+ ...importer.toStatements(props.current),
41
+ FilePrinter.enter(),
42
+ functor,
43
+ ],
44
+ });
45
+ };
46
+
47
+ const generate_function =
48
+ (checker: ts.TypeChecker) =>
49
+ (config: INestiaConfig) =>
50
+ (importer: ImportDictionary) =>
51
+ (route: IRoute): ts.Statement =>
52
+ ts.factory.createVariableStatement(
53
+ [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
54
+ ts.factory.createVariableDeclarationList(
55
+ [
56
+ ts.factory.createVariableDeclaration(
57
+ ts.factory.createIdentifier(getFunctionName(route)),
58
+ undefined,
59
+ undefined,
60
+ generate_arrow(checker)(config)(importer)(route),
61
+ ),
62
+ ],
63
+ ts.NodeFlags.Const,
64
+ ),
65
+ );
66
+
67
+ const generate_arrow =
68
+ (checker: ts.TypeChecker) =>
69
+ (config: INestiaConfig) =>
70
+ (importer: ImportDictionary) =>
71
+ (route: IRoute) => {
72
+ const headers = route.parameters.find(
73
+ (p) => p.category === "headers" && p.field === undefined,
74
+ );
75
+ const connection = headers
76
+ ? ts.factory.createObjectLiteralExpression(
77
+ [
78
+ ts.factory.createSpreadAssignment(
79
+ ts.factory.createIdentifier("connection"),
80
+ ),
81
+ ts.factory.createPropertyAssignment(
82
+ "headers",
83
+ ts.factory.createObjectLiteralExpression(
84
+ [
85
+ ts.factory.createSpreadAssignment(
86
+ IdentifierFactory.access(
87
+ ts.factory.createIdentifier("connection"),
88
+ )("headers"),
89
+ ),
90
+ ts.factory.createSpreadAssignment(
91
+ ts.factory.createCallExpression(
92
+ IdentifierFactory.access(
93
+ ts.factory.createIdentifier(
94
+ SdkImportWizard.typia(importer),
95
+ ),
96
+ )("random"),
97
+ [getTypeName(config)(importer)(headers)],
98
+ undefined,
99
+ ),
100
+ ),
101
+ ],
102
+ true,
103
+ ),
104
+ ),
105
+ ],
106
+ true,
107
+ )
108
+ : ts.factory.createIdentifier("connection");
109
+ const caller = ts.factory.createCallExpression(
110
+ ts.factory.createIdentifier(
111
+ ["api", "functional", ...route.accessors].join("."),
112
+ ),
113
+ undefined,
114
+ [
115
+ connection,
116
+ ...route.parameters
117
+ .filter((p) => p.category !== "headers")
118
+ .map((p) =>
119
+ ts.factory.createCallExpression(
120
+ IdentifierFactory.access(
121
+ ts.factory.createIdentifier(SdkImportWizard.typia(importer)),
122
+ )("random"),
123
+ [getTypeName(config)(importer)(p)],
124
+ undefined,
125
+ ),
126
+ ),
127
+ ],
128
+ );
129
+ const assert = ts.factory.createCallExpression(
130
+ IdentifierFactory.access(
131
+ ts.factory.createIdentifier(SdkImportWizard.typia(importer)),
132
+ )("assert"),
133
+ undefined,
134
+ [ts.factory.createIdentifier("output")],
135
+ );
136
+
137
+ return ts.factory.createArrowFunction(
138
+ [ts.factory.createModifier(ts.SyntaxKind.AsyncKeyword)],
139
+ undefined,
140
+ [
141
+ IdentifierFactory.parameter(
142
+ "connection",
143
+ ts.factory.createTypeReferenceNode("api.IConnection"),
144
+ ),
145
+ ],
146
+ undefined,
147
+ undefined,
148
+ ts.factory.createBlock([
149
+ ts.factory.createVariableStatement(
150
+ [],
151
+ ts.factory.createVariableDeclarationList(
152
+ [
153
+ ts.factory.createVariableDeclaration(
154
+ "output",
155
+ undefined,
156
+ config.propagate !== true && route.output.typeName === "void"
157
+ ? undefined
158
+ : SdkAliasCollection.output(checker)(config)(importer)(
159
+ route,
160
+ ),
161
+ ts.factory.createAwaitExpression(caller),
162
+ ),
163
+ ],
164
+ ts.NodeFlags.Const,
165
+ ),
166
+ ),
167
+ ts.factory.createExpressionStatement(assert),
168
+ ]),
169
+ );
170
+ };
171
+ }
172
+
173
+ const getFunctionName = (route: IRoute): string =>
174
+ ["test", "api", ...route.accessors].join("_");
175
+
176
+ const getTypeName =
177
+ (config: INestiaConfig) =>
178
+ (importer: ImportDictionary) =>
179
+ (p: IRoute.IParameter | IRoute.IOutput) =>
180
+ p.metadata
181
+ ? SdkTypeProgrammer.write(config)(importer)(p.metadata)
182
+ : ts.factory.createTypeReferenceNode(p.typeName);