UNPKG

@scalar/api-reference

Version:

Generate beautiful API references from OpenAPI documents

215 lines (214 loc) 6.97 kB
import { objectKeys } from "@scalar/helpers/object/object-keys"; import { getResolvedRef } from "@scalar/workspace-store/helpers/get-resolved-ref"; import { isArraySchema } from "@scalar/workspace-store/schemas/v3.1/strict/type-guards"; const mergeAllOfSchemas = (schemas, rootSchema) => { if (!schemas?.allOf?.length || !Array.isArray(schemas.allOf)) { return rootSchema || {}; } const result = {}; const { allOf: _, ...baseSchema } = schemas; for (const _schema of schemas.allOf) { if (!_schema || typeof _schema !== "object") { continue; } const schema = getResolvedRef(_schema); if (schema.allOf) { const nestedMerged = mergeAllOfSchemas(schema); mergeSchemaIntoResult(result, nestedMerged); continue; } mergeSchemaIntoResult(result, schema); } if (Object.keys(baseSchema).length > 0) { mergeSchemaIntoResult(result, baseSchema, true); } if (rootSchema && typeof rootSchema === "object") { if (rootSchema.allOf) { const nestedMerged = mergeAllOfSchemas(rootSchema); mergeSchemaIntoResult(result, nestedMerged, true); } else { mergeSchemaIntoResult(result, rootSchema, true); } } return result; }; const mergeSchemaIntoResult = (result, schema, override = false) => { const schemaKeys = objectKeys(schema); if (schemaKeys.length === 0) { return; } for (const key of schemaKeys) { const value = getResolvedRef(schema[key]); if (value === void 0) { continue; } if (key === "required") { if (Array.isArray(value) && value.length > 0) { if (result.required?.length) { result.required = [.../* @__PURE__ */ new Set([...result.required, ...value])]; } else { result.required = value.slice(); } } } else if (key === "properties") { if (value && typeof value === "object") { if (!result.properties) { result.properties = {}; } mergePropertiesIntoResult(result.properties, value); } } else if (key === "items") { const items = getResolvedRef(value); if (items) { if (isArraySchema(schema)) { if (!result.items) { result.items = {}; } if (items.allOf) { const mergedItems = mergeAllOfSchemas(items); Object.assign(result.items, mergedItems); } else { mergeItemsIntoResult(getResolvedRef(result.items), items); } } else if (items.allOf) { const mergedItems = mergeAllOfSchemas(items); if ("properties" in mergedItems) { if (!("properties" in result)) { result.properties = {}; } "properties" in result && mergePropertiesIntoResult(result.properties, mergedItems.properties); } } else if (!("items" in result)) { result.items = items; } } } else if (key === "enum") { if (Array.isArray(value) && value.length > 0) { result.enum = [.../* @__PURE__ */ new Set([...result.enum || [], ...value])]; } } else if (key === "oneOf" || key === "anyOf") { if (Array.isArray(value)) { if (!("properties" in result)) { result.properties = {}; } for (const _option of value) { const option = getResolvedRef(_option); if (option.properties && "properties" in result) { mergePropertiesIntoResult(result.properties, option.properties); } } } } else if (key === "allOf") { continue; } else { if (override || result[key] === void 0) { result[key] = value; } } } }; const mergePropertiesIntoResult = (result, properties) => { const propertyKeys = Object.keys(properties ?? {}); if (!properties || !result || propertyKeys.length === 0) { return; } for (const key of propertyKeys) { const schema = getResolvedRef(properties[key]); if (!schema) { delete result[key]; continue; } if (typeof schema !== "object") { result[key] = schema; continue; } if (!result[key]) { if (schema.allOf) { result[key] = mergeAllOfSchemas(schema); } else if (isArraySchema(schema) && getResolvedRef(schema.items)?.allOf) { result[key] = { ...schema, items: mergeAllOfSchemas(getResolvedRef(schema.items)) }; } else if (properties[key]) { result[key] = properties[key]; } continue; } const existing = getResolvedRef(result[key]); if (schema.allOf) { result[key] = mergeAllOfSchemas({ allOf: [existing, ...schema.allOf] }); } else if (isArraySchema(schema) && isArraySchema(existing) && schema.items) { const existingItems = getResolvedRef(existing.items); result[key] = { ...existing, type: "array", items: existingItems ? mergeItems(existingItems, getResolvedRef(schema.items)) : getResolvedRef(schema.items) }; } else { if ("properties" in existing && "properties" in schema) { const merged = { ...existing, ...schema }; merged.properties = { ...existing.properties }; mergePropertiesIntoResult(merged.properties, schema.properties); result[key] = merged; } else { result[key] = { ...schema, ...existing }; } } } }; const mergeItemsIntoResult = (result, items) => { if (items.allOf || result.allOf) { const allOfSchemas = []; if (result.allOf) { for (const schema of result.allOf) { allOfSchemas.push(getResolvedRef(schema)); } } else { allOfSchemas.push(result); } if (items.allOf) { for (const schema of items.allOf) { allOfSchemas.push(getResolvedRef(schema)); } } else { allOfSchemas.push(items); } const merged = mergeAllOfSchemas({ allOf: allOfSchemas }); Object.assign(result, merged); return; } Object.assign(result, items); if ("properties" in result && "properties" in items) { mergePropertiesIntoResult(result.properties, items.properties); } }; const mergeItems = (existing, incoming) => { if (existing.allOf || incoming.allOf) { const allOfSchemas = []; if (existing.allOf) { for (const schema of existing.allOf) { allOfSchemas.push(getResolvedRef(schema)); } } else { allOfSchemas.push(existing); } if (incoming.allOf) { for (const schema of incoming.allOf) { allOfSchemas.push(getResolvedRef(schema)); } } else { allOfSchemas.push(incoming); } return mergeAllOfSchemas({ allOf: allOfSchemas }); } const merged = { ...existing, ...incoming }; if ("properties" in existing && "properties" in incoming) { merged.properties = { ...existing.properties }; mergePropertiesIntoResult(merged.properties, incoming.properties); } return merged; }; export { mergeAllOfSchemas };