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 */
+52 -38
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,38 +388,44 @@ export function OpenAPISchemaPresentation(props: {
required={required} required={required}
context={context} context={context}
/> />
{typeof schema['x-deprecated-sunset'] === 'string' ? ( {circularRefId ? (
<div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown"> <OpenAPISchemaCircularRef id={circularRefId} schema={schema} />
Sunset date:{' '} ) : (
<span className="openapi-deprecated-sunset-date"> <>
{schema['x-deprecated-sunset']} {typeof schema['x-deprecated-sunset'] === 'string' ? (
</span> <div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown">
</div> Sunset date:{' '}
) : null} <span className="openapi-deprecated-sunset-date">
{description ? ( {schema['x-deprecated-sunset']}
<Markdown source={description} className="openapi-schema-description" /> </span>
) : null} </div>
{schema.default !== undefined ? ( ) : null}
<span className="openapi-schema-default"> {description ? (
Default:{' '} <Markdown source={description} className="openapi-schema-description" />
<code> ) : null}
{typeof schema.default === 'string' && schema.default {schema.default !== undefined ? (
? schema.default <span className="openapi-schema-default">
: stringifyOpenAPI(schema.default)} Default:{' '}
</code> <code>
</span> {typeof schema.default === 'string' && schema.default
) : null} ? schema.default
{typeof example === 'string' ? ( : stringifyOpenAPI(schema.default)}
<span className="openapi-schema-example"> </code>
Example: <code>{example}</code> </span>
</span> ) : null}
) : null} {typeof example === 'string' ? (
{schema.pattern ? ( <span className="openapi-schema-example">
<span className="openapi-schema-pattern"> Example: <code>{example}</code>
Pattern: <code>{schema.pattern}</code> </span>
</span> ) : null}
) : null} {schema.pattern ? (
<OpenAPISchemaEnum schema={schema} context={context} /> <span className="openapi-schema-pattern">
Pattern: <code>{schema.pattern}</code>
</span>
) : null}
<OpenAPISchemaEnum schema={schema} context={context} />
</>
)}
</div> </div>
); );
} }