@nestia/sdk 2.4.7 → 2.5.0-dev.20240128

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/lib/generates/internal/SdkFileProgrammer.js +23 -10
  2. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  3. package/lib/generates/internal/SdkFunctionProgrammer.d.ts +6 -1
  4. package/lib/generates/internal/SdkFunctionProgrammer.js +73 -323
  5. package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -1
  6. package/lib/generates/internal/SdkNamespaceProgrammer.d.ts +11 -0
  7. package/lib/generates/internal/SdkNamespaceProgrammer.js +175 -0
  8. package/lib/generates/internal/SdkNamespaceProgrammer.js.map +1 -0
  9. package/lib/generates/internal/SdkRouteProgrammer.d.ts +7 -0
  10. package/lib/generates/internal/SdkRouteProgrammer.js +55 -0
  11. package/lib/generates/internal/SdkRouteProgrammer.js.map +1 -0
  12. package/lib/generates/internal/SdkSimulationProgrammer.d.ts +7 -1
  13. package/lib/generates/internal/SdkSimulationProgrammer.js +98 -88
  14. package/lib/generates/internal/SdkSimulationProgrammer.js.map +1 -1
  15. package/lib/utils/ImportDictionary.d.ts +2 -0
  16. package/lib/utils/ImportDictionary.js +45 -0
  17. package/lib/utils/ImportDictionary.js.map +1 -1
  18. package/lib/utils/NodeUtil.d.ts +5 -0
  19. package/lib/utils/NodeUtil.js +16 -0
  20. package/lib/utils/NodeUtil.js.map +1 -0
  21. package/package.json +6 -3
  22. package/src/analyses/ConfigAnalyzer.ts +147 -147
  23. package/src/analyses/ControllerAnalyzer.ts +390 -390
  24. package/src/analyses/PathAnalyzer.ts +110 -110
  25. package/src/analyses/ReflectAnalyzer.ts +464 -464
  26. package/src/generates/SwaggerGenerator.ts +376 -376
  27. package/src/generates/internal/SdkFileProgrammer.ts +42 -13
  28. package/src/generates/internal/SdkFunctionProgrammer.ts +176 -475
  29. package/src/generates/internal/SdkNamespaceProgrammer.ts +495 -0
  30. package/src/generates/internal/SdkRouteProgrammer.ts +82 -0
  31. package/src/generates/internal/SdkSimulationProgrammer.ts +359 -133
  32. package/src/generates/internal/SwaggerSchemaGenerator.ts +444 -444
  33. package/src/utils/ImportDictionary.ts +72 -0
  34. package/src/utils/NodeUtil.ts +19 -0
@@ -1,133 +1,359 @@
1
- import { INestiaConfig } from "../../INestiaConfig";
2
- import { IRoute } from "../../structures/IRoute";
3
- import { ImportDictionary } from "../../utils/ImportDictionary";
4
- import { SdkImportWizard } from "./SdkImportWizard";
5
- import { SdkTypeDefiner } from "./SdkTypeDefiner";
6
-
7
- export namespace SdkSimulationProgrammer {
8
- export const generate =
9
- (config: INestiaConfig) =>
10
- (importer: ImportDictionary) =>
11
- (route: IRoute): string => {
12
- const output: boolean =
13
- config.propagate === true || route.output.typeName !== "void";
14
- const body: string[] = [
15
- ...(route.parameters.filter((p) => p.category !== "headers").length !==
16
- 0
17
- ? assert(config)(importer)(route)
18
- : []),
19
- ...(output ? returns(config)(route) : []),
20
- ];
21
- return [
22
- `export const simulate = async (`,
23
- ` ${
24
- route.parameters.filter((p) => p.category !== "headers").length ===
25
- 0 && route.output.typeName === "void"
26
- ? "_connection"
27
- : "connection"
28
- }: ${
29
- route.parameters.some(
30
- (p) => p.category === "headers" && p.field === undefined,
31
- )
32
- ? `${SdkImportWizard.IConnection(importer)}<${route.name}.Headers>`
33
- : SdkImportWizard.IConnection(importer)
34
- },`,
35
- ...route.parameters
36
- .filter((p) => p.category !== "headers")
37
- .map(
38
- (p) =>
39
- ` ${p.name}: ${
40
- p.category === "query" || p.category === "body"
41
- ? `${route.name}.${
42
- p.category === "query" ? "Query" : "Input"
43
- }`
44
- : SdkTypeDefiner.name(config)(importer)(p)
45
- },`,
46
- ),
47
- `): Promise<${output ? "Output" : "void"}> => {`,
48
- ...body.map((l) => ` ${l}`),
49
- `}`,
50
- ]
51
- .map((line) => ` ${line}`)
52
- .join("\n");
53
- };
54
-
55
- const assert =
56
- (config: INestiaConfig) =>
57
- (importer: ImportDictionary) =>
58
- (route: IRoute): string[] => {
59
- const typia = SdkImportWizard.typia(importer);
60
- const func: string[] = [
61
- `const assert = ${importer.internal({
62
- file: `${config.output}/utils/NestiaSimulator.ts`,
63
- instance: "NestiaSimulator",
64
- type: false,
65
- })}.assert({`,
66
- ` method: METADATA.method,`,
67
- ` host: connection.host,`,
68
- ` path: path(${route.parameters
69
- .filter((p) => p.category === "param" || p.category === "query")
70
- .map((p) => p.name)
71
- .join(", ")}),`,
72
- ` contentType: ${JSON.stringify(route.output.contentType)},`,
73
- `});`,
74
- ];
75
- const individual: string[] = route.parameters
76
- .filter((p) => p.category !== "headers")
77
- .map((p) =>
78
- p.category === "body"
79
- ? `assert.body(() => ${typia}.assert(${p.name}));`
80
- : p.category === "query"
81
- ? `assert.query(() => ${typia}.assert(${p.name}));`
82
- : p.category === "headers"
83
- ? `assert.headers(() => ${typia}.assert(connection.headers);`
84
- : `assert.param("${p.field}")(() => ${typia}.assert(${p.name}));`,
85
- );
86
- if (config.propagate !== true) return [...func, ...individual];
87
-
88
- return [
89
- ...func,
90
- `try {`,
91
- ...individual.map((l) => ` ${l}`),
92
- `} catch (exp) {`,
93
- ` if (!${typia}.is<${SdkImportWizard.HttpError(
94
- importer,
95
- )}>(exp)) throw exp;`,
96
- ` return {`,
97
- ` success: false,`,
98
- ` status: exp.status,`,
99
- ` headers: exp.headers,`,
100
- ` data: exp.toJSON().message,`,
101
- ` } as any;`,
102
- `}`,
103
- ];
104
- };
105
-
106
- const returns =
107
- (config: INestiaConfig) =>
108
- (route: IRoute): string[] => {
109
- const random = (prefix: string, postfix: string) =>
110
- route.output.typeName === "void"
111
- ? [`${prefix} undefined${postfix}`]
112
- : [
113
- `${prefix} random(`,
114
- ` typeof connection.simulate === 'object' &&`,
115
- ` connection.simulate !== null`,
116
- ` ? connection.simulate`,
117
- ` : undefined`,
118
- `)${postfix}`,
119
- ];
120
- if (config.propagate !== true) return random("return", ";");
121
-
122
- return [
123
- `return {`,
124
- ` success: true,`,
125
- ` status: ${route.status ?? (route.method === "POST" ? 201 : 200)},`,
126
- ` headers: {`,
127
- ` "Content-Type": "${route.output.contentType}",`,
128
- ` },`,
129
- ...random("data:", ",").map((r) => ` ${r}`),
130
- `}`,
131
- ];
132
- };
133
- }
1
+ import ts from "typescript";
2
+ import { IdentifierFactory } from "typia/lib/factories/IdentifierFactory";
3
+ import { LiteralFactory } from "typia/lib/factories/LiteralFactory";
4
+ import { StatementFactory } from "typia/lib/factories/StatementFactory";
5
+ import { TypeFactory } from "typia/lib/factories/TypeFactory";
6
+
7
+ import { INestiaConfig } from "../../INestiaConfig";
8
+ import { IRoute } from "../../structures/IRoute";
9
+ import { ImportDictionary } from "../../utils/ImportDictionary";
10
+ import { SdkDtoGenerator } from "./SdkDtoGenerator";
11
+ import { SdkImportWizard } from "./SdkImportWizard";
12
+ import { SdkTypeDefiner } from "./SdkTypeDefiner";
13
+
14
+ export namespace SdkSimulationProgrammer {
15
+ export const random =
16
+ (config: INestiaConfig) =>
17
+ (importer: ImportDictionary) =>
18
+ (route: IRoute): ts.VariableStatement =>
19
+ constant("random")(
20
+ ts.factory.createArrowFunction(
21
+ undefined,
22
+ undefined,
23
+ [
24
+ ts.factory.createParameterDeclaration(
25
+ undefined,
26
+ undefined,
27
+ "g",
28
+ ts.factory.createToken(ts.SyntaxKind.QuestionToken),
29
+ ts.factory.createTypeReferenceNode(
30
+ ts.factory.createIdentifier("Partial"),
31
+ [
32
+ ts.factory.createTypeReferenceNode(
33
+ `${SdkImportWizard.typia(importer)}.IRandomGenerator`,
34
+ ),
35
+ ],
36
+ ),
37
+ ),
38
+ ],
39
+ undefined,
40
+ undefined,
41
+ ts.factory.createCallExpression(
42
+ IdentifierFactory.access(
43
+ ts.factory.createIdentifier(SdkImportWizard.typia(importer)),
44
+ )("random"),
45
+ [
46
+ ts.factory.createTypeReferenceNode(
47
+ SdkTypeDefiner.responseBody(config)(importer)(route),
48
+ ),
49
+ ],
50
+ [ts.factory.createIdentifier("g")],
51
+ ),
52
+ ),
53
+ );
54
+
55
+ export const simulate =
56
+ (config: INestiaConfig) =>
57
+ (importer: ImportDictionary) =>
58
+ (
59
+ route: IRoute,
60
+ props: {
61
+ headers: IRoute.IParameter | undefined;
62
+ query: IRoute.IParameter | undefined;
63
+ input: IRoute.IParameter | undefined;
64
+ },
65
+ ): ts.VariableStatement => {
66
+ const output: boolean =
67
+ config.propagate === true || route.output.typeName !== "void";
68
+ const caller = () =>
69
+ ts.factory.createCallExpression(
70
+ ts.factory.createIdentifier("random"),
71
+ undefined,
72
+ [
73
+ ts.factory.createConditionalExpression(
74
+ ts.factory.createLogicalAnd(
75
+ ts.factory.createStrictEquality(
76
+ ts.factory.createStringLiteral("object"),
77
+ ts.factory.createTypeOfExpression(
78
+ ts.factory.createIdentifier("connection.simulate"),
79
+ ),
80
+ ),
81
+ ts.factory.createStrictInequality(
82
+ ts.factory.createNull(),
83
+ ts.factory.createIdentifier("connection.simulate"),
84
+ ),
85
+ ),
86
+ undefined,
87
+ ts.factory.createIdentifier("connection.simulate"),
88
+ undefined,
89
+ ts.factory.createIdentifier("undefined"),
90
+ ),
91
+ ],
92
+ );
93
+
94
+ return constant("simulate")(
95
+ ts.factory.createArrowFunction(
96
+ undefined,
97
+ undefined,
98
+ [
99
+ IdentifierFactory.parameter(
100
+ "connection",
101
+ ts.factory.createTypeReferenceNode(
102
+ SdkImportWizard.IConnection(importer),
103
+ route.parameters.some(
104
+ (p) => p.category === "headers" && p.field === undefined,
105
+ )
106
+ ? [
107
+ ts.factory.createTypeReferenceNode(
108
+ `${route.name}.Headers`,
109
+ ),
110
+ ]
111
+ : [],
112
+ ),
113
+ ),
114
+ ...route.parameters
115
+ .filter((p) => p.category !== "headers")
116
+ .map((p) =>
117
+ ts.factory.createParameterDeclaration(
118
+ [],
119
+ undefined,
120
+ p.name,
121
+ p.optional
122
+ ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
123
+ : undefined,
124
+ ts.factory.createTypeReferenceNode(
125
+ config.primitive !== false &&
126
+ (p === props.query || p === props.input)
127
+ ? `${route.name}.${p === props.query ? "Query" : "Input"}`
128
+ : getTypeName(config)(importer)(p),
129
+ ),
130
+ ),
131
+ ),
132
+ ],
133
+ ts.factory.createTypeReferenceNode(output ? "Output" : "void"),
134
+ undefined,
135
+ ts.factory.createBlock(
136
+ [
137
+ ...assert(config)(importer)(route),
138
+ ts.factory.createReturnStatement(
139
+ config.propagate
140
+ ? ts.factory.createObjectLiteralExpression(
141
+ [
142
+ ts.factory.createPropertyAssignment(
143
+ "success",
144
+ ts.factory.createTrue(),
145
+ ),
146
+ ts.factory.createPropertyAssignment(
147
+ "status",
148
+ ts.factory.createNumericLiteral(
149
+ route.status ??
150
+ (route.method === "POST" ? 201 : 200),
151
+ ),
152
+ ),
153
+ ts.factory.createPropertyAssignment(
154
+ "headers",
155
+ LiteralFactory.generate({
156
+ "Content-Type": route.output.contentType,
157
+ }),
158
+ ),
159
+ ts.factory.createPropertyAssignment("data", caller()),
160
+ ],
161
+ true,
162
+ )
163
+ : caller(),
164
+ ),
165
+ ],
166
+ true,
167
+ ),
168
+ ),
169
+ );
170
+ };
171
+
172
+ const assert =
173
+ (config: INestiaConfig) =>
174
+ (importer: ImportDictionary) =>
175
+ (route: IRoute): ts.Statement[] => {
176
+ const parameters = route.parameters.filter(
177
+ (p) => p.category !== "headers",
178
+ );
179
+ if (parameters.length === 0) return [];
180
+
181
+ const typia = SdkImportWizard.typia(importer);
182
+ const validator = StatementFactory.constant(
183
+ "assert",
184
+ ts.factory.createCallExpression(
185
+ IdentifierFactory.access(
186
+ ts.factory.createIdentifier(
187
+ importer.internal({
188
+ file: `${config.output}/utils/NestiaSimulator.ts`,
189
+ instance: "NestiaSimulator",
190
+ type: false,
191
+ }),
192
+ ),
193
+ )("assert"),
194
+ undefined,
195
+ [
196
+ ts.factory.createObjectLiteralExpression(
197
+ [
198
+ ts.factory.createPropertyAssignment(
199
+ "method",
200
+ ts.factory.createIdentifier("METADATA.method"),
201
+ ),
202
+ ts.factory.createPropertyAssignment(
203
+ "host",
204
+ ts.factory.createIdentifier("connection.host"),
205
+ ),
206
+ ts.factory.createPropertyAssignment(
207
+ "path",
208
+ ts.factory.createCallExpression(
209
+ ts.factory.createIdentifier("path"),
210
+ undefined,
211
+ route.parameters
212
+ .filter(
213
+ (p) => p.category === "param" || p.category === "query",
214
+ )
215
+ .map((p) => ts.factory.createIdentifier(p.name)),
216
+ ),
217
+ ),
218
+ ts.factory.createPropertyAssignment(
219
+ "contentType",
220
+ ts.factory.createIdentifier(
221
+ JSON.stringify(route.output.contentType),
222
+ ),
223
+ ),
224
+ ],
225
+ true,
226
+ ),
227
+ ],
228
+ ),
229
+ );
230
+ const individual = parameters
231
+ .map((p) =>
232
+ ts.factory.createCallExpression(
233
+ (() => {
234
+ const base = IdentifierFactory.access(
235
+ ts.factory.createIdentifier("assert"),
236
+ )(p.category);
237
+ if (p.category !== "param") return base;
238
+ return ts.factory.createCallExpression(base, undefined, [
239
+ ts.factory.createStringLiteral(p.name),
240
+ ]);
241
+ })(),
242
+ undefined,
243
+ [
244
+ ts.factory.createArrowFunction(
245
+ undefined,
246
+ undefined,
247
+ [],
248
+ undefined,
249
+ undefined,
250
+ ts.factory.createCallExpression(
251
+ IdentifierFactory.access(ts.factory.createIdentifier(typia))(
252
+ "assert",
253
+ ),
254
+ undefined,
255
+ [
256
+ ts.factory.createIdentifier(
257
+ p.category === "headers" ? "connection.headers" : p.name,
258
+ ),
259
+ ],
260
+ ),
261
+ ),
262
+ ],
263
+ ),
264
+ )
265
+ .map(ts.factory.createExpressionStatement);
266
+
267
+ return [
268
+ validator,
269
+ ...(config.propagate !== true
270
+ ? individual
271
+ : [tryAndCatch(importer)(individual)]),
272
+ ];
273
+ };
274
+
275
+ const tryAndCatch =
276
+ (importer: ImportDictionary) => (individual: ts.Statement[]) =>
277
+ ts.factory.createTryStatement(
278
+ ts.factory.createBlock(individual, true),
279
+ ts.factory.createCatchClause(
280
+ "exp",
281
+ ts.factory.createBlock(
282
+ [
283
+ ts.factory.createIfStatement(
284
+ ts.factory.createLogicalNot(
285
+ ts.factory.createCallExpression(
286
+ IdentifierFactory.access(
287
+ ts.factory.createIdentifier(
288
+ SdkImportWizard.typia(importer),
289
+ ),
290
+ )("is"),
291
+ [
292
+ ts.factory.createTypeReferenceNode(
293
+ SdkImportWizard.HttpError(importer),
294
+ ),
295
+ ],
296
+ [ts.factory.createIdentifier("exp")],
297
+ ),
298
+ ),
299
+ ts.factory.createThrowStatement(
300
+ ts.factory.createIdentifier("exp"),
301
+ ),
302
+ ),
303
+ ts.factory.createReturnStatement(
304
+ ts.factory.createAsExpression(
305
+ ts.factory.createObjectLiteralExpression(
306
+ [
307
+ ts.factory.createPropertyAssignment(
308
+ "success",
309
+ ts.factory.createFalse(),
310
+ ),
311
+ ts.factory.createPropertyAssignment(
312
+ "status",
313
+ ts.factory.createIdentifier("exp.status"),
314
+ ),
315
+ ts.factory.createPropertyAssignment(
316
+ "headers",
317
+ ts.factory.createIdentifier("exp.headers"),
318
+ ),
319
+ ts.factory.createPropertyAssignment(
320
+ "data",
321
+ ts.factory.createIdentifier("exp.toJSON().message"),
322
+ ),
323
+ ],
324
+ true,
325
+ ),
326
+ TypeFactory.keyword("any"),
327
+ ),
328
+ ),
329
+ ],
330
+ true,
331
+ ),
332
+ ),
333
+ undefined,
334
+ );
335
+ }
336
+
337
+ const constant = (name: string) => (expression: ts.Expression) =>
338
+ ts.factory.createVariableStatement(
339
+ [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
340
+ ts.factory.createVariableDeclarationList(
341
+ [
342
+ ts.factory.createVariableDeclaration(
343
+ ts.factory.createIdentifier(name),
344
+ undefined,
345
+ undefined,
346
+ expression,
347
+ ),
348
+ ],
349
+ ts.NodeFlags.Const,
350
+ ),
351
+ );
352
+
353
+ const getTypeName =
354
+ (config: INestiaConfig) =>
355
+ (importer: ImportDictionary) =>
356
+ (p: IRoute.IParameter | IRoute.IOutput) =>
357
+ p.metadata
358
+ ? SdkDtoGenerator.decode(config)(importer)(p.metadata)
359
+ : p.typeName;