swagger-tools/src/utils/format.ts
rimskij cc789d3b32 feat: initial MCP server for OpenAPI/Swagger parsing
- Parse and validate OpenAPI 3.x / Swagger 2.0 specs
- Query endpoints by method, path pattern, tag, operationId
- Get component schema details
- Generate TypeScript interfaces from schemas
- Support local files and remote URLs

Tools: parse-spec, validate-spec, query-endpoints, get-schema, generate-types

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-12 14:33:10 +01:00

146 lines
3.6 KiB
TypeScript

import type { EndpointInfo, ParsedSpec, ValidationResult, SchemaInfo } from '../lib/types.js';
export function formatMetadata(metadata: ParsedSpec): string {
const lines = [
`# ${metadata.title}`,
`Version: ${metadata.version}`,
];
if (metadata.description) {
lines.push(`Description: ${metadata.description}`);
}
lines.push('');
lines.push(`## Statistics`);
lines.push(`- Paths: ${metadata.pathCount}`);
lines.push(`- Operations: ${metadata.operationCount}`);
lines.push(`- Schemas: ${metadata.schemaCount}`);
if (metadata.servers.length > 0) {
lines.push('');
lines.push(`## Servers`);
metadata.servers.forEach(s => lines.push(`- ${s}`));
}
if (metadata.tags.length > 0) {
lines.push('');
lines.push(`## Tags`);
metadata.tags.forEach(t => lines.push(`- ${t}`));
}
return lines.join('\n');
}
export function formatValidation(result: ValidationResult): string {
const lines: string[] = [];
if (result.valid) {
lines.push('Validation: PASSED');
} else {
lines.push('Validation: FAILED');
}
if (result.errors.length > 0) {
lines.push('');
lines.push('## Errors');
for (const err of result.errors) {
const path = err.path ? `[${err.path}] ` : '';
lines.push(`- ${path}${err.message}`);
}
}
if (result.warnings.length > 0) {
lines.push('');
lines.push('## Warnings');
for (const warn of result.warnings) {
const path = warn.path ? `[${warn.path}] ` : '';
lines.push(`- ${path}${warn.message}`);
}
}
return lines.join('\n');
}
export function formatEndpoints(endpoints: EndpointInfo[]): string {
if (endpoints.length === 0) {
return 'No endpoints found matching criteria.';
}
const lines = [`Found ${endpoints.length} endpoint(s):`, ''];
for (const ep of endpoints) {
lines.push(`## ${ep.method.toUpperCase()} ${ep.path}`);
if (ep.operationId) {
lines.push(`Operation ID: ${ep.operationId}`);
}
if (ep.summary) {
lines.push(`Summary: ${ep.summary}`);
}
if (ep.tags.length > 0) {
lines.push(`Tags: ${ep.tags.join(', ')}`);
}
if (ep.parameters.length > 0) {
lines.push('');
lines.push('### Parameters');
for (const param of ep.parameters) {
const required = param.required ? ' (required)' : '';
lines.push(`- **${param.name}** [${param.in}]${required}`);
if (param.description) {
lines.push(` ${param.description}`);
}
}
}
if (ep.requestBody) {
lines.push('');
lines.push('### Request Body');
const required = ep.requestBody.required ? ' (required)' : '';
lines.push(`Content types${required}: ${ep.requestBody.contentTypes.join(', ')}`);
if (ep.requestBody.description) {
lines.push(ep.requestBody.description);
}
}
if (ep.responses.length > 0) {
lines.push('');
lines.push('### Responses');
for (const resp of ep.responses) {
lines.push(`- **${resp.statusCode}**: ${resp.description || 'No description'}`);
}
}
lines.push('');
}
return lines.join('\n');
}
export function formatSchema(schema: SchemaInfo): string {
const lines = [
`# ${schema.name}`,
];
if (schema.description) {
lines.push(schema.description);
}
if (schema.type) {
lines.push(`Type: ${schema.type}`);
}
lines.push('');
lines.push('## Schema');
lines.push('```json');
lines.push(JSON.stringify(schema.schema, null, 2));
lines.push('```');
return lines.join('\n');
}
export function formatTypes(types: string): string {
return ['## Generated TypeScript Types', '', '```typescript', types, '```'].join('\n');
}