UNPKG

@kubb/plugin-client

Version:

API client generator plugin for Kubb, creating type-safe HTTP clients (Axios, Fetch) from OpenAPI specifications for making API requests.

319 lines (312 loc) 12.1 kB
import { URLPath, buildJSDoc } from "@kubb/core/utils"; import { getComments, getPathParams } from "@kubb/plugin-oas/utils"; import { Const, File, Function, FunctionParams } from "@kubb/react-fabric"; import { isOptional } from "@kubb/oas"; import { Fragment, jsx, jsxs } from "@kubb/react-fabric/jsx-runtime"; //#region src/components/Url.tsx function getParams$1({ paramsType, paramsCasing, pathParamsType, typeSchemas }) { if (paramsType === "object") return FunctionParams.factory({ data: { mode: "object", children: { ...getPathParams(typeSchemas.pathParams, { typed: true, casing: paramsCasing }) } } }); return FunctionParams.factory({ pathParams: typeSchemas.pathParams?.name ? { mode: pathParamsType === "object" ? "object" : "inlineSpread", children: getPathParams(typeSchemas.pathParams, { typed: true, casing: paramsCasing }), optional: isOptional(typeSchemas.pathParams?.schema) } : void 0 }); } function Url({ name, isExportable = true, isIndexable = true, typeSchemas, baseURL, paramsType, paramsCasing, pathParamsType, operation }) { const path = new URLPath(operation.path, { casing: paramsCasing }); const params = getParams$1({ paramsType, paramsCasing, pathParamsType, typeSchemas }); return /* @__PURE__ */ jsx(File.Source, { name, isExportable, isIndexable, children: /* @__PURE__ */ jsxs(Function, { name, export: isExportable, params: params.toConstructor(), children: [ /* @__PURE__ */ jsx(Const, { name: "res", children: `{ method: '${operation.method.toUpperCase()}', url: ${path.toTemplateString({ prefix: baseURL })} as const }` }), /* @__PURE__ */ jsx("br", {}), "return res" ] }) }); } Url.getParams = getParams$1; //#endregion //#region src/components/Client.tsx function getParams({ paramsType, paramsCasing, pathParamsType, typeSchemas, isConfigurable }) { if (paramsType === "object") return FunctionParams.factory({ data: { mode: "object", children: { ...getPathParams(typeSchemas.pathParams, { typed: true, casing: paramsCasing }), data: typeSchemas.request?.name ? { type: typeSchemas.request?.name, optional: isOptional(typeSchemas.request?.schema) } : void 0, params: typeSchemas.queryParams?.name ? { type: typeSchemas.queryParams?.name, optional: isOptional(typeSchemas.queryParams?.schema) } : void 0, headers: typeSchemas.headerParams?.name ? { type: typeSchemas.headerParams?.name, optional: isOptional(typeSchemas.headerParams?.schema) } : void 0 } }, config: isConfigurable ? { type: typeSchemas.request?.name ? `Partial<RequestConfig<${typeSchemas.request?.name}>> & { client?: typeof fetch }` : "Partial<RequestConfig> & { client?: typeof fetch }", default: "{}" } : void 0 }); return FunctionParams.factory({ pathParams: typeSchemas.pathParams?.name ? { mode: pathParamsType === "object" ? "object" : "inlineSpread", children: getPathParams(typeSchemas.pathParams, { typed: true, casing: paramsCasing }), optional: isOptional(typeSchemas.pathParams?.schema) } : void 0, data: typeSchemas.request?.name ? { type: typeSchemas.request?.name, optional: isOptional(typeSchemas.request?.schema) } : void 0, params: typeSchemas.queryParams?.name ? { type: typeSchemas.queryParams?.name, optional: isOptional(typeSchemas.queryParams?.schema) } : void 0, headers: typeSchemas.headerParams?.name ? { type: typeSchemas.headerParams?.name, optional: isOptional(typeSchemas.headerParams?.schema) } : void 0, config: isConfigurable ? { type: typeSchemas.request?.name ? `Partial<RequestConfig<${typeSchemas.request?.name}>> & { client?: typeof fetch }` : "Partial<RequestConfig> & { client?: typeof fetch }", default: "{}" } : void 0 }); } function Client({ name, isExportable = true, isIndexable = true, returnType, typeSchemas, baseURL, dataReturnType, parser, zodSchemas, paramsType, paramsCasing, pathParamsType, operation, urlName, children, isConfigurable = true }) { const path = new URLPath(operation.path, { casing: paramsCasing }); const contentType = operation.getContentType(); const isFormData = contentType === "multipart/form-data"; const headers = [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : void 0, typeSchemas.headerParams?.name ? "...headers" : void 0].filter(Boolean); const TError = `ResponseErrorConfig<${typeSchemas.errors?.map((item) => item.name).join(" | ") || "Error"}>`; const generics = [ typeSchemas.response.name, TError, typeSchemas.request?.name || "unknown" ].filter(Boolean); const params = getParams({ paramsType, paramsCasing, pathParamsType, typeSchemas, isConfigurable }); const urlParams = Url.getParams({ paramsType, paramsCasing, pathParamsType, typeSchemas }); const clientParams = FunctionParams.factory({ config: { mode: "object", children: { method: { value: JSON.stringify(operation.method.toUpperCase()) }, url: { value: urlName ? `${urlName}(${urlParams.toCall()}).url.toString()` : path.template }, baseURL: baseURL && !urlName ? { value: `\`${baseURL}\`` } : void 0, params: typeSchemas.queryParams?.name ? {} : void 0, data: typeSchemas.request?.name ? { value: isFormData ? "formData as FormData" : "requestData" } : void 0, requestConfig: isConfigurable ? { mode: "inlineSpread" } : void 0, headers: headers.length ? { value: isConfigurable ? `{ ${headers.join(", ")}, ...requestConfig.headers }` : `{ ${headers.join(", ")} }` } : void 0 } } }); const childrenElement = children ? children : /* @__PURE__ */ jsxs(Fragment, { children: [ dataReturnType === "full" && parser === "zod" && zodSchemas && `return {...res, data: ${zodSchemas.response.name}.parse(res.data)}`, dataReturnType === "data" && parser === "zod" && zodSchemas && `return ${zodSchemas.response.name}.parse(res.data)`, dataReturnType === "full" && parser === "client" && "return res", dataReturnType === "data" && parser === "client" && "return res.data" ] }); return /* @__PURE__ */ jsx(File.Source, { name, isExportable, isIndexable, children: /* @__PURE__ */ jsxs(Function, { name, async: true, export: isExportable, params: params.toConstructor(), JSDoc: { comments: getComments(operation) }, returnType, children: [ isConfigurable ? "const { client: request = fetch, ...requestConfig } = config" : "", /* @__PURE__ */ jsx("br", {}), /* @__PURE__ */ jsx("br", {}), parser === "zod" && zodSchemas?.request?.name ? `const requestData = ${zodSchemas.request.name}.parse(data)` : typeSchemas?.request?.name && "const requestData = data", /* @__PURE__ */ jsx("br", {}), isFormData && typeSchemas?.request?.name && "const formData = buildFormData(requestData)", /* @__PURE__ */ jsx("br", {}), isConfigurable ? `const res = await request<${generics.join(", ")}>(${clientParams.toCall()})` : `const res = await fetch<${generics.join(", ")}>(${clientParams.toCall()})`, /* @__PURE__ */ jsx("br", {}), childrenElement ] }) }); } Client.getParams = getParams; //#endregion //#region src/components/ClassClient.tsx function buildHeaders(contentType, hasHeaderParams) { return [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : void 0, hasHeaderParams ? "...headers" : void 0].filter(Boolean); } function buildGenerics(typeSchemas) { const TError = `ResponseErrorConfig<${typeSchemas.errors?.map((item) => item.name).join(" | ") || "Error"}>`; return [ typeSchemas.response.name, TError, typeSchemas.request?.name || "unknown" ].filter(Boolean); } function buildClientParams({ operation, path, baseURL, typeSchemas, isFormData, headers }) { return FunctionParams.factory({ config: { mode: "object", children: { method: { value: JSON.stringify(operation.method.toUpperCase()) }, url: { value: path.template }, baseURL: baseURL ? { value: JSON.stringify(baseURL) } : void 0, params: typeSchemas.queryParams?.name ? {} : void 0, data: typeSchemas.request?.name ? { value: isFormData ? "formData as FormData" : "requestData" } : void 0, requestConfig: { mode: "inlineSpread" }, headers: headers.length ? { value: `{ ${headers.join(", ")}, ...requestConfig.headers }` } : void 0 } } }); } function buildRequestDataLine({ parser, zodSchemas, typeSchemas }) { if (parser === "zod" && zodSchemas?.request?.name) return `const requestData = ${zodSchemas.request.name}.parse(data)`; if (typeSchemas?.request?.name) return "const requestData = data"; return ""; } function buildFormDataLine(isFormData, hasRequest) { return isFormData && hasRequest ? "const formData = buildFormData(requestData)" : ""; } function buildReturnStatement({ dataReturnType, parser, zodSchemas }) { if (dataReturnType === "full" && parser === "zod" && zodSchemas) return `return {...res, data: ${zodSchemas.response.name}.parse(res.data)}`; if (dataReturnType === "data" && parser === "zod" && zodSchemas) return `return ${zodSchemas.response.name}.parse(res.data)`; if (dataReturnType === "full" && parser === "client") return "return res"; return "return res.data"; } function generateMethod({ operation, name, typeSchemas, zodSchemas, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType }) { const path = new URLPath(operation.path, { casing: paramsCasing }); const contentType = operation.getContentType(); const isFormData = contentType === "multipart/form-data"; const headers = buildHeaders(contentType, !!typeSchemas.headerParams?.name); const generics = buildGenerics(typeSchemas); const params = ClassClient.getParams({ paramsType, paramsCasing, pathParamsType, typeSchemas, isConfigurable: true }); const clientParams = buildClientParams({ operation, path, baseURL, typeSchemas, isFormData, headers }); const jsdoc = buildJSDoc(getComments(operation)); const requestDataLine = buildRequestDataLine({ parser, zodSchemas, typeSchemas }); const formDataLine = buildFormDataLine(isFormData, !!typeSchemas?.request?.name); const returnStatement = buildReturnStatement({ dataReturnType, parser, zodSchemas }); const methodBody = [ "const { client: request = this.#client, ...requestConfig } = config", "", requestDataLine, formDataLine, `const res = await request<${generics.join(", ")}>(${clientParams.toCall()})`, returnStatement ].filter(Boolean).map((line) => ` ${line}`).join("\n"); return `${jsdoc}async ${name}(${params.toConstructor()}) {\n${methodBody}\n }`; } function ClassClient({ name, isExportable = true, isIndexable = true, operations, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType, children }) { const classCode = `export class ${name} { #client: typeof fetch constructor(config: Partial<RequestConfig> & { client?: typeof fetch } = {}) { this.#client = config.client || fetch } ${operations.map(({ operation, name: methodName, typeSchemas, zodSchemas }) => generateMethod({ operation, name: methodName, typeSchemas, zodSchemas, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType })).join("\n\n")} }`; return /* @__PURE__ */ jsxs(File.Source, { name, isExportable, isIndexable, children: [classCode, children] }); } ClassClient.getParams = Client.getParams; //#endregion //#region src/components/Operations.tsx function Operations({ name, operations }) { const operationsObject = {}; operations.forEach((operation) => { operationsObject[operation.getOperationId()] = { path: new URLPath(operation.path).URL, method: operation.method }; }); return /* @__PURE__ */ jsx(File.Source, { name, isExportable: true, isIndexable: true, children: /* @__PURE__ */ jsx(Const, { name, export: true, children: JSON.stringify(operationsObject, void 0, 2) }) }); } //#endregion export { Url as i, ClassClient as n, Client as r, Operations as t }; //# sourceMappingURL=Operations-hfmOLxuh.js.map