@bagelink/sdk 1.2.18 → 1.2.22

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 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 || !mediaTypeObject.schema) return;
128
- const responseType = schemaToTypeWithCollection(mediaTypeObject.schema);
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 params = path.match(pathParamRegex)?.map((p) => p.slice(1, -1));
174
- return params;
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
- const formattedPath = params ? `\`${path.replace(pathParamRegex, (v) => `$${toCamelCase(v)}`)}\`` : `'${path}'`;
179
- return formattedPath;
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 paramList = [];
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
- paramList.push(
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: paramList.length ? { params: paramList.join(", ") } : {}
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
- return generateAxiosFunction(
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
- functionsInventory[funcID] = generateFunctionForOperation(
312
- method,
313
- path,
314
- operation
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 = { ...operation }[method];
348
- acc[objFuncKey] = createFunctionPlaceholder(path, methods[0], opp);
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 += `export const ${parent} = ${JSON.stringify(object, void 0, 2)};
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
- tsString = fileTemplate(tsString, allTypes, baseUrl);
365
- return tsString;
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 || !mediaTypeObject.schema) return;
122
- const responseType = schemaToTypeWithCollection(mediaTypeObject.schema);
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 params = path.match(pathParamRegex)?.map((p) => p.slice(1, -1));
168
- return params;
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
- const formattedPath = params ? `\`${path.replace(pathParamRegex, (v) => `$${toCamelCase(v)}`)}\`` : `'${path}'`;
173
- return formattedPath;
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 paramList = [];
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
- paramList.push(
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: paramList.length ? { params: paramList.join(", ") } : {}
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
- return generateAxiosFunction(
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
- functionsInventory[funcID] = generateFunctionForOperation(
306
- method,
307
- path,
308
- operation
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 = { ...operation }[method];
342
- acc[objFuncKey] = createFunctionPlaceholder(path, methods[0], opp);
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 += `export const ${parent} = ${JSON.stringify(object, void 0, 2)};
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
- tsString = fileTemplate(tsString, allTypes, baseUrl);
359
- return tsString;
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) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/sdk",
3
3
  "type": "module",
4
- "version": "1.2.18",
4
+ "version": "1.2.22",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Neveh Allon",