import { isAllOptional, isOptional } from '@kubb/oas' import { Client } from '@kubb/plugin-client/components' import type { OperationSchemas } from '@kubb/plugin-oas' import { getPathParams } from '@kubb/plugin-oas/utils' import { File, Function, FunctionParams } from '@kubb/react-fabric' import type { FabricReactNode } from '@kubb/react-fabric/types' import type { PluginSolidQuery } from '../types.ts' import { QueryKey } from './QueryKey.tsx' type Props = { name: string clientName: string queryKeyName: string typeSchemas: OperationSchemas paramsCasing: PluginSolidQuery['resolvedOptions']['paramsCasing'] paramsType: PluginSolidQuery['resolvedOptions']['paramsType'] pathParamsType: PluginSolidQuery['resolvedOptions']['pathParamsType'] dataReturnType: PluginSolidQuery['resolvedOptions']['client']['dataReturnType'] } type GetParamsProps = { paramsCasing: PluginSolidQuery['resolvedOptions']['paramsCasing'] paramsType: PluginSolidQuery['resolvedOptions']['paramsType'] pathParamsType: PluginSolidQuery['resolvedOptions']['pathParamsType'] typeSchemas: OperationSchemas } function getParams({ paramsType, paramsCasing, pathParamsType, typeSchemas }: GetParamsProps) { if (paramsType === 'object') { const pathParams = getPathParams(typeSchemas.pathParams, { typed: true, casing: paramsCasing, override: (item) => ({ ...item, type: `${item.type} | undefined` }), }) const children = { ...pathParams, data: typeSchemas.request?.name ? { type: typeSchemas.request?.name, optional: isOptional(typeSchemas.request?.schema), } : undefined, params: typeSchemas.queryParams?.name ? { type: typeSchemas.queryParams?.name, optional: isOptional(typeSchemas.queryParams?.schema), } : undefined, headers: typeSchemas.headerParams?.name ? { type: typeSchemas.headerParams?.name, optional: isOptional(typeSchemas.headerParams?.schema), } : undefined, } // Check if all children are optional or undefined const allChildrenAreOptional = Object.values(children).every((child) => !child || child.optional) return FunctionParams.factory({ data: { mode: 'object', children, default: allChildrenAreOptional ? '{}' : undefined, }, config: { type: typeSchemas.request?.name ? `Partial> & { client?: Client }` : 'Partial & { client?: Client }', default: '{}', }, }) } return FunctionParams.factory({ pathParams: typeSchemas.pathParams?.name ? { mode: pathParamsType === 'object' ? 'object' : 'inlineSpread', children: getPathParams(typeSchemas.pathParams, { typed: true, casing: paramsCasing, override: (item) => ({ ...item, type: `${item.type} | undefined` }), }), default: isAllOptional(typeSchemas.pathParams?.schema) ? '{}' : undefined, } : undefined, data: typeSchemas.request?.name ? { type: typeSchemas.request?.name, optional: isOptional(typeSchemas.request?.schema), } : undefined, params: typeSchemas.queryParams?.name ? { type: typeSchemas.queryParams?.name, optional: isOptional(typeSchemas.queryParams?.schema), } : undefined, headers: typeSchemas.headerParams?.name ? { type: typeSchemas.headerParams?.name, optional: isOptional(typeSchemas.headerParams?.schema), } : undefined, config: { type: typeSchemas.request?.name ? `Partial> & { client?: Client }` : 'Partial & { client?: Client }', default: '{}', }, }) } export function QueryOptions({ name, clientName, typeSchemas, paramsCasing, paramsType, dataReturnType, pathParamsType, queryKeyName, }: Props): FabricReactNode { const TData = dataReturnType === 'data' ? typeSchemas.response.name : `ResponseConfig<${typeSchemas.response.name}>` const TError = `ResponseErrorConfig<${typeSchemas.errors?.map((item) => item.name).join(' | ') || 'Error'}>` const params = getParams({ paramsType, paramsCasing, pathParamsType, typeSchemas }) const clientParams = Client.getParams({ paramsCasing, typeSchemas, paramsType, pathParamsType, isConfigurable: true, }) const queryKeyParams = QueryKey.getParams({ pathParamsType, paramsCasing, typeSchemas, }) const enabledPathParams = getPathParams(typeSchemas.pathParams, { casing: paramsCasing }) const enabledParamNames = new Set( Object.entries(enabledPathParams) // Only include if the parameter exists and is NOT optional // This ensures we only check required parameters .filter(([, item]) => item && !item.optional && !item.default) .map(([key]) => key), ) const enabled = [...enabledParamNames].join(' && ') const enabledText = enabled ? `enabled: !!(${enabled}),` : '' return ( {` const queryKey = ${queryKeyName}(${queryKeyParams.toCall()}) return queryOptions<${TData}, ${TError}, ${TData}, typeof queryKey>({ ${enabledText} queryKey, queryFn: async ({ signal }) => { return ${clientName}(${clientParams.toCall({ transformName(name) { if (name === 'config') { return '{ ...config, signal: config.signal ?? signal }' } return enabledParamNames.has(name) ? `${name}!` : name }, })}) }, }) `} ) } QueryOptions.getParams = getParams