mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-25 04:20:02 +00:00
OpenAPI: Support required in allOf schemas
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'fumadocs-openapi': patch
|
||||
---
|
||||
|
||||
Support `required` in `allOf` schemas
|
||||
@@ -2,6 +2,7 @@ import type { OpenAPIV3 as OpenAPI } from 'openapi-types';
|
||||
import { Fragment, type ReactNode } from 'react';
|
||||
import { noRef } from '@/utils/schema';
|
||||
import type { RenderContext } from '@/types';
|
||||
import { combineSchema } from '@/utils/combine-schema';
|
||||
import { Markdown } from './markdown';
|
||||
|
||||
const keys: {
|
||||
@@ -224,40 +225,6 @@ export function Schema({
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine multiple object schemas into one
|
||||
*/
|
||||
function combineSchema(schema: OpenAPI.SchemaObject[]): OpenAPI.SchemaObject {
|
||||
const result: OpenAPI.SchemaObject = {
|
||||
type: 'object',
|
||||
};
|
||||
|
||||
function add(s: OpenAPI.SchemaObject): void {
|
||||
if (s.properties) {
|
||||
result.properties ??= {};
|
||||
Object.assign(result.properties, s.properties);
|
||||
}
|
||||
|
||||
if (s.additionalProperties === true) {
|
||||
result.additionalProperties = true;
|
||||
} else if (
|
||||
s.additionalProperties &&
|
||||
typeof result.additionalProperties !== 'boolean'
|
||||
) {
|
||||
result.additionalProperties ??= {};
|
||||
Object.assign(result.additionalProperties, s.additionalProperties);
|
||||
}
|
||||
|
||||
if (s.allOf) {
|
||||
noRef(s.allOf).forEach(add);
|
||||
}
|
||||
}
|
||||
|
||||
schema.forEach(add);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the schema needs another collapsible to explain
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { type OpenAPIV3 as OpenAPI } from 'openapi-types';
|
||||
import { noRef } from '@/utils/schema';
|
||||
|
||||
/**
|
||||
* Combine multiple object schemas into one
|
||||
*/
|
||||
export function combineSchema(
|
||||
schema: OpenAPI.SchemaObject[],
|
||||
): OpenAPI.SchemaObject {
|
||||
const result: OpenAPI.SchemaObject = {
|
||||
type: 'object',
|
||||
};
|
||||
|
||||
function add(s: OpenAPI.SchemaObject): void {
|
||||
if (s.properties) {
|
||||
result.properties ??= {};
|
||||
Object.assign(result.properties, s.properties);
|
||||
}
|
||||
|
||||
if (s.additionalProperties === true) {
|
||||
result.additionalProperties = true;
|
||||
} else if (
|
||||
s.additionalProperties &&
|
||||
typeof result.additionalProperties !== 'boolean'
|
||||
) {
|
||||
result.additionalProperties ??= {};
|
||||
Object.assign(result.additionalProperties, s.additionalProperties);
|
||||
}
|
||||
|
||||
if (s.required) {
|
||||
result.required ??= [];
|
||||
result.required.push(...s.required);
|
||||
}
|
||||
|
||||
if (s.allOf) {
|
||||
noRef(s.allOf).forEach(add);
|
||||
}
|
||||
}
|
||||
|
||||
schema.forEach(add);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import { combineSchema } from '@/utils/combine-schema';
|
||||
|
||||
describe('Merge object schemas', () => {
|
||||
test('Merge single object', () => {
|
||||
const result = combineSchema([
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
test: {
|
||||
type: 'string',
|
||||
enum: ['one', 'two'],
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
{
|
||||
"properties": {
|
||||
"test": {
|
||||
"enum": [
|
||||
"one",
|
||||
"two",
|
||||
],
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"type": "object",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('Merge multiple objects', () => {
|
||||
const result = combineSchema([
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
test: {
|
||||
type: 'string',
|
||||
enum: ['one', 'two'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
{
|
||||
"properties": {
|
||||
"hello": {
|
||||
"type": "number",
|
||||
},
|
||||
"test": {
|
||||
"enum": [
|
||||
"one",
|
||||
"two",
|
||||
],
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"type": "object",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('Merge multiple objects: required', () => {
|
||||
const result = combineSchema([
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
test: {
|
||||
type: 'string',
|
||||
enum: ['one', 'two'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
required: ['hello'],
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
{
|
||||
"properties": {
|
||||
"hello": {
|
||||
"type": "number",
|
||||
},
|
||||
"test": {
|
||||
"enum": [
|
||||
"one",
|
||||
"two",
|
||||
],
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"hello",
|
||||
],
|
||||
"type": "object",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('Merge multiple objects: additional properties', () => {
|
||||
const result = combineSchema([
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
test: {
|
||||
type: 'string',
|
||||
enum: ['one', 'two'],
|
||||
},
|
||||
},
|
||||
additionalProperties: true,
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
{
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"test": {
|
||||
"enum": [
|
||||
"one",
|
||||
"two",
|
||||
],
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"type": "object",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('Merge multiple objects: `allOf`', () => {
|
||||
const result = combineSchema([
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
test: {
|
||||
type: 'string',
|
||||
enum: ['one', 'two'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
allOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
world: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
{
|
||||
"properties": {
|
||||
"hello": {
|
||||
"type": "number",
|
||||
},
|
||||
"test": {
|
||||
"enum": [
|
||||
"one",
|
||||
"two",
|
||||
],
|
||||
"type": "string",
|
||||
},
|
||||
"world": {
|
||||
"type": "number",
|
||||
},
|
||||
},
|
||||
"type": "object",
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user