@nestia/sdk 3.11.0-dev.20240813-10 → 3.11.0-dev.20240814

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 (135) hide show
  1. package/assets/bundle/api/Resolved.ts +1 -0
  2. package/assets/bundle/api/module.ts +1 -0
  3. package/lib/NestiaSdkApplication.d.ts +1 -0
  4. package/lib/NestiaSdkApplication.js +24 -26
  5. package/lib/NestiaSdkApplication.js.map +1 -1
  6. package/lib/analyses/ReflectControllerAnalyzer.js +2 -0
  7. package/lib/analyses/ReflectControllerAnalyzer.js.map +1 -1
  8. package/lib/analyses/ReflectHttpOperationAnalyzer.js +10 -1
  9. package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -1
  10. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.d.ts +15 -0
  11. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js +50 -0
  12. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js.map +1 -0
  13. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js +14 -9
  14. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js.map +1 -1
  15. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js +2 -1
  16. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js.map +1 -1
  17. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js +3 -2
  18. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js.map +1 -1
  19. package/lib/analyses/TypedHttpRouteAnalyzer.js +3 -1
  20. package/lib/analyses/TypedHttpRouteAnalyzer.js.map +1 -1
  21. package/lib/executable/internal/NestiaSdkCommand.d.ts +1 -0
  22. package/lib/executable/internal/NestiaSdkCommand.js +3 -2
  23. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  24. package/lib/executable/sdk.js +3 -0
  25. package/lib/executable/sdk.js.map +1 -1
  26. package/lib/generates/CloneGenerator.d.ts +4 -0
  27. package/lib/generates/CloneGenerator.js +62 -60
  28. package/lib/generates/CloneGenerator.js.map +1 -1
  29. package/lib/generates/SdkGenerator.js +4 -3
  30. package/lib/generates/SdkGenerator.js.map +1 -1
  31. package/lib/generates/SwaggerGenerator.js +60 -8
  32. package/lib/generates/SwaggerGenerator.js.map +1 -1
  33. package/lib/generates/internal/E2eFileProgrammer.js +11 -3
  34. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  35. package/lib/generates/internal/ImportDictionary.js +1 -1
  36. package/lib/generates/internal/ImportDictionary.js.map +1 -1
  37. package/lib/generates/internal/SdkAliasCollection.d.ts +5 -1
  38. package/lib/generates/internal/SdkAliasCollection.js +24 -8
  39. package/lib/generates/internal/SdkAliasCollection.js.map +1 -1
  40. package/lib/generates/internal/SdkFileProgrammer.js +1 -1
  41. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  42. package/lib/generates/internal/SdkHttpCloneProgrammer.d.ts +11 -0
  43. package/lib/generates/internal/SdkHttpCloneProgrammer.js +75 -142
  44. package/lib/generates/internal/SdkHttpCloneProgrammer.js.map +1 -1
  45. package/lib/generates/internal/SdkHttpCloneReferencer.d.ts +4 -0
  46. package/lib/generates/internal/SdkHttpCloneReferencer.js +62 -0
  47. package/lib/generates/internal/SdkHttpCloneReferencer.js.map +1 -0
  48. package/lib/generates/internal/SdkHttpFunctionProgrammer.js +26 -13
  49. package/lib/generates/internal/SdkHttpFunctionProgrammer.js.map +1 -1
  50. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js +17 -8
  51. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js.map +1 -1
  52. package/lib/generates/internal/SdkHttpRouteProgrammer.js +2 -2
  53. package/lib/generates/internal/SdkHttpRouteProgrammer.js.map +1 -1
  54. package/lib/generates/internal/SdkHttpSimulationProgrammer.js +8 -5
  55. package/lib/generates/internal/SdkHttpSimulationProgrammer.js.map +1 -1
  56. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js +12 -5
  57. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js.map +1 -1
  58. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js +3 -3
  59. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js.map +1 -1
  60. package/lib/generates/internal/SwaggerOperationComposer.js +19 -1
  61. package/lib/generates/internal/SwaggerOperationComposer.js.map +1 -1
  62. package/lib/generates/internal/SwaggerOperationParameterComposer.js +3 -3
  63. package/lib/generates/internal/SwaggerOperationParameterComposer.js.map +1 -1
  64. package/lib/structures/IReflectHttpOperation.d.ts +1 -1
  65. package/lib/structures/IReflectHttpOperationException.d.ts +2 -2
  66. package/lib/structures/ITypedApplication.d.ts +2 -0
  67. package/lib/transform.js +2 -2
  68. package/lib/transform.js.map +1 -1
  69. package/lib/transformers/IOperationMetadata.d.ts +6 -1
  70. package/lib/transformers/{ISdkTransformerContext.d.ts → ISdkOperationTransformerContext.d.ts} +1 -1
  71. package/lib/transformers/{ISdkTransformerContext.js → ISdkOperationTransformerContext.js} +1 -1
  72. package/lib/transformers/ISdkOperationTransformerContext.js.map +1 -0
  73. package/lib/transformers/SdkOperationProgrammer.d.ts +13 -0
  74. package/lib/transformers/{SdkMetadataProgrammer.js → SdkOperationProgrammer.js} +36 -55
  75. package/lib/transformers/SdkOperationProgrammer.js.map +1 -0
  76. package/lib/transformers/SdkOperationTransformer.d.ts +4 -0
  77. package/lib/transformers/{SdkTransformer.js → SdkOperationTransformer.js} +56 -16
  78. package/lib/transformers/SdkOperationTransformer.js.map +1 -0
  79. package/lib/utils/MetadataUtil.d.ts +4 -0
  80. package/lib/utils/MetadataUtil.js +34 -0
  81. package/lib/utils/MetadataUtil.js.map +1 -0
  82. package/lib/utils/StringUtil.d.ts +1 -0
  83. package/lib/utils/StringUtil.js +6 -0
  84. package/lib/utils/StringUtil.js.map +1 -1
  85. package/lib/validators/HttpHeadersValidator.d.ts +5 -0
  86. package/lib/validators/HttpHeadersValidator.js +29 -0
  87. package/lib/validators/HttpHeadersValidator.js.map +1 -0
  88. package/lib/validators/HttpQueryValidator.d.ts +5 -0
  89. package/lib/validators/HttpQueryValidator.js +29 -0
  90. package/lib/validators/HttpQueryValidator.js.map +1 -0
  91. package/package.json +8 -8
  92. package/src/NestiaSdkApplication.ts +20 -30
  93. package/src/analyses/ReflectControllerAnalyzer.ts +2 -0
  94. package/src/analyses/ReflectHttpOperationAnalyzer.ts +10 -1
  95. package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +71 -0
  96. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +37 -8
  97. package/src/analyses/ReflectHttpOperationResponseAnalyzer.ts +8 -0
  98. package/src/analyses/ReflectWebSocketOperationAnalyzer.ts +10 -2
  99. package/src/analyses/TypedHttpRouteAnalyzer.ts +4 -1
  100. package/src/executable/internal/NestiaSdkCommand.ts +3 -2
  101. package/src/executable/sdk.ts +2 -0
  102. package/src/generates/CloneGenerator.ts +61 -60
  103. package/src/generates/SdkGenerator.ts +3 -3
  104. package/src/generates/SwaggerGenerator.ts +84 -10
  105. package/src/generates/internal/E2eFileProgrammer.ts +13 -3
  106. package/src/generates/internal/ImportDictionary.ts +1 -1
  107. package/src/generates/internal/SdkAliasCollection.ts +32 -10
  108. package/src/generates/internal/SdkFileProgrammer.ts +1 -1
  109. package/src/generates/internal/SdkHttpCloneProgrammer.ts +118 -144
  110. package/src/generates/internal/SdkHttpCloneReferencer.ts +71 -0
  111. package/src/generates/internal/SdkHttpFunctionProgrammer.ts +31 -16
  112. package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +252 -230
  113. package/src/generates/internal/SdkHttpRouteProgrammer.ts +2 -2
  114. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +30 -24
  115. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +14 -6
  116. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +6 -8
  117. package/src/generates/internal/SwaggerOperationComposer.ts +25 -0
  118. package/src/generates/internal/SwaggerOperationParameterComposer.ts +3 -0
  119. package/src/structures/IReflectHttpOperation.ts +1 -4
  120. package/src/structures/IReflectHttpOperationException.ts +2 -2
  121. package/src/structures/ITypedApplication.ts +3 -0
  122. package/src/transform.ts +2 -2
  123. package/src/transformers/IOperationMetadata.ts +7 -1
  124. package/src/transformers/{ISdkTransformerContext.ts → ISdkOperationTransformerContext.ts} +1 -1
  125. package/src/transformers/{SdkMetadataProgrammer.ts → SdkOperationProgrammer.ts} +40 -62
  126. package/src/transformers/{SdkTransformer.ts → SdkOperationTransformer.ts} +88 -16
  127. package/src/utils/MetadataUtil.ts +26 -0
  128. package/src/utils/StringUtil.ts +8 -0
  129. package/src/validators/HttpHeadersValidator.ts +34 -0
  130. package/src/validators/HttpQueryValidator.ts +34 -0
  131. package/lib/transformers/ISdkTransformerContext.js.map +0 -1
  132. package/lib/transformers/SdkMetadataProgrammer.d.ts +0 -11
  133. package/lib/transformers/SdkMetadataProgrammer.js.map +0 -1
  134. package/lib/transformers/SdkTransformer.d.ts +0 -4
  135. package/lib/transformers/SdkTransformer.js.map +0 -1
@@ -0,0 +1,71 @@
1
+ import { TypedException } from "@nestia/core";
2
+ import { JsonMetadataFactory } from "typia/lib/factories/JsonMetadataFactory";
3
+
4
+ import { IReflectController } from "../structures/IReflectController";
5
+ import { IReflectHttpOperationException } from "../structures/IReflectHttpOperationException";
6
+ import { IReflectOperationError } from "../structures/IReflectOperationError";
7
+ import { IOperationMetadata } from "../transformers/IOperationMetadata";
8
+
9
+ export namespace ReflectHttpOperationExceptionAnalyzer {
10
+ export interface IContext {
11
+ controller: IReflectController;
12
+ function: Function;
13
+ functionName: string;
14
+ httpMethod: string;
15
+ metadata: IOperationMetadata;
16
+ errors: IReflectOperationError[];
17
+ }
18
+ export const analyze = (
19
+ ctx: IContext,
20
+ ): Record<string, IReflectHttpOperationException> => {
21
+ const preconfigured: TypedException.IProps<any>[] = analyzePreconfigured(
22
+ ctx.function,
23
+ )
24
+ .slice()
25
+ .reverse();
26
+ const errors: IReflectOperationError[] = [];
27
+ const exceptions: IReflectHttpOperationException[] = preconfigured
28
+ .map((pre, i) => {
29
+ const matched: IOperationMetadata.IException | null =
30
+ ctx.metadata.exceptions[i];
31
+ if (matched === undefined) {
32
+ errors.push({
33
+ file: ctx.controller.file,
34
+ class: ctx.controller.class.name,
35
+ function: ctx.functionName,
36
+ from: `exception (status: ${pre.status})`,
37
+ contents: ["Unable to find exception type."],
38
+ });
39
+ return null;
40
+ } else if (matched.type === null) {
41
+ errors.push({
42
+ file: ctx.controller.file,
43
+ class: ctx.controller.class.name,
44
+ function: ctx.functionName,
45
+ from: `exception (status: ${pre.status})`,
46
+ contents: ["Failed to get the type info."],
47
+ });
48
+ }
49
+ const schema: IOperationMetadata.ISchema | null = matched.primitive
50
+ .success
51
+ ? matched.primitive.data
52
+ : null;
53
+ if (schema === null || matched.type === null) return null; // unreachable
54
+ return {
55
+ status: pre.status,
56
+ description: pre.description ?? null,
57
+ example: pre.example,
58
+ examples: pre.examples,
59
+ type: matched.type,
60
+ ...schema,
61
+ validate: JsonMetadataFactory.validate,
62
+ } satisfies IReflectHttpOperationException;
63
+ })
64
+ .filter((e) => e !== null);
65
+ if (errors.length) ctx.errors.push(...errors);
66
+ return Object.fromEntries(exceptions.map((e) => [e.status, e]));
67
+ };
68
+
69
+ const analyzePreconfigured = (func: Function): TypedException.IProps<any>[] =>
70
+ Reflect.getMetadata("nestia/TypedException", func) ?? [];
71
+ }
@@ -1,3 +1,4 @@
1
+ import { SwaggerExample } from "@nestia/core";
1
2
  import { ROUTE_ARGS_METADATA } from "@nestjs/common/constants";
2
3
  import { RouteParamtypes } from "@nestjs/common/enums/route-paramtypes.enum";
3
4
  import { JsonMetadataFactory } from "typia/lib/factories/JsonMetadataFactory";
@@ -9,9 +10,10 @@ import { HttpQueryProgrammer } from "typia/lib/programmers/http/HttpQueryProgram
9
10
  import { IReflectController } from "../structures/IReflectController";
10
11
  import { IReflectHttpOperationParameter } from "../structures/IReflectHttpOperationParameter";
11
12
  import { IReflectOperationError } from "../structures/IReflectOperationError";
12
- import { IReflectTypeImport } from "../structures/IReflectTypeImport";
13
13
  import { IOperationMetadata } from "../transformers/IOperationMetadata";
14
14
  import { TextPlainValidator } from "../transformers/TextPlainValidator";
15
+ import { HttpHeadersValidator } from "../validators/HttpHeadersValidator";
16
+ import { HttpQueryValidator } from "../validators/HttpQueryValidator";
15
17
 
16
18
  export namespace ReflectHttpOperationParameterAnalyzer {
17
19
  export interface IContext {
@@ -25,7 +27,6 @@ export namespace ReflectHttpOperationParameterAnalyzer {
25
27
  export const analyze = (ctx: IContext): IReflectHttpOperationParameter[] => {
26
28
  const preconfigured: IReflectHttpOperationParameter.IPreconfigured[] =
27
29
  analyzePreconfigured(ctx);
28
- const imports: IReflectTypeImport[] = [];
29
30
  const errors: IReflectOperationError[] = [];
30
31
 
31
32
  //----
@@ -148,8 +149,15 @@ export namespace ReflectHttpOperationParameterAnalyzer {
148
149
  )
149
150
  return null; // unreachable
150
151
 
152
+ const example: SwaggerExample.IData<any> | undefined = (
153
+ Reflect.getMetadata(
154
+ "nestia/SwaggerExample/Parameters",
155
+ ctx.controller.class.prototype,
156
+ ctx.functionName,
157
+ ) ?? []
158
+ ).find((x: SwaggerExample.IData<any>) => x.index === matched.index);
159
+
151
160
  // COMPOSITION
152
- imports.push(...matched.imports);
153
161
  if (p.category === "param")
154
162
  return {
155
163
  category: p.category,
@@ -160,21 +168,40 @@ export namespace ReflectHttpOperationParameterAnalyzer {
160
168
  validate: HttpParameterProgrammer.validate,
161
169
  description: matched.description,
162
170
  jsDocTags: matched.jsDocTags,
171
+ example: example?.example,
172
+ examples: example?.examples,
163
173
  ...schema,
164
174
  };
165
- else if (p.category === "query" || p.category === "headers")
175
+ else if (p.category === "query")
166
176
  return {
167
177
  category: p.category,
168
178
  index: p.index,
169
179
  field: p.field ?? null,
170
180
  name: matched.name,
171
181
  type: matched.type,
172
- validate:
173
- p.category === "query"
174
- ? HttpQueryProgrammer.validate
175
- : HttpHeadersProgrammer.validate,
182
+ validate: p.field
183
+ ? HttpQueryValidator.validate
184
+ : HttpQueryProgrammer.validate,
185
+ description: matched.description,
186
+ jsDocTags: matched.jsDocTags,
187
+ example: example?.example,
188
+ examples: example?.examples,
189
+ ...schema,
190
+ };
191
+ else if (p.category === "headers")
192
+ return {
193
+ category: p.category,
194
+ index: p.index,
195
+ field: p.field ?? null,
196
+ name: matched.name,
197
+ type: matched.type,
198
+ validate: p.field
199
+ ? HttpHeadersValidator.validate
200
+ : HttpHeadersProgrammer.validate,
176
201
  description: matched.description,
177
202
  jsDocTags: matched.jsDocTags,
203
+ example: example?.example,
204
+ examples: example?.examples,
178
205
  ...schema,
179
206
  };
180
207
  else if (p.category === "body")
@@ -195,6 +222,8 @@ export namespace ReflectHttpOperationParameterAnalyzer {
195
222
  : TextPlainValidator.validate,
196
223
  description: matched.description,
197
224
  jsDocTags: matched.jsDocTags,
225
+ example: example?.example,
226
+ examples: example?.examples,
198
227
  ...schema,
199
228
  };
200
229
  else {
@@ -1,3 +1,4 @@
1
+ import { SwaggerExample } from "@nestia/core";
1
2
  import {
2
3
  HEADERS_METADATA,
3
4
  HTTP_CODE_METADATA,
@@ -78,6 +79,11 @@ export namespace ReflectHttpOperationResponseAnalyzer {
78
79
  !typia.is<IReflectHttpOperationSuccess["contentType"]>(contentType)
79
80
  )
80
81
  return null;
82
+
83
+ const example: SwaggerExample.IData<any> | undefined = Reflect.getMetadata(
84
+ "nestia/SwaggerExample/Response",
85
+ ctx.function,
86
+ );
81
87
  return {
82
88
  contentType: contentType,
83
89
  encrypted,
@@ -96,6 +102,8 @@ export namespace ReflectHttpOperationResponseAnalyzer {
96
102
  meta.size()
97
103
  ? ["HEAD method must not have any return value."]
98
104
  : [],
105
+ example: example?.example,
106
+ examples: example?.examples,
99
107
  };
100
108
  };
101
109
 
@@ -85,7 +85,16 @@ export namespace ReflectWebSocketOperationAnalyzer {
85
85
  );
86
86
 
87
87
  // COMPLETE COMPOSITION
88
- imports.push(...matched.imports);
88
+ imports.push(
89
+ ...matched.imports.filter(
90
+ (i) =>
91
+ !(
92
+ i.file.includes("tgrid/lib") &&
93
+ (i.file.endsWith("Driver.d.ts") ||
94
+ i.file.endsWith("WebSocketAcceptor.d.ts"))
95
+ ),
96
+ ),
97
+ );
89
98
  if (
90
99
  p.category === "acceptor" ||
91
100
  p.category === "driver" ||
@@ -109,7 +118,6 @@ export namespace ReflectWebSocketOperationAnalyzer {
109
118
  } satisfies IReflectWebSocketOperationParameter.IParam;
110
119
 
111
120
  // UNKNOWN TYPE, MAYBE NEW FEATURE
112
- console.log(p);
113
121
  return errors.push(
114
122
  `@WebSocketRoute.${StringUtil.capitalize(p.category)}() has not been supported yet. How about upgrading the nestia packages?`,
115
123
  );
@@ -151,7 +151,10 @@ export namespace TypedHttpRouteAnalyzer {
151
151
  },
152
152
  ),
153
153
  };
154
- if (errors.length) return [];
154
+ if (errors.length) {
155
+ props.errors.push(...errors);
156
+ return [];
157
+ }
155
158
  return props.paths.map((path) => ({
156
159
  ...props.operation,
157
160
  controller: props.controller,
@@ -9,12 +9,13 @@ export namespace NestiaSdkCommand {
9
9
  export const swagger = () => main((app) => app.swagger());
10
10
  export const openai = () => main((app) => app.openai());
11
11
  export const e2e = () => main((app) => app.e2e());
12
+ export const all = () => main((app) => app.all());
12
13
 
13
14
  const main = async (task: (app: NestiaSdkApplication) => Promise<void>) => {
14
- await generate(task);
15
+ await _Generate(task);
15
16
  };
16
17
 
17
- const generate = async (
18
+ const _Generate = async (
18
19
  task: (app: NestiaSdkApplication) => Promise<void>,
19
20
  ) => {
20
21
  // LOAD CONFIG INFO
@@ -18,6 +18,7 @@ npx @nestia/sdk [command] [options?]
18
18
  4. npx @nestia/sdk swagger --config? [config file] --project? [project file]
19
19
  5. npx @nestia/sdk openai --config? [config file] --project? [project file]
20
20
  6. npx @nestia/sdk e2e --config? [config file] --project? [project file]
21
+ 7. npx @nestia/sdk generate --config? [config file] --project? [project file]
21
22
  `;
22
23
 
23
24
  function halt(desc: string): never {
@@ -65,6 +66,7 @@ async function main() {
65
66
  else if (type === "swagger") await execute((c) => c.swagger());
66
67
  else if (type === "openai") await execute((c) => c.openai());
67
68
  else if (type === "e2e") await execute((c) => c.e2e());
69
+ else if (type === "all") await execute((c) => c.all());
68
70
  else halt(USAGE);
69
71
 
70
72
  process.exit(0);
@@ -1,65 +1,66 @@
1
- // import fs from "fs";
2
- // import ts from "typescript";
1
+ import fs from "fs";
2
+ import ts from "typescript";
3
3
 
4
- // import { INestiaProject } from "../structures/INestiaProject";
5
- // import { ITypedApplication } from "../structures/ITypedApplication";
6
- // import { FilePrinter } from "./internal/FilePrinter";
7
- // import { ImportDictionary } from "./internal/ImportDictionary";
8
- // // import { SdkHttpCloneProgrammer } from "./internal/SdkHttpCloneProgrammer";
4
+ import { INestiaProject } from "../structures/INestiaProject";
5
+ import { ITypedApplication } from "../structures/ITypedApplication";
6
+ import { FilePrinter } from "./internal/FilePrinter";
7
+ import { ImportDictionary } from "./internal/ImportDictionary";
8
+ import { SdkHttpCloneProgrammer } from "./internal/SdkHttpCloneProgrammer";
9
+ import { SdkHttpCloneReferencer } from "./internal/SdkHttpCloneReferencer";
9
10
 
10
- // export namespace CloneGenerator {
11
- // export const write = async (app: ITypedApplication): Promise<void> => {
12
- // // const dict: Map<string, SdkHttpCloneProgrammer.IModule> =
13
- // // SdkHttpCloneProgrammer.write(app.project)(
14
- // // app.routes.filter((r) => r.protocol === "http"),
15
- // // );
16
- // if (dict.size === 0) return;
17
- // try {
18
- // await fs.promises.mkdir(`${app.project.config.output}/structures`);
19
- // } catch {}
20
- // for (const [key, value] of dict)
21
- // await writeDtoFile(app.project)(key, value);
22
- // };
11
+ export namespace CloneGenerator {
12
+ export const write = async (app: ITypedApplication): Promise<void> => {
13
+ const dict: Map<string, SdkHttpCloneProgrammer.IModule> =
14
+ SdkHttpCloneProgrammer.write(app);
15
+ if (dict.size === 0) return;
23
16
 
24
- // const writeDtoFile =
25
- // (project: INestiaProject) =>
26
- // async (
27
- // key: string,
28
- // value: SdkHttpCloneProgrammer.IModule,
29
- // ): Promise<void> => {
30
- // const location: string = `${project.config.output}/structures/${key}.ts`;
31
- // const importer: ImportDictionary = new ImportDictionary(location);
32
- // const statements: ts.Statement[] = iterate(importer)(value);
33
- // if (statements.length === 0) return;
17
+ SdkHttpCloneReferencer.replace(app);
18
+ try {
19
+ await fs.promises.mkdir(`${app.project.config.output}/structures`);
20
+ } catch {}
21
+ for (const [key, value] of dict)
22
+ await writeDtoFile(app.project)(key, value);
23
+ };
34
24
 
35
- // await FilePrinter.write({
36
- // location,
37
- // statements: [
38
- // ...importer.toStatements(`${project.config.output}/structures`),
39
- // ...(importer.empty() ? [] : [FilePrinter.enter()]),
40
- // ...statements,
41
- // ],
42
- // });
43
- // };
25
+ const writeDtoFile =
26
+ (project: INestiaProject) =>
27
+ async (
28
+ key: string,
29
+ value: SdkHttpCloneProgrammer.IModule,
30
+ ): Promise<void> => {
31
+ const location: string = `${project.config.output}/structures/${key}.ts`;
32
+ const importer: ImportDictionary = new ImportDictionary(location);
33
+ const statements: ts.Statement[] = iterate(importer)(value);
34
+ if (statements.length === 0) return;
44
35
 
45
- // const iterate =
46
- // (importer: ImportDictionary) =>
47
- // (modulo: SdkHttpCloneProgrammer.IModule): ts.Statement[] => {
48
- // const output: ts.Statement[] = [];
49
- // if (modulo.programmer !== null) output.push(modulo.programmer(importer));
50
- // if (modulo.children.size) {
51
- // const internal: ts.Statement[] = [];
52
- // for (const child of modulo.children.values())
53
- // internal.push(...iterate(importer)(child));
54
- // output.push(
55
- // ts.factory.createModuleDeclaration(
56
- // [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
57
- // ts.factory.createIdentifier(modulo.name),
58
- // ts.factory.createModuleBlock(internal),
59
- // ts.NodeFlags.Namespace,
60
- // ),
61
- // );
62
- // }
63
- // return output;
64
- // };
65
- // }
36
+ await FilePrinter.write({
37
+ location,
38
+ statements: [
39
+ ...importer.toStatements(`${project.config.output}/structures`),
40
+ ...(importer.empty() ? [] : [FilePrinter.enter()]),
41
+ ...statements,
42
+ ],
43
+ });
44
+ };
45
+
46
+ const iterate =
47
+ (importer: ImportDictionary) =>
48
+ (modulo: SdkHttpCloneProgrammer.IModule): ts.Statement[] => {
49
+ const output: ts.Statement[] = [];
50
+ if (modulo.programmer !== null) output.push(modulo.programmer(importer));
51
+ if (modulo.children.size) {
52
+ const internal: ts.Statement[] = [];
53
+ for (const child of modulo.children.values())
54
+ internal.push(...iterate(importer)(child));
55
+ output.push(
56
+ ts.factory.createModuleDeclaration(
57
+ [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
58
+ ts.factory.createIdentifier(modulo.name),
59
+ ts.factory.createModuleBlock(internal),
60
+ ts.NodeFlags.Namespace,
61
+ ),
62
+ );
63
+ }
64
+ return output;
65
+ };
66
+ }
@@ -7,7 +7,7 @@ import { IReflectOperationError } from "../structures/IReflectOperationError";
7
7
  import { IReflectType } from "../structures/IReflectType";
8
8
  import { ITypedApplication } from "../structures/ITypedApplication";
9
9
  import { ITypedHttpRoute } from "../structures/ITypedHttpRoute";
10
- // import { CloneGenerator } from "./CloneGenerator";
10
+ import { CloneGenerator } from "./CloneGenerator";
11
11
  import { SdkDistributionComposer } from "./internal/SdkDistributionComposer";
12
12
  import { SdkFileProgrammer } from "./internal/SdkFileProgrammer";
13
13
 
@@ -44,8 +44,8 @@ export namespace SdkGenerator {
44
44
  }
45
45
  }
46
46
 
47
- // // STRUCTURES
48
- // if (app.project.config.clone === true) await CloneGenerator.write(app);
47
+ // STRUCTURES
48
+ if (app.project.config.clone === true) await CloneGenerator.write(app);
49
49
 
50
50
  // FUNCTIONAL
51
51
  await SdkFileProgrammer.generate(app);
@@ -1,3 +1,4 @@
1
+ import { SwaggerCustomizer } from "@nestia/core";
1
2
  import { OpenApi, OpenApiV3, SwaggerV2 } from "@samchon/openapi";
2
3
  import fs from "fs";
3
4
  import path from "path";
@@ -16,6 +17,7 @@ import { SwaggerOperationComposer } from "./internal/SwaggerOperationComposer";
16
17
  export namespace SwaggerGenerator {
17
18
  export const generate = async (app: ITypedApplication): Promise<void> => {
18
19
  // GET CONFIGURATION
20
+ console.log("Generating Swagger Document");
19
21
  if (app.project.config.swagger === undefined)
20
22
  throw new Error("Swagger configuration is not defined.");
21
23
  const config: INestiaConfig.ISwaggerConfig = app.project.config.swagger;
@@ -92,7 +94,7 @@ export namespace SwaggerGenerator {
92
94
  const document: OpenApi.IDocument = props.document;
93
95
  document.components.schemas ??= {};
94
96
  Object.assign(document.components.schemas, json.components.schemas);
95
- document.paths = writePaths({ ...props, schema });
97
+ fillPaths({ ...props, schema, document });
96
98
 
97
99
  return document;
98
100
  };
@@ -175,23 +177,85 @@ export namespace SwaggerGenerator {
175
177
  };
176
178
  };
177
179
 
178
- const writePaths = (props: {
180
+ const fillPaths = (props: {
179
181
  config: INestiaConfig.ISwaggerConfig;
180
182
  document: OpenApi.IDocument;
181
183
  schema: (metadata: Metadata) => OpenApi.IJsonSchema | undefined;
182
184
  routes: ITypedHttpRoute[];
183
- }): Record<string, OpenApi.IPath> => {
184
- const output: Record<string, OpenApi.IPath> = {};
185
+ }): void => {
186
+ // SWAGGER CUSTOMIZER
187
+ const customizers: Array<() => void> = [];
188
+ const neighbor = {
189
+ at: new Singleton(() => {
190
+ const functor: Map<Function, Endpoint> = new Map();
191
+ for (const r of props.routes) {
192
+ const method: OpenApi.Method =
193
+ r.method.toLowerCase() as OpenApi.Method;
194
+ const path: string = getPath(r);
195
+ const operation: OpenApi.IOperation | undefined =
196
+ props.document.paths?.[path]?.[method];
197
+ if (operation === undefined) continue;
198
+ functor.set(r.function, {
199
+ method,
200
+ path,
201
+ route: operation,
202
+ });
203
+ }
204
+ return functor;
205
+ }),
206
+ get: new Singleton(
207
+ () =>
208
+ (key: Accessor): OpenApi.IOperation | undefined => {
209
+ const method: OpenApi.Method =
210
+ key.method.toLowerCase() as OpenApi.Method;
211
+ const path: string =
212
+ "/" +
213
+ key.path
214
+ .split("/")
215
+ .filter((str) => !!str.length)
216
+ .map((str) =>
217
+ str.startsWith(":") ? `{${str.substring(1)}}` : str,
218
+ )
219
+ .join("/");
220
+ return props.document.paths?.[path]?.[method];
221
+ },
222
+ ),
223
+ };
224
+
225
+ // COMPOSE OPERATIONS
185
226
  for (const r of props.routes) {
227
+ const operation: OpenApi.IOperation = SwaggerOperationComposer.compose({
228
+ ...props,
229
+ route: r,
230
+ });
186
231
  const path: string = getPath(r);
187
- output[path] ??= {};
188
- output[path][r.method.toLowerCase() as "get"] =
189
- SwaggerOperationComposer.compose({
190
- ...props,
191
- route: r,
232
+ props.document.paths ??= {};
233
+ props.document.paths[path] ??= {};
234
+ props.document.paths[path][r.method.toLowerCase() as "get"] = operation;
235
+
236
+ const closure: Function | Function[] | undefined = Reflect.getMetadata(
237
+ "nestia/SwaggerCustomizer",
238
+ r.controller.class.prototype,
239
+ r.name,
240
+ );
241
+ if (closure !== undefined) {
242
+ const array: Function[] = Array.isArray(closure) ? closure : [closure];
243
+ customizers.push(() => {
244
+ for (const closure of array)
245
+ closure({
246
+ swagger: props.document,
247
+ method: r.method,
248
+ path,
249
+ route: operation,
250
+ at: (func: Function) => neighbor.at.get().get(func),
251
+ get: (accessor: Accessor) => neighbor.get.get()(accessor),
252
+ } satisfies SwaggerCustomizer.IProps);
192
253
  });
254
+ }
193
255
  }
194
- return output;
256
+
257
+ // DO CUSTOMIZE
258
+ for (const fn of customizers) fn();
195
259
  };
196
260
 
197
261
  const getPath = (route: {
@@ -207,3 +271,13 @@ export namespace SwaggerGenerator {
207
271
  return str;
208
272
  };
209
273
  }
274
+
275
+ interface Accessor {
276
+ method: string;
277
+ path: string;
278
+ }
279
+ interface Endpoint {
280
+ method: string;
281
+ path: string;
282
+ route: OpenApi.IOperation;
283
+ }
@@ -66,7 +66,7 @@ export namespace E2eFileProgrammer {
66
66
  (importer: ImportDictionary) =>
67
67
  (route: ITypedHttpRoute) => {
68
68
  const headers = route.parameters.find(
69
- (p) => p.category === "headers" && p.field === undefined,
69
+ (p) => p.category === "headers" && p.field === null,
70
70
  );
71
71
  const connection = headers
72
72
  ? ts.factory.createObjectLiteralExpression(
@@ -90,7 +90,13 @@ export namespace E2eFileProgrammer {
90
90
  SdkImportWizard.typia(importer),
91
91
  ),
92
92
  )("random"),
93
- [SdkAliasCollection.name(headers.type)],
93
+ [
94
+ project.config.clone === true
95
+ ? SdkAliasCollection.from(project)(importer)(
96
+ headers.metadata,
97
+ )
98
+ : SdkAliasCollection.name(headers),
99
+ ],
94
100
  undefined,
95
101
  ),
96
102
  ),
@@ -116,7 +122,11 @@ export namespace E2eFileProgrammer {
116
122
  IdentifierFactory.access(
117
123
  ts.factory.createIdentifier(SdkImportWizard.typia(importer)),
118
124
  )("random"),
119
- [SdkAliasCollection.name(p.type)],
125
+ [
126
+ project.config.clone === true
127
+ ? SdkAliasCollection.from(project)(importer)(p.metadata)
128
+ : SdkAliasCollection.name(p),
129
+ ],
120
130
  undefined,
121
131
  ),
122
132
  ),
@@ -16,7 +16,7 @@ export class ImportDictionary {
16
16
 
17
17
  public external(props: ImportDictionary.IExternalProps): string {
18
18
  const composition: IComposition = this.components_.take(
19
- new Pair(props.library, props.type),
19
+ new Pair(`node_modules/${props.library}`, props.type),
20
20
  () => ({
21
21
  location: `node_modules/${props.library}`,
22
22
  elements: new HashSet(),