@nestia/sdk 1.0.5 → 1.0.7
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/generates/FunctionGenerator.js +7 -7
- package/lib/generates/SwaggerGenerator.js +11 -12
- package/lib/generates/SwaggerGenerator.js.map +1 -1
- package/lib/structures/ISwaggerDocument.d.ts +1 -1
- package/package.json +2 -2
- package/src/executable/internal/NestiaSdkConfig.ts +36 -36
- package/src/generates/FunctionGenerator.ts +323 -323
- package/src/generates/SwaggerGenerator.ts +433 -433
- package/src/index.ts +4 -4
- package/src/structures/ISwaggerDocument.ts +1 -1
|
@@ -1,323 +1,323 @@
|
|
|
1
|
-
import { Vector } from "tstl/container/Vector";
|
|
2
|
-
import { Pair } from "tstl/utility/Pair";
|
|
3
|
-
import ts from "typescript";
|
|
4
|
-
|
|
5
|
-
import { Escaper } from "typia/lib/utils/Escaper";
|
|
6
|
-
|
|
7
|
-
import { INestiaConfig } from "../INestiaConfig";
|
|
8
|
-
import { IRoute } from "../structures/IRoute";
|
|
9
|
-
|
|
10
|
-
export namespace FunctionGenerator {
|
|
11
|
-
export function generate(config: INestiaConfig, route: IRoute): string {
|
|
12
|
-
const query: IRoute.IParameter | undefined = route.parameters.find(
|
|
13
|
-
(param) => param.category === "query" && param.field === undefined,
|
|
14
|
-
);
|
|
15
|
-
const input: IRoute.IParameter | undefined = route.parameters.find(
|
|
16
|
-
(param) => param.category === "body",
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
return [head, body, tail]
|
|
20
|
-
.map((closure) => closure(route, query, input, config))
|
|
21
|
-
.filter((str) => !!str)
|
|
22
|
-
.join("\n");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/* ---------------------------------------------------------
|
|
26
|
-
BODY
|
|
27
|
-
--------------------------------------------------------- */
|
|
28
|
-
function body(
|
|
29
|
-
route: IRoute,
|
|
30
|
-
query: IRoute.IParameter | undefined,
|
|
31
|
-
input: IRoute.IParameter | undefined,
|
|
32
|
-
config: INestiaConfig,
|
|
33
|
-
): string {
|
|
34
|
-
// FETCH ARGUMENTS WITH REQUST BODY
|
|
35
|
-
const parameters = filter_parameters(route, query);
|
|
36
|
-
const fetchArguments: string[] = [
|
|
37
|
-
"connection",
|
|
38
|
-
`${route.name}.ENCRYPTED`,
|
|
39
|
-
`${route.name}.METHOD`,
|
|
40
|
-
`${route.name}.path(${parameters.map((p) => p.name).join(", ")})`,
|
|
41
|
-
];
|
|
42
|
-
if (input !== undefined) {
|
|
43
|
-
fetchArguments.push(input.name);
|
|
44
|
-
if (config.json === true)
|
|
45
|
-
fetchArguments.push(`${route.name}.stringify`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const assertions: string =
|
|
49
|
-
config.assert === true && route.parameters.length !== 0
|
|
50
|
-
? route.parameters
|
|
51
|
-
.map(
|
|
52
|
-
(param) =>
|
|
53
|
-
` typia.assert<typeof ${param.name}>(${param.name});`,
|
|
54
|
-
)
|
|
55
|
-
.join("\n") + "\n\n"
|
|
56
|
-
: "";
|
|
57
|
-
|
|
58
|
-
// FUNCTION CALL STATEMENT
|
|
59
|
-
const caller: string =
|
|
60
|
-
"Fetcher.fetch\n" +
|
|
61
|
-
" (\n" +
|
|
62
|
-
fetchArguments.map((param) => ` ${param}`).join(",\n") +
|
|
63
|
-
"\n" +
|
|
64
|
-
" )";
|
|
65
|
-
if (route.setHeaders.length === 0)
|
|
66
|
-
return `{\n${assertions} return ${caller};\n}`;
|
|
67
|
-
|
|
68
|
-
// SET HEADERS
|
|
69
|
-
const content: string[] = [
|
|
70
|
-
`{\n`,
|
|
71
|
-
assertions,
|
|
72
|
-
` const output: ${route.name}.Output = await ${caller};\n`,
|
|
73
|
-
"\n",
|
|
74
|
-
` // configure header(s)\n`,
|
|
75
|
-
` connection.headers ??= {};\n`,
|
|
76
|
-
];
|
|
77
|
-
|
|
78
|
-
for (const header of route.setHeaders) {
|
|
79
|
-
if (header.type === "assigner")
|
|
80
|
-
content.push(
|
|
81
|
-
" ",
|
|
82
|
-
`Object.assign(connection.headers, ${access(
|
|
83
|
-
"output",
|
|
84
|
-
header.source,
|
|
85
|
-
)});\n`,
|
|
86
|
-
);
|
|
87
|
-
else
|
|
88
|
-
content.push(
|
|
89
|
-
" ",
|
|
90
|
-
`${access(
|
|
91
|
-
"connection.headers",
|
|
92
|
-
header.target ?? header.source,
|
|
93
|
-
)} = ${access("output", header.source)};\n`,
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
content.push("\n", " return output;\n", "}");
|
|
97
|
-
return content.join("");
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function filter_parameters(
|
|
101
|
-
route: IRoute,
|
|
102
|
-
query: IRoute.IParameter | undefined,
|
|
103
|
-
): IRoute.IParameter[] {
|
|
104
|
-
const parameters: IRoute.IParameter[] = route.parameters.filter(
|
|
105
|
-
(param) =>
|
|
106
|
-
param.category === "param" ||
|
|
107
|
-
(param.category === "query" && param.field !== undefined),
|
|
108
|
-
);
|
|
109
|
-
if (query) parameters.push(query);
|
|
110
|
-
return parameters;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function access(x: string, y: string): string {
|
|
114
|
-
return y[0] === "[" ? `${x}${y}` : `${x}.${y}`;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/* ---------------------------------------------------------
|
|
118
|
-
HEAD & TAIL
|
|
119
|
-
--------------------------------------------------------- */
|
|
120
|
-
function head(
|
|
121
|
-
route: IRoute,
|
|
122
|
-
query: IRoute.IParameter | undefined,
|
|
123
|
-
input: IRoute.IParameter | undefined,
|
|
124
|
-
config: INestiaConfig,
|
|
125
|
-
): string {
|
|
126
|
-
//----
|
|
127
|
-
// CONSTRUCT COMMENT
|
|
128
|
-
//----
|
|
129
|
-
// MAIN DESCRIPTION
|
|
130
|
-
const comments: string[] = route.comments
|
|
131
|
-
.map((part) => `${part.kind === "linkText" ? " " : ""}${part.text}`)
|
|
132
|
-
.map((str) => str.split("\r\n").join("\n"))
|
|
133
|
-
.join("")
|
|
134
|
-
.split("\n")
|
|
135
|
-
.filter((str, i, array) => str !== "" || i !== array.length - 1);
|
|
136
|
-
if (comments.length) comments.push("");
|
|
137
|
-
|
|
138
|
-
// FILTER TAGS (VULNERABLE PARAMETERS WOULD BE REMOVED)
|
|
139
|
-
const tagList: ts.JSDocTagInfo[] = route.tags.filter(
|
|
140
|
-
(tag) => tag.text !== undefined,
|
|
141
|
-
);
|
|
142
|
-
if (tagList.length !== 0) {
|
|
143
|
-
const index: number = tagList.findIndex((t) => t.name === "param");
|
|
144
|
-
if (index !== -1) {
|
|
145
|
-
const capsule: Vector<ts.JSDocTagInfo> = Vector.wrap(tagList);
|
|
146
|
-
capsule.insert(capsule.nth(index), {
|
|
147
|
-
name: "param",
|
|
148
|
-
text: [
|
|
149
|
-
{
|
|
150
|
-
kind: "parameterName",
|
|
151
|
-
text: "connection",
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
kind: "space",
|
|
155
|
-
text: " ",
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
kind: "text",
|
|
159
|
-
text: "connection Information of the remote HTTP(s) server with headers (+encryption password)",
|
|
160
|
-
},
|
|
161
|
-
],
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
comments.push(
|
|
165
|
-
...tagList.map(
|
|
166
|
-
(tag) =>
|
|
167
|
-
`@${tag.name} ${tag
|
|
168
|
-
.text!.map((elem) => elem.text)
|
|
169
|
-
.join("")}`,
|
|
170
|
-
),
|
|
171
|
-
"",
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// COMPLETE THE COMMENT
|
|
176
|
-
comments.push(
|
|
177
|
-
`@controller ${route.symbol}`,
|
|
178
|
-
`@path ${route.method} ${route.path}`,
|
|
179
|
-
`@nestia Generated by Nestia - https://github.com/samchon/nestia`,
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
//----
|
|
183
|
-
// FINALIZATION
|
|
184
|
-
//----
|
|
185
|
-
// REFORM PARAMETERS TEXT
|
|
186
|
-
const parameters: string[] = [
|
|
187
|
-
"connection: IConnection",
|
|
188
|
-
...route.parameters.map((param) => {
|
|
189
|
-
const type: string =
|
|
190
|
-
config.primitive !== false &&
|
|
191
|
-
(param === query || param === input)
|
|
192
|
-
? `Primitive<${route.name}.${
|
|
193
|
-
param === query ? "Query" : "Input"
|
|
194
|
-
}>`
|
|
195
|
-
: param.type.name;
|
|
196
|
-
return `${param.name}: ${type}`;
|
|
197
|
-
}),
|
|
198
|
-
];
|
|
199
|
-
|
|
200
|
-
// OUTPUT TYPE
|
|
201
|
-
const output: string =
|
|
202
|
-
route.output.name === "void" ? "void" : `${route.name}.Output`;
|
|
203
|
-
|
|
204
|
-
// RETURNS WITH CONSTRUCTION
|
|
205
|
-
return (
|
|
206
|
-
"" +
|
|
207
|
-
"/**\n" +
|
|
208
|
-
comments.map((str) => ` * ${str}`).join("\n") +
|
|
209
|
-
"\n" +
|
|
210
|
-
" */\n" +
|
|
211
|
-
`export${route.setHeaders.length ? " async" : ""} function ${
|
|
212
|
-
route.name
|
|
213
|
-
}\n` +
|
|
214
|
-
` (\n` +
|
|
215
|
-
`${parameters.map((str) => ` ${str}`).join(",\n")}\n` +
|
|
216
|
-
` ): Promise<${output}>`
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function tail(
|
|
221
|
-
route: IRoute,
|
|
222
|
-
query: IRoute.IParameter | undefined,
|
|
223
|
-
input: IRoute.IParameter | undefined,
|
|
224
|
-
config: INestiaConfig,
|
|
225
|
-
): string | null {
|
|
226
|
-
// LIST UP TYPES
|
|
227
|
-
const types: Pair<string, string>[] = [];
|
|
228
|
-
if (query !== undefined) types.push(new Pair("Query", query.type.name));
|
|
229
|
-
if (input !== undefined) types.push(new Pair("Input", input.type.name));
|
|
230
|
-
if (route.output.name !== "void")
|
|
231
|
-
types.push(new Pair("Output", route.output.name));
|
|
232
|
-
|
|
233
|
-
// PATH WITH PARAMETERS
|
|
234
|
-
const parameters: IRoute.IParameter[] = filter_parameters(route, query);
|
|
235
|
-
const path: string = compute_path(query, parameters, route.path);
|
|
236
|
-
|
|
237
|
-
return (
|
|
238
|
-
`export namespace ${route.name}\n` +
|
|
239
|
-
"{\n" +
|
|
240
|
-
(types.length !== 0
|
|
241
|
-
? types
|
|
242
|
-
.map(
|
|
243
|
-
(tuple) =>
|
|
244
|
-
` export type ${tuple.first} = ${
|
|
245
|
-
config.primitive !== false
|
|
246
|
-
? `Primitive<${tuple.second}>`
|
|
247
|
-
: tuple.second
|
|
248
|
-
};`,
|
|
249
|
-
)
|
|
250
|
-
.join("\n") + "\n"
|
|
251
|
-
: "") +
|
|
252
|
-
"\n" +
|
|
253
|
-
` export const METHOD = "${route.method}" as const;\n` +
|
|
254
|
-
` export const PATH: string = "${route.path}";\n` +
|
|
255
|
-
` export const ENCRYPTED: Fetcher.IEncrypted = {\n` +
|
|
256
|
-
` request: ${input !== undefined && input.encrypted},\n` +
|
|
257
|
-
` response: ${route.encrypted},\n` +
|
|
258
|
-
` };\n` +
|
|
259
|
-
"\n" +
|
|
260
|
-
` export function path(${parameters
|
|
261
|
-
.map((param) => `${param.name}: ${param.type.name}`)
|
|
262
|
-
.join(", ")}): string\n` +
|
|
263
|
-
` {\n` +
|
|
264
|
-
` return ${path};\n` +
|
|
265
|
-
` }\n` +
|
|
266
|
-
(config.json === true &&
|
|
267
|
-
(route.method === "POST" ||
|
|
268
|
-
route.method === "PUT" ||
|
|
269
|
-
route.method === "PATCH")
|
|
270
|
-
? ` export const stringify = (input: Input) => typia.assertStringify(input);\n`
|
|
271
|
-
: "") +
|
|
272
|
-
"}"
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function compute_path(
|
|
277
|
-
query: IRoute.IParameter | undefined,
|
|
278
|
-
parameters: IRoute.IParameter[],
|
|
279
|
-
path: string,
|
|
280
|
-
): string {
|
|
281
|
-
for (const param of parameters)
|
|
282
|
-
if (param.category === "param")
|
|
283
|
-
path = path.replace(
|
|
284
|
-
`:${param.field}`,
|
|
285
|
-
`\${encodeURIComponent(${param.name})}`,
|
|
286
|
-
);
|
|
287
|
-
const queryParams: IRoute.IParameter[] = parameters.filter(
|
|
288
|
-
(param) => param.category === "query" && param.field !== undefined,
|
|
289
|
-
);
|
|
290
|
-
if (query === undefined && queryParams.length === 0)
|
|
291
|
-
return `\`${path}\``;
|
|
292
|
-
|
|
293
|
-
const wrapper = (str: string) =>
|
|
294
|
-
`\`${path}?\${new URLSearchParams(${str}).toString()}\``;
|
|
295
|
-
if (query !== undefined && queryParams.length === 0)
|
|
296
|
-
return wrapper(`${query.name} as any`);
|
|
297
|
-
else if (query === undefined)
|
|
298
|
-
return wrapper(`
|
|
299
|
-
{
|
|
300
|
-
${rest_query_parameters(queryParams)}
|
|
301
|
-
} as any`);
|
|
302
|
-
|
|
303
|
-
return wrapper(`
|
|
304
|
-
{
|
|
305
|
-
...${query.name},
|
|
306
|
-
${rest_query_parameters(queryParams)},
|
|
307
|
-
} as any`);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
function rest_query_parameters(parameters: IRoute.IParameter[]): string {
|
|
311
|
-
return parameters
|
|
312
|
-
.map((param) =>
|
|
313
|
-
param.name === param.field
|
|
314
|
-
? param.name
|
|
315
|
-
: `${
|
|
316
|
-
Escaper.variable(param.field!)
|
|
317
|
-
? param.field
|
|
318
|
-
: JSON.stringify(param.field)
|
|
319
|
-
}: ${param.name}`,
|
|
320
|
-
)
|
|
321
|
-
.join(`,\n${" ".repeat(12)}`);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
1
|
+
import { Vector } from "tstl/container/Vector";
|
|
2
|
+
import { Pair } from "tstl/utility/Pair";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
|
|
5
|
+
import { Escaper } from "typia/lib/utils/Escaper";
|
|
6
|
+
|
|
7
|
+
import { INestiaConfig } from "../INestiaConfig";
|
|
8
|
+
import { IRoute } from "../structures/IRoute";
|
|
9
|
+
|
|
10
|
+
export namespace FunctionGenerator {
|
|
11
|
+
export function generate(config: INestiaConfig, route: IRoute): string {
|
|
12
|
+
const query: IRoute.IParameter | undefined = route.parameters.find(
|
|
13
|
+
(param) => param.category === "query" && param.field === undefined,
|
|
14
|
+
);
|
|
15
|
+
const input: IRoute.IParameter | undefined = route.parameters.find(
|
|
16
|
+
(param) => param.category === "body",
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
return [head, body, tail]
|
|
20
|
+
.map((closure) => closure(route, query, input, config))
|
|
21
|
+
.filter((str) => !!str)
|
|
22
|
+
.join("\n");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* ---------------------------------------------------------
|
|
26
|
+
BODY
|
|
27
|
+
--------------------------------------------------------- */
|
|
28
|
+
function body(
|
|
29
|
+
route: IRoute,
|
|
30
|
+
query: IRoute.IParameter | undefined,
|
|
31
|
+
input: IRoute.IParameter | undefined,
|
|
32
|
+
config: INestiaConfig,
|
|
33
|
+
): string {
|
|
34
|
+
// FETCH ARGUMENTS WITH REQUST BODY
|
|
35
|
+
const parameters = filter_parameters(route, query);
|
|
36
|
+
const fetchArguments: string[] = [
|
|
37
|
+
"connection",
|
|
38
|
+
`${route.name}.ENCRYPTED`,
|
|
39
|
+
`${route.name}.METHOD`,
|
|
40
|
+
`${route.name}.path(${parameters.map((p) => p.name).join(", ")})`,
|
|
41
|
+
];
|
|
42
|
+
if (input !== undefined) {
|
|
43
|
+
fetchArguments.push(input.name);
|
|
44
|
+
if (config.json === true)
|
|
45
|
+
fetchArguments.push(`${route.name}.stringify`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const assertions: string =
|
|
49
|
+
config.assert === true && route.parameters.length !== 0
|
|
50
|
+
? route.parameters
|
|
51
|
+
.map(
|
|
52
|
+
(param) =>
|
|
53
|
+
` typia.assert<typeof ${param.name}>(${param.name});`,
|
|
54
|
+
)
|
|
55
|
+
.join("\n") + "\n\n"
|
|
56
|
+
: "";
|
|
57
|
+
|
|
58
|
+
// FUNCTION CALL STATEMENT
|
|
59
|
+
const caller: string =
|
|
60
|
+
"Fetcher.fetch\n" +
|
|
61
|
+
" (\n" +
|
|
62
|
+
fetchArguments.map((param) => ` ${param}`).join(",\n") +
|
|
63
|
+
"\n" +
|
|
64
|
+
" )";
|
|
65
|
+
if (route.setHeaders.length === 0)
|
|
66
|
+
return `{\n${assertions} return ${caller};\n}`;
|
|
67
|
+
|
|
68
|
+
// SET HEADERS
|
|
69
|
+
const content: string[] = [
|
|
70
|
+
`{\n`,
|
|
71
|
+
assertions,
|
|
72
|
+
` const output: ${route.name}.Output = await ${caller};\n`,
|
|
73
|
+
"\n",
|
|
74
|
+
` // configure header(s)\n`,
|
|
75
|
+
` connection.headers ??= {};\n`,
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
for (const header of route.setHeaders) {
|
|
79
|
+
if (header.type === "assigner")
|
|
80
|
+
content.push(
|
|
81
|
+
" ",
|
|
82
|
+
`Object.assign(connection.headers, ${access(
|
|
83
|
+
"output",
|
|
84
|
+
header.source,
|
|
85
|
+
)});\n`,
|
|
86
|
+
);
|
|
87
|
+
else
|
|
88
|
+
content.push(
|
|
89
|
+
" ",
|
|
90
|
+
`${access(
|
|
91
|
+
"connection.headers",
|
|
92
|
+
header.target ?? header.source,
|
|
93
|
+
)} = ${access("output", header.source)};\n`,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
content.push("\n", " return output;\n", "}");
|
|
97
|
+
return content.join("");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function filter_parameters(
|
|
101
|
+
route: IRoute,
|
|
102
|
+
query: IRoute.IParameter | undefined,
|
|
103
|
+
): IRoute.IParameter[] {
|
|
104
|
+
const parameters: IRoute.IParameter[] = route.parameters.filter(
|
|
105
|
+
(param) =>
|
|
106
|
+
param.category === "param" ||
|
|
107
|
+
(param.category === "query" && param.field !== undefined),
|
|
108
|
+
);
|
|
109
|
+
if (query) parameters.push(query);
|
|
110
|
+
return parameters;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function access(x: string, y: string): string {
|
|
114
|
+
return y[0] === "[" ? `${x}${y}` : `${x}.${y}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* ---------------------------------------------------------
|
|
118
|
+
HEAD & TAIL
|
|
119
|
+
--------------------------------------------------------- */
|
|
120
|
+
function head(
|
|
121
|
+
route: IRoute,
|
|
122
|
+
query: IRoute.IParameter | undefined,
|
|
123
|
+
input: IRoute.IParameter | undefined,
|
|
124
|
+
config: INestiaConfig,
|
|
125
|
+
): string {
|
|
126
|
+
//----
|
|
127
|
+
// CONSTRUCT COMMENT
|
|
128
|
+
//----
|
|
129
|
+
// MAIN DESCRIPTION
|
|
130
|
+
const comments: string[] = route.comments
|
|
131
|
+
.map((part) => `${part.kind === "linkText" ? " " : ""}${part.text}`)
|
|
132
|
+
.map((str) => str.split("\r\n").join("\n"))
|
|
133
|
+
.join("")
|
|
134
|
+
.split("\n")
|
|
135
|
+
.filter((str, i, array) => str !== "" || i !== array.length - 1);
|
|
136
|
+
if (comments.length) comments.push("");
|
|
137
|
+
|
|
138
|
+
// FILTER TAGS (VULNERABLE PARAMETERS WOULD BE REMOVED)
|
|
139
|
+
const tagList: ts.JSDocTagInfo[] = route.tags.filter(
|
|
140
|
+
(tag) => tag.text !== undefined,
|
|
141
|
+
);
|
|
142
|
+
if (tagList.length !== 0) {
|
|
143
|
+
const index: number = tagList.findIndex((t) => t.name === "param");
|
|
144
|
+
if (index !== -1) {
|
|
145
|
+
const capsule: Vector<ts.JSDocTagInfo> = Vector.wrap(tagList);
|
|
146
|
+
capsule.insert(capsule.nth(index), {
|
|
147
|
+
name: "param",
|
|
148
|
+
text: [
|
|
149
|
+
{
|
|
150
|
+
kind: "parameterName",
|
|
151
|
+
text: "connection",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
kind: "space",
|
|
155
|
+
text: " ",
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
kind: "text",
|
|
159
|
+
text: "connection Information of the remote HTTP(s) server with headers (+encryption password)",
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
comments.push(
|
|
165
|
+
...tagList.map(
|
|
166
|
+
(tag) =>
|
|
167
|
+
`@${tag.name} ${tag
|
|
168
|
+
.text!.map((elem) => elem.text)
|
|
169
|
+
.join("")}`,
|
|
170
|
+
),
|
|
171
|
+
"",
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// COMPLETE THE COMMENT
|
|
176
|
+
comments.push(
|
|
177
|
+
`@controller ${route.symbol}`,
|
|
178
|
+
`@path ${route.method} ${route.path}`,
|
|
179
|
+
`@nestia Generated by Nestia - https://github.com/samchon/nestia`,
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
//----
|
|
183
|
+
// FINALIZATION
|
|
184
|
+
//----
|
|
185
|
+
// REFORM PARAMETERS TEXT
|
|
186
|
+
const parameters: string[] = [
|
|
187
|
+
"connection: IConnection",
|
|
188
|
+
...route.parameters.map((param) => {
|
|
189
|
+
const type: string =
|
|
190
|
+
config.primitive !== false &&
|
|
191
|
+
(param === query || param === input)
|
|
192
|
+
? `Primitive<${route.name}.${
|
|
193
|
+
param === query ? "Query" : "Input"
|
|
194
|
+
}>`
|
|
195
|
+
: param.type.name;
|
|
196
|
+
return `${param.name}: ${type}`;
|
|
197
|
+
}),
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
// OUTPUT TYPE
|
|
201
|
+
const output: string =
|
|
202
|
+
route.output.name === "void" ? "void" : `${route.name}.Output`;
|
|
203
|
+
|
|
204
|
+
// RETURNS WITH CONSTRUCTION
|
|
205
|
+
return (
|
|
206
|
+
"" +
|
|
207
|
+
"/**\n" +
|
|
208
|
+
comments.map((str) => ` * ${str}`).join("\n") +
|
|
209
|
+
"\n" +
|
|
210
|
+
" */\n" +
|
|
211
|
+
`export${route.setHeaders.length ? " async" : ""} function ${
|
|
212
|
+
route.name
|
|
213
|
+
}\n` +
|
|
214
|
+
` (\n` +
|
|
215
|
+
`${parameters.map((str) => ` ${str}`).join(",\n")}\n` +
|
|
216
|
+
` ): Promise<${output}>`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function tail(
|
|
221
|
+
route: IRoute,
|
|
222
|
+
query: IRoute.IParameter | undefined,
|
|
223
|
+
input: IRoute.IParameter | undefined,
|
|
224
|
+
config: INestiaConfig,
|
|
225
|
+
): string | null {
|
|
226
|
+
// LIST UP TYPES
|
|
227
|
+
const types: Pair<string, string>[] = [];
|
|
228
|
+
if (query !== undefined) types.push(new Pair("Query", query.type.name));
|
|
229
|
+
if (input !== undefined) types.push(new Pair("Input", input.type.name));
|
|
230
|
+
if (route.output.name !== "void")
|
|
231
|
+
types.push(new Pair("Output", route.output.name));
|
|
232
|
+
|
|
233
|
+
// PATH WITH PARAMETERS
|
|
234
|
+
const parameters: IRoute.IParameter[] = filter_parameters(route, query);
|
|
235
|
+
const path: string = compute_path(query, parameters, route.path);
|
|
236
|
+
|
|
237
|
+
return (
|
|
238
|
+
`export namespace ${route.name}\n` +
|
|
239
|
+
"{\n" +
|
|
240
|
+
(types.length !== 0
|
|
241
|
+
? types
|
|
242
|
+
.map(
|
|
243
|
+
(tuple) =>
|
|
244
|
+
` export type ${tuple.first} = ${
|
|
245
|
+
config.primitive !== false
|
|
246
|
+
? `Primitive<${tuple.second}>`
|
|
247
|
+
: tuple.second
|
|
248
|
+
};`,
|
|
249
|
+
)
|
|
250
|
+
.join("\n") + "\n"
|
|
251
|
+
: "") +
|
|
252
|
+
"\n" +
|
|
253
|
+
` export const METHOD = "${route.method}" as const;\n` +
|
|
254
|
+
` export const PATH: string = "${route.path}";\n` +
|
|
255
|
+
` export const ENCRYPTED: Fetcher.IEncrypted = {\n` +
|
|
256
|
+
` request: ${input !== undefined && input.encrypted},\n` +
|
|
257
|
+
` response: ${route.encrypted},\n` +
|
|
258
|
+
` };\n` +
|
|
259
|
+
"\n" +
|
|
260
|
+
` export function path(${parameters
|
|
261
|
+
.map((param) => `${param.name}: ${param.type.name}`)
|
|
262
|
+
.join(", ")}): string\n` +
|
|
263
|
+
` {\n` +
|
|
264
|
+
` return ${path};\n` +
|
|
265
|
+
` }\n` +
|
|
266
|
+
(config.json === true &&
|
|
267
|
+
(route.method === "POST" ||
|
|
268
|
+
route.method === "PUT" ||
|
|
269
|
+
route.method === "PATCH")
|
|
270
|
+
? ` export const stringify = (input: Input) => typia.assertStringify(input);\n`
|
|
271
|
+
: "") +
|
|
272
|
+
"}"
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function compute_path(
|
|
277
|
+
query: IRoute.IParameter | undefined,
|
|
278
|
+
parameters: IRoute.IParameter[],
|
|
279
|
+
path: string,
|
|
280
|
+
): string {
|
|
281
|
+
for (const param of parameters)
|
|
282
|
+
if (param.category === "param")
|
|
283
|
+
path = path.replace(
|
|
284
|
+
`:${param.field}`,
|
|
285
|
+
`\${encodeURIComponent(${param.name})}`,
|
|
286
|
+
);
|
|
287
|
+
const queryParams: IRoute.IParameter[] = parameters.filter(
|
|
288
|
+
(param) => param.category === "query" && param.field !== undefined,
|
|
289
|
+
);
|
|
290
|
+
if (query === undefined && queryParams.length === 0)
|
|
291
|
+
return `\`${path}\``;
|
|
292
|
+
|
|
293
|
+
const wrapper = (str: string) =>
|
|
294
|
+
`\`${path}?\${new URLSearchParams(${str}).toString()}\``;
|
|
295
|
+
if (query !== undefined && queryParams.length === 0)
|
|
296
|
+
return wrapper(`${query.name} as any`);
|
|
297
|
+
else if (query === undefined)
|
|
298
|
+
return wrapper(`
|
|
299
|
+
{
|
|
300
|
+
${rest_query_parameters(queryParams)}
|
|
301
|
+
} as any`);
|
|
302
|
+
|
|
303
|
+
return wrapper(`
|
|
304
|
+
{
|
|
305
|
+
...${query.name},
|
|
306
|
+
${rest_query_parameters(queryParams)},
|
|
307
|
+
} as any`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function rest_query_parameters(parameters: IRoute.IParameter[]): string {
|
|
311
|
+
return parameters
|
|
312
|
+
.map((param) =>
|
|
313
|
+
param.name === param.field
|
|
314
|
+
? param.name
|
|
315
|
+
: `${
|
|
316
|
+
Escaper.variable(param.field!)
|
|
317
|
+
? param.field
|
|
318
|
+
: JSON.stringify(param.field)
|
|
319
|
+
}: ${param.name}`,
|
|
320
|
+
)
|
|
321
|
+
.join(`,\n${" ".repeat(12)}`);
|
|
322
|
+
}
|
|
323
|
+
}
|