Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,30 @@ describe("getSchemaName", () => {
} as SchemaObject;
expect(getSchemaName(schema)).toBe("integer[][][]");
});

it("joins OpenAPI 3.1 type arrays with ` | ` (issue #950)", () => {
const schema = { type: ["string", "null"] } as unknown as SchemaObject;
expect(getSchemaName(schema)).toBe("string | null");
});

it("unwraps a single-element type array", () => {
const schema = { type: ["integer"] } as unknown as SchemaObject;
expect(getSchemaName(schema)).toBe("integer");
});

it("renders type union with format", () => {
const schema = {
type: ["string", "null"],
format: "uuid",
} as unknown as SchemaObject;
expect(getSchemaName(schema)).toBe("string | null<uuid>");
});

it("renders array of items whose type is a union", () => {
const schema: SchemaObject = {
type: "array",
items: { type: ["string", "null"] } as any,
} as SchemaObject;
expect(getSchemaName(schema)).toBe("string | null[]");
});
});
47 changes: 36 additions & 11 deletions packages/docusaurus-plugin-openapi-docs/src/markdown/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,39 @@

import { SchemaObject } from "../openapi/types";

// OpenAPI 3.1 / JSON Schema 2020-12 allows `type` to be an array of type names
// (e.g. `["string", "null"]`). Normalize to a `string | string[]` view and a
// pretty-printed form joined with ` | `.
function normalizeType(type: unknown): {
single?: string;
pretty?: string;
isUnion: boolean;
} {
if (Array.isArray(type)) {
const filtered = type.filter((t): t is string => typeof t === "string");
if (filtered.length === 0) return { isUnion: false };
if (filtered.length === 1) return { single: filtered[0], isUnion: false };
return { pretty: filtered.join(" | "), isUnion: true };
}
if (typeof type === "string") return { single: type, isUnion: false };
return { isUnion: false };
}

function prettyName(schema: SchemaObject, circular?: boolean) {
// Handle enum-only schemas (valid in JSON Schema)
// When enum is present without explicit type, treat as string
if (schema.enum && !schema.type) {
return "string";
}

const t = normalizeType(schema.type);

if (schema.format) {
if (schema.type) {
return `${schema.type}<${schema.format}>`;
if (t.single) {
return `${t.single}<${schema.format}>`;
}
if (t.isUnion) {
return `${t.pretty}<${schema.format}>`;
}
return schema.format;
}
Expand All @@ -39,21 +62,23 @@ function prettyName(schema: SchemaObject, circular?: boolean) {
return "object";
}

if (schema.type === "object") {
return schema.xml?.name ?? schema.type;
// return schema.type;
if (t.single === "object") {
return schema.xml?.name ?? t.single;
}

if (t.single === "array") {
return schema.xml?.name ?? t.single;
}

if (schema.type === "array") {
return schema.xml?.name ?? schema.type;
// return schema.type;
if (t.isUnion) {
return schema.title ? `${schema.title} (${t.pretty})` : t.pretty;
}

if (schema.title && schema.type) {
return `${schema.title} (${schema.type})`;
if (schema.title && t.single) {
return `${schema.title} (${t.single})`;
}

return schema.title ?? schema.type;
return schema.title ?? t.single;
}

export function getSchemaName(
Expand Down
Loading