@nestia/sdk 2.4.7 → 2.5.0-dev.20240129

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 (40) hide show
  1. package/lib/generates/internal/E2eFileProgrammer.js +44 -46
  2. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  3. package/lib/generates/internal/SdkDtoGenerator.js +2 -1
  4. package/lib/generates/internal/SdkDtoGenerator.js.map +1 -1
  5. package/lib/generates/internal/SdkFileProgrammer.js +16 -10
  6. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  7. package/lib/generates/internal/SdkFunctionProgrammer.d.ts +6 -1
  8. package/lib/generates/internal/SdkFunctionProgrammer.js +73 -323
  9. package/lib/generates/internal/SdkFunctionProgrammer.js.map +1 -1
  10. package/lib/generates/internal/SdkNamespaceProgrammer.d.ts +11 -0
  11. package/lib/generates/internal/SdkNamespaceProgrammer.js +175 -0
  12. package/lib/generates/internal/SdkNamespaceProgrammer.js.map +1 -0
  13. package/lib/generates/internal/SdkRouteProgrammer.d.ts +7 -0
  14. package/lib/generates/internal/SdkRouteProgrammer.js +55 -0
  15. package/lib/generates/internal/SdkRouteProgrammer.js.map +1 -0
  16. package/lib/generates/internal/SdkSimulationProgrammer.d.ts +7 -1
  17. package/lib/generates/internal/SdkSimulationProgrammer.js +98 -88
  18. package/lib/generates/internal/SdkSimulationProgrammer.js.map +1 -1
  19. package/lib/utils/FormatUtil.d.ts +6 -0
  20. package/lib/utils/FormatUtil.js +36 -0
  21. package/lib/utils/FormatUtil.js.map +1 -0
  22. package/lib/utils/ImportDictionary.d.ts +2 -0
  23. package/lib/utils/ImportDictionary.js +45 -0
  24. package/lib/utils/ImportDictionary.js.map +1 -1
  25. package/package.json +6 -3
  26. package/src/analyses/ConfigAnalyzer.ts +147 -147
  27. package/src/analyses/ControllerAnalyzer.ts +390 -390
  28. package/src/analyses/PathAnalyzer.ts +110 -110
  29. package/src/analyses/ReflectAnalyzer.ts +464 -464
  30. package/src/generates/SwaggerGenerator.ts +376 -376
  31. package/src/generates/internal/E2eFileProgrammer.ts +148 -73
  32. package/src/generates/internal/SdkDtoGenerator.ts +6 -1
  33. package/src/generates/internal/SdkFileProgrammer.ts +40 -13
  34. package/src/generates/internal/SdkFunctionProgrammer.ts +176 -475
  35. package/src/generates/internal/SdkNamespaceProgrammer.ts +495 -0
  36. package/src/generates/internal/SdkRouteProgrammer.ts +82 -0
  37. package/src/generates/internal/SdkSimulationProgrammer.ts +359 -133
  38. package/src/generates/internal/SwaggerSchemaGenerator.ts +444 -444
  39. package/src/utils/FormatUtil.ts +30 -0
  40. package/src/utils/ImportDictionary.ts +72 -0
@@ -1,6 +1,6 @@
1
- import { Pair } from "tstl/utility/Pair";
2
- import { IJsDocTagInfo } from "typia/lib/schemas/metadata/IJsDocTagInfo";
3
- import { Escaper } from "typia/lib/utils/Escaper";
1
+ import ts from "typescript";
2
+ import typia from "typia";
3
+ import { IdentifierFactory } from "typia/lib/factories/IdentifierFactory";
4
4
 
5
5
  import { INestiaConfig } from "../../INestiaConfig";
6
6
  import { IController } from "../../structures/IController";
@@ -8,507 +8,208 @@ import { IRoute } from "../../structures/IRoute";
8
8
  import { ImportDictionary } from "../../utils/ImportDictionary";
9
9
  import { SdkDtoGenerator } from "./SdkDtoGenerator";
10
10
  import { SdkImportWizard } from "./SdkImportWizard";
11
- import { SdkSimulationProgrammer } from "./SdkSimulationProgrammer";
12
- import { SdkTypeDefiner } from "./SdkTypeDefiner";
13
11
 
14
12
  export namespace SdkFunctionProgrammer {
15
13
  export const generate =
16
14
  (config: INestiaConfig) =>
17
15
  (importer: ImportDictionary) =>
18
- (route: IRoute): string => {
19
- const [x, y, z] = [head, body, tail].map((closure) =>
20
- closure(config)(importer)(route)({
21
- headers: route.parameters.find(
22
- (param) =>
23
- param.category === "headers" && param.field === undefined,
16
+ (
17
+ route: IRoute,
18
+ props: {
19
+ headers: IRoute.IParameter | undefined;
20
+ query: IRoute.IParameter | undefined;
21
+ input: IRoute.IParameter | undefined;
22
+ },
23
+ ): ts.FunctionDeclaration => {
24
+ return ts.factory.createFunctionDeclaration(
25
+ [
26
+ ts.factory.createModifier(ts.SyntaxKind.ExportKeyword),
27
+ ts.factory.createModifier(ts.SyntaxKind.AsyncKeyword),
28
+ ],
29
+ undefined,
30
+ route.name,
31
+ undefined,
32
+ [
33
+ IdentifierFactory.parameter(
34
+ "connection",
35
+ ts.factory.createTypeReferenceNode(
36
+ SdkImportWizard.IConnection(importer),
37
+ props.headers
38
+ ? [ts.factory.createTypeReferenceNode(`${route.name}.Headers`)]
39
+ : undefined,
40
+ ),
24
41
  ),
25
- query: route.parameters.find(
26
- (param) => param.category === "query" && param.field === undefined,
42
+ ...route.parameters
43
+ .filter((p) => p.category !== "headers")
44
+ .map((p) =>
45
+ ts.factory.createParameterDeclaration(
46
+ [],
47
+ undefined,
48
+ p.name,
49
+ p.optional
50
+ ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
51
+ : undefined,
52
+ ts.factory.createTypeReferenceNode(
53
+ config.primitive !== false &&
54
+ (p === props.query || p === props.input)
55
+ ? `${route.name}.${p === props.query ? "Query" : "Input"}`
56
+ : getTypeName(config)(importer)(p),
57
+ ),
58
+ ),
59
+ ),
60
+ ],
61
+ ts.factory.createTypeReferenceNode("Promise", [
62
+ ts.factory.createTypeReferenceNode(
63
+ config.propagate !== true && route.output.typeName === "void"
64
+ ? "void"
65
+ : `${route.name}.Output`,
27
66
  ),
28
- input: route.parameters.find((param) => param.category === "body"),
29
- }),
67
+ ]),
68
+ ts.factory.createBlock(
69
+ generate_body(config)(importer)(route, props),
70
+ true,
71
+ ),
30
72
  );
31
- return `${x} ${y}\n${z}`;
32
73
  };
33
74
 
34
- /* ---------------------------------------------------------
35
- BODY
36
- --------------------------------------------------------- */
37
- const body =
75
+ const generate_body =
38
76
  (config: INestiaConfig) =>
39
77
  (importer: ImportDictionary) =>
40
- (route: IRoute) =>
41
- (props: {
42
- query: IRoute.IParameter | undefined;
43
- input: IRoute.IParameter | undefined;
44
- }): string => {
78
+ (
79
+ route: IRoute,
80
+ props: {
81
+ headers: IRoute.IParameter | undefined;
82
+ query: IRoute.IParameter | undefined;
83
+ input: IRoute.IParameter | undefined;
84
+ },
85
+ ): ts.Statement[] => {
45
86
  const encrypted: boolean =
46
87
  route.encrypted === true ||
47
88
  (props.input !== undefined &&
48
89
  props.input.custom === true &&
49
90
  props.input.category === "body" &&
50
91
  props.input.encrypted === true);
51
-
52
- // FETCH ARGUMENTS WITH REQUST BODY
53
- const parameters: IRoute.IParameter[] = filter_path_parameters(route)(
54
- props.query,
55
- );
56
92
  const contentType: string | undefined =
57
93
  props.input !== undefined
58
- ? (props.input as IController.IBodyParameter).encrypted
59
- ? "text/plain"
60
- : (props.input as IController.IBodyParameter).contentType ??
61
- "application/json"
94
+ ? typia.is<IController.IBodyParameter>(props.input)
95
+ ? props.input.contentType
96
+ : "application/json"
62
97
  : undefined;
63
- const fetchArguments: Array<string | string[]> = [
64
- contentType
65
- ? [
66
- "{",
67
- " ...connection,",
68
- " headers: {",
69
- " ...(connection.headers ?? {}),",
70
- ` "Content-Type": "${contentType}",`,
71
- " },",
72
- "}",
73
- ]
74
- : "connection",
75
- [
76
- "{",
77
- ` ...${route.name}.METADATA,`,
78
- ` path: ${route.name}.path(${parameters
79
- .map((p) => p.name)
80
- .join(", ")}),`,
81
- "} as const",
82
- ],
83
- ];
84
- if (props.input !== undefined) {
85
- fetchArguments.push(props.input.name);
86
- if (config.json === true)
87
- fetchArguments.push(`${route.name}.stringify`);
88
- }
89
-
90
- const assertions: string =
91
- config.assert === true &&
92
- route.parameters.filter(
93
- (p) => p.category !== "headers" || p.field === undefined,
94
- ).length !== 0
95
- ? route.parameters
96
- .filter((p) => p.category !== "headers" || p.field === undefined)
97
- .map(
98
- (param) =>
99
- ` ${SdkImportWizard.typia(importer)}.assert<typeof ${
100
- param.name
101
- }>(${param.name});`,
102
- )
103
- .join("\n") + "\n\n"
104
- : "";
105
98
 
106
- // FUNCTION CALL STATEMENT
107
- const caller = (awa: boolean) => {
108
- const random = () =>
99
+ const caller = () =>
100
+ ts.factory.createCallExpression(
101
+ IdentifierFactory.access(
102
+ ts.factory.createIdentifier(
103
+ SdkImportWizard.Fetcher(encrypted)(importer),
104
+ ),
105
+ )(config.propagate ? "propagate" : "fetch"),
106
+ undefined,
109
107
  [
110
- `${awa ? "await " : ""}${route.name}.simulate(`,
111
- ` connection,`,
112
- ...route.parameters
108
+ contentType
109
+ ? ts.factory.createObjectLiteralExpression(
110
+ [
111
+ ts.factory.createSpreadAssignment(
112
+ ts.factory.createIdentifier("connection"),
113
+ ),
114
+ ts.factory.createPropertyAssignment(
115
+ "headers",
116
+ ts.factory.createObjectLiteralExpression(
117
+ [
118
+ ts.factory.createSpreadAssignment(
119
+ IdentifierFactory.access(
120
+ ts.factory.createIdentifier("connection"),
121
+ )("headers"),
122
+ ),
123
+ ts.factory.createPropertyAssignment(
124
+ ts.factory.createStringLiteral("Content-Type"),
125
+ ts.factory.createStringLiteral(contentType),
126
+ ),
127
+ ],
128
+ true,
129
+ ),
130
+ ),
131
+ ],
132
+ true,
133
+ )
134
+ : ts.factory.createIdentifier("connection"),
135
+ ts.factory.createObjectLiteralExpression(
136
+ [
137
+ ts.factory.createSpreadAssignment(
138
+ IdentifierFactory.access(
139
+ ts.factory.createIdentifier(route.name),
140
+ )("METADATA"),
141
+ ),
142
+ ts.factory.createPropertyAssignment(
143
+ "path",
144
+ ts.factory.createCallExpression(
145
+ IdentifierFactory.access(
146
+ ts.factory.createIdentifier(route.name),
147
+ )("path"),
148
+ undefined,
149
+ route.parameters
150
+ .filter(
151
+ (p) => p.category === "param" || p.category === "query",
152
+ )
153
+ .map((p) => ts.factory.createIdentifier(p.name)),
154
+ ),
155
+ ),
156
+ ],
157
+ true,
158
+ ),
159
+ ...(props.input
160
+ ? [ts.factory.createIdentifier(props.input.name)]
161
+ : []),
162
+ ...(config.json && props.input?.category === "body"
163
+ ? [ts.factory.createIdentifier(`${route.name}.stringify`)]
164
+ : []),
165
+ ],
166
+ );
167
+ return [
168
+ ...(config.assert
169
+ ? route.parameters
113
170
  .filter((p) => p.category !== "headers")
114
- .map((p) => ` ${p.name},`),
115
- `)`,
116
- ]
117
- .map((line, i) => (i === 0 ? line : `${space(10)}${line}`))
118
- .join("\n");
119
- const fetch = (tab: string) =>
120
- [
121
- `${awa ? "await " : ""}${SdkImportWizard.Fetcher(encrypted)(
122
- importer,
123
- )}.${config.propagate === true ? "propagate" : "fetch"}(`,
124
- fetchArguments
125
- .map((param) =>
126
- typeof param === "string"
127
- ? `${tab} ${param}`
128
- : param.map((str) => `${tab} ${str}`).join("\n"),
171
+ .map((p) =>
172
+ ts.factory.createExpressionStatement(
173
+ ts.factory.createCallExpression(
174
+ IdentifierFactory.access(
175
+ ts.factory.createIdentifier(
176
+ SdkImportWizard.typia(importer),
177
+ ),
178
+ )("assert"),
179
+ [
180
+ ts.factory.createTypeQueryNode(
181
+ ts.factory.createIdentifier(p.name),
182
+ ),
183
+ ],
184
+ [ts.factory.createIdentifier(p.name)],
185
+ ),
186
+ ),
129
187
  )
130
- .join(",\n") + ",",
131
- `${tab})`,
132
- ].join("\n");
133
- if (!config.simulate) return fetch(space(4));
134
- return (
135
- `!!connection.simulate\n` +
136
- ` ? ${random()}\n` +
137
- ` : ${fetch(space(10))}`
138
- );
139
- };
140
- if (route.setHeaders.length === 0)
141
- return `{\n${assertions} return ${caller(false)};\n}`;
142
-
143
- // SET HEADERS
144
- const content: string[] = [
145
- `{\n`,
146
- assertions,
147
- ` const output: ${route.name}.Output = ${caller(true)};\n`,
148
- "\n",
149
- ` // configure header(s)\n`,
150
- ` connection.headers ??= {};\n`,
151
- ];
152
- const headerContents = (variable: string) =>
153
- route.setHeaders.map((header) =>
154
- header.type === "assigner"
155
- ? `Object.assign(connection.headers, ${access(variable)(
156
- header.source,
157
- )});`
158
- : `${access("connection.headers")(
159
- header.target ?? header.source,
160
- )} = ${access(variable)(header.source)};`,
161
- );
162
- if (config.propagate === true) {
163
- content.push(` if (output.success) {\n`);
164
- content.push(
165
- ...headerContents("output.data").map((line) => ` ${line}\n`),
166
- );
167
- content.push(` }\n`);
168
- } else
169
- content.push(
170
- ...headerContents("output").map((line) => ` ${line}\n`),
171
- );
172
- content.push("\n", " return output;\n", "}");
173
- return content.join("");
174
- };
175
-
176
- const filter_path_parameters =
177
- (route: IRoute) =>
178
- (query: IRoute.IParameter | undefined): IRoute.IParameter[] => {
179
- const parameters: IRoute.IParameter[] = route.parameters.filter(
180
- (param) =>
181
- param.category === "param" ||
182
- (param.category === "query" && param.field !== undefined),
183
- );
184
- if (query) parameters.push(query);
185
- return parameters;
186
- };
187
-
188
- const access =
189
- (x: string) =>
190
- (y: string): string =>
191
- y[0] === "[" ? `${x}${y}` : `${x}.${y}`;
192
-
193
- /* ---------------------------------------------------------
194
- HEAD & TAIL
195
- --------------------------------------------------------- */
196
- const head =
197
- (config: INestiaConfig) =>
198
- (importer: ImportDictionary) =>
199
- (route: IRoute) =>
200
- (props: {
201
- query: IRoute.IParameter | undefined;
202
- input: IRoute.IParameter | undefined;
203
- }): string => {
204
- //----
205
- // CONSTRUCT COMMENT
206
- //----
207
- // MAIN DESCRIPTION
208
- const comments: string[] = route.description
209
- ? route.description.split("\n")
210
- : [];
211
-
212
- // COMMENT TAGS
213
- const tags: IJsDocTagInfo[] = route.jsDocTags.filter(
214
- (tag) =>
215
- tag.name !== "param" ||
216
- route.parameters
217
- .filter((p) => p.category !== "headers")
218
- .some((p) => p.name === tag.text?.[0]?.text),
219
- );
220
- if (tags.length !== 0) {
221
- const content: string[] = tags.map((t) =>
222
- t.text?.length
223
- ? `@${t.name} ${t.text.map((e) => e.text).join("")}`
224
- : `@${t.name}`,
225
- );
226
- comments.push("", ...new Set(content));
227
- }
228
-
229
- // EXCEPTIONS
230
- for (const [key, value] of Object.entries(route.exceptions)) {
231
- if (
232
- comments.some(
233
- (str) =>
234
- str.startsWith(`@throw ${key}`) ||
235
- str.startsWith(`@throws ${key}`),
236
- )
237
- )
238
- continue;
239
- comments.push(
240
- value.description?.length
241
- ? `@throws ${key} ${value.description.split("\n")[0]}`
242
- : `@throws ${key}`,
243
- );
244
- }
245
-
246
- // POSTFIX
247
- if (!!comments.length) comments.push("");
248
- comments.push(
249
- `@controller ${route.symbol.class}.${route.symbol.function}`,
250
- `@path ${route.method} ${route.path}`,
251
- `@nestia Generated by Nestia - https://github.com/samchon/nestia`,
252
- );
253
-
254
- //----
255
- // FINALIZATION
256
- //----
257
- // REFORM PARAMETERS TEXT
258
- const parameters: string[] = [
259
- route.parameters.some(
260
- (p) => p.category === "headers" && p.field === undefined,
261
- )
262
- ? `connection: ${SdkImportWizard.IConnection(
263
- importer,
264
- )}<${`${route.name}.Headers`}>`
265
- : `connection: ${SdkImportWizard.IConnection(importer)}`,
266
- ...route.parameters
267
- .filter((p) => p.category !== "headers")
268
- .map((param) => {
269
- const type: string =
270
- config.primitive !== false &&
271
- (param === props.query || param === props.input)
272
- ? `${route.name}.${param === props.query ? "Query" : "Input"}`
273
- : getTypeName(config)(importer)(param);
274
- return `${param.name}${param.optional ? "?" : ""}: ${type}`;
275
- }),
276
- ];
277
-
278
- // OUTPUT TYPE
279
- const output: string =
280
- config.propagate !== true && route.output.typeName === "void"
281
- ? "void"
282
- : `${route.name}.Output`;
283
-
284
- // RETURNS WITH CONSTRUCTION
285
- return (
286
- "" +
287
- "/**\n" +
288
- comments.map((str) => ` * ${str}`).join("\n") +
289
- "\n" +
290
- " */\n" +
291
- `export async function ${route.name}(\n` +
292
- parameters.map((str) => ` ${str},\n`).join("") +
293
- `): Promise<${output}>`
294
- );
295
- };
296
-
297
- const tail =
298
- (config: INestiaConfig) =>
299
- (importer: ImportDictionary) =>
300
- (route: IRoute) =>
301
- (props: {
302
- query: IRoute.IParameter | undefined;
303
- headers: IRoute.IParameter | undefined;
304
- input: IRoute.IParameter | undefined;
305
- }): string => {
306
- // LIST UP TYPES
307
- const types: Pair<string, string>[] = [];
308
- if (props.headers !== undefined)
309
- types.push(
310
- new Pair(
311
- "Headers",
312
- SdkTypeDefiner.headers(config)(importer)(props.headers),
313
- ),
314
- );
315
- if (props.query !== undefined)
316
- types.push(
317
- new Pair(
318
- "Query",
319
- SdkTypeDefiner.query(config)(importer)(props.query),
320
- ),
321
- );
322
- if (props.input !== undefined)
323
- types.push(
324
- new Pair(
325
- "Input",
326
- SdkTypeDefiner.input(config)(importer)(props.input),
327
- ),
328
- );
329
- if (config.propagate === true || route.output.typeName !== "void")
330
- types.push(
331
- new Pair("Output", SdkTypeDefiner.output(config)(importer)(route)),
332
- );
333
-
334
- // PATH WITH PARAMETERS
335
- const parameters: IRoute.IParameter[] = filter_path_parameters(route)(
336
- props.query,
337
- );
338
- const path: string = compute_path({
339
- path: route.path,
340
- query: props.query,
341
- parameters,
342
- });
343
- return (
344
- `export namespace ${route.name} {\n` +
345
- (types.length !== 0
346
- ? types
347
- .map(
348
- (tuple) => ` export type ${tuple.first} = ${tuple.second};`,
188
+ : []),
189
+ ts.factory.createReturnStatement(
190
+ config.simulate
191
+ ? ts.factory.createConditionalExpression(
192
+ ts.factory.createIdentifier("!!connection.simulate"),
193
+ undefined,
194
+ ts.factory.createCallExpression(
195
+ ts.factory.createIdentifier(`${route.name}.simulate`),
196
+ [],
197
+ [
198
+ ts.factory.createIdentifier("connection"),
199
+ ...route.parameters
200
+ .filter((p) => p.category !== "headers")
201
+ .map((p) => ts.factory.createIdentifier(p.name)),
202
+ ],
203
+ ),
204
+ undefined,
205
+ caller(),
349
206
  )
350
- .join("\n") + "\n"
351
- : "") +
352
- "\n" +
353
- [
354
- "export const METADATA = {",
355
- ` method: "${route.method}",`,
356
- ` path: "${route.path}",`,
357
- ...(props.input
358
- ? [
359
- `request: {`,
360
- ` type: "${
361
- (props.input as IController.IBodyParameter).encrypted
362
- ? "text/plain"
363
- : (props.input as IController.IBodyParameter).contentType ??
364
- "application/json"
365
- }",`,
366
- ` encrypted: ${
367
- props.input.custom &&
368
- props.input.category === "body" &&
369
- props.input.encrypted
370
- }`,
371
- `},`,
372
- ].map((str) => ` ${str}`)
373
- : [" request: null,"]),
374
- ...(route.method !== "HEAD"
375
- ? [
376
- `response: {`,
377
- ` type: "${route.output.contentType}",`,
378
- ` encrypted: ${route.encrypted},`,
379
- `},`,
380
- ].map((str) => ` ${str}`)
381
- : [" response: null,"]),
382
- ...(route.status
383
- ? [` status: ${route.status},`]
384
- : [" status: null,"]),
385
- ...(route.output.contentType === "application/x-www-form-urlencoded"
386
- ? [
387
- ` parseQuery: (input: URLSearchParams) => ${SdkImportWizard.typia(
388
- importer,
389
- )}.http.assertQuery<${route.output.typeName}>(input),`,
390
- ]
391
- : []),
392
- "} as const;",
393
- ]
394
- .map((line) => ` ${line}`)
395
- .join("\n") +
396
- "\n\n" +
397
- ` export const path = (${parameters
398
- .map(
399
- (param) =>
400
- `${param.name}: ${
401
- param.category === "query" &&
402
- param.typeName === props.query?.typeName
403
- ? `${route.name}.Query`
404
- : getTypeName(config)(importer)(param)
405
- }`,
406
- )
407
- .join(", ")}): string => {\n` +
408
- `${path};\n` +
409
- ` }\n` +
410
- (config.simulate === true && route.output.typeName !== "void"
411
- ? ` export const random = (g?: Partial<${SdkImportWizard.typia(
412
- importer,
413
- )}.IRandomGenerator>): ${SdkTypeDefiner.responseBody(config)(
414
- importer,
415
- )(route)} =>\n` +
416
- ` ${SdkImportWizard.typia(
417
- importer,
418
- )}.random<${SdkTypeDefiner.responseBody(config)(importer)(
419
- route,
420
- )}>(g);\n`
421
- : "") +
422
- (config.simulate === true
423
- ? SdkSimulationProgrammer.generate(config)(importer)(route) + "\n"
424
- : "") +
425
- (config.json === true &&
426
- route.parameters.find((param) => param.category === "body") !==
427
- undefined
428
- ? ` export const stringify = (input: Input) => ${SdkImportWizard.typia(
429
- importer,
430
- )}.json.assertStringify(input);\n`
431
- : "") +
432
- "}"
433
- );
207
+ : caller(),
208
+ ),
209
+ ];
434
210
  };
435
-
436
- const compute_path = (props: {
437
- query: IRoute.IParameter | undefined;
438
- parameters: IRoute.IParameter[];
439
- path: string;
440
- }): string => {
441
- for (const param of props.parameters)
442
- if (param.category === "param")
443
- props.path = props.path.replace(
444
- `:${param.field}`,
445
- `\${encodeURIComponent(${param.name} ?? "null")}`,
446
- );
447
-
448
- // NO QUERY PARAMETER
449
- const queryParams: IRoute.IParameter[] = props.parameters.filter(
450
- (param) => param.category === "query" && param.field !== undefined,
451
- );
452
- if (props.query === undefined && queryParams.length === 0)
453
- return `${space(8)}return \`${props.path}\``;
454
-
455
- const computeName = (str: string): string =>
456
- props.parameters
457
- .filter((p) => p.category !== "headers")
458
- .find((p) => p.name === str) !== undefined
459
- ? computeName("_" + str)
460
- : str;
461
- const variables: string = computeName("variables");
462
- const search: string = computeName("search");
463
- const encoded: string = computeName("encoded");
464
-
465
- const wrapper = (expr: string) =>
466
- [
467
- `const ${variables}: Record<any, any> = ${expr};`,
468
- `const ${search}: URLSearchParams = new URLSearchParams();`,
469
- `for (const [key, value] of Object.entries(${variables}))`,
470
- ` if (value === undefined) continue;`,
471
- ` else if (Array.isArray(value))`,
472
- ` value.forEach((elem) => ${search}.append(key, String(elem)));`,
473
- ` else`,
474
- ` ${search}.set(key, String(value));`,
475
- `const ${encoded}: string = ${search}.toString();`,
476
- `return \`${props.path}\${${encoded}.length ? \`?\${${encoded}}\` : ""}\`;`,
477
- ]
478
- .map((str) => `${space(8)}${str}`)
479
- .join("\n");
480
-
481
- if (props.query !== undefined && queryParams.length === 0)
482
- return wrapper(`${props.query.name} as any`);
483
- else if (props.query === undefined)
484
- return wrapper(`
485
- {
486
- ${rest_query_parameters(queryParams)}
487
- } as any`);
488
-
489
- return wrapper(`
490
- {
491
- ...${props.query.name},
492
- ${rest_query_parameters(queryParams)},
493
- } as any`);
494
- };
495
-
496
- const rest_query_parameters = (parameters: IRoute.IParameter[]): string =>
497
- parameters
498
- .filter((param) => param.category !== "headers")
499
- .map((param) =>
500
- param.name === param.field
501
- ? param.name
502
- : `${
503
- Escaper.variable(param.field!)
504
- ? param.field
505
- : JSON.stringify(param.field)
506
- }: ${param.name}`,
507
- )
508
- .join(`,\n${space(12)}`);
509
211
  }
510
212
 
511
- const space = (count: number) => " ".repeat(count);
512
213
  const getTypeName =
513
214
  (config: INestiaConfig) =>
514
215
  (importer: ImportDictionary) =>