@nestia/sdk 2.0.0-dev.20230904-2 → 2.0.0-dev.20230907
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/utils/NestiaSimulator.ts +0 -14
- package/lib/INestiaConfig.d.ts +22 -0
- 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 +9 -1
- 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 +9 -6
- package/lib/generates/SwaggerGenerator.js.map +1 -1
- package/lib/generates/internal/E2eFileProgrammer.js +20 -14
- 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 +15 -12
- package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -1
- package/lib/generates/internal/SdkImportWizard.d.ts +1 -0
- package/lib/generates/internal/SdkImportWizard.js +5 -0
- package/lib/generates/internal/SdkImportWizard.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/SdkTypeDefiner.d.ts +10 -0
- package/lib/generates/internal/SdkTypeDefiner.js +92 -0
- package/lib/generates/internal/SdkTypeDefiner.js.map +1 -0
- package/lib/generates/internal/SwaggerSchemaGenerator.js +2 -2
- package/lib/generates/internal/SwaggerSchemaGenerator.js.map +1 -1
- package/lib/structures/IController.d.ts +2 -0
- package/lib/structures/IRoute.d.ts +5 -1
- package/package.json +6 -6
- package/src/INestiaConfig.ts +24 -0
- 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 +11 -7
- package/src/generates/internal/E2eFileProgrammer.ts +32 -19
- package/src/generates/internal/SdkDtoGenerator.ts +384 -0
- package/src/generates/internal/SdkFileProgrammer.ts +8 -7
- package/src/generates/internal/SdkFunctionProgrammer.ts +41 -16
- package/src/generates/internal/SdkImportWizard.ts +7 -0
- package/src/generates/internal/SdkSimulationProgrammer.ts +10 -1
- package/src/generates/internal/SdkTypeDefiner.ts +123 -0
- package/src/generates/internal/SwaggerSchemaGenerator.ts +2 -2
- package/src/structures/IController.ts +2 -0
- package/src/structures/IRoute.ts +7 -2
|
@@ -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,8 +7,10 @@ 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";
|
|
13
|
+
import { SdkTypeDefiner } from "./SdkTypeDefiner";
|
|
12
14
|
|
|
13
15
|
export namespace SdkFunctionProgrammer {
|
|
14
16
|
export const generate =
|
|
@@ -132,7 +134,9 @@ export namespace SdkFunctionProgrammer {
|
|
|
132
134
|
[
|
|
133
135
|
`${awa ? "await " : ""}${SdkImportWizard.Fetcher(
|
|
134
136
|
encrypted,
|
|
135
|
-
)(importer)}
|
|
137
|
+
)(importer)}.${
|
|
138
|
+
config.propagate === true ? "propagate" : "fetch"
|
|
139
|
+
}(`,
|
|
136
140
|
fetchArguments
|
|
137
141
|
.map((param) =>
|
|
138
142
|
typeof param === "string"
|
|
@@ -221,7 +225,7 @@ export namespace SdkFunctionProgrammer {
|
|
|
221
225
|
: [];
|
|
222
226
|
|
|
223
227
|
// COMMENT TAGS
|
|
224
|
-
const tags: IJsDocTagInfo[] = route.
|
|
228
|
+
const tags: IJsDocTagInfo[] = route.jsDocTags.filter(
|
|
225
229
|
(tag) =>
|
|
226
230
|
tag.name !== "param" ||
|
|
227
231
|
route.parameters
|
|
@@ -283,7 +287,7 @@ export namespace SdkFunctionProgrammer {
|
|
|
283
287
|
? `${route.name}.${
|
|
284
288
|
param === props.query ? "Query" : "Input"
|
|
285
289
|
}`
|
|
286
|
-
: param
|
|
290
|
+
: getTypeName(config)(importer)(param);
|
|
287
291
|
return `${param.name}${
|
|
288
292
|
param.optional ? "?" : ""
|
|
289
293
|
}: ${type}`;
|
|
@@ -321,13 +325,33 @@ export namespace SdkFunctionProgrammer {
|
|
|
321
325
|
// LIST UP TYPES
|
|
322
326
|
const types: Pair<string, string>[] = [];
|
|
323
327
|
if (props.headers !== undefined)
|
|
324
|
-
types.push(
|
|
328
|
+
types.push(
|
|
329
|
+
new Pair(
|
|
330
|
+
"Headers",
|
|
331
|
+
SdkTypeDefiner.headers(config)(importer)(props.headers),
|
|
332
|
+
),
|
|
333
|
+
);
|
|
325
334
|
if (props.query !== undefined)
|
|
326
|
-
types.push(
|
|
335
|
+
types.push(
|
|
336
|
+
new Pair(
|
|
337
|
+
"Query",
|
|
338
|
+
SdkTypeDefiner.query(config)(importer)(props.query),
|
|
339
|
+
),
|
|
340
|
+
);
|
|
327
341
|
if (props.input !== undefined)
|
|
328
|
-
types.push(
|
|
329
|
-
|
|
330
|
-
|
|
342
|
+
types.push(
|
|
343
|
+
new Pair(
|
|
344
|
+
"Input",
|
|
345
|
+
SdkTypeDefiner.input(config)(importer)(props.input),
|
|
346
|
+
),
|
|
347
|
+
);
|
|
348
|
+
if (config.propagate !== true && route.output.typeName !== "void")
|
|
349
|
+
types.push(
|
|
350
|
+
new Pair(
|
|
351
|
+
"Output",
|
|
352
|
+
SdkTypeDefiner.output(config)(importer)(route),
|
|
353
|
+
),
|
|
354
|
+
);
|
|
331
355
|
|
|
332
356
|
// PATH WITH PARAMETERS
|
|
333
357
|
const parameters: IRoute.IParameter[] = filter_path_parameters(
|
|
@@ -344,13 +368,7 @@ export namespace SdkFunctionProgrammer {
|
|
|
344
368
|
? types
|
|
345
369
|
.map(
|
|
346
370
|
(tuple) =>
|
|
347
|
-
` export type ${tuple.first} = ${
|
|
348
|
-
config.primitive !== false
|
|
349
|
-
? `${SdkImportWizard.Primitive(
|
|
350
|
-
importer,
|
|
351
|
-
)}<${tuple.second}>`
|
|
352
|
-
: tuple.second
|
|
353
|
-
};`,
|
|
371
|
+
` export type ${tuple.first} = ${tuple.second};`,
|
|
354
372
|
)
|
|
355
373
|
.join("\n") + "\n"
|
|
356
374
|
: "") +
|
|
@@ -401,7 +419,7 @@ export namespace SdkFunctionProgrammer {
|
|
|
401
419
|
param.category === "query" &&
|
|
402
420
|
param.typeName === props.query?.typeName
|
|
403
421
|
? `${route.name}.Query`
|
|
404
|
-
: param
|
|
422
|
+
: getTypeName(config)(importer)(param)
|
|
405
423
|
}`,
|
|
406
424
|
)
|
|
407
425
|
.join(", ")}): string => {\n` +
|
|
@@ -507,3 +525,10 @@ export namespace SdkFunctionProgrammer {
|
|
|
507
525
|
}
|
|
508
526
|
|
|
509
527
|
const space = (count: number) => " ".repeat(count);
|
|
528
|
+
const getTypeName =
|
|
529
|
+
(config: INestiaConfig) =>
|
|
530
|
+
(importer: ImportDictionary) =>
|
|
531
|
+
(p: IRoute.IParameter | IRoute.IOutput) =>
|
|
532
|
+
p.metadata
|
|
533
|
+
? SdkDtoGenerator.decode(config)(importer)(p.metadata)
|
|
534
|
+
: p.typeName;
|
|
@@ -18,6 +18,13 @@ export namespace SdkImportWizard {
|
|
|
18
18
|
instance: "Primitive",
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
+
export const Resolved = (importer: ImportDictionary) =>
|
|
22
|
+
importer.external({
|
|
23
|
+
type: true,
|
|
24
|
+
library: "@nestia/fetcher",
|
|
25
|
+
instance: "Resolved",
|
|
26
|
+
});
|
|
27
|
+
|
|
21
28
|
export const typia = (importer: ImportDictionary) =>
|
|
22
29
|
importer.external({
|
|
23
30
|
type: false,
|
|
@@ -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;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { INestiaConfig } from "../../INestiaConfig";
|
|
2
|
+
import { IRoute } from "../../structures/IRoute";
|
|
3
|
+
import { ImportDictionary } from "../../utils/ImportDictionary";
|
|
4
|
+
import { SdkDtoGenerator } from "./SdkDtoGenerator";
|
|
5
|
+
|
|
6
|
+
export namespace SdkTypeDefiner {
|
|
7
|
+
export const name =
|
|
8
|
+
(config: INestiaConfig) =>
|
|
9
|
+
(importer: ImportDictionary) =>
|
|
10
|
+
(p: IRoute.IParameter | IRoute.IOutput): string =>
|
|
11
|
+
p.metadata
|
|
12
|
+
? SdkDtoGenerator.decode(config)(importer)(p.metadata)
|
|
13
|
+
: p.typeName;
|
|
14
|
+
|
|
15
|
+
export const headers =
|
|
16
|
+
(config: INestiaConfig) =>
|
|
17
|
+
(importer: ImportDictionary) =>
|
|
18
|
+
(param: IRoute.IParameter): string => {
|
|
19
|
+
const type: string = name(config)(importer)(param);
|
|
20
|
+
if (config.primitive === false) return type;
|
|
21
|
+
|
|
22
|
+
const resolved: string = importer.external({
|
|
23
|
+
type: true,
|
|
24
|
+
library: "@nestia/fetcher",
|
|
25
|
+
instance: "Resolved",
|
|
26
|
+
});
|
|
27
|
+
return `${resolved}<${type}>`;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const query =
|
|
31
|
+
(config: INestiaConfig) =>
|
|
32
|
+
(importer: ImportDictionary) =>
|
|
33
|
+
(param: IRoute.IParameter): string => {
|
|
34
|
+
const type: string = name(config)(importer)(param);
|
|
35
|
+
if (config.primitive === false) return type;
|
|
36
|
+
|
|
37
|
+
const resolved: string = importer.external({
|
|
38
|
+
type: true,
|
|
39
|
+
library: "@nestia/fetcher",
|
|
40
|
+
instance: "Resolved",
|
|
41
|
+
});
|
|
42
|
+
return `${resolved}<${type}>`;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const input =
|
|
46
|
+
(config: INestiaConfig) =>
|
|
47
|
+
(importer: ImportDictionary) =>
|
|
48
|
+
(param: IRoute.IParameter): string => {
|
|
49
|
+
const type: string = name(config)(importer)(param);
|
|
50
|
+
if (config.primitive === false) return type;
|
|
51
|
+
|
|
52
|
+
const primitive: string = importer.external({
|
|
53
|
+
type: true,
|
|
54
|
+
library: "@nestia/fetcher",
|
|
55
|
+
instance: "Primitive",
|
|
56
|
+
});
|
|
57
|
+
return `${primitive}<${type}>`;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const output =
|
|
61
|
+
(config: INestiaConfig) =>
|
|
62
|
+
(importer: ImportDictionary) =>
|
|
63
|
+
(route: IRoute): string => {
|
|
64
|
+
if (config.propagate !== true) {
|
|
65
|
+
const type: string = name(config)(importer)(route.output);
|
|
66
|
+
if (type === "void" || config.primitive === false) return type;
|
|
67
|
+
|
|
68
|
+
const primitive: string = importer.external({
|
|
69
|
+
type: true,
|
|
70
|
+
library: "@nestia/fetcher",
|
|
71
|
+
instance: "Primitive",
|
|
72
|
+
});
|
|
73
|
+
return `${primitive}<${type}>`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const propagation: string = importer.external({
|
|
77
|
+
type: true,
|
|
78
|
+
library: "@nestia/fetcher",
|
|
79
|
+
instance: "IPropagation",
|
|
80
|
+
});
|
|
81
|
+
const branches: IBranch[] = [
|
|
82
|
+
{
|
|
83
|
+
body: name(config)(importer)(route.output),
|
|
84
|
+
status: route.status
|
|
85
|
+
? String(route.status)
|
|
86
|
+
: route.method === "GET" ||
|
|
87
|
+
route.method === "DELETE" ||
|
|
88
|
+
route.method === "HEAD"
|
|
89
|
+
? "200"
|
|
90
|
+
: "201",
|
|
91
|
+
success: "true",
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
for (const [key, value] of Object.entries(route.exceptions))
|
|
95
|
+
branches.push({
|
|
96
|
+
body: name(config)(importer)(value),
|
|
97
|
+
status: key.endsWith("XX")
|
|
98
|
+
? `${propagation}.StatusRange<${key}>`
|
|
99
|
+
: key,
|
|
100
|
+
success: "false",
|
|
101
|
+
});
|
|
102
|
+
branches.push({
|
|
103
|
+
status: "number",
|
|
104
|
+
body: "any",
|
|
105
|
+
success: "boolean",
|
|
106
|
+
});
|
|
107
|
+
return (
|
|
108
|
+
"\n" +
|
|
109
|
+
branches
|
|
110
|
+
.map(
|
|
111
|
+
(b) =>
|
|
112
|
+
` | ${propagation}<${b.status}, ${b.body}, ${b.success}>`,
|
|
113
|
+
)
|
|
114
|
+
.join("\n")
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
interface IBranch {
|
|
120
|
+
body: string;
|
|
121
|
+
status: string;
|
|
122
|
+
success: string;
|
|
123
|
+
}
|