UNPKG

@scalar/api-reference

Version:

Generate beautiful API references from OpenAPI documents

133 lines (132 loc) 4.37 kB
import { getResolvedRef } from "@scalar/workspace-store/helpers/get-resolved-ref"; import { isObjectSchema } from "@scalar/workspace-store/schemas/v3.1/strict/type-guards"; //#region src/helpers/openapi.ts var isSchemaObject = (value) => typeof value === "object" && value !== null; var schemaTypeToString = (schema) => { if (!("type" in schema)) return ""; if (typeof schema.type === "string") return schema.type; return Array.isArray(schema.type) ? schema.type.join("|") : ""; }; /** * Resolves a schema reference from workspace-store to a SchemaObject. * Returns undefined when a reference exists but has not been resolved yet. */ function resolveSchemaRef(ref) { if (typeof ref === "object" && ref !== null && "$ref" in ref) return isSchemaObject(ref["$ref-value"]) ? ref["$ref-value"] : void 0; return ref; } /** * Formats a property object into a string. */ function formatProperty(key, obj) { let output = key; const isRequired = obj.required?.includes(key); output += isRequired ? " REQUIRED " : " optional "; const propRef = obj.properties[key]; if (!propRef) return output; const property = resolveSchemaRef(propRef); if (property) { output += schemaTypeToString(property); if ("description" in property && typeof property.description === "string") output += ` ${property.description}`; } return output; } /** * Recursively logs the properties of an object. */ function recursiveLogger(obj) { const results = ["Body"]; const schema = getResolvedRef(obj?.schema); if (!schema || !isObjectSchema(schema) || !schema.properties) return results; const properties = schema.properties; const schemaWithProps = { properties, required: schema.required }; Object.keys(properties).forEach((key) => { if (!obj.schema) return; results.push(formatProperty(key, schemaWithProps)); const propRef = properties[key]; if (!propRef) return; const property = resolveSchemaRef(propRef); if (property && isObjectSchema(property) && property.properties) { const nestedProperties = property.properties; Object.keys(nestedProperties).forEach((subKey) => { const ref = nestedProperties[subKey]; if (!ref) return; const nested = resolveSchemaRef(ref); const typeStr = nested ? schemaTypeToString(nested) : ""; results.push(`${subKey} ${typeStr}`); }); } }); return results; } /** * Extracts the request body from an operation. */ function extractRequestBody(operation) { const content = getResolvedRef(operation?.requestBody)?.content; const contentValue = Object.values(content ?? {}); if (contentValue.length === 0) return null; return contentValue.flatMap((media) => recursiveLogger(media)); } /** * Formats a parameter into a searchable string. */ function formatParameter(param) { const output = [param.name]; output.push(param.required ? "REQUIRED" : "optional"); output.push(param.in); if ("schema" in param && param.schema) { const schema = getResolvedRef(param.schema); if (schema) output.push(schemaTypeToString(schema)); } if (param.description) output.push(param.description); return output.join(" "); } /** * Extracts parameters from an operation into searchable strings. */ function extractParameters(parameters) { return parameters.map((parameter) => formatParameter(getResolvedRef(parameter))); } /** * Deep merge for objects */ function deepMerge(source, target) { for (const [key, val] of Object.entries(source)) if (val !== null && typeof val === "object") { target[key] ??= new val.__proto__.constructor(); deepMerge(val, target[key]); } else if (typeof val !== "undefined") target[key] = val; return target; } /** * Creates an empty specification object. * The returning object has the same structure as a valid OpenAPI specification, but everything is empty. */ function createEmptySpecification(partialSpecification) { const emptySpecification = { openapi: "3.1.0", info: { title: "", description: "", termsOfService: "", version: "", license: { name: "", url: "" }, contact: { email: "" } }, servers: [], tags: [], "x-scalar-original-document-hash": "" }; if (!partialSpecification) return emptySpecification; deepMerge(partialSpecification, emptySpecification); return emptySpecification; } //#endregion export { createEmptySpecification, extractParameters, extractRequestBody }; //# sourceMappingURL=openapi.js.map