Improve OpenAPI circular references (#3821)

This commit is contained in:
Nolann B.
2025-11-19 22:44:32 +01:00
committed by GitHub
parent c51076efc4
commit 344842f5ce
3 changed files with 61 additions and 41 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@gitbook/react-openapi': patch
'gitbook': patch
---
Improve OpenAPI circular references
@@ -182,7 +182,7 @@
/* Schema Presentation */ /* Schema Presentation */
.openapi-schema-presentation { .openapi-schema-presentation {
@apply flex flex-col gap-1 font-normal; @apply flex flex-col gap-1 font-normal scroll-mt-[calc(var(--toc-top-offset)+0.5rem)];
} }
.openapi-schema-properties:last-child { .openapi-schema-properties:last-child {
@@ -249,7 +249,7 @@
} }
.openapi-schema-circular { .openapi-schema-circular {
@apply text-xs text-tint; @apply text-sm text-tint;
} }
.openapi-schema-circular a { .openapi-schema-circular a {
@@ -257,7 +257,7 @@
} }
.openapi-schema-circular-glyph { .openapi-schema-circular-glyph {
@apply text-base; @apply text-base mr-1;
} }
/* Schema Enum */ /* Schema Enum */
+20 -6
View File
@@ -47,7 +47,13 @@ function OpenAPISchemaProperty(
const circularRefId = parentCircularRefs.get(schema); const circularRefId = parentCircularRefs.get(schema);
// Avoid recursing infinitely, and instead render a link to the parent schema // Avoid recursing infinitely, and instead render a link to the parent schema
if (circularRefId) { if (circularRefId) {
return <OpenAPISchemaCircularRef id={circularRefId} schema={schema} />; return (
<OpenAPISchemaPresentation
context={context}
property={property}
circularRefId={circularRefId}
/>
);
} }
const circularRefs = new Map(parentCircularRefs); const circularRefs = new Map(parentCircularRefs);
@@ -58,7 +64,7 @@ function OpenAPISchemaProperty(
const ancestors = new Set(circularRefs.keys()); const ancestors = new Set(circularRefs.keys());
const alternatives = getSchemaAlternatives(schema, ancestors); const alternatives = getSchemaAlternatives(schema, ancestors);
const header = <OpenAPISchemaPresentation context={context} property={property} />; const header = <OpenAPISchemaPresentation id={id} context={context} property={property} />;
const content = (() => { const content = (() => {
if (alternatives?.schemas) { if (alternatives?.schemas) {
const { schemas, discriminator } = alternatives; const { schemas, discriminator } = alternatives;
@@ -101,10 +107,8 @@ function OpenAPISchemaProperty(
return ( return (
<OpenAPIDisclosure <OpenAPIDisclosure
icon={context.icons.plus} icon={context.icons.plus}
className={clsx('openapi-schema', className)}
header={header} header={header}
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })} label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
{...rest}
> >
{content} {content}
</OpenAPIDisclosure> </OpenAPIDisclosure>
@@ -289,8 +293,8 @@ function OpenAPISchemaCircularRef(props: { id: string; schema: OpenAPIV3.SchemaO
return ( return (
<div className="openapi-schema-circular"> <div className="openapi-schema-circular">
<span className="openapi-schema-circular-glyph"></span>
Circular reference to <a href={`#${id}`}>{getSchemaTitle(schema)}</a>{' '} Circular reference to <a href={`#${id}`}>{getSchemaTitle(schema)}</a>{' '}
<span className="openapi-schema-circular-glyph"></span>
</div> </div>
); );
} }
@@ -359,11 +363,15 @@ function OpenAPISchemaEnum(props: {
* Render the top row of a schema. e.g: name, type, and required status. * Render the top row of a schema. e.g: name, type, and required status.
*/ */
export function OpenAPISchemaPresentation(props: { export function OpenAPISchemaPresentation(props: {
id?: string;
property: OpenAPISchemaPropertyEntry; property: OpenAPISchemaPropertyEntry;
context: OpenAPIClientContext; context: OpenAPIClientContext;
circularRefId?: string;
}) { }) {
const { const {
id,
property: { schema, propertyName, required, isDiscriminatorProperty }, property: { schema, propertyName, required, isDiscriminatorProperty },
circularRefId,
context, context,
} = props; } = props;
@@ -371,7 +379,7 @@ export function OpenAPISchemaPresentation(props: {
const example = resolveFirstExample(schema); const example = resolveFirstExample(schema);
return ( return (
<div className="openapi-schema-presentation"> <div id={id} className="openapi-schema-presentation">
<OpenAPISchemaName <OpenAPISchemaName
schema={schema} schema={schema}
type={getSchemaTitle(schema)} type={getSchemaTitle(schema)}
@@ -380,6 +388,10 @@ export function OpenAPISchemaPresentation(props: {
required={required} required={required}
context={context} context={context}
/> />
{circularRefId ? (
<OpenAPISchemaCircularRef id={circularRefId} schema={schema} />
) : (
<>
{typeof schema['x-deprecated-sunset'] === 'string' ? ( {typeof schema['x-deprecated-sunset'] === 'string' ? (
<div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown"> <div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown">
Sunset date:{' '} Sunset date:{' '}
@@ -412,6 +424,8 @@ export function OpenAPISchemaPresentation(props: {
</span> </span>
) : null} ) : null}
<OpenAPISchemaEnum schema={schema} context={context} /> <OpenAPISchemaEnum schema={schema} context={context} />
</>
)}
</div> </div>
); );
} }