@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.
- package/assets/bundle/api/Resolved.ts +1 -0
- package/assets/bundle/api/module.ts +1 -0
- package/lib/NestiaSdkApplication.d.ts +1 -0
- package/lib/NestiaSdkApplication.js +24 -26
- package/lib/NestiaSdkApplication.js.map +1 -1
- package/lib/analyses/ReflectControllerAnalyzer.js +2 -0
- package/lib/analyses/ReflectControllerAnalyzer.js.map +1 -1
- package/lib/analyses/ReflectHttpOperationAnalyzer.js +10 -1
- package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -1
- package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.d.ts +15 -0
- package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js +50 -0
- package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js.map +1 -0
- package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js +14 -9
- package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js.map +1 -1
- package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js +2 -1
- package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js.map +1 -1
- package/lib/analyses/ReflectWebSocketOperationAnalyzer.js +3 -2
- package/lib/analyses/ReflectWebSocketOperationAnalyzer.js.map +1 -1
- package/lib/analyses/TypedHttpRouteAnalyzer.js +3 -1
- package/lib/analyses/TypedHttpRouteAnalyzer.js.map +1 -1
- package/lib/executable/internal/NestiaSdkCommand.d.ts +1 -0
- package/lib/executable/internal/NestiaSdkCommand.js +3 -2
- package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
- package/lib/executable/sdk.js +3 -0
- package/lib/executable/sdk.js.map +1 -1
- package/lib/generates/CloneGenerator.d.ts +4 -0
- package/lib/generates/CloneGenerator.js +62 -60
- package/lib/generates/CloneGenerator.js.map +1 -1
- package/lib/generates/SdkGenerator.js +4 -3
- package/lib/generates/SdkGenerator.js.map +1 -1
- package/lib/generates/SwaggerGenerator.js +60 -8
- package/lib/generates/SwaggerGenerator.js.map +1 -1
- package/lib/generates/internal/E2eFileProgrammer.js +11 -3
- package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
- package/lib/generates/internal/ImportDictionary.js +1 -1
- package/lib/generates/internal/ImportDictionary.js.map +1 -1
- package/lib/generates/internal/SdkAliasCollection.d.ts +5 -1
- package/lib/generates/internal/SdkAliasCollection.js +24 -8
- package/lib/generates/internal/SdkAliasCollection.js.map +1 -1
- package/lib/generates/internal/SdkFileProgrammer.js +1 -1
- package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkHttpCloneProgrammer.d.ts +11 -0
- package/lib/generates/internal/SdkHttpCloneProgrammer.js +75 -142
- package/lib/generates/internal/SdkHttpCloneProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkHttpCloneReferencer.d.ts +4 -0
- package/lib/generates/internal/SdkHttpCloneReferencer.js +62 -0
- package/lib/generates/internal/SdkHttpCloneReferencer.js.map +1 -0
- package/lib/generates/internal/SdkHttpFunctionProgrammer.js +26 -13
- package/lib/generates/internal/SdkHttpFunctionProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkHttpNamespaceProgrammer.js +17 -8
- package/lib/generates/internal/SdkHttpNamespaceProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkHttpRouteProgrammer.js +2 -2
- package/lib/generates/internal/SdkHttpRouteProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkHttpSimulationProgrammer.js +8 -5
- package/lib/generates/internal/SdkHttpSimulationProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js +12 -5
- package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkWebSocketRouteProgrammer.js +3 -3
- package/lib/generates/internal/SdkWebSocketRouteProgrammer.js.map +1 -1
- package/lib/generates/internal/SwaggerOperationComposer.js +19 -1
- package/lib/generates/internal/SwaggerOperationComposer.js.map +1 -1
- package/lib/generates/internal/SwaggerOperationParameterComposer.js +3 -3
- package/lib/generates/internal/SwaggerOperationParameterComposer.js.map +1 -1
- package/lib/structures/IReflectHttpOperation.d.ts +1 -1
- package/lib/structures/IReflectHttpOperationException.d.ts +2 -2
- package/lib/structures/ITypedApplication.d.ts +2 -0
- package/lib/transform.js +2 -2
- package/lib/transform.js.map +1 -1
- package/lib/transformers/IOperationMetadata.d.ts +6 -1
- package/lib/transformers/{ISdkTransformerContext.d.ts → ISdkOperationTransformerContext.d.ts} +1 -1
- package/lib/transformers/{ISdkTransformerContext.js → ISdkOperationTransformerContext.js} +1 -1
- package/lib/transformers/ISdkOperationTransformerContext.js.map +1 -0
- package/lib/transformers/SdkOperationProgrammer.d.ts +13 -0
- package/lib/transformers/{SdkMetadataProgrammer.js → SdkOperationProgrammer.js} +36 -55
- package/lib/transformers/SdkOperationProgrammer.js.map +1 -0
- package/lib/transformers/SdkOperationTransformer.d.ts +4 -0
- package/lib/transformers/{SdkTransformer.js → SdkOperationTransformer.js} +56 -16
- package/lib/transformers/SdkOperationTransformer.js.map +1 -0
- package/lib/utils/MetadataUtil.d.ts +4 -0
- package/lib/utils/MetadataUtil.js +34 -0
- package/lib/utils/MetadataUtil.js.map +1 -0
- package/lib/utils/StringUtil.d.ts +1 -0
- package/lib/utils/StringUtil.js +6 -0
- package/lib/utils/StringUtil.js.map +1 -1
- package/lib/validators/HttpHeadersValidator.d.ts +5 -0
- package/lib/validators/HttpHeadersValidator.js +29 -0
- package/lib/validators/HttpHeadersValidator.js.map +1 -0
- package/lib/validators/HttpQueryValidator.d.ts +5 -0
- package/lib/validators/HttpQueryValidator.js +29 -0
- package/lib/validators/HttpQueryValidator.js.map +1 -0
- package/package.json +8 -8
- package/src/NestiaSdkApplication.ts +20 -30
- package/src/analyses/ReflectControllerAnalyzer.ts +2 -0
- package/src/analyses/ReflectHttpOperationAnalyzer.ts +10 -1
- package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +71 -0
- package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +37 -8
- package/src/analyses/ReflectHttpOperationResponseAnalyzer.ts +8 -0
- package/src/analyses/ReflectWebSocketOperationAnalyzer.ts +10 -2
- package/src/analyses/TypedHttpRouteAnalyzer.ts +4 -1
- package/src/executable/internal/NestiaSdkCommand.ts +3 -2
- package/src/executable/sdk.ts +2 -0
- package/src/generates/CloneGenerator.ts +61 -60
- package/src/generates/SdkGenerator.ts +3 -3
- package/src/generates/SwaggerGenerator.ts +84 -10
- package/src/generates/internal/E2eFileProgrammer.ts +13 -3
- package/src/generates/internal/ImportDictionary.ts +1 -1
- package/src/generates/internal/SdkAliasCollection.ts +32 -10
- package/src/generates/internal/SdkFileProgrammer.ts +1 -1
- package/src/generates/internal/SdkHttpCloneProgrammer.ts +118 -144
- package/src/generates/internal/SdkHttpCloneReferencer.ts +71 -0
- package/src/generates/internal/SdkHttpFunctionProgrammer.ts +31 -16
- package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +252 -230
- package/src/generates/internal/SdkHttpRouteProgrammer.ts +2 -2
- package/src/generates/internal/SdkHttpSimulationProgrammer.ts +30 -24
- package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +14 -6
- package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +6 -8
- package/src/generates/internal/SwaggerOperationComposer.ts +25 -0
- package/src/generates/internal/SwaggerOperationParameterComposer.ts +3 -0
- package/src/structures/IReflectHttpOperation.ts +1 -4
- package/src/structures/IReflectHttpOperationException.ts +2 -2
- package/src/structures/ITypedApplication.ts +3 -0
- package/src/transform.ts +2 -2
- package/src/transformers/IOperationMetadata.ts +7 -1
- package/src/transformers/{ISdkTransformerContext.ts → ISdkOperationTransformerContext.ts} +1 -1
- package/src/transformers/{SdkMetadataProgrammer.ts → SdkOperationProgrammer.ts} +40 -62
- package/src/transformers/{SdkTransformer.ts → SdkOperationTransformer.ts} +88 -16
- package/src/utils/MetadataUtil.ts +26 -0
- package/src/utils/StringUtil.ts +8 -0
- package/src/validators/HttpHeadersValidator.ts +34 -0
- package/src/validators/HttpQueryValidator.ts +34 -0
- package/lib/transformers/ISdkTransformerContext.js.map +0 -1
- package/lib/transformers/SdkMetadataProgrammer.d.ts +0 -11
- package/lib/transformers/SdkMetadataProgrammer.js.map +0 -1
- package/lib/transformers/SdkTransformer.d.ts +0 -4
- 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"
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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(
|
|
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)
|
|
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
|
|
15
|
+
await _Generate(task);
|
|
15
16
|
};
|
|
16
17
|
|
|
17
|
-
const
|
|
18
|
+
const _Generate = async (
|
|
18
19
|
task: (app: NestiaSdkApplication) => Promise<void>,
|
|
19
20
|
) => {
|
|
20
21
|
// LOAD CONFIG INFO
|
package/src/executable/sdk.ts
CHANGED
|
@@ -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
|
-
|
|
2
|
-
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import ts from "typescript";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
48
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
}):
|
|
184
|
-
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
-
|
|
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 ===
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
|
19
|
+
new Pair(`node_modules/${props.library}`, props.type),
|
|
20
20
|
() => ({
|
|
21
21
|
location: `node_modules/${props.library}`,
|
|
22
22
|
elements: new HashSet(),
|