import { URLPath } from '@kubb/core/utils'
import { useOperation, useOperationManager } from '@kubb/plugin-oas/hooks'
import { getComments, getPathParams } from '@kubb/plugin-oas/utils'
import { File, Function, Parser, useApp } from '@kubb/react'
import { pluginTsName } from '@kubb/swagger-ts'
import { isOptional } from '@kubb/oas'
import type { HttpMethod } from '@kubb/oas'
import type { KubbNode, Params } from '@kubb/react'
import type { ComponentProps, ComponentType } from 'react'
import type { FileMeta, PluginClient } from '../types.ts'
type TemplateProps = {
/**
* Name of the function
*/
name: string
/**
* Parameters/options/props that need to be used
*/
params: Params
/**
* Generics that needs to be added for TypeScript
*/
generics?: string
/**
* ReturnType(see async for adding Promise type)
*/
returnType?: string
/**
* Options for JSdocs
*/
JSDoc?: {
comments: string[]
}
client: {
baseURL: string | undefined
generics: string | string[]
method: HttpMethod
path: URLPath
dataReturnType: PluginClient['options']['dataReturnType']
withQueryParams: boolean
withData: boolean
withHeaders: boolean
contentType: string
}
}
function Template({ name, generics, returnType, params, JSDoc, client }: TemplateProps): KubbNode {
const isFormData = client.contentType === 'multipart/form-data'
const headers = [
client.contentType !== 'application/json' ? `'Content-Type': '${client.contentType}'` : undefined,
client.withHeaders ? '...headers' : undefined,
]
.filter(Boolean)
.join(', ')
const clientParams: Params = {
data: {
mode: 'object',
children: {
method: {
type: 'string',
value: JSON.stringify(client.method),
},
url: {
type: 'string',
value: client.path.template,
},
baseURL: client.baseURL
? {
type: 'string',
value: JSON.stringify(client.baseURL),
}
: undefined,
params: client.withQueryParams
? {
type: 'any',
}
: undefined,
data: client.withData
? {
type: 'any',
value: isFormData ? 'formData' : undefined,
}
: undefined,
headers: headers.length
? {
type: 'any',
value: headers.length ? `{ ${headers}, ...options.headers }` : undefined,
}
: undefined,
options: {
type: 'any',
mode: 'inlineSpread',
},
},
},
}
const formData = isFormData
? `
const formData = new FormData()
if(data) {
Object.keys(data).forEach((key) => {
const value = data[key];
if (typeof key === "string" && (typeof value === "string" || value instanceof Blob)) {
formData.append(key, value);
}
})
}
`
: undefined
return (
{formData || ''}
} />
{client.dataReturnType === 'data' ? 'res.data' : 'res'}
)
}
type RootTemplateProps = {
children?: React.ReactNode
}
function RootTemplate({ children }: RootTemplateProps) {
const {
plugin: {
options: {
client: { importPath },
extName,
},
},
} = useApp()
const { getSchemas, getFile } = useOperationManager()
const operation = useOperation()
const file = getFile(operation)
const fileType = getFile(operation, { pluginKey: [pluginTsName] })
const schemas = getSchemas(operation, { pluginKey: [pluginTsName], type: 'type' })
return (
baseName={file.baseName} path={file.path} meta={file.meta}>
{children}
)
}
const defaultTemplates = { default: Template, root: RootTemplate } as const
type Templates = Partial
type ClientProps = {
baseURL: string | undefined
/**
* This will make it possible to override the default behaviour.
*/
Template?: ComponentType>
}
export function Client({ baseURL, Template = defaultTemplates.default }: ClientProps): KubbNode {
const {
plugin: {
options: { client, dataReturnType, pathParamsType },
},
} = useApp()
const { getSchemas, getName } = useOperationManager()
const operation = useOperation()
const contentType = operation.getContentType()
const name = getName(operation, { type: 'function' })
const schemas = getSchemas(operation, { pluginKey: [pluginTsName], type: 'type' })
return (
[0]>',
default: '{}',
},
}}
returnType={dataReturnType === 'data' ? `ResponseConfig<${schemas.response.name}>["data"]` : `ResponseConfig<${schemas.response.name}>`}
JSDoc={{
comments: getComments(operation),
}}
client={{
baseURL,
generics: [schemas.response.name, schemas.request?.name].filter(Boolean),
dataReturnType,
withQueryParams: !!schemas.queryParams?.name,
withData: !!schemas.request?.name,
withHeaders: !!schemas.headerParams?.name,
method: operation.method,
path: new URLPath(operation.path),
contentType,
}}
/>
)
}
type FileProps = {
baseURL: string | undefined
/**
* This will make it possible to override the default behaviour.
*/
templates?: Templates
}
Client.File = function ({ baseURL, ...props }: FileProps): KubbNode {
const templates = { ...defaultTemplates, ...props.templates }
const Template = templates.default
const RootTemplate = templates.root
return (
)
}
Client.templates = defaultTemplates