UNPKG

fumadocs-openapi

Version:

Generate MDX docs for your OpenAPI spec

157 lines (155 loc) 5.8 kB
import { resolveRequestData } from "../../utils/url.js"; import { getPreferredType, pickExample } from "../../utils/schema.js"; import { MethodLabel } from "../components/method-label.js"; import { encodeRequestData } from "../../requests/media/encode.js"; import { AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger, Accordions } from "../components/accordion.js"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "fumadocs-ui/components/tabs"; import { sample } from "openapi-sampler"; //#region src/ui/operation/request-tabs.tsx function getExampleRequests(path, operation, ctx) { const media = operation.requestBody ? getPreferredType(operation.requestBody.content) : null; const bodyOfType = media ? operation.requestBody?.content[media] : null; if (bodyOfType?.examples) { const result = []; for (const [key, value] of Object.entries(bodyOfType.examples)) { const data$1 = getRequestData(path, operation, key, ctx); result.push({ id: key, name: value.summary || key, description: value.description, data: data$1, encoded: encodeRequestData(data$1, ctx.mediaAdapters, operation.parameters ?? []) }); } if (result.length > 0) return result; } const data = getRequestData(path, operation, null, ctx); return [{ id: "_default", name: "Default", description: bodyOfType?.schema?.description, data, encoded: encodeRequestData(data, ctx.mediaAdapters, operation.parameters ?? []) }]; } function getRequestData(path, method, sampleKey, _ctx) { const result = { path: {}, cookie: {}, header: {}, query: {}, method: method.method }; for (const param of method.parameters ?? []) { let value = pickExample(param); if (value === void 0 && param.required) { if (param.schema) value = sample(param.schema); else if (param.content) { const type = getPreferredType(param.content); const content = type ? param.content[type] : void 0; if (!content || !content.schema) throw new Error(`Cannot find "${param.name}" parameter info for media type "${type}" in ${path} ${method.method}`); value = sample(content.schema); } } switch (param.in) { case "cookie": result.cookie[param.name] = value; break; case "header": result.header[param.name] = value; break; case "query": result.query[param.name] = value; break; default: result.path[param.name] = value; } } if (method.requestBody) { const body = method.requestBody.content; const type = getPreferredType(body); if (!type) throw new Error(`Cannot find body schema for ${path} ${method.method}: missing media type`); result.bodyMediaType = type; const bodyOfType = body[type]; if (bodyOfType.examples && sampleKey) result.body = bodyOfType.examples[sampleKey].value; else if (bodyOfType.example) result.body = bodyOfType.example; else result.body = sample(bodyOfType?.schema ?? {}, { skipReadOnly: method.method !== "GET", skipWriteOnly: method.method === "GET", skipNonRequired: true }); } return result; } async function RequestTabs({ path, operation, ctx }) { if (!operation.requestBody) return null; const { renderRequestTabs = renderRequestTabsDefault } = ctx.content ?? {}; return renderRequestTabs(getExampleRequests(path, operation, ctx), { ...ctx, route: path, operation }); } function renderRequestTabsDefault(items, ctx) { function renderItem(item) { const requestData = item.data; const displayNames = { body: /* @__PURE__ */ jsxs(Fragment, { children: ["Body", /* @__PURE__ */ jsx("code", { className: "text-xs text-fd-muted-foreground ms-auto", children: requestData.bodyMediaType })] }), cookie: "Cookie", header: "Header", query: "Query Parameters", path: "Path Parameters" }; return /* @__PURE__ */ jsxs(Fragment, { children: [ item.description && ctx.renderMarkdown(item.description), /* @__PURE__ */ jsxs("div", { className: "flex flex-row gap-2 items-center justify-between", children: [/* @__PURE__ */ jsx(MethodLabel, { children: requestData.method }), /* @__PURE__ */ jsx("code", { children: resolveRequestData(ctx.route, item.encoded) })] }), /* @__PURE__ */ jsx(Accordions, { type: "multiple", className: "mt-2", children: Object.entries(displayNames).map(([k, v]) => { const data = requestData[k]; if (!data || Object.keys(data).length === 0) return; return /* @__PURE__ */ jsxs(AccordionItem, { value: k, children: [/* @__PURE__ */ jsx(AccordionHeader, { children: /* @__PURE__ */ jsx(AccordionTrigger, { children: v }) }), /* @__PURE__ */ jsx(AccordionContent, { className: "prose-no-margin", children: ctx.renderCodeBlock("json", JSON.stringify(data, null, 2)) })] }, k); }) }) ] }); } let children; if (items.length > 1) children = /* @__PURE__ */ jsxs(Tabs, { defaultValue: items[0].id, children: [/* @__PURE__ */ jsx(TabsList, { children: items.map((item) => /* @__PURE__ */ jsx(TabsTrigger, { value: item.id, children: item.name }, item.id)) }), items.map((item) => /* @__PURE__ */ jsx(TabsContent, { value: item.id, children: renderItem(item) }, item.id))] }); else if (items.length === 1) children = renderItem(items[0]); else children = /* @__PURE__ */ jsx("p", { className: "text-fd-muted-foreground text-xs", children: "Empty" }); return /* @__PURE__ */ jsxs("div", { className: "p-3 rounded-xl border prose-no-margin bg-fd-card text-fd-card-foreground shadow-md", children: [/* @__PURE__ */ jsx("p", { className: "font-semibold border-b pb-2", children: "Example Requests" }), children] }); } //#endregion export { RequestTabs, getExampleRequests }; //# sourceMappingURL=request-tabs.js.map