@alauda/doom
Version:
Doctor Doom making docs.
139 lines (138 loc) • 7.8 kB
JavaScript
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;