create-swagger-client 0.1.3 → 0.1.5
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/LICENSE +21 -0
- package/index.mjs +71 -61
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Cuong Nguyen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/index.mjs
CHANGED
|
@@ -20,67 +20,76 @@ var isUrl = (str) => {
|
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
async function generate() {
|
|
23
|
-
if (!source)
|
|
24
|
-
return;
|
|
23
|
+
if (!source) return;
|
|
25
24
|
if (isUrl(source) === false) {
|
|
26
25
|
source = resolve(process.cwd(), source);
|
|
27
26
|
}
|
|
28
27
|
const spinner = ora(`Generating API client from ${source}...`).start();
|
|
29
28
|
const ast = await openapiTS(source);
|
|
30
29
|
const contents = astToString(ast);
|
|
31
|
-
const project = new tsMorph.Project;
|
|
32
|
-
const sourceFile = project.createSourceFile(
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
const project = new tsMorph.Project();
|
|
31
|
+
const sourceFile = project.createSourceFile(
|
|
32
|
+
resolve(process.cwd(), outPut),
|
|
33
|
+
contents,
|
|
34
|
+
{
|
|
35
|
+
overwrite: true,
|
|
36
|
+
},
|
|
37
|
+
);
|
|
35
38
|
sourceFile.addTypeAlias({
|
|
36
39
|
name: "RestMethod",
|
|
37
40
|
isExported: true,
|
|
38
|
-
type: '"get" | "post" | "put" | "delete" | "patch"'
|
|
41
|
+
type: '"get" | "post" | "put" | "delete" | "patch"',
|
|
39
42
|
});
|
|
40
43
|
sourceFile.addTypeAlias({
|
|
41
44
|
name: "KeyPaths",
|
|
42
45
|
isExported: true,
|
|
43
|
-
type: "keyof paths"
|
|
46
|
+
type: "keyof paths",
|
|
44
47
|
});
|
|
45
48
|
sourceFile.addTypeAlias({
|
|
46
49
|
name: "ExtractPathParams",
|
|
47
50
|
isExported: true,
|
|
48
|
-
typeParameters: ["
|
|
49
|
-
type: "paths[
|
|
51
|
+
typeParameters: ["K extends KeyPaths", "M extends RestMethod"],
|
|
52
|
+
type: "paths[K][M] extends { parameters: { path?: infer P } } ? P : never",
|
|
50
53
|
});
|
|
51
54
|
sourceFile.addTypeAlias({
|
|
52
55
|
name: "ExtractQueryParams",
|
|
53
56
|
isExported: true,
|
|
54
|
-
typeParameters: ["
|
|
55
|
-
type: "paths[
|
|
57
|
+
typeParameters: ["K extends KeyPaths", "M extends RestMethod"],
|
|
58
|
+
type: "paths[K][M] extends { parameters: { query?: infer Q } } ? Q : never",
|
|
56
59
|
});
|
|
57
60
|
sourceFile.addTypeAlias({
|
|
58
61
|
name: "ExtractHeaderParams",
|
|
59
62
|
isExported: true,
|
|
60
|
-
typeParameters: ["
|
|
61
|
-
type: "paths[
|
|
63
|
+
typeParameters: ["K extends KeyPaths", "M extends RestMethod"],
|
|
64
|
+
type: "paths[K][M] extends { parameters: { header?: infer H } } ? H : never",
|
|
62
65
|
});
|
|
63
66
|
sourceFile.addTypeAlias({
|
|
64
67
|
name: "ExtractBody",
|
|
65
68
|
isExported: true,
|
|
66
|
-
typeParameters: ["
|
|
67
|
-
type: `paths[
|
|
69
|
+
typeParameters: ["K extends KeyPaths", "M extends RestMethod"],
|
|
70
|
+
type: `paths[K][M] extends {
|
|
68
71
|
requestBody: { content: { "application/json": infer B } };
|
|
69
72
|
}
|
|
70
73
|
? B
|
|
71
|
-
: never
|
|
74
|
+
: never`,
|
|
72
75
|
});
|
|
73
76
|
sourceFile.addTypeAlias({
|
|
74
77
|
name: "APIResponse",
|
|
75
78
|
isExported: true,
|
|
76
|
-
typeParameters: ["
|
|
77
|
-
type: `paths[
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
typeParameters: ["K extends KeyPaths", "M extends RestMethod"],
|
|
80
|
+
type: `paths[K][M] extends { responses: infer R }
|
|
81
|
+
? R extends {
|
|
82
|
+
content: { "application/json": infer C };
|
|
83
|
+
}
|
|
84
|
+
? C
|
|
85
|
+
: R extends {
|
|
86
|
+
[status: number]: infer S;
|
|
87
|
+
}
|
|
88
|
+
? S extends { content: { "application/json": infer C } }
|
|
89
|
+
? C
|
|
90
|
+
: never
|
|
91
|
+
: never
|
|
92
|
+
: never;`,
|
|
84
93
|
});
|
|
85
94
|
sourceFile.addTypeAlias({
|
|
86
95
|
name: "ApiPayload",
|
|
@@ -91,7 +100,7 @@ async function generate() {
|
|
|
91
100
|
query?: ExtractQueryParams<T, K>;
|
|
92
101
|
body?: K extends "post" | "put" | "patch" ? ExtractBody<T, K> : never;
|
|
93
102
|
headers?: ExtractHeaderParams<T, K>;
|
|
94
|
-
}
|
|
103
|
+
}`,
|
|
95
104
|
});
|
|
96
105
|
sourceFile.addTypeAlias({
|
|
97
106
|
name: "ApiClientType",
|
|
@@ -101,14 +110,14 @@ async function generate() {
|
|
|
101
110
|
path: T,
|
|
102
111
|
payload?: ApiPayload<T, K>,
|
|
103
112
|
) => Promise<APIResponse<T, K>>;
|
|
104
|
-
}
|
|
113
|
+
}`,
|
|
105
114
|
});
|
|
106
115
|
sourceFile.addTypeAlias({
|
|
107
116
|
name: "TypePaths",
|
|
108
117
|
typeParameters: ["T extends RestMethod"],
|
|
109
118
|
type: `{
|
|
110
119
|
[K in KeyPaths]: paths[K] extends { [M in T]: unknown } ? K : never;
|
|
111
|
-
}[KeyPaths]
|
|
120
|
+
}[KeyPaths]`,
|
|
112
121
|
});
|
|
113
122
|
sourceFile.addClass({
|
|
114
123
|
name: "RestApiClient",
|
|
@@ -121,10 +130,10 @@ async function generate() {
|
|
|
121
130
|
name: "option",
|
|
122
131
|
type: "RequestInit",
|
|
123
132
|
hasQuestionToken: true,
|
|
124
|
-
scope: tsMorph.Scope.Private
|
|
125
|
-
}
|
|
126
|
-
]
|
|
127
|
-
}
|
|
133
|
+
scope: tsMorph.Scope.Private,
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
},
|
|
128
137
|
],
|
|
129
138
|
methods: [
|
|
130
139
|
{
|
|
@@ -133,7 +142,7 @@ async function generate() {
|
|
|
133
142
|
isAsync: true,
|
|
134
143
|
parameters: [
|
|
135
144
|
{ name: "input", type: "RequestInfo" },
|
|
136
|
-
{ name: "init", type: "RequestInit", hasQuestionToken: true }
|
|
145
|
+
{ name: "init", type: "RequestInit", hasQuestionToken: true },
|
|
137
146
|
],
|
|
138
147
|
statements: `const headers = {
|
|
139
148
|
"Content-Type": "application/json",
|
|
@@ -147,7 +156,7 @@ async function generate() {
|
|
|
147
156
|
\`API request failed: \${response.status} \${response.statusText} - \${errorBody}\`,
|
|
148
157
|
);
|
|
149
158
|
}
|
|
150
|
-
return response.json()
|
|
159
|
+
return response.json();`,
|
|
151
160
|
},
|
|
152
161
|
{
|
|
153
162
|
name: "request",
|
|
@@ -158,8 +167,8 @@ async function generate() {
|
|
|
158
167
|
{
|
|
159
168
|
name: "init",
|
|
160
169
|
type: "ApiPayload<P, M>",
|
|
161
|
-
initializer: "{} as ApiPayload<P, M>"
|
|
162
|
-
}
|
|
170
|
+
initializer: "{} as ApiPayload<P, M>",
|
|
171
|
+
},
|
|
163
172
|
],
|
|
164
173
|
returnType: "Promise<APIResponse<P, M>>",
|
|
165
174
|
statements: `const url = new URL(this.basePath + String(path));
|
|
@@ -179,7 +188,7 @@ async function generate() {
|
|
|
179
188
|
|
|
180
189
|
return this.fetcher(url.toString(), requestInit) as Promise<
|
|
181
190
|
APIResponse<P, M>
|
|
182
|
-
|
|
191
|
+
>;`,
|
|
183
192
|
},
|
|
184
193
|
{
|
|
185
194
|
name: "get",
|
|
@@ -190,11 +199,11 @@ async function generate() {
|
|
|
190
199
|
{
|
|
191
200
|
name: "payload",
|
|
192
201
|
type: 'ApiPayload<T, "get">',
|
|
193
|
-
hasQuestionToken: true
|
|
194
|
-
}
|
|
202
|
+
hasQuestionToken: true,
|
|
203
|
+
},
|
|
195
204
|
],
|
|
196
205
|
returnType: 'Promise<APIResponse<T, "get">>',
|
|
197
|
-
statements: 'return this.request("get", path, payload);'
|
|
206
|
+
statements: 'return this.request("get", path, payload);',
|
|
198
207
|
},
|
|
199
208
|
{
|
|
200
209
|
name: "post",
|
|
@@ -205,11 +214,11 @@ async function generate() {
|
|
|
205
214
|
{
|
|
206
215
|
name: "payload",
|
|
207
216
|
type: 'ApiPayload<T, "post">',
|
|
208
|
-
hasQuestionToken: true
|
|
209
|
-
}
|
|
217
|
+
hasQuestionToken: true,
|
|
218
|
+
},
|
|
210
219
|
],
|
|
211
220
|
returnType: 'Promise<APIResponse<T, "post">>',
|
|
212
|
-
statements: 'return this.request("post", path, payload);'
|
|
221
|
+
statements: 'return this.request("post", path, payload);',
|
|
213
222
|
},
|
|
214
223
|
{
|
|
215
224
|
name: "put",
|
|
@@ -220,11 +229,11 @@ async function generate() {
|
|
|
220
229
|
{
|
|
221
230
|
name: "payload",
|
|
222
231
|
type: 'ApiPayload<T, "put">',
|
|
223
|
-
hasQuestionToken: true
|
|
224
|
-
}
|
|
232
|
+
hasQuestionToken: true,
|
|
233
|
+
},
|
|
225
234
|
],
|
|
226
235
|
returnType: 'Promise<APIResponse<T, "put">>',
|
|
227
|
-
statements: 'return this.request("put", path, payload);'
|
|
236
|
+
statements: 'return this.request("put", path, payload);',
|
|
228
237
|
},
|
|
229
238
|
{
|
|
230
239
|
name: "delete",
|
|
@@ -235,11 +244,11 @@ async function generate() {
|
|
|
235
244
|
{
|
|
236
245
|
name: "payload",
|
|
237
246
|
type: 'ApiPayload<T, "delete">',
|
|
238
|
-
hasQuestionToken: true
|
|
239
|
-
}
|
|
247
|
+
hasQuestionToken: true,
|
|
248
|
+
},
|
|
240
249
|
],
|
|
241
250
|
returnType: 'Promise<APIResponse<T, "delete">>',
|
|
242
|
-
statements: 'return this.request("delete", path, payload);'
|
|
251
|
+
statements: 'return this.request("delete", path, payload);',
|
|
243
252
|
},
|
|
244
253
|
{
|
|
245
254
|
name: "patch",
|
|
@@ -250,18 +259,18 @@ async function generate() {
|
|
|
250
259
|
{
|
|
251
260
|
name: "payload",
|
|
252
261
|
type: 'ApiPayload<T, "patch">',
|
|
253
|
-
hasQuestionToken: true
|
|
254
|
-
}
|
|
262
|
+
hasQuestionToken: true,
|
|
263
|
+
},
|
|
255
264
|
],
|
|
256
265
|
returnType: 'Promise<APIResponse<T, "patch">>',
|
|
257
|
-
statements: 'return this.request("patch", path, payload);'
|
|
266
|
+
statements: 'return this.request("patch", path, payload);',
|
|
258
267
|
},
|
|
259
268
|
{
|
|
260
269
|
name: "buildPathUrl",
|
|
261
270
|
scope: tsMorph.Scope.Private,
|
|
262
271
|
parameters: [
|
|
263
272
|
{ name: "basePath", type: "string" },
|
|
264
|
-
{ name: "pathParams", type: "unknown", hasQuestionToken: true }
|
|
273
|
+
{ name: "pathParams", type: "unknown", hasQuestionToken: true },
|
|
265
274
|
],
|
|
266
275
|
returnType: "string",
|
|
267
276
|
statements: `let pathname = basePath;
|
|
@@ -271,27 +280,27 @@ async function generate() {
|
|
|
271
280
|
encodeURIComponent(String(params[key])),
|
|
272
281
|
);
|
|
273
282
|
}
|
|
274
|
-
return pathname
|
|
283
|
+
return pathname;`,
|
|
275
284
|
},
|
|
276
285
|
{
|
|
277
286
|
name: "prepareBody",
|
|
278
287
|
scope: tsMorph.Scope.Private,
|
|
279
288
|
parameters: [
|
|
280
289
|
{ name: "method", type: "RestMethod" },
|
|
281
|
-
{ name: "body", type: "unknown", hasQuestionToken: true }
|
|
290
|
+
{ name: "body", type: "unknown", hasQuestionToken: true },
|
|
282
291
|
],
|
|
283
292
|
returnType: "string | undefined",
|
|
284
293
|
statements: `if (body && ["post", "put", "patch"].includes(method)) {
|
|
285
294
|
return JSON.stringify(body);
|
|
286
295
|
}
|
|
287
|
-
return undefined
|
|
296
|
+
return undefined;`,
|
|
288
297
|
},
|
|
289
298
|
{
|
|
290
299
|
name: "appendQueryParams",
|
|
291
300
|
scope: tsMorph.Scope.Private,
|
|
292
301
|
parameters: [
|
|
293
302
|
{ name: "url", type: "URL" },
|
|
294
|
-
{ name: "queryParams", type: "unknown", hasQuestionToken: true }
|
|
303
|
+
{ name: "queryParams", type: "unknown", hasQuestionToken: true },
|
|
295
304
|
],
|
|
296
305
|
returnType: "void",
|
|
297
306
|
statements: `if (queryParams != null) {
|
|
@@ -301,15 +310,16 @@ async function generate() {
|
|
|
301
310
|
url.searchParams.append(key, String(value));
|
|
302
311
|
}
|
|
303
312
|
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
]
|
|
313
|
+
}`,
|
|
314
|
+
},
|
|
315
|
+
],
|
|
307
316
|
});
|
|
308
317
|
await sourceFile.formatText();
|
|
309
318
|
await project.save();
|
|
310
319
|
spinner.stopAndPersist({
|
|
311
320
|
symbol: "✔",
|
|
312
|
-
text: `API client generated at ${resolve(process.cwd(), outPut)}
|
|
321
|
+
text: `API client generated at ${resolve(process.cwd(), outPut)}`,
|
|
313
322
|
});
|
|
314
323
|
}
|
|
324
|
+
|
|
315
325
|
generate();
|