UNPKG

@alauda/doom

Version:

Doctor Doom making docs.

139 lines (138 loc) 7.8 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { usePageData } from '@rspress/core/runtime'; import { Badge } from '@rspress/core/theme'; import openapisMap from 'doom-@api-openapisMap'; import virtual from 'doom-@api-virtual'; import BananaSlug from 'github-slugger'; import { OpenAPIV3 } from 'openapi-types'; import { Fragment, useId, useMemo } from 'react'; import { omitRoutePathRefs, resolveRef } from '../utils.js'; import { Markdown } from './Markdown.js'; import { OpenAPIProperties, OpenAPIProperty, OpenAPIRef } from './OpenAPIRef.js'; import { HeadingTitle } from './_HeadingTitle.js'; import { RefLink } from './_RefLink.js'; import { X } from './_X.js'; import { UidProvider } from './_context.js'; export const OpenAPIParameters = ({ parameters, openapi, }) => { return (_jsx(X.ul, { children: parameters.map((param, index) => { const paramObj = '$ref' in param ? resolveRef(openapi, param.$ref) : param; const type = paramObj.schema && ('$ref' in paramObj.schema ? paramObj.schema : paramObj.schema.type); let typeNode; if (typeof type === 'string') { typeNode = _jsx("code", { children: type }); } else if (type) { typeNode = _jsx(RefLink, { "$ref": type.$ref }); } return ( // eslint-disable-next-line @eslint-react/no-array-index-key _jsxs(X.li, { children: [_jsx("code", { children: paramObj.name }), " (", _jsxs("em", { children: ["in ", paramObj.in] }), "): ", typeNode, paramObj.required && (_jsxs(_Fragment, { children: [' ', _jsx(Badge, { children: "required" })] })), _jsxs(_Fragment, { children: [' ', _jsx(Markdown, { children: paramObj.description })] })] }, index)); }) })); }; export const OpenAPIResponses = ({ responses, openapi, }) => { return (_jsx(X.ul, { children: Object.entries(responses).map(([code, response]) => { const responseObj = '$ref' in response ? resolveRef(openapi, response.$ref) : response; const responseContent = responseObj.content; const schema = (responseContent?.['application/json'] ?? responseContent?.['*/*'])?.schema; const type = schema && ('$ref' in schema ? schema : schema.type); let typeNode; let extraNode; if (typeof type === 'string') { typeNode = _jsx("code", { children: type }); if (type === 'object' && 'properties' in schema && schema.properties) { extraNode = (_jsxs("div", { className: "my-4", children: [_jsx("em", { children: "Properties:" }), _jsx(OpenAPIProperties, { properties: schema.properties, openapi: openapi })] })); } else if (type === 'array' && 'items' in schema && schema.items) { extraNode = (_jsxs("div", { className: "my-4", children: [_jsx("em", { children: "Items:" }), _jsx(OpenAPIProperty, { property: schema.items, openapi: openapi })] })); } } else if (type && '$ref' in type) { typeNode = _jsx(RefLink, { "$ref": type.$ref }); } return (_jsxs(X.li, { children: [_jsx("code", { children: code }), typeNode, ": ", responseObj.description, extraNode] }, code)); }) })); }; const getRefsForPath = (openapi, path, knownRefs) => { const pathSchema = openapi.paths?.[path]; if (!pathSchema) { return []; } const refs = new Set(); const collectRefs = (schema) => { if ('$ref' in schema && typeof schema.$ref === 'string') { const ref = schema.$ref.replace('#/components/schemas/', ''); if (!knownRefs[ref]) { refs.add(ref); schema = resolveRef(openapi, schema.$ref); } } for (const value of Object.values(schema)) { if (value && typeof value === 'object') { collectRefs(value); } } }; for (const method of Object.values(OpenAPIV3.HttpMethods)) { if (pathSchema[method]?.requestBody) { collectRefs(pathSchema[method].requestBody); } if (pathSchema[method]?.responses) { for (const response in pathSchema[method].responses) { collectRefs(pathSchema[method].responses[response]); } } } return Array.from(refs); }; export const OpenAPIPath = ({ path, openapiPath: openapiPath_, pathPrefix: pathPrefix_, }) => { // eslint-disable-next-line @typescript-eslint/no-deprecated -- `usePage` is not exported... const { page } = usePageData(); const pathPrefix = pathPrefix_ ?? (virtual.pathPrefix || ''); const uid = useId(); const slugger = useMemo(() => new BananaSlug(), []); const [pathItem, openapi, openapiPath, refs] = useMemo(() => { for (const [pathname, openapi] of Object.entries(openapisMap)) { if (openapiPath_ && pathname !== openapiPath_) { continue; } const pathItem = openapi.paths?.[path]; if (pathItem) { return [ pathItem, openapi, pathname, getRefsForPath(openapi, path, omitRoutePathRefs(page.routePath)), ]; } } return []; }, [openapiPath_, page.routePath, path]); if (!pathItem || !openapi) { console.error(`No OpenAPI path definition found for ${path}`); return null; } return (_jsxs(UidProvider, { value: uid, children: [_jsxs(HeadingTitle, { slugger: slugger, level: 2, children: [pathPrefix, path] }), pathItem.parameters && (_jsxs(_Fragment, { children: [_jsx(HeadingTitle, { slugger: slugger, level: 3, children: "Common Parameters" }), _jsx(OpenAPIParameters, { parameters: pathItem.parameters, openapi: openapi })] })), Object.values(OpenAPIV3.HttpMethods).map((method) => { if (!pathItem[method]) { return null; } const { description, parameters, requestBody, responses, summary } = pathItem[method]; const requestBodyRef = requestBody && ('$ref' in requestBody ? requestBody.$ref : requestBody.content['application/json'].schema?.$ref); const requestBodySchema = requestBodyRef ? resolveRef(openapi, requestBodyRef) : undefined; return (_jsxs(Fragment, { children: [_jsxs(HeadingTitle, { slugger: slugger, level: 3, children: [_jsx("code", { children: method }), summary] }), _jsx(Markdown, { children: description }), parameters && (_jsxs(_Fragment, { children: [_jsx(HeadingTitle, { slugger: slugger, level: 4, children: "Parameters" }), _jsx(OpenAPIParameters, { parameters: parameters, openapi: openapi })] })), requestBodySchema && (_jsxs(_Fragment, { children: [_jsx(HeadingTitle, { slugger: slugger, level: 4, children: "Request Body" }), _jsxs(X.p, { children: [_jsx(RefLink, { "$ref": requestBodyRef }), requestBodySchema.required && _jsx(Badge, { children: "required" })] })] })), responses && (_jsxs(_Fragment, { children: [_jsx(HeadingTitle, { slugger: slugger, level: 4, children: "Response" }), _jsx(OpenAPIResponses, { responses: responses, openapi: openapi })] }))] }, method)); }), refs?.map((ref) => { return (_jsx(OpenAPIRef, { schema: ref, openapiPath: openapiPath, isCommonRef: false, collectRefs: false }, ref)); })] })); }; export default OpenAPIPath;