@bagelink/sdk 1.5.32 → 1.6.4
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 +34 -11
- package/dist/index.mjs +34 -11
- package/package.json +1 -1
- package/src/openAPITools/functionGenerator.ts +61 -26
package/dist/index.cjs
CHANGED
|
@@ -317,7 +317,7 @@ function generateResponseType(responses) {
|
|
|
317
317
|
for (const [statusCode, response] of Object.entries(responses)) {
|
|
318
318
|
if (statusCode.startsWith("2")) {
|
|
319
319
|
const responseType = getResponseType(response);
|
|
320
|
-
if (responseType && "any"
|
|
320
|
+
if (responseType && responseType !== "any") {
|
|
321
321
|
types.push(responseType);
|
|
322
322
|
}
|
|
323
323
|
}
|
|
@@ -337,7 +337,7 @@ function formatPathWithParams(path) {
|
|
|
337
337
|
}
|
|
338
338
|
function generateRequestBody(requestBody) {
|
|
339
339
|
const content = dereference(requestBody)?.content;
|
|
340
|
-
if (!content ||
|
|
340
|
+
if (!content || Object.keys(content).length === 0) {
|
|
341
341
|
return { requestBodyParam: "", requestBodyPayload: "" };
|
|
342
342
|
}
|
|
343
343
|
if (content["multipart/form-data"]) {
|
|
@@ -390,7 +390,7 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
390
390
|
collectTypeForImportStatement(paramType);
|
|
391
391
|
const paramName = param.name;
|
|
392
392
|
const varName = toCamelCaseSafe(param.name);
|
|
393
|
-
if ("path"
|
|
393
|
+
if (param.in === "path" || param.in === "query" || param.in === "header") {
|
|
394
394
|
functionParams.push(
|
|
395
395
|
formatVarType({
|
|
396
396
|
varName,
|
|
@@ -400,7 +400,7 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
400
400
|
})
|
|
401
401
|
);
|
|
402
402
|
}
|
|
403
|
-
if ("query"
|
|
403
|
+
if (param.in === "query" || param.in === "header") {
|
|
404
404
|
queryParams.push(
|
|
405
405
|
paramName === varName ? paramName : `'${paramName}': ${varName}`
|
|
406
406
|
);
|
|
@@ -430,7 +430,7 @@ function combineAllParams(parameters, requestBodyParam) {
|
|
|
430
430
|
if (requestBodyParam) {
|
|
431
431
|
allParamsArray.push(requestBodyParam.trim());
|
|
432
432
|
}
|
|
433
|
-
if (
|
|
433
|
+
if (allParamsArray.length === 0) {
|
|
434
434
|
return "";
|
|
435
435
|
}
|
|
436
436
|
const parsedParams = allParamsArray.filter(Boolean).map(parseParameter);
|
|
@@ -441,12 +441,12 @@ function combineAllParams(parameters, requestBodyParam) {
|
|
|
441
441
|
return `{ ${destructuredNames} }: { ${typeDefinition} } = {}`;
|
|
442
442
|
}
|
|
443
443
|
function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
|
|
444
|
-
if ("undefined"
|
|
444
|
+
if (allParams === "undefined") {
|
|
445
445
|
allParams = "";
|
|
446
446
|
}
|
|
447
447
|
let axiosFunction = `async (${allParams})${responseTypeStr} => {`;
|
|
448
448
|
const paramStr = parameters.config?.params ? `params: {${parameters.config.params}}` : "";
|
|
449
|
-
if ("formData"
|
|
449
|
+
if (requestBodyPayload === "formData") {
|
|
450
450
|
if (allParams.includes("file: File")) {
|
|
451
451
|
axiosFunction += `
|
|
452
452
|
const formData = new FormData()
|
|
@@ -496,6 +496,21 @@ function generateFunctionForOperation(method, path, operation) {
|
|
|
496
496
|
if (!operation) {
|
|
497
497
|
return "";
|
|
498
498
|
}
|
|
499
|
+
const methodLower = method.toLowerCase();
|
|
500
|
+
if (["get", "delete"].includes(methodLower) && operation.requestBody) {
|
|
501
|
+
const requestBodyDeref = dereference(operation.requestBody);
|
|
502
|
+
const content = requestBodyDeref?.content;
|
|
503
|
+
if (content && Object.keys(content).length > 0) {
|
|
504
|
+
const hasSchema = Object.values(content).some(
|
|
505
|
+
(mediaType) => mediaType && "schema" in mediaType && mediaType.schema !== void 0 && mediaType.schema !== null
|
|
506
|
+
);
|
|
507
|
+
if (hasSchema) {
|
|
508
|
+
throw new Error(
|
|
509
|
+
`Invalid OpenAPI spec: ${method.toUpperCase()} request at path "${path}" has a request body. GET and DELETE requests should not have request bodies according to HTTP standards. Please move the body parameters to query parameters or use a different HTTP method.`
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
499
514
|
const multiPartSchema = dereference(operation.requestBody)?.content?.["multipart/form-data"]?.schema;
|
|
500
515
|
const isFileUpload = isReferenceObject(multiPartSchema) && multiPartSchema?.$ref?.includes("Body_upload_files");
|
|
501
516
|
const parameters = generateFunctionParameters(
|
|
@@ -524,7 +539,7 @@ function hasConflict(path, method) {
|
|
|
524
539
|
(p) => p.path === cleanPathName && p.method === method
|
|
525
540
|
);
|
|
526
541
|
pathOperations.push({ path: cleanPathName, method });
|
|
527
|
-
return
|
|
542
|
+
return matchingPaths.length > 0;
|
|
528
543
|
}
|
|
529
544
|
function generateRandomString() {
|
|
530
545
|
return Math.random().toString(36).slice(7);
|
|
@@ -570,13 +585,21 @@ function generateFunctions(paths, baseUrl) {
|
|
|
570
585
|
return acc;
|
|
571
586
|
}
|
|
572
587
|
const methods = Object.keys(operation);
|
|
573
|
-
|
|
588
|
+
const currentPathClean = cleanPath(path);
|
|
589
|
+
const currentPathPrefix = splitPath.slice(0, index + 1).join("/");
|
|
590
|
+
const prefixWithSlash = `${currentPathPrefix}/`;
|
|
591
|
+
const hasChildPaths = allPathsClean.some(
|
|
592
|
+
(otherPath) => otherPath !== currentPathClean && otherPath.startsWith(prefixWithSlash)
|
|
593
|
+
);
|
|
594
|
+
if (index === array.length - 1 && methods.length === 1 && allPathsClean.filter((p) => p === currentPathClean).length === 1 && !hasChildPaths) {
|
|
574
595
|
const method = methods[0];
|
|
575
596
|
const opp = operation[method];
|
|
576
597
|
acc[objFuncKey] = createFunctionPlaceholder(path, method, opp);
|
|
577
598
|
} else if (index === array.length - 1) {
|
|
578
|
-
|
|
579
|
-
|
|
599
|
+
const existingValue = acc[objFuncKey];
|
|
600
|
+
const existingObj = existingValue && typeof existingValue === "object" && !Array.isArray(existingValue) ? existingValue : {};
|
|
601
|
+
acc[objFuncKey] = handlePathSegment(path, operation, existingObj);
|
|
602
|
+
} else if (!acc[objFuncKey] || typeof acc[objFuncKey] !== "object") {
|
|
580
603
|
acc[objFuncKey] = {};
|
|
581
604
|
}
|
|
582
605
|
return acc[objFuncKey];
|
package/dist/index.mjs
CHANGED
|
@@ -311,7 +311,7 @@ function generateResponseType(responses) {
|
|
|
311
311
|
for (const [statusCode, response] of Object.entries(responses)) {
|
|
312
312
|
if (statusCode.startsWith("2")) {
|
|
313
313
|
const responseType = getResponseType(response);
|
|
314
|
-
if (responseType && "any"
|
|
314
|
+
if (responseType && responseType !== "any") {
|
|
315
315
|
types.push(responseType);
|
|
316
316
|
}
|
|
317
317
|
}
|
|
@@ -331,7 +331,7 @@ function formatPathWithParams(path) {
|
|
|
331
331
|
}
|
|
332
332
|
function generateRequestBody(requestBody) {
|
|
333
333
|
const content = dereference(requestBody)?.content;
|
|
334
|
-
if (!content ||
|
|
334
|
+
if (!content || Object.keys(content).length === 0) {
|
|
335
335
|
return { requestBodyParam: "", requestBodyPayload: "" };
|
|
336
336
|
}
|
|
337
337
|
if (content["multipart/form-data"]) {
|
|
@@ -384,7 +384,7 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
384
384
|
collectTypeForImportStatement(paramType);
|
|
385
385
|
const paramName = param.name;
|
|
386
386
|
const varName = toCamelCaseSafe(param.name);
|
|
387
|
-
if ("path"
|
|
387
|
+
if (param.in === "path" || param.in === "query" || param.in === "header") {
|
|
388
388
|
functionParams.push(
|
|
389
389
|
formatVarType({
|
|
390
390
|
varName,
|
|
@@ -394,7 +394,7 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
394
394
|
})
|
|
395
395
|
);
|
|
396
396
|
}
|
|
397
|
-
if ("query"
|
|
397
|
+
if (param.in === "query" || param.in === "header") {
|
|
398
398
|
queryParams.push(
|
|
399
399
|
paramName === varName ? paramName : `'${paramName}': ${varName}`
|
|
400
400
|
);
|
|
@@ -424,7 +424,7 @@ function combineAllParams(parameters, requestBodyParam) {
|
|
|
424
424
|
if (requestBodyParam) {
|
|
425
425
|
allParamsArray.push(requestBodyParam.trim());
|
|
426
426
|
}
|
|
427
|
-
if (
|
|
427
|
+
if (allParamsArray.length === 0) {
|
|
428
428
|
return "";
|
|
429
429
|
}
|
|
430
430
|
const parsedParams = allParamsArray.filter(Boolean).map(parseParameter);
|
|
@@ -435,12 +435,12 @@ function combineAllParams(parameters, requestBodyParam) {
|
|
|
435
435
|
return `{ ${destructuredNames} }: { ${typeDefinition} } = {}`;
|
|
436
436
|
}
|
|
437
437
|
function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
|
|
438
|
-
if ("undefined"
|
|
438
|
+
if (allParams === "undefined") {
|
|
439
439
|
allParams = "";
|
|
440
440
|
}
|
|
441
441
|
let axiosFunction = `async (${allParams})${responseTypeStr} => {`;
|
|
442
442
|
const paramStr = parameters.config?.params ? `params: {${parameters.config.params}}` : "";
|
|
443
|
-
if ("formData"
|
|
443
|
+
if (requestBodyPayload === "formData") {
|
|
444
444
|
if (allParams.includes("file: File")) {
|
|
445
445
|
axiosFunction += `
|
|
446
446
|
const formData = new FormData()
|
|
@@ -490,6 +490,21 @@ function generateFunctionForOperation(method, path, operation) {
|
|
|
490
490
|
if (!operation) {
|
|
491
491
|
return "";
|
|
492
492
|
}
|
|
493
|
+
const methodLower = method.toLowerCase();
|
|
494
|
+
if (["get", "delete"].includes(methodLower) && operation.requestBody) {
|
|
495
|
+
const requestBodyDeref = dereference(operation.requestBody);
|
|
496
|
+
const content = requestBodyDeref?.content;
|
|
497
|
+
if (content && Object.keys(content).length > 0) {
|
|
498
|
+
const hasSchema = Object.values(content).some(
|
|
499
|
+
(mediaType) => mediaType && "schema" in mediaType && mediaType.schema !== void 0 && mediaType.schema !== null
|
|
500
|
+
);
|
|
501
|
+
if (hasSchema) {
|
|
502
|
+
throw new Error(
|
|
503
|
+
`Invalid OpenAPI spec: ${method.toUpperCase()} request at path "${path}" has a request body. GET and DELETE requests should not have request bodies according to HTTP standards. Please move the body parameters to query parameters or use a different HTTP method.`
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
493
508
|
const multiPartSchema = dereference(operation.requestBody)?.content?.["multipart/form-data"]?.schema;
|
|
494
509
|
const isFileUpload = isReferenceObject(multiPartSchema) && multiPartSchema?.$ref?.includes("Body_upload_files");
|
|
495
510
|
const parameters = generateFunctionParameters(
|
|
@@ -518,7 +533,7 @@ function hasConflict(path, method) {
|
|
|
518
533
|
(p) => p.path === cleanPathName && p.method === method
|
|
519
534
|
);
|
|
520
535
|
pathOperations.push({ path: cleanPathName, method });
|
|
521
|
-
return
|
|
536
|
+
return matchingPaths.length > 0;
|
|
522
537
|
}
|
|
523
538
|
function generateRandomString() {
|
|
524
539
|
return Math.random().toString(36).slice(7);
|
|
@@ -564,13 +579,21 @@ function generateFunctions(paths, baseUrl) {
|
|
|
564
579
|
return acc;
|
|
565
580
|
}
|
|
566
581
|
const methods = Object.keys(operation);
|
|
567
|
-
|
|
582
|
+
const currentPathClean = cleanPath(path);
|
|
583
|
+
const currentPathPrefix = splitPath.slice(0, index + 1).join("/");
|
|
584
|
+
const prefixWithSlash = `${currentPathPrefix}/`;
|
|
585
|
+
const hasChildPaths = allPathsClean.some(
|
|
586
|
+
(otherPath) => otherPath !== currentPathClean && otherPath.startsWith(prefixWithSlash)
|
|
587
|
+
);
|
|
588
|
+
if (index === array.length - 1 && methods.length === 1 && allPathsClean.filter((p) => p === currentPathClean).length === 1 && !hasChildPaths) {
|
|
568
589
|
const method = methods[0];
|
|
569
590
|
const opp = operation[method];
|
|
570
591
|
acc[objFuncKey] = createFunctionPlaceholder(path, method, opp);
|
|
571
592
|
} else if (index === array.length - 1) {
|
|
572
|
-
|
|
573
|
-
|
|
593
|
+
const existingValue = acc[objFuncKey];
|
|
594
|
+
const existingObj = existingValue && typeof existingValue === "object" && !Array.isArray(existingValue) ? existingValue : {};
|
|
595
|
+
acc[objFuncKey] = handlePathSegment(path, operation, existingObj);
|
|
596
|
+
} else if (!acc[objFuncKey] || typeof acc[objFuncKey] !== "object") {
|
|
574
597
|
acc[objFuncKey] = {};
|
|
575
598
|
}
|
|
576
599
|
return acc[objFuncKey];
|
package/package.json
CHANGED
|
@@ -75,8 +75,8 @@ function collectTypeForImportStatement(typeName: string): void {
|
|
|
75
75
|
const isPrimitive = primitiveTypes.includes(typeName)
|
|
76
76
|
typeName = formatType(typeName)
|
|
77
77
|
|
|
78
|
-
if (!typeName || isPrimitive) {return}
|
|
79
|
-
if (!allTypes.includes(typeName)) {allTypes.push(typeName)}
|
|
78
|
+
if (!typeName || isPrimitive) { return }
|
|
79
|
+
if (!allTypes.includes(typeName)) { allTypes.push(typeName) }
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
@@ -100,7 +100,7 @@ function getResponseType(response: OpenAPIResponse | ReferenceObject): string |
|
|
|
100
100
|
return undefined // TODO: handle references properly
|
|
101
101
|
}
|
|
102
102
|
const mediaTypeObject = response.content?.['application/json']
|
|
103
|
-
if (!mediaTypeObject?.schema) {return undefined}
|
|
103
|
+
if (!mediaTypeObject?.schema) { return undefined }
|
|
104
104
|
return schemaToTypeWithCollection(mediaTypeObject.schema)
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -110,13 +110,13 @@ function getResponseType(response: OpenAPIResponse | ReferenceObject): string |
|
|
|
110
110
|
* @returns The TypeScript response type string
|
|
111
111
|
*/
|
|
112
112
|
function generateResponseType(responses?: OpenAPIResponses): string {
|
|
113
|
-
if (!responses) {return ''}
|
|
113
|
+
if (!responses) { return '' }
|
|
114
114
|
|
|
115
115
|
const types: string[] = []
|
|
116
116
|
for (const [statusCode, response] of Object.entries(responses)) {
|
|
117
117
|
if (statusCode.startsWith('2')) {
|
|
118
118
|
const responseType = getResponseType(response)
|
|
119
|
-
if (responseType && 'any'
|
|
119
|
+
if (responseType && responseType !== 'any') {
|
|
120
120
|
types.push(responseType)
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -142,7 +142,7 @@ function getParamsFromPath(path: string): string[] | undefined {
|
|
|
142
142
|
*/
|
|
143
143
|
function formatPathWithParams(path: string): string {
|
|
144
144
|
const params = getParamsFromPath(path)
|
|
145
|
-
if (!params) {return `'${path}'`}
|
|
145
|
+
if (!params) { return `'${path}'` }
|
|
146
146
|
|
|
147
147
|
return `\`${path.replace(/\{([^}]+)\}/g, (_, paramName) => `\${${toCamelCase(paramName)}}`)}\``
|
|
148
148
|
}
|
|
@@ -160,7 +160,7 @@ function generateRequestBody(requestBody?: OpenAPIOperation['requestBody']): {
|
|
|
160
160
|
// return { requestBodyParam: '', requestBodyPayload: '' }
|
|
161
161
|
|
|
162
162
|
const content = dereference(requestBody)?.content
|
|
163
|
-
if (!content ||
|
|
163
|
+
if (!content || Object.keys(content).length === 0) {
|
|
164
164
|
return { requestBodyParam: '', requestBodyPayload: '' }
|
|
165
165
|
}
|
|
166
166
|
|
|
@@ -217,7 +217,7 @@ function generateFunctionParameters(
|
|
|
217
217
|
params?: OpenAPIOperation['parameters'],
|
|
218
218
|
isFileUpload = false
|
|
219
219
|
): { params?: string, config?: { params?: string } } {
|
|
220
|
-
if (!params?.length) {return {}}
|
|
220
|
+
if (!params?.length) { return {} }
|
|
221
221
|
|
|
222
222
|
// Special handling for file uploads
|
|
223
223
|
if (isFileUpload) {
|
|
@@ -241,7 +241,7 @@ function generateFunctionParameters(
|
|
|
241
241
|
const paramName = param.name
|
|
242
242
|
const varName = toCamelCaseSafe(param.name)
|
|
243
243
|
|
|
244
|
-
if ('path'
|
|
244
|
+
if (param.in === 'path' || param.in === 'query' || param.in === 'header') {
|
|
245
245
|
functionParams.push(
|
|
246
246
|
formatVarType({
|
|
247
247
|
varName,
|
|
@@ -252,7 +252,7 @@ function generateFunctionParameters(
|
|
|
252
252
|
)
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
if ('query'
|
|
255
|
+
if (param.in === 'query' || param.in === 'header') {
|
|
256
256
|
queryParams.push(
|
|
257
257
|
paramName === varName ? paramName : `'${paramName}': ${varName}`
|
|
258
258
|
)
|
|
@@ -316,7 +316,7 @@ function combineAllParams(
|
|
|
316
316
|
allParamsArray.push(requestBodyParam.trim())
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
-
if (
|
|
319
|
+
if (allParamsArray.length === 0) {
|
|
320
320
|
return ''
|
|
321
321
|
}
|
|
322
322
|
|
|
@@ -357,14 +357,14 @@ function generateAxiosFunction(
|
|
|
357
357
|
parameters: { config?: { params?: string } },
|
|
358
358
|
requestBodyPayload: string
|
|
359
359
|
): string {
|
|
360
|
-
if ('undefined'
|
|
360
|
+
if (allParams === 'undefined') { allParams = '' }
|
|
361
361
|
|
|
362
362
|
let axiosFunction = `async (${allParams})${responseTypeStr} => {`
|
|
363
363
|
const paramStr = parameters.config?.params
|
|
364
364
|
? `params: {${parameters.config.params}}`
|
|
365
365
|
: ''
|
|
366
366
|
|
|
367
|
-
if ('formData'
|
|
367
|
+
if (requestBodyPayload === 'formData') {
|
|
368
368
|
// Check if this is a file upload with specific file parameter
|
|
369
369
|
if (allParams.includes('file: File')) {
|
|
370
370
|
axiosFunction += `
|
|
@@ -384,8 +384,6 @@ function generateAxiosFunction(
|
|
|
384
384
|
} else {
|
|
385
385
|
const configParams = paramStr ? `, { ${paramStr} }` : ''
|
|
386
386
|
const bodyVar = requestBodyPayload || '{}'
|
|
387
|
-
|
|
388
|
-
// Handle different HTTP methods appropriately
|
|
389
387
|
axiosFunction += `return axios.${method}(${formattedPath}${
|
|
390
388
|
['get', 'delete'].includes(method)
|
|
391
389
|
? configParams
|
|
@@ -415,7 +413,7 @@ function buildJSDocComment(operation: OpenAPIOperation, method: string, path: st
|
|
|
415
413
|
// Add description if available
|
|
416
414
|
if (operation.description) {
|
|
417
415
|
// If there's already a summary, add a line break
|
|
418
|
-
if (operation.summary) {functionComment += ` *\n`}
|
|
416
|
+
if (operation.summary) { functionComment += ` *\n` }
|
|
419
417
|
|
|
420
418
|
// Split description into lines and add each line with proper JSDoc formatting
|
|
421
419
|
const descriptionLines = operation.description.split('\n')
|
|
@@ -443,7 +441,28 @@ function generateFunctionForOperation(
|
|
|
443
441
|
path: string,
|
|
444
442
|
operation: OpenAPIOperation
|
|
445
443
|
): string {
|
|
446
|
-
if (!operation) {return ''}
|
|
444
|
+
if (!operation) { return '' }
|
|
445
|
+
|
|
446
|
+
// Validate: GET and DELETE requests should not have request bodies
|
|
447
|
+
const methodLower = method.toLowerCase()
|
|
448
|
+
if (['get', 'delete'].includes(methodLower) && operation.requestBody) {
|
|
449
|
+
const requestBodyDeref = dereference(operation.requestBody)
|
|
450
|
+
const content = requestBodyDeref?.content
|
|
451
|
+
// Check if request body has actual content with schemas
|
|
452
|
+
if (content && Object.keys(content).length > 0) {
|
|
453
|
+
// Check if any content type has a schema (indicating actual body data)
|
|
454
|
+
const hasSchema = Object.values(content).some(
|
|
455
|
+
mediaType => mediaType && 'schema' in mediaType && mediaType.schema !== undefined && mediaType.schema !== null
|
|
456
|
+
)
|
|
457
|
+
if (hasSchema) {
|
|
458
|
+
throw new Error(
|
|
459
|
+
`Invalid OpenAPI spec: ${method.toUpperCase()} request at path "${path}" has a request body. `
|
|
460
|
+
+ `GET and DELETE requests should not have request bodies according to HTTP standards. `
|
|
461
|
+
+ `Please move the body parameters to query parameters or use a different HTTP method.`
|
|
462
|
+
)
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
447
466
|
|
|
448
467
|
// Check if this is a file upload
|
|
449
468
|
const multiPartSchema = dereference(operation.requestBody)?.content?.[
|
|
@@ -500,7 +519,7 @@ function hasConflict(path: string, method: string): boolean {
|
|
|
500
519
|
)
|
|
501
520
|
|
|
502
521
|
pathOperations.push({ path: cleanPathName, method })
|
|
503
|
-
return
|
|
522
|
+
return matchingPaths.length > 0
|
|
504
523
|
}
|
|
505
524
|
|
|
506
525
|
/**
|
|
@@ -585,24 +604,40 @@ export function generateFunctions(paths: OpenAPIPaths, baseUrl: string): string
|
|
|
585
604
|
|
|
586
605
|
splitPath.reduce((acc, key: string, index: number, array: string[]) => {
|
|
587
606
|
const objFuncKey = toCamelCaseSafe(key)
|
|
588
|
-
if (!objFuncKey) {return acc}
|
|
607
|
+
if (!objFuncKey) { return acc }
|
|
589
608
|
|
|
590
609
|
const methods = Object.keys(operation) as Array<keyof OpenAPIPath>
|
|
610
|
+
const currentPathClean = cleanPath(path)
|
|
611
|
+
const currentPathPrefix = splitPath.slice(0, index + 1).join('/')
|
|
612
|
+
|
|
613
|
+
// Check if any other path has this path as a prefix (indicating child paths exist)
|
|
614
|
+
const prefixWithSlash = `${currentPathPrefix}/`
|
|
615
|
+
const hasChildPaths = allPathsClean.some(
|
|
616
|
+
otherPath => otherPath !== currentPathClean && otherPath.startsWith(prefixWithSlash)
|
|
617
|
+
)
|
|
591
618
|
|
|
592
619
|
if (
|
|
593
620
|
index === array.length - 1
|
|
594
|
-
&&
|
|
595
|
-
&&
|
|
621
|
+
&& methods.length === 1
|
|
622
|
+
&& allPathsClean.filter(p => p === currentPathClean).length === 1
|
|
623
|
+
&& !hasChildPaths
|
|
596
624
|
) {
|
|
597
|
-
// Single method endpoint with unique path
|
|
625
|
+
// Single method endpoint with unique path and no child paths
|
|
598
626
|
const method = methods[0]
|
|
599
627
|
const opp = operation[method!] as OpenAPIOperation
|
|
600
628
|
acc[objFuncKey] = createFunctionPlaceholder(path, method!, opp)
|
|
601
629
|
} else if (index === array.length - 1) {
|
|
602
|
-
// Multiple methods endpoint or path with conflicts
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
630
|
+
// Multiple methods endpoint or path with conflicts or has child paths
|
|
631
|
+
// Ensure we have an object to merge with (handlePathSegment expects an object)
|
|
632
|
+
const existingValue = acc[objFuncKey]
|
|
633
|
+
const existingObj = (existingValue && typeof existingValue === 'object' && !Array.isArray(existingValue))
|
|
634
|
+
? existingValue
|
|
635
|
+
: {}
|
|
636
|
+
acc[objFuncKey] = handlePathSegment(path, operation, existingObj)
|
|
637
|
+
} else if (!acc[objFuncKey] || typeof acc[objFuncKey] !== 'object') {
|
|
638
|
+
// Intermediate path segment - ensure it's an object
|
|
639
|
+
// If it's already a function, we need to preserve it but this shouldn't happen
|
|
640
|
+
// if hasChildPaths check works correctly
|
|
606
641
|
acc[objFuncKey] = {}
|
|
607
642
|
}
|
|
608
643
|
|