@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.
- package/README.md +12 -9
- package/assets/config/nestia.config.ts +82 -79
- package/lib/INestiaConfig.d.ts +28 -6
- package/lib/NestiaSdkApplication.js +12 -10
- package/lib/NestiaSdkApplication.js.map +1 -1
- package/lib/analyses/ConfigAnalyzer.js +1 -1
- package/lib/analyses/ConfigAnalyzer.js.map +1 -1
- package/lib/analyses/ControllerAnalyzer.js +30 -15
- package/lib/analyses/ControllerAnalyzer.js.map +1 -1
- package/lib/analyses/ExceptionAnalyzer.js +35 -6
- package/lib/analyses/ExceptionAnalyzer.js.map +1 -1
- package/lib/analyses/ImportAnalyzer.d.ts +1 -2
- package/lib/analyses/ImportAnalyzer.js +2 -2
- package/lib/analyses/ImportAnalyzer.js.map +1 -1
- package/lib/analyses/PathAnalyzer.d.ts +2 -4
- package/lib/analyses/PathAnalyzer.js +27 -11
- package/lib/analyses/PathAnalyzer.js.map +1 -1
- package/lib/analyses/ReflectAnalyzer.js +34 -22
- package/lib/analyses/ReflectAnalyzer.js.map +1 -1
- package/lib/analyses/SecurityAnalyzer.js +13 -8
- package/lib/analyses/SecurityAnalyzer.js.map +1 -1
- package/lib/executable/internal/NestiaConfigLoader.js +300 -220
- package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
- package/lib/executable/sdk.js +11 -11
- package/lib/generates/CloneGenerator.d.ts +6 -0
- package/lib/generates/CloneGenerator.js +62 -0
- package/lib/generates/CloneGenerator.js.map +1 -0
- package/lib/generates/E2eGenerator.d.ts +2 -1
- package/lib/generates/E2eGenerator.js +2 -2
- package/lib/generates/E2eGenerator.js.map +1 -1
- package/lib/generates/SdkGenerator.js +3 -11
- package/lib/generates/SdkGenerator.js.map +1 -1
- package/lib/generates/SwaggerGenerator.d.ts +2 -0
- package/lib/generates/SwaggerGenerator.js +119 -62
- package/lib/generates/SwaggerGenerator.js.map +1 -1
- package/lib/generates/internal/E2eFileProgrammer.d.ts +2 -1
- package/lib/generates/internal/E2eFileProgrammer.js +49 -53
- package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
- package/lib/generates/internal/FilePrinter.d.ts +10 -0
- package/lib/generates/internal/FilePrinter.js +46 -0
- package/lib/generates/internal/FilePrinter.js.map +1 -0
- package/lib/{utils → generates/internal}/ImportDictionary.d.ts +2 -1
- package/lib/{utils → generates/internal}/ImportDictionary.js +20 -14
- package/lib/generates/internal/ImportDictionary.js.map +1 -0
- package/lib/generates/internal/SdkAliasCollection.d.ts +12 -0
- package/lib/generates/internal/SdkAliasCollection.js +97 -0
- package/lib/generates/internal/SdkAliasCollection.js.map +1 -0
- package/lib/generates/internal/SdkCloneProgrammer.d.ts +12 -0
- package/lib/generates/internal/SdkCloneProgrammer.js +99 -0
- package/lib/generates/internal/SdkCloneProgrammer.js.map +1 -0
- package/lib/generates/internal/SdkFileProgrammer.d.ts +2 -1
- package/lib/generates/internal/SdkFileProgrammer.js +27 -28
- package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkFunctionProgrammer.d.ts +7 -2
- package/lib/generates/internal/SdkFunctionProgrammer.js +115 -322
- package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkImportWizard.d.ts +1 -1
- package/lib/generates/internal/SdkNamespaceProgrammer.d.ts +11 -0
- package/lib/generates/internal/SdkNamespaceProgrammer.js +180 -0
- package/lib/generates/internal/SdkNamespaceProgrammer.js.map +1 -0
- package/lib/generates/internal/SdkRouteProgrammer.d.ts +7 -0
- package/lib/generates/internal/SdkRouteProgrammer.js +55 -0
- package/lib/generates/internal/SdkRouteProgrammer.js.map +1 -0
- package/lib/generates/internal/SdkSimulationProgrammer.d.ts +8 -2
- package/lib/generates/internal/SdkSimulationProgrammer.js +103 -89
- package/lib/generates/internal/SdkSimulationProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkTypeProgrammer.d.ts +9 -0
- package/lib/generates/internal/SdkTypeProgrammer.js +228 -0
- package/lib/generates/internal/SdkTypeProgrammer.js.map +1 -0
- package/lib/generates/internal/SwaggerSchemaGenerator.d.ts +4 -4
- package/lib/generates/internal/SwaggerSchemaGenerator.js +30 -28
- package/lib/generates/internal/SwaggerSchemaGenerator.js.map +1 -1
- package/lib/structures/IController.d.ts +4 -2
- package/lib/structures/IRoute.d.ts +5 -4
- package/lib/structures/ISwaggerLazyProperty.d.ts +2 -2
- package/lib/structures/ISwaggerLazySchema.d.ts +2 -2
- package/lib/structures/ParamCategory.d.ts +1 -1
- package/lib/structures/TypeEntry.js +2 -2
- package/lib/structures/TypeEntry.js.map +1 -1
- package/lib/utils/StringUtil.d.ts +3 -0
- package/lib/utils/StringUtil.js +8 -0
- package/lib/utils/StringUtil.js.map +1 -0
- package/package.json +12 -16
- package/src/INestiaConfig.ts +30 -6
- package/src/NestiaSdkApplication.ts +255 -253
- package/src/analyses/AccessorAnalyzer.ts +60 -60
- package/src/analyses/ConfigAnalyzer.ts +147 -147
- package/src/analyses/ControllerAnalyzer.ts +42 -19
- package/src/analyses/ExceptionAnalyzer.ts +148 -115
- package/src/analyses/GenericAnalyzer.ts +51 -51
- package/src/analyses/ImportAnalyzer.ts +1 -2
- package/src/analyses/PathAnalyzer.ts +110 -98
- package/src/analyses/ReflectAnalyzer.ts +39 -35
- package/src/analyses/SecurityAnalyzer.ts +24 -20
- package/src/executable/internal/CommandParser.ts +15 -15
- package/src/executable/internal/NestiaConfigLoader.ts +67 -67
- package/src/executable/internal/NestiaSdkCommand.ts +60 -60
- package/src/executable/sdk.ts +73 -73
- package/src/generates/CloneGenerator.ts +62 -0
- package/src/generates/E2eGenerator.ts +66 -64
- package/src/generates/SdkGenerator.ts +84 -96
- package/src/generates/SwaggerGenerator.ts +145 -53
- package/src/generates/internal/E2eFileProgrammer.ts +182 -123
- package/src/generates/internal/FilePrinter.ts +53 -0
- package/src/{utils → generates/internal}/ImportDictionary.ts +35 -13
- package/src/generates/internal/SdkAliasCollection.ts +152 -0
- package/src/generates/internal/SdkCloneProgrammer.ts +155 -0
- package/src/generates/internal/SdkDistributionComposer.ts +91 -91
- package/src/generates/internal/SdkFileProgrammer.ts +115 -106
- package/src/generates/internal/SdkFunctionProgrammer.ts +298 -518
- package/src/generates/internal/SdkImportWizard.ts +55 -55
- package/src/generates/internal/SdkNamespaceProgrammer.ts +510 -0
- package/src/generates/internal/SdkRouteDirectory.ts +17 -17
- package/src/generates/internal/SdkRouteProgrammer.ts +83 -0
- package/src/generates/internal/SdkSimulationProgrammer.ts +365 -133
- package/src/generates/internal/SdkTypeProgrammer.ts +386 -0
- package/src/generates/internal/SwaggerSchemaGenerator.ts +437 -427
- package/src/generates/internal/SwaggerSchemaValidator.ts +198 -198
- package/src/index.ts +4 -4
- package/src/module.ts +2 -2
- package/src/structures/IController.ts +94 -95
- package/src/structures/IErrorReport.ts +6 -6
- package/src/structures/INestiaProject.ts +13 -13
- package/src/structures/INormalizedInput.ts +20 -20
- package/src/structures/IRoute.ts +53 -53
- package/src/structures/ISwaggerLazyProperty.ts +2 -2
- package/src/structures/ISwaggerLazySchema.ts +2 -2
- package/src/structures/ITypeTuple.ts +6 -6
- package/src/structures/MethodType.ts +5 -5
- package/src/structures/ParamCategory.ts +1 -1
- package/src/structures/TypeEntry.ts +1 -1
- package/src/utils/ArrayUtil.ts +26 -26
- package/src/utils/FileRetriever.ts +22 -22
- package/src/utils/MapUtil.ts +14 -14
- package/src/utils/PathUtil.ts +10 -10
- package/src/utils/SourceFinder.ts +66 -66
- package/src/utils/StringUtil.ts +6 -0
- package/src/utils/StripEnums.ts +5 -5
- package/assets/bundle/api/utils/NestiaSimulator.ts +0 -70
- package/lib/generates/internal/SdkDtoGenerator.d.ts +0 -9
- package/lib/generates/internal/SdkDtoGenerator.js +0 -294
- package/lib/generates/internal/SdkDtoGenerator.js.map +0 -1
- package/lib/generates/internal/SdkTypeDefiner.d.ts +0 -11
- package/lib/generates/internal/SdkTypeDefiner.js +0 -82
- package/lib/generates/internal/SdkTypeDefiner.js.map +0 -1
- package/lib/structures/ISwagger.d.ts +0 -72
- package/lib/structures/ISwagger.js +0 -3
- package/lib/structures/ISwagger.js.map +0 -1
- package/lib/structures/ISwaggerComponents.d.ts +0 -26
- package/lib/structures/ISwaggerComponents.js +0 -3
- package/lib/structures/ISwaggerComponents.js.map +0 -1
- package/lib/structures/ISwaggerInfo.d.ts +0 -71
- package/lib/structures/ISwaggerInfo.js +0 -3
- package/lib/structures/ISwaggerInfo.js.map +0 -1
- package/lib/structures/ISwaggerRoute.d.ts +0 -47
- package/lib/structures/ISwaggerRoute.js +0 -3
- package/lib/structures/ISwaggerRoute.js.map +0 -1
- package/lib/structures/ISwaggerSecurityScheme.d.ts +0 -56
- package/lib/structures/ISwaggerSecurityScheme.js +0 -3
- package/lib/structures/ISwaggerSecurityScheme.js.map +0 -1
- package/lib/utils/ImportDictionary.js.map +0 -1
- package/src/generates/internal/SdkDtoGenerator.ts +0 -424
- package/src/generates/internal/SdkTypeDefiner.ts +0 -119
- package/src/structures/ISwagger.ts +0 -91
- package/src/structures/ISwaggerComponents.ts +0 -29
- package/src/structures/ISwaggerInfo.ts +0 -80
- package/src/structures/ISwaggerRoute.ts +0 -51
- 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
|
|
3
|
+
import { Singleton } from "tstl";
|
|
4
4
|
import ts from "typescript";
|
|
5
|
-
import typia, { IJsonApplication
|
|
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:
|
|
66
|
-
const pathDict: Map<string, Record<string,
|
|
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,
|
|
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
|
|
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.
|
|
118
|
-
}.${e.route.
|
|
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:
|
|
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.
|
|
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<
|
|
261
|
+
): Promise<OpenApi.IDocument> => {
|
|
205
262
|
const pack = new Singleton(
|
|
206
|
-
async (): Promise<Partial<
|
|
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
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
|
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):
|
|
346
|
+
(route: IRoute): OpenApi.IOperation => {
|
|
347
|
+
// FIND REQUEST BODY
|
|
287
348
|
const body = route.parameters.find((param) => param.category === "body");
|
|
288
|
-
|
|
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
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
return
|
|
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: [...
|
|
399
|
+
tags: [...tagSet],
|
|
322
400
|
operationId:
|
|
323
401
|
route.operationId ??
|
|
324
402
|
props.config.operationId?.({
|
|
325
|
-
class: route.
|
|
326
|
-
function: route.
|
|
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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:
|
|
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:
|
|
363
|
-
):
|
|
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
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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);
|