Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/yellow-jobs-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@gitbook/react-openapi': patch
'gitbook': patch
---

Improve OpenAPI circular references
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@

/* 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 {
Expand Down Expand Up @@ -249,15 +249,15 @@
}

.openapi-schema-circular {
@apply text-xs text-tint;
@apply text-sm text-tint;
}

.openapi-schema-circular a {
@apply underline;
}

.openapi-schema-circular-glyph {
@apply text-base;
@apply text-base mr-1;
}

/* Schema Enum */
Expand Down
90 changes: 52 additions & 38 deletions packages/react-openapi/src/OpenAPISchema.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,13 @@ function OpenAPISchemaProperty(
const circularRefId = parentCircularRefs.get(schema);
// Avoid recursing infinitely, and instead render a link to the parent schema
if (circularRefId) {
return <OpenAPISchemaCircularRef id={circularRefId} schema={schema} />;
return (
<OpenAPISchemaPresentation
context={context}
property={property}
circularRefId={circularRefId}
/>
);
}

const circularRefs = new Map(parentCircularRefs);
Expand All @@ -58,7 +64,7 @@ function OpenAPISchemaProperty(
const ancestors = new Set(circularRefs.keys());
const alternatives = getSchemaAlternatives(schema, ancestors);

const header = <OpenAPISchemaPresentation context={context} property={property} />;
const header = <OpenAPISchemaPresentation id={id} context={context} property={property} />;
const content = (() => {
if (alternatives?.schemas) {
const { schemas, discriminator } = alternatives;
Expand Down Expand Up @@ -101,10 +107,8 @@ function OpenAPISchemaProperty(
return (
<OpenAPIDisclosure
icon={context.icons.plus}
className={clsx('openapi-schema', className)}
header={header}
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
{...rest}
>
{content}
</OpenAPIDisclosure>
Expand Down Expand Up @@ -289,8 +293,8 @@ function OpenAPISchemaCircularRef(props: { id: string; schema: OpenAPIV3.SchemaO

return (
<div className="openapi-schema-circular">
<span className="openapi-schema-circular-glyph">⤷</span>
Circular reference to <a href={`#${id}`}>{getSchemaTitle(schema)}</a>{' '}
<span className="openapi-schema-circular-glyph">↩</span>
</div>
);
}
Expand Down Expand Up @@ -359,19 +363,23 @@ function OpenAPISchemaEnum(props: {
* Render the top row of a schema. e.g: name, type, and required status.
*/
export function OpenAPISchemaPresentation(props: {
id?: string;
property: OpenAPISchemaPropertyEntry;
context: OpenAPIClientContext;
circularRefId?: string;
}) {
const {
id,
property: { schema, propertyName, required, isDiscriminatorProperty },
circularRefId,
context,
} = props;

const description = resolveDescription(schema);
const example = resolveFirstExample(schema);

return (
<div className="openapi-schema-presentation">
<div id={id} className="openapi-schema-presentation">
<OpenAPISchemaName
schema={schema}
type={getSchemaTitle(schema)}
Expand All @@ -380,38 +388,44 @@ export function OpenAPISchemaPresentation(props: {
required={required}
context={context}
/>
{typeof schema['x-deprecated-sunset'] === 'string' ? (
<div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown">
Sunset date:{' '}
<span className="openapi-deprecated-sunset-date">
{schema['x-deprecated-sunset']}
</span>
</div>
) : null}
{description ? (
<Markdown source={description} className="openapi-schema-description" />
) : null}
{schema.default !== undefined ? (
<span className="openapi-schema-default">
Default:{' '}
<code>
{typeof schema.default === 'string' && schema.default
? schema.default
: stringifyOpenAPI(schema.default)}
</code>
</span>
) : null}
{typeof example === 'string' ? (
<span className="openapi-schema-example">
Example: <code>{example}</code>
</span>
) : null}
{schema.pattern ? (
<span className="openapi-schema-pattern">
Pattern: <code>{schema.pattern}</code>
</span>
) : null}
<OpenAPISchemaEnum schema={schema} context={context} />
{circularRefId ? (
<OpenAPISchemaCircularRef id={circularRefId} schema={schema} />
) : (
<>
{typeof schema['x-deprecated-sunset'] === 'string' ? (
<div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown">
Sunset date:{' '}
<span className="openapi-deprecated-sunset-date">
{schema['x-deprecated-sunset']}
</span>
</div>
) : null}
{description ? (
<Markdown source={description} className="openapi-schema-description" />
) : null}
{schema.default !== undefined ? (
<span className="openapi-schema-default">
Default:{' '}
<code>
{typeof schema.default === 'string' && schema.default
? schema.default
: stringifyOpenAPI(schema.default)}
</code>
</span>
) : null}
{typeof example === 'string' ? (
<span className="openapi-schema-example">
Example: <code>{example}</code>
</span>
) : null}
{schema.pattern ? (
<span className="openapi-schema-pattern">
Pattern: <code>{schema.pattern}</code>
</span>
) : null}
<OpenAPISchemaEnum schema={schema} context={context} />
</>
)}
</div>
);
}
Expand Down