@nestia/sdk 2.0.0-dev.20230904 → 2.0.0-dev.20230906
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/lib/INestiaConfig.d.ts +40 -32
- package/lib/NestiaSdkApplication.d.ts +1 -1
- package/lib/NestiaSdkApplication.js +5 -5
- package/lib/NestiaSdkApplication.js.map +1 -1
- package/lib/analyses/ControllerAnalyzer.js +4 -4
- package/lib/analyses/ControllerAnalyzer.js.map +1 -1
- package/lib/analyses/ReflectAnalyzer.js +9 -1
- package/lib/analyses/ReflectAnalyzer.js.map +1 -1
- package/lib/executable/internal/NestiaConfigLoader.js +17 -13
- package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
- package/lib/generates/SdkGenerator.d.ts +2 -1
- package/lib/generates/SdkGenerator.js +5 -1
- package/lib/generates/SdkGenerator.js.map +1 -1
- package/lib/generates/SwaggerGenerator.js +12 -8
- package/lib/generates/SwaggerGenerator.js.map +1 -1
- package/lib/generates/internal/E2eFileProgrammer.js +15 -10
- package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkDtoGenerator.d.ts +9 -0
- package/lib/generates/internal/SdkDtoGenerator.js +264 -0
- package/lib/generates/internal/SdkDtoGenerator.js.map +1 -0
- package/lib/generates/internal/SdkFileProgrammer.js +8 -7
- package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkFunctionProgrammer.js +11 -7
- package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkSimulationProgrammer.js +5 -1
- package/lib/generates/internal/SdkSimulationProgrammer.js.map +1 -1
- package/lib/generates/internal/SwaggerSchemaGenerator.d.ts +1 -1
- package/lib/generates/internal/SwaggerSchemaGenerator.js +59 -71
- package/lib/generates/internal/SwaggerSchemaGenerator.js.map +1 -1
- package/lib/generates/internal/SwaggerSchemaValidator.js +0 -4
- package/lib/generates/internal/SwaggerSchemaValidator.js.map +1 -1
- package/lib/structures/IController.d.ts +2 -0
- package/lib/structures/IRoute.d.ts +5 -1
- package/package.json +5 -5
- package/src/INestiaConfig.ts +43 -34
- package/src/NestiaSdkApplication.ts +5 -9
- package/src/analyses/ControllerAnalyzer.ts +5 -5
- package/src/analyses/ReflectAnalyzer.ts +8 -0
- package/src/generates/SdkGenerator.ts +7 -0
- package/src/generates/SwaggerGenerator.ts +16 -11
- package/src/generates/internal/E2eFileProgrammer.ts +24 -11
- package/src/generates/internal/SdkDtoGenerator.ts +384 -0
- package/src/generates/internal/SdkFileProgrammer.ts +8 -7
- package/src/generates/internal/SdkFunctionProgrammer.ts +35 -7
- package/src/generates/internal/SdkSimulationProgrammer.ts +10 -1
- package/src/generates/internal/SwaggerSchemaGenerator.ts +85 -88
- package/src/generates/internal/SwaggerSchemaValidator.ts +0 -6
- package/src/structures/IController.ts +2 -0
- package/src/structures/IRoute.ts +7 -2
|
@@ -71,7 +71,8 @@ export namespace SwaggerGenerator {
|
|
|
71
71
|
> = new Map();
|
|
72
72
|
|
|
73
73
|
for (const route of routeList) {
|
|
74
|
-
if (route.
|
|
74
|
+
if (route.jsDocTags.find((tag) => tag.name === "internal"))
|
|
75
|
+
continue;
|
|
75
76
|
|
|
76
77
|
const path: Record<string, ISwaggerRoute> = MapUtil.take(
|
|
77
78
|
pathDict,
|
|
@@ -111,9 +112,9 @@ export namespace SwaggerGenerator {
|
|
|
111
112
|
if (errors.length) {
|
|
112
113
|
for (const e of errors)
|
|
113
114
|
console.error(
|
|
114
|
-
`${path.relative(location, process.cwd())}:${
|
|
115
|
-
e.route.symbol
|
|
116
|
-
}:${
|
|
115
|
+
`${path.relative(e.route.location, process.cwd())}:${
|
|
116
|
+
e.route.symbol.class
|
|
117
|
+
}.${e.route.symbol.function}:${
|
|
117
118
|
e.from
|
|
118
119
|
} - error TS(@nestia/sdk): invalid type detected.\n\n` +
|
|
119
120
|
e.messages.map((m) => ` - ${m}`).join("\n"),
|
|
@@ -297,8 +298,8 @@ export namespace SwaggerGenerator {
|
|
|
297
298
|
const body = route.parameters.find(
|
|
298
299
|
(param) => param.category === "body",
|
|
299
300
|
);
|
|
300
|
-
const
|
|
301
|
-
route.
|
|
301
|
+
const getJsDocTexts = (name: string) =>
|
|
302
|
+
route.jsDocTags
|
|
302
303
|
.filter(
|
|
303
304
|
(tag) =>
|
|
304
305
|
tag.name === name &&
|
|
@@ -320,7 +321,7 @@ export namespace SwaggerGenerator {
|
|
|
320
321
|
const summary: string | undefined = (() => {
|
|
321
322
|
if (description === undefined) return undefined;
|
|
322
323
|
|
|
323
|
-
const [explicit] =
|
|
324
|
+
const [explicit] = getJsDocTexts("summary");
|
|
324
325
|
if (explicit?.length) return explicit;
|
|
325
326
|
|
|
326
327
|
const index: number = description.indexOf(".");
|
|
@@ -329,13 +330,16 @@ export namespace SwaggerGenerator {
|
|
|
329
330
|
const content: string = description.substring(0, index).trim();
|
|
330
331
|
return content.length ? content : undefined;
|
|
331
332
|
})();
|
|
332
|
-
const deprecated = route.
|
|
333
|
+
const deprecated = route.jsDocTags.find(
|
|
333
334
|
(tag) => tag.name === "deprecated",
|
|
334
335
|
);
|
|
335
336
|
|
|
336
337
|
return {
|
|
337
338
|
deprecated: deprecated ? true : undefined,
|
|
338
|
-
tags:
|
|
339
|
+
tags: [
|
|
340
|
+
...route.swaggerTags,
|
|
341
|
+
...new Set([...getJsDocTexts("tag")]),
|
|
342
|
+
],
|
|
339
343
|
operationId:
|
|
340
344
|
route.operationId ??
|
|
341
345
|
props.config.operationId?.({
|
|
@@ -348,7 +352,8 @@ export namespace SwaggerGenerator {
|
|
|
348
352
|
.filter((param) => param.category !== "body")
|
|
349
353
|
.map((param) =>
|
|
350
354
|
SwaggerSchemaGenerator.parameter(props)(route)(param),
|
|
351
|
-
)
|
|
355
|
+
)
|
|
356
|
+
.flat(),
|
|
352
357
|
requestBody: body
|
|
353
358
|
? SwaggerSchemaGenerator.body(props)(route)(body)
|
|
354
359
|
: undefined,
|
|
@@ -362,7 +367,7 @@ export namespace SwaggerGenerator {
|
|
|
362
367
|
.filter((str) => str.length && str[0] !== ":"),
|
|
363
368
|
route.name,
|
|
364
369
|
].join("."),
|
|
365
|
-
"x-nestia-jsDocTags": route.
|
|
370
|
+
"x-nestia-jsDocTags": route.jsDocTags,
|
|
366
371
|
"x-nestia-method": route.method,
|
|
367
372
|
};
|
|
368
373
|
};
|
|
@@ -3,6 +3,7 @@ import fs from "fs";
|
|
|
3
3
|
import { INestiaConfig } from "../../INestiaConfig";
|
|
4
4
|
import { IRoute } from "../../structures/IRoute";
|
|
5
5
|
import { ImportDictionary } from "../../utils/ImportDictionary";
|
|
6
|
+
import { SdkDtoGenerator } from "./SdkDtoGenerator";
|
|
6
7
|
import { SdkImportWizard } from "./SdkImportWizard";
|
|
7
8
|
|
|
8
9
|
export namespace E2eFileProgrammer {
|
|
@@ -11,20 +12,21 @@ export namespace E2eFileProgrammer {
|
|
|
11
12
|
(props: { api: string; current: string }) =>
|
|
12
13
|
async (route: IRoute): Promise<void> => {
|
|
13
14
|
const importer: ImportDictionary = new ImportDictionary();
|
|
14
|
-
|
|
15
|
-
for (const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
if (config.clone !== true)
|
|
16
|
+
for (const tuple of route.imports)
|
|
17
|
+
for (const instance of tuple[1])
|
|
18
|
+
importer.internal({
|
|
19
|
+
file: tuple[0],
|
|
20
|
+
type: true,
|
|
21
|
+
instance,
|
|
22
|
+
});
|
|
22
23
|
importer.internal({
|
|
23
24
|
type: false,
|
|
24
25
|
file: props.api,
|
|
25
26
|
instance: null,
|
|
26
27
|
name: "api",
|
|
27
28
|
});
|
|
29
|
+
|
|
28
30
|
const body: string = arrow(config)(importer)(route);
|
|
29
31
|
const content: string = [
|
|
30
32
|
importer.toScript(props.current),
|
|
@@ -57,7 +59,9 @@ export namespace E2eFileProgrammer {
|
|
|
57
59
|
" ...(connection.headers ?? {}),",
|
|
58
60
|
` ...${SdkImportWizard.typia(
|
|
59
61
|
importer,
|
|
60
|
-
)}.random<${
|
|
62
|
+
)}.random<${getTypeName(config)(importer)(
|
|
63
|
+
headers,
|
|
64
|
+
)}>(),`,
|
|
61
65
|
" },",
|
|
62
66
|
"},",
|
|
63
67
|
]
|
|
@@ -77,7 +81,7 @@ export namespace E2eFileProgrammer {
|
|
|
77
81
|
? [` ${output}`]
|
|
78
82
|
: [
|
|
79
83
|
` const output: ${primitive(config)(importer)(
|
|
80
|
-
route.output
|
|
84
|
+
getTypeName(config)(importer)(route.output),
|
|
81
85
|
)} = `,
|
|
82
86
|
` ${output}`,
|
|
83
87
|
` ${SdkImportWizard.typia(
|
|
@@ -95,7 +99,9 @@ export namespace E2eFileProgrammer {
|
|
|
95
99
|
(param: IRoute.IParameter): string => {
|
|
96
100
|
const middle: string = `${SdkImportWizard.typia(
|
|
97
101
|
importer,
|
|
98
|
-
)}.random<${primitive(config)(importer)(
|
|
102
|
+
)}.random<${primitive(config)(importer)(
|
|
103
|
+
getTypeName(config)(importer)(param),
|
|
104
|
+
)}>()`;
|
|
99
105
|
return `${" ".repeat(4 * tab)}${middle},`;
|
|
100
106
|
};
|
|
101
107
|
|
|
@@ -113,3 +119,10 @@ export namespace E2eFileProgrammer {
|
|
|
113
119
|
? `${SdkImportWizard.Primitive(importer)}<${name}>`
|
|
114
120
|
: name;
|
|
115
121
|
}
|
|
122
|
+
const getTypeName =
|
|
123
|
+
(config: INestiaConfig) =>
|
|
124
|
+
(importer: ImportDictionary) =>
|
|
125
|
+
(p: IRoute.IParameter | IRoute.IOutput) =>
|
|
126
|
+
p.metadata
|
|
127
|
+
? SdkDtoGenerator.decode(config)(importer)(p.metadata)
|
|
128
|
+
: p.typeName;
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
|
|
4
|
+
import { MetadataCollection } from "typia/lib/factories/MetadataCollection";
|
|
5
|
+
import { MetadataFactory } from "typia/lib/factories/MetadataFactory";
|
|
6
|
+
import { IJsDocTagInfo } from "typia/lib/schemas/metadata/IJsDocTagInfo";
|
|
7
|
+
import { IMetadataTypeTag } from "typia/lib/schemas/metadata/IMetadataTypeTag";
|
|
8
|
+
import { Metadata } from "typia/lib/schemas/metadata/Metadata";
|
|
9
|
+
import { MetadataAlias } from "typia/lib/schemas/metadata/MetadataAlias";
|
|
10
|
+
import { MetadataArray } from "typia/lib/schemas/metadata/MetadataArray";
|
|
11
|
+
import { MetadataAtomic } from "typia/lib/schemas/metadata/MetadataAtomic";
|
|
12
|
+
import { MetadataConstant } from "typia/lib/schemas/metadata/MetadataConstant";
|
|
13
|
+
import { MetadataObject } from "typia/lib/schemas/metadata/MetadataObject";
|
|
14
|
+
import { MetadataProperty } from "typia/lib/schemas/metadata/MetadataProperty";
|
|
15
|
+
import { MetadataTuple } from "typia/lib/schemas/metadata/MetadataTuple";
|
|
16
|
+
import { Escaper } from "typia/lib/utils/Escaper";
|
|
17
|
+
|
|
18
|
+
import { INestiaConfig } from "../../INestiaConfig";
|
|
19
|
+
import { IRoute } from "../../structures/IRoute";
|
|
20
|
+
import { ImportDictionary } from "../../utils/ImportDictionary";
|
|
21
|
+
import { MapUtil } from "../../utils/MapUtil";
|
|
22
|
+
|
|
23
|
+
export namespace SdkDtoGenerator {
|
|
24
|
+
export const generate =
|
|
25
|
+
(checker: ts.TypeChecker) =>
|
|
26
|
+
(config: INestiaConfig) =>
|
|
27
|
+
async (routes: IRoute[]): Promise<void> => {
|
|
28
|
+
try {
|
|
29
|
+
await fs.promises.mkdir(`${config.output}/structures`);
|
|
30
|
+
} catch {}
|
|
31
|
+
|
|
32
|
+
const collection = new MetadataCollection({
|
|
33
|
+
replace: MetadataCollection.replace,
|
|
34
|
+
});
|
|
35
|
+
for (const r of routes) {
|
|
36
|
+
for (const p of r.parameters) {
|
|
37
|
+
const res = MetadataFactory.analyze(checker)({
|
|
38
|
+
escape: false,
|
|
39
|
+
constant: true,
|
|
40
|
+
absorb: false,
|
|
41
|
+
})(collection)(p.type);
|
|
42
|
+
if (res.success) p.metadata = res.data;
|
|
43
|
+
}
|
|
44
|
+
const res = MetadataFactory.analyze(checker)({
|
|
45
|
+
escape: true,
|
|
46
|
+
constant: true,
|
|
47
|
+
absorb: false,
|
|
48
|
+
})(collection)(r.output.type);
|
|
49
|
+
if (res.success) r.output.metadata = res.data;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const modules: Map<string, IModule> = new Map();
|
|
53
|
+
for (const alias of collection.aliases())
|
|
54
|
+
prepare(modules)(alias.name)((importer) =>
|
|
55
|
+
defineAlias(config)(importer)(alias),
|
|
56
|
+
);
|
|
57
|
+
for (const object of collection.objects())
|
|
58
|
+
prepare(modules)(object.name)((importer) =>
|
|
59
|
+
defineObject(config)(importer)(object),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
for (const module of modules.values())
|
|
63
|
+
await generateFile(config)(module);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const prepare =
|
|
67
|
+
(dict: Map<string, IModule>) =>
|
|
68
|
+
(name: string) =>
|
|
69
|
+
(programmer: (importer: ImportDictionary) => string) => {
|
|
70
|
+
const accessors: string[] = name.split(".");
|
|
71
|
+
let module: IModule;
|
|
72
|
+
|
|
73
|
+
accessors.forEach((acc, i) => {
|
|
74
|
+
module = MapUtil.take(dict, acc, () => ({
|
|
75
|
+
name: accessors.slice(0, i + 1).join("."),
|
|
76
|
+
children: new Map(),
|
|
77
|
+
}));
|
|
78
|
+
module.programmer = programmer;
|
|
79
|
+
dict = module.children;
|
|
80
|
+
});
|
|
81
|
+
return module!;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const generateFile =
|
|
85
|
+
(config: INestiaConfig) =>
|
|
86
|
+
async (module: IModule): Promise<void> => {
|
|
87
|
+
const importer: ImportDictionary = new ImportDictionary();
|
|
88
|
+
|
|
89
|
+
const body: string = writeModule(importer)(module);
|
|
90
|
+
const content: string[] = [];
|
|
91
|
+
if (!importer.empty())
|
|
92
|
+
content.push(
|
|
93
|
+
importer.toScript(`${config.output}/structures`),
|
|
94
|
+
"",
|
|
95
|
+
);
|
|
96
|
+
content.push(body);
|
|
97
|
+
|
|
98
|
+
const location: string = `${config.output}/structures/${module.name}.ts`;
|
|
99
|
+
await fs.promises.writeFile(location, content.join("\n"), "utf8");
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const writeModule =
|
|
103
|
+
(importer: ImportDictionary) =>
|
|
104
|
+
(module: IModule): string => {
|
|
105
|
+
const content: string[] = [];
|
|
106
|
+
if (module.programmer) content.push(module.programmer(importer));
|
|
107
|
+
if (module.children.size) {
|
|
108
|
+
content.push(
|
|
109
|
+
`export namespace ${module.name.split(".").at(-1)} {`,
|
|
110
|
+
);
|
|
111
|
+
for (const child of module.children.values())
|
|
112
|
+
content.push(
|
|
113
|
+
writeModule(importer)(child)
|
|
114
|
+
.split("\n")
|
|
115
|
+
.map((l) => ` ${l}`)
|
|
116
|
+
.join("\n"),
|
|
117
|
+
);
|
|
118
|
+
content.push("}");
|
|
119
|
+
}
|
|
120
|
+
return content.join("\n");
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const defineAlias =
|
|
124
|
+
(config: INestiaConfig) =>
|
|
125
|
+
(importer: ImportDictionary) =>
|
|
126
|
+
(alias: MetadataAlias) =>
|
|
127
|
+
[
|
|
128
|
+
...writeComment(alias.description, alias.jsDocTags),
|
|
129
|
+
`export type ${alias.name.split(".").pop()!} = ${decode(config)(
|
|
130
|
+
importer,
|
|
131
|
+
)(alias.value)};`,
|
|
132
|
+
].join("\n");
|
|
133
|
+
|
|
134
|
+
const defineObject =
|
|
135
|
+
(config: INestiaConfig) =>
|
|
136
|
+
(importer: ImportDictionary) =>
|
|
137
|
+
(object: MetadataObject) => {
|
|
138
|
+
const top: string = [
|
|
139
|
+
...writeComment(object.description ?? null, object.jsDocTags),
|
|
140
|
+
`export type ${object.name.split(".").pop()!} = `,
|
|
141
|
+
].join("\n");
|
|
142
|
+
if (object.properties.length === 0) return top + "{};";
|
|
143
|
+
|
|
144
|
+
const regular: MetadataProperty[] = object.properties.filter((p) =>
|
|
145
|
+
p.key.isSoleLiteral(),
|
|
146
|
+
);
|
|
147
|
+
const dynamic: MetadataProperty[] = object.properties.filter(
|
|
148
|
+
(p) => !p.key.isSoleLiteral(),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const brackets: string[][] = [];
|
|
152
|
+
if (regular.length) {
|
|
153
|
+
const row: string[] = ["{"];
|
|
154
|
+
for (const p of regular) {
|
|
155
|
+
const key: string = p.key.constants[0].values[0] as string;
|
|
156
|
+
const identifier: string = Escaper.variable(key)
|
|
157
|
+
? key
|
|
158
|
+
: JSON.stringify(key);
|
|
159
|
+
row.push(
|
|
160
|
+
...writeComment(p.description, p.jsDocTags).map(
|
|
161
|
+
(l) => ` ${l}`,
|
|
162
|
+
),
|
|
163
|
+
` ${identifier}: ${decode(config)(importer)(
|
|
164
|
+
p.value,
|
|
165
|
+
)};`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
row.push("}");
|
|
169
|
+
brackets.push(row);
|
|
170
|
+
}
|
|
171
|
+
for (const p of dynamic) {
|
|
172
|
+
const row: string[] = ["{"];
|
|
173
|
+
row.push(
|
|
174
|
+
...writeComment(p.description, p.jsDocTags).map(
|
|
175
|
+
(l) => ` ${l}`,
|
|
176
|
+
),
|
|
177
|
+
` [key: ${decode(config)(importer)(p.key)}]: ${decode(
|
|
178
|
+
config,
|
|
179
|
+
)(importer)(p.value)};`,
|
|
180
|
+
);
|
|
181
|
+
row.push("}");
|
|
182
|
+
brackets.push(row);
|
|
183
|
+
}
|
|
184
|
+
return top + brackets.map((row) => row.join("\n")).join(" & ");
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const writeComment = (
|
|
188
|
+
description: string | null,
|
|
189
|
+
jsDocTags: IJsDocTagInfo[],
|
|
190
|
+
): string[] => {
|
|
191
|
+
const lines: string[] = [];
|
|
192
|
+
if (description?.length)
|
|
193
|
+
lines.push(...description.split("\n").map((s) => `${s}`));
|
|
194
|
+
if (description?.length && jsDocTags?.length) lines.push("");
|
|
195
|
+
if (jsDocTags?.length)
|
|
196
|
+
lines.push(
|
|
197
|
+
...jsDocTags.map((t) =>
|
|
198
|
+
t.text?.length
|
|
199
|
+
? `@${t.name} ${t.text.map((e) => e.text).join("")}`
|
|
200
|
+
: `@${t.name}`,
|
|
201
|
+
),
|
|
202
|
+
);
|
|
203
|
+
if (lines.length === 0) return [];
|
|
204
|
+
return ["/**", ...lines.map((s) => ` * ${s}`), " */"];
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export const decode =
|
|
208
|
+
(config: INestiaConfig) =>
|
|
209
|
+
(importer: ImportDictionary) =>
|
|
210
|
+
(meta: Metadata): string => {
|
|
211
|
+
const union: string[] = [];
|
|
212
|
+
|
|
213
|
+
// COALESCES
|
|
214
|
+
if (meta.nullable) union.push("null");
|
|
215
|
+
if (meta.required === false) union.push("undefined");
|
|
216
|
+
|
|
217
|
+
// ATOMICS
|
|
218
|
+
for (const atomic of meta.atomics)
|
|
219
|
+
union.push(decodeAtomic(importer)(atomic));
|
|
220
|
+
for (const constant of meta.constants)
|
|
221
|
+
union.push(decodeConstant(constant));
|
|
222
|
+
for (const tpl of meta.templates)
|
|
223
|
+
union.push(decodeTemplate(config)(importer)(tpl));
|
|
224
|
+
|
|
225
|
+
// ARRAYS
|
|
226
|
+
for (const array of meta.arrays)
|
|
227
|
+
union.push(decodeArray(config)(importer)(array));
|
|
228
|
+
for (const tuple of meta.tuples)
|
|
229
|
+
union.push(decodeTuple(config)(importer)(tuple));
|
|
230
|
+
|
|
231
|
+
// OBJECTS
|
|
232
|
+
for (const obj of meta.objects)
|
|
233
|
+
union.push(decodeObject(config)(importer)(obj));
|
|
234
|
+
for (const alias of meta.aliases)
|
|
235
|
+
union.push(decodeAlias(config)(importer)(alias));
|
|
236
|
+
|
|
237
|
+
return union.join(" | ");
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const decodeTypeTag =
|
|
241
|
+
(importer: ImportDictionary) =>
|
|
242
|
+
(tag: IMetadataTypeTag): string => {
|
|
243
|
+
const front: string = tag.name.split("<")[0];
|
|
244
|
+
if (NATIVE_TYPE_TAGS.has(front)) {
|
|
245
|
+
importer.external({
|
|
246
|
+
type: true,
|
|
247
|
+
library: `typia/lib/tags/${front}`,
|
|
248
|
+
instance: front,
|
|
249
|
+
});
|
|
250
|
+
return tag.name;
|
|
251
|
+
}
|
|
252
|
+
importer.external({
|
|
253
|
+
type: true,
|
|
254
|
+
library: `typia/lib/tags/TagBase`,
|
|
255
|
+
instance: "TagBase",
|
|
256
|
+
});
|
|
257
|
+
return `TagBase<${JSON.stringify(tag)}>`;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const decodeTypeTagMatrix =
|
|
261
|
+
(importer: ImportDictionary) =>
|
|
262
|
+
(base: string, tags: IMetadataTypeTag[][]): string => {
|
|
263
|
+
if (tags.length === 0) return base;
|
|
264
|
+
else if (tags.length === 1)
|
|
265
|
+
return `(${base} & ${tags[0]
|
|
266
|
+
.map((t) => decodeTypeTag(importer)(t))
|
|
267
|
+
.join(" & ")})`;
|
|
268
|
+
return (
|
|
269
|
+
"(" +
|
|
270
|
+
[
|
|
271
|
+
base,
|
|
272
|
+
...tags.map(
|
|
273
|
+
(row) =>
|
|
274
|
+
`(${row
|
|
275
|
+
.map((t) => decodeTypeTag(importer)(t))
|
|
276
|
+
.join(" & ")})`,
|
|
277
|
+
),
|
|
278
|
+
] +
|
|
279
|
+
")"
|
|
280
|
+
);
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const decodeAtomic =
|
|
284
|
+
(importer: ImportDictionary) =>
|
|
285
|
+
(atomic: MetadataAtomic): string =>
|
|
286
|
+
decodeTypeTagMatrix(importer)(atomic.type, atomic.tags);
|
|
287
|
+
|
|
288
|
+
const decodeTemplate =
|
|
289
|
+
(config: INestiaConfig) =>
|
|
290
|
+
(importer: ImportDictionary) =>
|
|
291
|
+
(template: Metadata[]): string =>
|
|
292
|
+
"`" +
|
|
293
|
+
template
|
|
294
|
+
.map((meta) =>
|
|
295
|
+
meta.size() === 1 &&
|
|
296
|
+
meta.isRequired() &&
|
|
297
|
+
meta.nullable === false &&
|
|
298
|
+
meta.constants.length === 1
|
|
299
|
+
? String(meta.constants[0].values[0])
|
|
300
|
+
.split("`")
|
|
301
|
+
.join("\\`")
|
|
302
|
+
: `\${${decode(config)(importer)(meta)}}`,
|
|
303
|
+
)
|
|
304
|
+
.join("") +
|
|
305
|
+
"`";
|
|
306
|
+
|
|
307
|
+
const decodeConstant = (constant: MetadataConstant): string => {
|
|
308
|
+
if (constant.values.length === 0)
|
|
309
|
+
return JSON.stringify(constant.values[0]);
|
|
310
|
+
return `(${constant.values
|
|
311
|
+
.map((val) => JSON.stringify(val))
|
|
312
|
+
.join(" | ")})`;
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const decodeArray =
|
|
316
|
+
(config: INestiaConfig) =>
|
|
317
|
+
(importer: ImportDictionary) =>
|
|
318
|
+
(array: MetadataArray): string =>
|
|
319
|
+
decodeTypeTagMatrix(importer)(
|
|
320
|
+
`Array<${decode(config)(importer)(array.type.value)}>`,
|
|
321
|
+
array.tags,
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
const decodeTuple =
|
|
325
|
+
(config: INestiaConfig) =>
|
|
326
|
+
(importer: ImportDictionary) =>
|
|
327
|
+
(tuple: MetadataTuple): string =>
|
|
328
|
+
"[" +
|
|
329
|
+
tuple.type.elements.map((e) =>
|
|
330
|
+
e.rest
|
|
331
|
+
? `...${decode(config)(importer)(e.rest)}`
|
|
332
|
+
: decode(config)(importer)(e),
|
|
333
|
+
) +
|
|
334
|
+
"]";
|
|
335
|
+
|
|
336
|
+
const decodeAlias =
|
|
337
|
+
(config: INestiaConfig) =>
|
|
338
|
+
(importer: ImportDictionary) =>
|
|
339
|
+
(alias: MetadataAlias) => {
|
|
340
|
+
importInternalFile(config)(importer)(alias.name);
|
|
341
|
+
return alias.name;
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const decodeObject =
|
|
345
|
+
(config: INestiaConfig) =>
|
|
346
|
+
(importer: ImportDictionary) =>
|
|
347
|
+
(object: MetadataObject) => {
|
|
348
|
+
importInternalFile(config)(importer)(object.name);
|
|
349
|
+
return object.name;
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const importInternalFile =
|
|
353
|
+
(config: INestiaConfig) =>
|
|
354
|
+
(importer: ImportDictionary) =>
|
|
355
|
+
(name: string) => {
|
|
356
|
+
const top = name.split(".")[0];
|
|
357
|
+
importer.internal({
|
|
358
|
+
type: true,
|
|
359
|
+
file: `${config.output}/structures/${name.split(".")[0]}`,
|
|
360
|
+
instance: top,
|
|
361
|
+
});
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const NATIVE_TYPE_TAGS = new Set([
|
|
366
|
+
"ExclusiveMinimum",
|
|
367
|
+
"ExclusiveMaximum",
|
|
368
|
+
"Format",
|
|
369
|
+
"Maximum",
|
|
370
|
+
"MaxItems",
|
|
371
|
+
"MaxLength",
|
|
372
|
+
"Minimum",
|
|
373
|
+
"MinItems",
|
|
374
|
+
"MinLength",
|
|
375
|
+
"MultipleOf",
|
|
376
|
+
"Pattern",
|
|
377
|
+
"Type",
|
|
378
|
+
]);
|
|
379
|
+
|
|
380
|
+
interface IModule {
|
|
381
|
+
name: string;
|
|
382
|
+
children: Map<string, IModule>;
|
|
383
|
+
programmer?: (importer: ImportDictionary) => string;
|
|
384
|
+
}
|
|
@@ -73,13 +73,14 @@ export namespace SdkFileProgrammer {
|
|
|
73
73
|
type: false,
|
|
74
74
|
});
|
|
75
75
|
directory.routes.forEach((route, i) => {
|
|
76
|
-
|
|
77
|
-
for (const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
if (config.clone !== true)
|
|
77
|
+
for (const tuple of route.imports)
|
|
78
|
+
for (const instance of tuple[1])
|
|
79
|
+
importer.internal({
|
|
80
|
+
file: tuple[0],
|
|
81
|
+
instance,
|
|
82
|
+
type: true,
|
|
83
|
+
});
|
|
83
84
|
|
|
84
85
|
content.push(
|
|
85
86
|
SdkFunctionProgrammer.generate(config)(importer)(route),
|
|
@@ -7,6 +7,7 @@ import { INestiaConfig } from "../../INestiaConfig";
|
|
|
7
7
|
import { IController } from "../../structures/IController";
|
|
8
8
|
import { IRoute } from "../../structures/IRoute";
|
|
9
9
|
import { ImportDictionary } from "../../utils/ImportDictionary";
|
|
10
|
+
import { SdkDtoGenerator } from "./SdkDtoGenerator";
|
|
10
11
|
import { SdkImportWizard } from "./SdkImportWizard";
|
|
11
12
|
import { SdkSimulationProgrammer } from "./SdkSimulationProgrammer";
|
|
12
13
|
|
|
@@ -221,7 +222,7 @@ export namespace SdkFunctionProgrammer {
|
|
|
221
222
|
: [];
|
|
222
223
|
|
|
223
224
|
// COMMENT TAGS
|
|
224
|
-
const tags: IJsDocTagInfo[] = route.
|
|
225
|
+
const tags: IJsDocTagInfo[] = route.jsDocTags.filter(
|
|
225
226
|
(tag) =>
|
|
226
227
|
tag.name !== "param" ||
|
|
227
228
|
route.parameters
|
|
@@ -283,7 +284,7 @@ export namespace SdkFunctionProgrammer {
|
|
|
283
284
|
? `${route.name}.${
|
|
284
285
|
param === props.query ? "Query" : "Input"
|
|
285
286
|
}`
|
|
286
|
-
: param
|
|
287
|
+
: getTypeName(config)(importer)(param);
|
|
287
288
|
return `${param.name}${
|
|
288
289
|
param.optional ? "?" : ""
|
|
289
290
|
}: ${type}`;
|
|
@@ -321,13 +322,33 @@ export namespace SdkFunctionProgrammer {
|
|
|
321
322
|
// LIST UP TYPES
|
|
322
323
|
const types: Pair<string, string>[] = [];
|
|
323
324
|
if (props.headers !== undefined)
|
|
324
|
-
types.push(
|
|
325
|
+
types.push(
|
|
326
|
+
new Pair(
|
|
327
|
+
"Headers",
|
|
328
|
+
getTypeName(config)(importer)(props.headers),
|
|
329
|
+
),
|
|
330
|
+
);
|
|
325
331
|
if (props.query !== undefined)
|
|
326
|
-
types.push(
|
|
332
|
+
types.push(
|
|
333
|
+
new Pair(
|
|
334
|
+
"Query",
|
|
335
|
+
getTypeName(config)(importer)(props.query),
|
|
336
|
+
),
|
|
337
|
+
);
|
|
327
338
|
if (props.input !== undefined)
|
|
328
|
-
types.push(
|
|
339
|
+
types.push(
|
|
340
|
+
new Pair(
|
|
341
|
+
"Input",
|
|
342
|
+
getTypeName(config)(importer)(props.input),
|
|
343
|
+
),
|
|
344
|
+
);
|
|
329
345
|
if (route.output.typeName !== "void")
|
|
330
|
-
types.push(
|
|
346
|
+
types.push(
|
|
347
|
+
new Pair(
|
|
348
|
+
"Output",
|
|
349
|
+
getTypeName(config)(importer)(route.output),
|
|
350
|
+
),
|
|
351
|
+
);
|
|
331
352
|
|
|
332
353
|
// PATH WITH PARAMETERS
|
|
333
354
|
const parameters: IRoute.IParameter[] = filter_path_parameters(
|
|
@@ -401,7 +422,7 @@ export namespace SdkFunctionProgrammer {
|
|
|
401
422
|
param.category === "query" &&
|
|
402
423
|
param.typeName === props.query?.typeName
|
|
403
424
|
? `${route.name}.Query`
|
|
404
|
-
: param
|
|
425
|
+
: getTypeName(config)(importer)(param)
|
|
405
426
|
}`,
|
|
406
427
|
)
|
|
407
428
|
.join(", ")}): string => {\n` +
|
|
@@ -507,3 +528,10 @@ export namespace SdkFunctionProgrammer {
|
|
|
507
528
|
}
|
|
508
529
|
|
|
509
530
|
const space = (count: number) => " ".repeat(count);
|
|
531
|
+
const getTypeName =
|
|
532
|
+
(config: INestiaConfig) =>
|
|
533
|
+
(importer: ImportDictionary) =>
|
|
534
|
+
(p: IRoute.IParameter | IRoute.IOutput) =>
|
|
535
|
+
p.metadata
|
|
536
|
+
? SdkDtoGenerator.decode(config)(importer)(p.metadata)
|
|
537
|
+
: p.typeName;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { INestiaConfig } from "../../INestiaConfig";
|
|
2
2
|
import { IRoute } from "../../structures/IRoute";
|
|
3
3
|
import { ImportDictionary } from "../../utils/ImportDictionary";
|
|
4
|
+
import { SdkDtoGenerator } from "./SdkDtoGenerator";
|
|
4
5
|
import { SdkImportWizard } from "./SdkImportWizard";
|
|
5
6
|
|
|
6
7
|
export namespace SdkSimulationProgrammer {
|
|
@@ -52,7 +53,7 @@ export namespace SdkSimulationProgrammer {
|
|
|
52
53
|
? "Query"
|
|
53
54
|
: "Input"
|
|
54
55
|
}`
|
|
55
|
-
: p
|
|
56
|
+
: getTypeName(config)(importer)(p)
|
|
56
57
|
},`,
|
|
57
58
|
),
|
|
58
59
|
`): Promise<${output ? "Output" : "void"}> => {`,
|
|
@@ -106,3 +107,11 @@ export namespace SdkSimulationProgrammer {
|
|
|
106
107
|
];
|
|
107
108
|
};
|
|
108
109
|
}
|
|
110
|
+
|
|
111
|
+
const getTypeName =
|
|
112
|
+
(config: INestiaConfig) =>
|
|
113
|
+
(importer: ImportDictionary) =>
|
|
114
|
+
(p: IRoute.IParameter | IRoute.IOutput) =>
|
|
115
|
+
p.metadata
|
|
116
|
+
? SdkDtoGenerator.decode(config)(importer)(p.metadata)
|
|
117
|
+
: p.typeName;
|