@bagelink/sdk 1.2.20 → 1.2.25
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/dist/index.cjs +153 -80
- package/dist/index.mjs +153 -80
- package/package.json +1 -1
- package/src/openAPITools/functionGenerator.ts +390 -162
- package/src/openAPITools/openApiTypes.ts +2 -0
package/dist/index.cjs
CHANGED
|
@@ -101,14 +101,15 @@ const primitiveTypes = [
|
|
|
101
101
|
"void",
|
|
102
102
|
"any",
|
|
103
103
|
"{ [key: string]: any }",
|
|
104
|
-
"undefined"
|
|
105
|
-
"{ [key: string]: any }"
|
|
104
|
+
"undefined"
|
|
106
105
|
];
|
|
106
|
+
const functionsInventory = {};
|
|
107
|
+
const pathOperations = [];
|
|
107
108
|
function collectTypeForImportStatement(typeName) {
|
|
108
109
|
typeName = typeName.trim().replace("[]", "");
|
|
109
110
|
if (typeName.includes("|")) {
|
|
110
111
|
typeName.split("|").forEach((singleType) => {
|
|
111
|
-
collectTypeForImportStatement(singleType);
|
|
112
|
+
collectTypeForImportStatement(singleType.trim());
|
|
112
113
|
});
|
|
113
114
|
return;
|
|
114
115
|
}
|
|
@@ -124,9 +125,8 @@ function schemaToTypeWithCollection(schema) {
|
|
|
124
125
|
}
|
|
125
126
|
function getResponseType(response) {
|
|
126
127
|
const mediaTypeObject = response.content?.["application/json"];
|
|
127
|
-
if (!mediaTypeObject
|
|
128
|
-
|
|
129
|
-
return responseType;
|
|
128
|
+
if (!mediaTypeObject?.schema) return void 0;
|
|
129
|
+
return schemaToTypeWithCollection(mediaTypeObject.schema);
|
|
130
130
|
}
|
|
131
131
|
function generateResponseType(responses) {
|
|
132
132
|
if (!responses) return "";
|
|
@@ -141,42 +141,14 @@ function generateResponseType(responses) {
|
|
|
141
141
|
}
|
|
142
142
|
return types.join(" | ");
|
|
143
143
|
}
|
|
144
|
-
function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
|
|
145
|
-
if (allParams === "undefined") allParams = "";
|
|
146
|
-
let axiosFunction = `async (${allParams})${responseTypeStr} => {`;
|
|
147
|
-
if (requestBodyPayload === "formData") {
|
|
148
|
-
const paramStr = parameters?.config?.params ? `params: {${parameters.config.params}}` : "";
|
|
149
|
-
if (allParams.includes("file: File")) {
|
|
150
|
-
axiosFunction += `
|
|
151
|
-
const formData = new FormData()
|
|
152
|
-
formData.append('upload', file)
|
|
153
|
-
return axios.${method}(${formattedPath}, formData, {
|
|
154
|
-
headers: { 'Content-Type': 'multipart/form-data' },
|
|
155
|
-
onUploadProgress: options?.onUploadProgress${paramStr ? `, ${paramStr}` : ""}
|
|
156
|
-
})`;
|
|
157
|
-
} else {
|
|
158
|
-
axiosFunction += `
|
|
159
|
-
return axios.${method}(${formattedPath}, formData, {
|
|
160
|
-
headers: { 'Content-Type': 'multipart/form-data' }${paramStr ? `, ${paramStr}` : ""}
|
|
161
|
-
})`;
|
|
162
|
-
}
|
|
163
|
-
} else {
|
|
164
|
-
const paramStr = parameters?.config?.params ? `, { params: {${parameters.config.params}} }` : "";
|
|
165
|
-
const bodyVar = requestBodyPayload ? `${requestBodyPayload}` : "{}";
|
|
166
|
-
axiosFunction += `return axios.${method}(${formattedPath}${["get", "delete"].includes(method) ? paramStr : `, ${bodyVar}${paramStr}`})`;
|
|
167
|
-
}
|
|
168
|
-
axiosFunction += "}";
|
|
169
|
-
return axiosFunction;
|
|
170
|
-
}
|
|
171
|
-
const pathParamRegex = /\{([^}]+)\}/g;
|
|
172
144
|
function getParamsFromPath(path) {
|
|
173
|
-
const
|
|
174
|
-
return
|
|
145
|
+
const pathParamRegex = /\{[^}]+\}/g;
|
|
146
|
+
return path.match(pathParamRegex)?.map((p) => p.slice(1, -1));
|
|
175
147
|
}
|
|
176
148
|
function formatPathWithParams(path) {
|
|
177
149
|
const params = getParamsFromPath(path);
|
|
178
|
-
|
|
179
|
-
return
|
|
150
|
+
if (!params) return `'${path}'`;
|
|
151
|
+
return `\`${path.replace(/\{([^}]+)\}/g, (_, paramName) => `\${${toCamelCase(paramName)}}`)}\``;
|
|
180
152
|
}
|
|
181
153
|
function generateRequestBody(requestBody) {
|
|
182
154
|
if (!requestBody?.content)
|
|
@@ -210,14 +182,6 @@ function generateRequestBody(requestBody) {
|
|
|
210
182
|
});
|
|
211
183
|
return { requestBodyParam, requestBodyPayload };
|
|
212
184
|
}
|
|
213
|
-
function combineAllParams(parameters, requestBodyParam) {
|
|
214
|
-
let allParamsArray = [];
|
|
215
|
-
if (parameters && parameters.params)
|
|
216
|
-
allParamsArray = parameters.params.split(",").map((p) => p.trim());
|
|
217
|
-
if (requestBodyParam) allParamsArray.push(requestBodyParam.trim());
|
|
218
|
-
allParamsArray = allParamsArray.filter((p) => p).sort((a, b) => (a.includes("?") ? 1 : -1) - (b.includes("?") ? 1 : -1));
|
|
219
|
-
return allParamsArray.join(", ");
|
|
220
|
-
}
|
|
221
185
|
function generateFunctionParameters(params, isFileUpload = false) {
|
|
222
186
|
if (!params?.length) return {};
|
|
223
187
|
if (isFileUpload) {
|
|
@@ -230,7 +194,7 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
230
194
|
};
|
|
231
195
|
}
|
|
232
196
|
const functionParams = [];
|
|
233
|
-
const
|
|
197
|
+
const queryParams = [];
|
|
234
198
|
for (const param of params) {
|
|
235
199
|
const paramType = schemaToType(param.schema);
|
|
236
200
|
collectTypeForImportStatement(paramType);
|
|
@@ -247,16 +211,53 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
247
211
|
);
|
|
248
212
|
}
|
|
249
213
|
if (param.in === "query" || param.in === "header") {
|
|
250
|
-
|
|
214
|
+
queryParams.push(
|
|
251
215
|
paramName === varName ? paramName : `'${paramName}': ${varName}`
|
|
252
216
|
);
|
|
253
217
|
}
|
|
254
218
|
}
|
|
255
219
|
return {
|
|
256
220
|
params: functionParams.join(", "),
|
|
257
|
-
config:
|
|
221
|
+
config: queryParams.length ? { params: queryParams.join(", ") } : void 0
|
|
258
222
|
};
|
|
259
223
|
}
|
|
224
|
+
function combineAllParams(parameters, requestBodyParam) {
|
|
225
|
+
let allParamsArray = [];
|
|
226
|
+
if (parameters.params) {
|
|
227
|
+
allParamsArray = parameters.params.split(",").map((p) => p.trim());
|
|
228
|
+
}
|
|
229
|
+
if (requestBodyParam) {
|
|
230
|
+
allParamsArray.push(requestBodyParam.trim());
|
|
231
|
+
}
|
|
232
|
+
return allParamsArray.filter(Boolean).sort((a, b) => (a.includes("?") ? 1 : -1) - (b.includes("?") ? 1 : -1)).join(", ");
|
|
233
|
+
}
|
|
234
|
+
function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
|
|
235
|
+
if (allParams === "undefined") allParams = "";
|
|
236
|
+
let axiosFunction = `async (${allParams})${responseTypeStr} => {`;
|
|
237
|
+
const paramStr = parameters.config?.params ? `params: {${parameters.config.params}}` : "";
|
|
238
|
+
if (requestBodyPayload === "formData") {
|
|
239
|
+
if (allParams.includes("file: File")) {
|
|
240
|
+
axiosFunction += `
|
|
241
|
+
const formData = new FormData()
|
|
242
|
+
formData.append('upload', file)
|
|
243
|
+
return axios.${method}(${formattedPath}, formData, {
|
|
244
|
+
headers: { 'Content-Type': 'multipart/form-data' },
|
|
245
|
+
onUploadProgress: options?.onUploadProgress${paramStr ? `, ${paramStr}` : ""}
|
|
246
|
+
})`;
|
|
247
|
+
} else {
|
|
248
|
+
axiosFunction += `
|
|
249
|
+
return axios.${method}(${formattedPath}, formData, {
|
|
250
|
+
headers: { 'Content-Type': 'multipart/form-data' }${paramStr ? `, ${paramStr}` : ""}
|
|
251
|
+
})`;
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
const configParams = paramStr ? `, { ${paramStr} }` : "";
|
|
255
|
+
const bodyVar = requestBodyPayload || "{}";
|
|
256
|
+
axiosFunction += `return axios.${method}(${formattedPath}${["get", "delete"].includes(method) ? configParams : `, ${bodyVar}${configParams}`})`;
|
|
257
|
+
}
|
|
258
|
+
axiosFunction += "}";
|
|
259
|
+
return axiosFunction;
|
|
260
|
+
}
|
|
260
261
|
function generateFunctionForOperation(method, path, operation) {
|
|
261
262
|
if (!operation) return "";
|
|
262
263
|
const isFileUpload = operation.requestBody?.content["multipart/form-data"]?.schema?.$ref?.includes("Body_upload_files");
|
|
@@ -270,7 +271,61 @@ function generateFunctionForOperation(method, path, operation) {
|
|
|
270
271
|
const allParams = isFileUpload ? "file: File, options?: UploadOptions & { dirPath?: string, tags?: string[] }" : combineAllParams(parameters, requestBodyParam);
|
|
271
272
|
const responseType = generateResponseType(operation.responses);
|
|
272
273
|
const responseTypeStr = responseType ? `: Promise<AxiosResponse<${responseType}>>` : "";
|
|
273
|
-
|
|
274
|
+
let functionComment = "/**\n";
|
|
275
|
+
if (operation.summary) {
|
|
276
|
+
functionComment += ` * ${operation.summary}
|
|
277
|
+
`;
|
|
278
|
+
}
|
|
279
|
+
if (operation.description) {
|
|
280
|
+
if (operation.summary) functionComment += ` *
|
|
281
|
+
`;
|
|
282
|
+
const descriptionLines = operation.description.split("\n");
|
|
283
|
+
descriptionLines.forEach((line) => {
|
|
284
|
+
functionComment += ` * ${line}
|
|
285
|
+
`;
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
functionComment += ` *
|
|
289
|
+
* @endpoint ${method.toUpperCase()} ${path}
|
|
290
|
+
`;
|
|
291
|
+
if (operation.parameters?.length) {
|
|
292
|
+
functionComment += " *\n";
|
|
293
|
+
operation.parameters.forEach((param) => {
|
|
294
|
+
const paramType = schemaToType(param.schema);
|
|
295
|
+
const paramName = toCamelCase(param.name);
|
|
296
|
+
const required = param.required ? "" : "?";
|
|
297
|
+
functionComment += ` * @param {${paramType}} ${paramName}${required}`;
|
|
298
|
+
if (param.description) {
|
|
299
|
+
functionComment += ` - ${param.description}`;
|
|
300
|
+
} else {
|
|
301
|
+
functionComment += ` - ${param.name} parameter`;
|
|
302
|
+
}
|
|
303
|
+
functionComment += "\n";
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
if (operation.requestBody && requestBodyParam) {
|
|
307
|
+
const bodyParamName = requestBodyParam.split(":")[0].trim();
|
|
308
|
+
const bodyParamType = requestBodyParam.split(":")[1]?.split("=")[0]?.trim() || "any";
|
|
309
|
+
functionComment += ` * @param {${bodyParamType}} ${bodyParamName}`;
|
|
310
|
+
if (operation.requestBody.description) {
|
|
311
|
+
functionComment += ` - ${operation.requestBody.description}`;
|
|
312
|
+
} else {
|
|
313
|
+
functionComment += ` - Request body`;
|
|
314
|
+
}
|
|
315
|
+
functionComment += "\n";
|
|
316
|
+
}
|
|
317
|
+
if (responseType) {
|
|
318
|
+
functionComment += ` * @returns {Promise<AxiosResponse<${responseType}>>} The API response
|
|
319
|
+
`;
|
|
320
|
+
for (const [statusCode, response] of Object.entries(operation.responses)) {
|
|
321
|
+
if (statusCode.startsWith("2") && response.description) {
|
|
322
|
+
functionComment += ` * @response ${statusCode} - ${response.description}
|
|
323
|
+
`;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
functionComment += " */\n";
|
|
328
|
+
return functionComment + generateAxiosFunction(
|
|
274
329
|
method,
|
|
275
330
|
formatPathWithParams(path),
|
|
276
331
|
allParams,
|
|
@@ -279,25 +334,6 @@ function generateFunctionForOperation(method, path, operation) {
|
|
|
279
334
|
requestBodyPayload
|
|
280
335
|
);
|
|
281
336
|
}
|
|
282
|
-
const generateRandomString = () => Math.random().toString(36).slice(7);
|
|
283
|
-
const DOUBLE_QUOTE_REGEX = /"([^"]+)":/g;
|
|
284
|
-
function fileTemplate(tsString, typeForImport, baseURL) {
|
|
285
|
-
const templateCode = `import ax from 'axios';
|
|
286
|
-
import type { AxiosResponse } from 'axios';
|
|
287
|
-
import type {${typeForImport.join(", ")}} from './types.d';
|
|
288
|
-
|
|
289
|
-
export interface UploadOptions {
|
|
290
|
-
onUploadProgress?: (progressEvent: any) => void
|
|
291
|
-
dirPath?: string
|
|
292
|
-
tags?: string[]
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
export const axios = ax.create({baseURL:${baseURL}, withCredentials: true});
|
|
296
|
-
${tsString}`;
|
|
297
|
-
return templateCode.replace(DOUBLE_QUOTE_REGEX, "$1:");
|
|
298
|
-
}
|
|
299
|
-
const functionsInventory = {};
|
|
300
|
-
const pathOperations = [];
|
|
301
337
|
function hasConflict(path, method) {
|
|
302
338
|
const cleanPathName = path.split("/").filter((p) => p && !/\{|\}/.test(p)).join("/");
|
|
303
339
|
const matchingPaths = pathOperations.filter(
|
|
@@ -306,13 +342,20 @@ function hasConflict(path, method) {
|
|
|
306
342
|
pathOperations.push({ path: cleanPathName, method });
|
|
307
343
|
return matchingPaths.length > 0;
|
|
308
344
|
}
|
|
345
|
+
function generateRandomString() {
|
|
346
|
+
return Math.random().toString(36).slice(7);
|
|
347
|
+
}
|
|
309
348
|
function createFunctionPlaceholder(path, method, operation) {
|
|
310
349
|
const funcID = generateRandomString();
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
350
|
+
if (operation) {
|
|
351
|
+
functionsInventory[funcID] = generateFunctionForOperation(
|
|
352
|
+
method,
|
|
353
|
+
path,
|
|
354
|
+
operation
|
|
355
|
+
);
|
|
356
|
+
} else {
|
|
357
|
+
functionsInventory[funcID] = "";
|
|
358
|
+
}
|
|
316
359
|
return funcID;
|
|
317
360
|
}
|
|
318
361
|
function handlePathSegment(path, operation, existingObj = {}) {
|
|
@@ -333,7 +376,6 @@ function handlePathSegment(path, operation, existingObj = {}) {
|
|
|
333
376
|
return { ...obj, ...existingObj };
|
|
334
377
|
}
|
|
335
378
|
function generateFunctions(paths, baseUrl) {
|
|
336
|
-
let tsString = "";
|
|
337
379
|
const body = {};
|
|
338
380
|
const allPathsClean = Object.keys(paths).map(cleanPath);
|
|
339
381
|
for (const [path, operation] of Object.entries(paths)) {
|
|
@@ -344,8 +386,8 @@ function generateFunctions(paths, baseUrl) {
|
|
|
344
386
|
const methods = Object.keys(operation);
|
|
345
387
|
if (index === array.length - 1 && methods.length === 1 && allPathsClean.filter((p) => p === cleanPath(path)).length === 1) {
|
|
346
388
|
const method = methods[0];
|
|
347
|
-
const opp =
|
|
348
|
-
acc[objFuncKey] = createFunctionPlaceholder(path,
|
|
389
|
+
const opp = operation[method];
|
|
390
|
+
acc[objFuncKey] = createFunctionPlaceholder(path, method, opp);
|
|
349
391
|
} else if (index === array.length - 1) {
|
|
350
392
|
acc[objFuncKey] = handlePathSegment(path, operation, acc[objFuncKey]);
|
|
351
393
|
} else if (!acc[objFuncKey] || typeof acc[objFuncKey] !== "object") {
|
|
@@ -354,15 +396,46 @@ function generateFunctions(paths, baseUrl) {
|
|
|
354
396
|
return acc[objFuncKey];
|
|
355
397
|
}, body);
|
|
356
398
|
}
|
|
399
|
+
let tsString = "";
|
|
357
400
|
for (const [parent, object] of Object.entries(body)) {
|
|
358
|
-
tsString += `
|
|
401
|
+
tsString += `
|
|
402
|
+
/**
|
|
403
|
+
* API functions for ${parent} endpoints
|
|
404
|
+
*/
|
|
405
|
+
export const ${parent} = ${JSON.stringify(object, void 0, 2)};
|
|
359
406
|
`;
|
|
360
407
|
}
|
|
361
408
|
Object.entries(functionsInventory).forEach(([key, value]) => {
|
|
362
409
|
tsString = tsString.replace(`"${key}"`, value);
|
|
363
410
|
});
|
|
364
|
-
|
|
365
|
-
|
|
411
|
+
return fileTemplate(tsString, allTypes, baseUrl);
|
|
412
|
+
}
|
|
413
|
+
function fileTemplate(tsString, typeForImport, baseURL) {
|
|
414
|
+
const templateCode = `import ax from 'axios';
|
|
415
|
+
import type { AxiosResponse } from 'axios';
|
|
416
|
+
import type { ${typeForImport.join(", ")} } from './types.d';
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Options for file upload operations
|
|
420
|
+
*/
|
|
421
|
+
export interface UploadOptions {
|
|
422
|
+
/** Progress callback for upload operations */
|
|
423
|
+
onUploadProgress?: (progressEvent: any) => void
|
|
424
|
+
/** Directory path for the uploaded file */
|
|
425
|
+
dirPath?: string
|
|
426
|
+
/** Tags to associate with the uploaded file */
|
|
427
|
+
tags?: string[]
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Configured axios instance for API requests
|
|
432
|
+
* @example
|
|
433
|
+
* // Making a direct request with the axios instance
|
|
434
|
+
* const response = await axios.get('/some-endpoint');
|
|
435
|
+
*/
|
|
436
|
+
export const axios = ax.create({baseURL: ${baseURL}, withCredentials: true});
|
|
437
|
+
${tsString}`;
|
|
438
|
+
return templateCode.replace(/"([^"]+)":/g, "$1:");
|
|
366
439
|
}
|
|
367
440
|
|
|
368
441
|
function generateTypes(schemas) {
|
package/dist/index.mjs
CHANGED
|
@@ -95,14 +95,15 @@ const primitiveTypes = [
|
|
|
95
95
|
"void",
|
|
96
96
|
"any",
|
|
97
97
|
"{ [key: string]: any }",
|
|
98
|
-
"undefined"
|
|
99
|
-
"{ [key: string]: any }"
|
|
98
|
+
"undefined"
|
|
100
99
|
];
|
|
100
|
+
const functionsInventory = {};
|
|
101
|
+
const pathOperations = [];
|
|
101
102
|
function collectTypeForImportStatement(typeName) {
|
|
102
103
|
typeName = typeName.trim().replace("[]", "");
|
|
103
104
|
if (typeName.includes("|")) {
|
|
104
105
|
typeName.split("|").forEach((singleType) => {
|
|
105
|
-
collectTypeForImportStatement(singleType);
|
|
106
|
+
collectTypeForImportStatement(singleType.trim());
|
|
106
107
|
});
|
|
107
108
|
return;
|
|
108
109
|
}
|
|
@@ -118,9 +119,8 @@ function schemaToTypeWithCollection(schema) {
|
|
|
118
119
|
}
|
|
119
120
|
function getResponseType(response) {
|
|
120
121
|
const mediaTypeObject = response.content?.["application/json"];
|
|
121
|
-
if (!mediaTypeObject
|
|
122
|
-
|
|
123
|
-
return responseType;
|
|
122
|
+
if (!mediaTypeObject?.schema) return void 0;
|
|
123
|
+
return schemaToTypeWithCollection(mediaTypeObject.schema);
|
|
124
124
|
}
|
|
125
125
|
function generateResponseType(responses) {
|
|
126
126
|
if (!responses) return "";
|
|
@@ -135,42 +135,14 @@ function generateResponseType(responses) {
|
|
|
135
135
|
}
|
|
136
136
|
return types.join(" | ");
|
|
137
137
|
}
|
|
138
|
-
function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
|
|
139
|
-
if (allParams === "undefined") allParams = "";
|
|
140
|
-
let axiosFunction = `async (${allParams})${responseTypeStr} => {`;
|
|
141
|
-
if (requestBodyPayload === "formData") {
|
|
142
|
-
const paramStr = parameters?.config?.params ? `params: {${parameters.config.params}}` : "";
|
|
143
|
-
if (allParams.includes("file: File")) {
|
|
144
|
-
axiosFunction += `
|
|
145
|
-
const formData = new FormData()
|
|
146
|
-
formData.append('upload', file)
|
|
147
|
-
return axios.${method}(${formattedPath}, formData, {
|
|
148
|
-
headers: { 'Content-Type': 'multipart/form-data' },
|
|
149
|
-
onUploadProgress: options?.onUploadProgress${paramStr ? `, ${paramStr}` : ""}
|
|
150
|
-
})`;
|
|
151
|
-
} else {
|
|
152
|
-
axiosFunction += `
|
|
153
|
-
return axios.${method}(${formattedPath}, formData, {
|
|
154
|
-
headers: { 'Content-Type': 'multipart/form-data' }${paramStr ? `, ${paramStr}` : ""}
|
|
155
|
-
})`;
|
|
156
|
-
}
|
|
157
|
-
} else {
|
|
158
|
-
const paramStr = parameters?.config?.params ? `, { params: {${parameters.config.params}} }` : "";
|
|
159
|
-
const bodyVar = requestBodyPayload ? `${requestBodyPayload}` : "{}";
|
|
160
|
-
axiosFunction += `return axios.${method}(${formattedPath}${["get", "delete"].includes(method) ? paramStr : `, ${bodyVar}${paramStr}`})`;
|
|
161
|
-
}
|
|
162
|
-
axiosFunction += "}";
|
|
163
|
-
return axiosFunction;
|
|
164
|
-
}
|
|
165
|
-
const pathParamRegex = /\{([^}]+)\}/g;
|
|
166
138
|
function getParamsFromPath(path) {
|
|
167
|
-
const
|
|
168
|
-
return
|
|
139
|
+
const pathParamRegex = /\{[^}]+\}/g;
|
|
140
|
+
return path.match(pathParamRegex)?.map((p) => p.slice(1, -1));
|
|
169
141
|
}
|
|
170
142
|
function formatPathWithParams(path) {
|
|
171
143
|
const params = getParamsFromPath(path);
|
|
172
|
-
|
|
173
|
-
return
|
|
144
|
+
if (!params) return `'${path}'`;
|
|
145
|
+
return `\`${path.replace(/\{([^}]+)\}/g, (_, paramName) => `\${${toCamelCase(paramName)}}`)}\``;
|
|
174
146
|
}
|
|
175
147
|
function generateRequestBody(requestBody) {
|
|
176
148
|
if (!requestBody?.content)
|
|
@@ -204,14 +176,6 @@ function generateRequestBody(requestBody) {
|
|
|
204
176
|
});
|
|
205
177
|
return { requestBodyParam, requestBodyPayload };
|
|
206
178
|
}
|
|
207
|
-
function combineAllParams(parameters, requestBodyParam) {
|
|
208
|
-
let allParamsArray = [];
|
|
209
|
-
if (parameters && parameters.params)
|
|
210
|
-
allParamsArray = parameters.params.split(",").map((p) => p.trim());
|
|
211
|
-
if (requestBodyParam) allParamsArray.push(requestBodyParam.trim());
|
|
212
|
-
allParamsArray = allParamsArray.filter((p) => p).sort((a, b) => (a.includes("?") ? 1 : -1) - (b.includes("?") ? 1 : -1));
|
|
213
|
-
return allParamsArray.join(", ");
|
|
214
|
-
}
|
|
215
179
|
function generateFunctionParameters(params, isFileUpload = false) {
|
|
216
180
|
if (!params?.length) return {};
|
|
217
181
|
if (isFileUpload) {
|
|
@@ -224,7 +188,7 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
224
188
|
};
|
|
225
189
|
}
|
|
226
190
|
const functionParams = [];
|
|
227
|
-
const
|
|
191
|
+
const queryParams = [];
|
|
228
192
|
for (const param of params) {
|
|
229
193
|
const paramType = schemaToType(param.schema);
|
|
230
194
|
collectTypeForImportStatement(paramType);
|
|
@@ -241,16 +205,53 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
241
205
|
);
|
|
242
206
|
}
|
|
243
207
|
if (param.in === "query" || param.in === "header") {
|
|
244
|
-
|
|
208
|
+
queryParams.push(
|
|
245
209
|
paramName === varName ? paramName : `'${paramName}': ${varName}`
|
|
246
210
|
);
|
|
247
211
|
}
|
|
248
212
|
}
|
|
249
213
|
return {
|
|
250
214
|
params: functionParams.join(", "),
|
|
251
|
-
config:
|
|
215
|
+
config: queryParams.length ? { params: queryParams.join(", ") } : void 0
|
|
252
216
|
};
|
|
253
217
|
}
|
|
218
|
+
function combineAllParams(parameters, requestBodyParam) {
|
|
219
|
+
let allParamsArray = [];
|
|
220
|
+
if (parameters.params) {
|
|
221
|
+
allParamsArray = parameters.params.split(",").map((p) => p.trim());
|
|
222
|
+
}
|
|
223
|
+
if (requestBodyParam) {
|
|
224
|
+
allParamsArray.push(requestBodyParam.trim());
|
|
225
|
+
}
|
|
226
|
+
return allParamsArray.filter(Boolean).sort((a, b) => (a.includes("?") ? 1 : -1) - (b.includes("?") ? 1 : -1)).join(", ");
|
|
227
|
+
}
|
|
228
|
+
function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
|
|
229
|
+
if (allParams === "undefined") allParams = "";
|
|
230
|
+
let axiosFunction = `async (${allParams})${responseTypeStr} => {`;
|
|
231
|
+
const paramStr = parameters.config?.params ? `params: {${parameters.config.params}}` : "";
|
|
232
|
+
if (requestBodyPayload === "formData") {
|
|
233
|
+
if (allParams.includes("file: File")) {
|
|
234
|
+
axiosFunction += `
|
|
235
|
+
const formData = new FormData()
|
|
236
|
+
formData.append('upload', file)
|
|
237
|
+
return axios.${method}(${formattedPath}, formData, {
|
|
238
|
+
headers: { 'Content-Type': 'multipart/form-data' },
|
|
239
|
+
onUploadProgress: options?.onUploadProgress${paramStr ? `, ${paramStr}` : ""}
|
|
240
|
+
})`;
|
|
241
|
+
} else {
|
|
242
|
+
axiosFunction += `
|
|
243
|
+
return axios.${method}(${formattedPath}, formData, {
|
|
244
|
+
headers: { 'Content-Type': 'multipart/form-data' }${paramStr ? `, ${paramStr}` : ""}
|
|
245
|
+
})`;
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
const configParams = paramStr ? `, { ${paramStr} }` : "";
|
|
249
|
+
const bodyVar = requestBodyPayload || "{}";
|
|
250
|
+
axiosFunction += `return axios.${method}(${formattedPath}${["get", "delete"].includes(method) ? configParams : `, ${bodyVar}${configParams}`})`;
|
|
251
|
+
}
|
|
252
|
+
axiosFunction += "}";
|
|
253
|
+
return axiosFunction;
|
|
254
|
+
}
|
|
254
255
|
function generateFunctionForOperation(method, path, operation) {
|
|
255
256
|
if (!operation) return "";
|
|
256
257
|
const isFileUpload = operation.requestBody?.content["multipart/form-data"]?.schema?.$ref?.includes("Body_upload_files");
|
|
@@ -264,7 +265,61 @@ function generateFunctionForOperation(method, path, operation) {
|
|
|
264
265
|
const allParams = isFileUpload ? "file: File, options?: UploadOptions & { dirPath?: string, tags?: string[] }" : combineAllParams(parameters, requestBodyParam);
|
|
265
266
|
const responseType = generateResponseType(operation.responses);
|
|
266
267
|
const responseTypeStr = responseType ? `: Promise<AxiosResponse<${responseType}>>` : "";
|
|
267
|
-
|
|
268
|
+
let functionComment = "/**\n";
|
|
269
|
+
if (operation.summary) {
|
|
270
|
+
functionComment += ` * ${operation.summary}
|
|
271
|
+
`;
|
|
272
|
+
}
|
|
273
|
+
if (operation.description) {
|
|
274
|
+
if (operation.summary) functionComment += ` *
|
|
275
|
+
`;
|
|
276
|
+
const descriptionLines = operation.description.split("\n");
|
|
277
|
+
descriptionLines.forEach((line) => {
|
|
278
|
+
functionComment += ` * ${line}
|
|
279
|
+
`;
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
functionComment += ` *
|
|
283
|
+
* @endpoint ${method.toUpperCase()} ${path}
|
|
284
|
+
`;
|
|
285
|
+
if (operation.parameters?.length) {
|
|
286
|
+
functionComment += " *\n";
|
|
287
|
+
operation.parameters.forEach((param) => {
|
|
288
|
+
const paramType = schemaToType(param.schema);
|
|
289
|
+
const paramName = toCamelCase(param.name);
|
|
290
|
+
const required = param.required ? "" : "?";
|
|
291
|
+
functionComment += ` * @param {${paramType}} ${paramName}${required}`;
|
|
292
|
+
if (param.description) {
|
|
293
|
+
functionComment += ` - ${param.description}`;
|
|
294
|
+
} else {
|
|
295
|
+
functionComment += ` - ${param.name} parameter`;
|
|
296
|
+
}
|
|
297
|
+
functionComment += "\n";
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
if (operation.requestBody && requestBodyParam) {
|
|
301
|
+
const bodyParamName = requestBodyParam.split(":")[0].trim();
|
|
302
|
+
const bodyParamType = requestBodyParam.split(":")[1]?.split("=")[0]?.trim() || "any";
|
|
303
|
+
functionComment += ` * @param {${bodyParamType}} ${bodyParamName}`;
|
|
304
|
+
if (operation.requestBody.description) {
|
|
305
|
+
functionComment += ` - ${operation.requestBody.description}`;
|
|
306
|
+
} else {
|
|
307
|
+
functionComment += ` - Request body`;
|
|
308
|
+
}
|
|
309
|
+
functionComment += "\n";
|
|
310
|
+
}
|
|
311
|
+
if (responseType) {
|
|
312
|
+
functionComment += ` * @returns {Promise<AxiosResponse<${responseType}>>} The API response
|
|
313
|
+
`;
|
|
314
|
+
for (const [statusCode, response] of Object.entries(operation.responses)) {
|
|
315
|
+
if (statusCode.startsWith("2") && response.description) {
|
|
316
|
+
functionComment += ` * @response ${statusCode} - ${response.description}
|
|
317
|
+
`;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
functionComment += " */\n";
|
|
322
|
+
return functionComment + generateAxiosFunction(
|
|
268
323
|
method,
|
|
269
324
|
formatPathWithParams(path),
|
|
270
325
|
allParams,
|
|
@@ -273,25 +328,6 @@ function generateFunctionForOperation(method, path, operation) {
|
|
|
273
328
|
requestBodyPayload
|
|
274
329
|
);
|
|
275
330
|
}
|
|
276
|
-
const generateRandomString = () => Math.random().toString(36).slice(7);
|
|
277
|
-
const DOUBLE_QUOTE_REGEX = /"([^"]+)":/g;
|
|
278
|
-
function fileTemplate(tsString, typeForImport, baseURL) {
|
|
279
|
-
const templateCode = `import ax from 'axios';
|
|
280
|
-
import type { AxiosResponse } from 'axios';
|
|
281
|
-
import type {${typeForImport.join(", ")}} from './types.d';
|
|
282
|
-
|
|
283
|
-
export interface UploadOptions {
|
|
284
|
-
onUploadProgress?: (progressEvent: any) => void
|
|
285
|
-
dirPath?: string
|
|
286
|
-
tags?: string[]
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
export const axios = ax.create({baseURL:${baseURL}, withCredentials: true});
|
|
290
|
-
${tsString}`;
|
|
291
|
-
return templateCode.replace(DOUBLE_QUOTE_REGEX, "$1:");
|
|
292
|
-
}
|
|
293
|
-
const functionsInventory = {};
|
|
294
|
-
const pathOperations = [];
|
|
295
331
|
function hasConflict(path, method) {
|
|
296
332
|
const cleanPathName = path.split("/").filter((p) => p && !/\{|\}/.test(p)).join("/");
|
|
297
333
|
const matchingPaths = pathOperations.filter(
|
|
@@ -300,13 +336,20 @@ function hasConflict(path, method) {
|
|
|
300
336
|
pathOperations.push({ path: cleanPathName, method });
|
|
301
337
|
return matchingPaths.length > 0;
|
|
302
338
|
}
|
|
339
|
+
function generateRandomString() {
|
|
340
|
+
return Math.random().toString(36).slice(7);
|
|
341
|
+
}
|
|
303
342
|
function createFunctionPlaceholder(path, method, operation) {
|
|
304
343
|
const funcID = generateRandomString();
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
344
|
+
if (operation) {
|
|
345
|
+
functionsInventory[funcID] = generateFunctionForOperation(
|
|
346
|
+
method,
|
|
347
|
+
path,
|
|
348
|
+
operation
|
|
349
|
+
);
|
|
350
|
+
} else {
|
|
351
|
+
functionsInventory[funcID] = "";
|
|
352
|
+
}
|
|
310
353
|
return funcID;
|
|
311
354
|
}
|
|
312
355
|
function handlePathSegment(path, operation, existingObj = {}) {
|
|
@@ -327,7 +370,6 @@ function handlePathSegment(path, operation, existingObj = {}) {
|
|
|
327
370
|
return { ...obj, ...existingObj };
|
|
328
371
|
}
|
|
329
372
|
function generateFunctions(paths, baseUrl) {
|
|
330
|
-
let tsString = "";
|
|
331
373
|
const body = {};
|
|
332
374
|
const allPathsClean = Object.keys(paths).map(cleanPath);
|
|
333
375
|
for (const [path, operation] of Object.entries(paths)) {
|
|
@@ -338,8 +380,8 @@ function generateFunctions(paths, baseUrl) {
|
|
|
338
380
|
const methods = Object.keys(operation);
|
|
339
381
|
if (index === array.length - 1 && methods.length === 1 && allPathsClean.filter((p) => p === cleanPath(path)).length === 1) {
|
|
340
382
|
const method = methods[0];
|
|
341
|
-
const opp =
|
|
342
|
-
acc[objFuncKey] = createFunctionPlaceholder(path,
|
|
383
|
+
const opp = operation[method];
|
|
384
|
+
acc[objFuncKey] = createFunctionPlaceholder(path, method, opp);
|
|
343
385
|
} else if (index === array.length - 1) {
|
|
344
386
|
acc[objFuncKey] = handlePathSegment(path, operation, acc[objFuncKey]);
|
|
345
387
|
} else if (!acc[objFuncKey] || typeof acc[objFuncKey] !== "object") {
|
|
@@ -348,15 +390,46 @@ function generateFunctions(paths, baseUrl) {
|
|
|
348
390
|
return acc[objFuncKey];
|
|
349
391
|
}, body);
|
|
350
392
|
}
|
|
393
|
+
let tsString = "";
|
|
351
394
|
for (const [parent, object] of Object.entries(body)) {
|
|
352
|
-
tsString += `
|
|
395
|
+
tsString += `
|
|
396
|
+
/**
|
|
397
|
+
* API functions for ${parent} endpoints
|
|
398
|
+
*/
|
|
399
|
+
export const ${parent} = ${JSON.stringify(object, void 0, 2)};
|
|
353
400
|
`;
|
|
354
401
|
}
|
|
355
402
|
Object.entries(functionsInventory).forEach(([key, value]) => {
|
|
356
403
|
tsString = tsString.replace(`"${key}"`, value);
|
|
357
404
|
});
|
|
358
|
-
|
|
359
|
-
|
|
405
|
+
return fileTemplate(tsString, allTypes, baseUrl);
|
|
406
|
+
}
|
|
407
|
+
function fileTemplate(tsString, typeForImport, baseURL) {
|
|
408
|
+
const templateCode = `import ax from 'axios';
|
|
409
|
+
import type { AxiosResponse } from 'axios';
|
|
410
|
+
import type { ${typeForImport.join(", ")} } from './types.d';
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Options for file upload operations
|
|
414
|
+
*/
|
|
415
|
+
export interface UploadOptions {
|
|
416
|
+
/** Progress callback for upload operations */
|
|
417
|
+
onUploadProgress?: (progressEvent: any) => void
|
|
418
|
+
/** Directory path for the uploaded file */
|
|
419
|
+
dirPath?: string
|
|
420
|
+
/** Tags to associate with the uploaded file */
|
|
421
|
+
tags?: string[]
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Configured axios instance for API requests
|
|
426
|
+
* @example
|
|
427
|
+
* // Making a direct request with the axios instance
|
|
428
|
+
* const response = await axios.get('/some-endpoint');
|
|
429
|
+
*/
|
|
430
|
+
export const axios = ax.create({baseURL: ${baseURL}, withCredentials: true});
|
|
431
|
+
${tsString}`;
|
|
432
|
+
return templateCode.replace(/"([^"]+)":/g, "$1:");
|
|
360
433
|
}
|
|
361
434
|
|
|
362
435
|
function generateTypes(schemas) {
|