UNPKG

@pulzar/core

Version:

Next-generation Node.js framework for ultra-fast web applications with zero-reflection DI, GraphQL, WebSockets, events, and edge runtime support

153 lines 5.42 kB
import { z } from "zod"; export class OpenAPIGenerator { config; routes = new Map(); schemas = new Map(); constructor(config) { this.config = config; } addRoute(path, method, metadata) { const key = `${method.toUpperCase()} ${path}`; this.routes.set(key, metadata); } addSchema(name, schema) { this.schemas.set(name, schema); } generate() { const spec = { openapi: "3.1.0", info: { title: this.config.title, version: this.config.version, description: this.config.description, ...(this.config.contact && { contact: this.config.contact }), ...(this.config.license && { license: this.config.license }), }, servers: this.config.servers || [{ url: "/" }], paths: this.generatePaths(), components: { schemas: this.generateSchemas(), securitySchemes: this.generateSecuritySchemes(), }, security: this.config.security || [], }; return spec; } generatePaths() { const paths = {}; for (const [key, metadata] of this.routes) { const parts = key.split(" "); const method = parts[0]; const path = parts[1]; if (!method || !path) continue; const pathKey = this.normalizePath(path); if (!paths[pathKey]) { paths[pathKey] = {}; } paths[pathKey][method.toLowerCase()] = { summary: metadata.summary, description: metadata.description, tags: metadata.tags, parameters: metadata.parameters?.map((param) => ({ name: param.name, in: param.in, required: param.required, schema: this.zodToOpenAPI(param.schema), description: param.description, })), requestBody: metadata.requestBody ? { required: metadata.requestBody.required, content: Object.entries(metadata.requestBody.content).reduce((acc, [contentType, content]) => { acc[contentType] = { schema: this.zodToOpenAPI(content.schema), }; return acc; }, {}), } : undefined, responses: Object.entries(metadata.responses).reduce((acc, [code, response]) => { acc[code] = { description: response.description, content: response.content ? Object.entries(response.content).reduce((contentAcc, [contentType, content]) => { contentAcc[contentType] = { schema: this.zodToOpenAPI(content.schema), }; return contentAcc; }, {}) : undefined, }; return acc; }, {}), security: metadata.security, }; } return paths; } generateSchemas() { const schemas = {}; for (const [name, schema] of this.schemas) { schemas[name] = this.zodToOpenAPI(schema); } return schemas; } generateSecuritySchemes() { return { bearerAuth: { type: "http", scheme: "bearer", bearerFormat: "JWT", }, apiKeyAuth: { type: "apiKey", in: "header", name: "X-API-Key", }, }; } zodToOpenAPI(schema) { // This is a simplified conversion // In a real implementation, you'd need a more comprehensive zod-to-openapi converter if (schema instanceof z.ZodString) { return { type: "string" }; } if (schema instanceof z.ZodNumber) { return { type: "number" }; } if (schema instanceof z.ZodBoolean) { return { type: "boolean" }; } if (schema instanceof z.ZodArray) { return { type: "array", items: this.zodToOpenAPI(schema.element), }; } if (schema instanceof z.ZodObject) { return { type: "object", properties: Object.entries(schema.shape).reduce((acc, [key, value]) => { acc[key] = this.zodToOpenAPI(value); return acc; }, {}), }; } return { type: "string" }; } normalizePath(path) { return path.replace(/\[([^\]]+)\]/g, "{$1}"); } generateJSON() { return JSON.stringify(this.generate(), null, 2); } generateYAML() { // In a real implementation, you'd use a YAML library return JSON.stringify(this.generate(), null, 2); } } export function createOpenAPIGenerator(config) { return new OpenAPIGenerator(config); } //# sourceMappingURL=generator.js.map