UNPKG

fortify-schema

Version:

TypeScript interface-like schema validation system that's easier to use than Zod

228 lines (225 loc) 7.05 kB
'use strict'; /** * OpenAPI Converter - Convert schemas to OpenAPI specifications * * This module provides utilities to convert Fortify Schema definitions * to OpenAPI 3.0 specifications for API documentation. */ /** * OpenAPI converter for schema definitions */ class OpenAPIConverter { /** * Convert a schema to OpenAPI format */ static convertSchema(schema) { const properties = {}; const required = []; Object.entries(schema).forEach(([fieldName, fieldType]) => { const openApiProperty = this.convertField(fieldType); properties[fieldName] = openApiProperty.schema; if (openApiProperty.required) { required.push(fieldName); } }); return { type: "object", properties, required: required.length > 0 ? required : undefined }; } /** * Convert a single field to OpenAPI property */ static convertField(fieldType) { if (typeof fieldType === "string") { return this.convertStringField(fieldType); } if (typeof fieldType === "object" && !Array.isArray(fieldType)) { return this.convertObjectField(fieldType); } // Fallback return { schema: { type: "string" }, required: true }; } /** * Convert string-based field definitions */ static convertStringField(fieldType) { const isOptional = fieldType.includes("?"); const cleanType = fieldType.replace("?", ""); // Handle string types with constraints if (cleanType.startsWith("string")) { const constraints = this.parseStringConstraints(cleanType); return { schema: { type: "string", ...constraints }, required: !isOptional }; } // Handle specific string formats const formatMappings = { email: { type: "string", format: "email" }, url: { type: "string", format: "uri" }, uuid: { type: "string", format: "uuid" }, date: { type: "string", format: "date-time" }, phone: { type: "string", pattern: "^\\+?[1-9]\\d{1,14}$" } }; if (formatMappings[cleanType]) { return { schema: formatMappings[cleanType], required: !isOptional }; } // Handle number types if (cleanType === "number") { return { schema: { type: "number" }, required: !isOptional }; } if (cleanType === "positive") { return { schema: { type: "number", minimum: 0, exclusiveMinimum: true }, required: !isOptional }; } if (cleanType === "int") { return { schema: { type: "integer" }, required: !isOptional }; } // Handle boolean if (cleanType === "boolean") { return { schema: { type: "boolean" }, required: !isOptional }; } // Handle arrays if (cleanType.includes("[]")) { const itemType = cleanType.replace("[]", ""); const itemSchema = this.convertField(itemType).schema; return { schema: { type: "array", items: itemSchema }, required: !isOptional }; } // Default to string return { schema: { type: "string" }, required: !isOptional }; } /** * Convert object field definitions */ static convertObjectField(fieldType) { const nestedProperties = {}; const nestedRequired = []; Object.entries(fieldType).forEach(([nestedField, nestedType]) => { const nestedProperty = this.convertField(nestedType); nestedProperties[nestedField] = nestedProperty.schema; if (nestedProperty.required) { nestedRequired.push(nestedField); } }); return { schema: { type: "object", properties: nestedProperties, required: nestedRequired.length > 0 ? nestedRequired : undefined }, required: true }; } /** * Parse string constraints from string(min,max) format */ static parseStringConstraints(stringType) { const constraints = {}; const match = stringType.match(/string\((\d+)?,?(\d+)?\)/); if (match) { if (match[1]) constraints.minLength = parseInt(match[1]); if (match[2]) constraints.maxLength = parseInt(match[2]); } return constraints; } /** * Generate complete OpenAPI specification */ static generateOpenAPISpec(schema, options) { const schemaObject = this.convertSchema(schema); return { openapi: "3.0.0", info: { title: options.title, version: options.version, description: options.description }, servers: options.servers?.map(url => ({ url })) || [], components: { schemas: { [options.schemaName || options.title]: schemaObject } }, paths: options.paths || {} }; } /** * Generate schema reference for use in OpenAPI paths */ static generateSchemaReference(schemaName) { return { $ref: `#/components/schemas/${schemaName}` }; } /** * Generate request body specification */ static generateRequestBody(schema, options = {}) { const schemaObject = this.convertSchema(schema); return { description: options.description || "Request body", required: options.required !== false, content: { "application/json": { schema: schemaObject, examples: options.examples } } }; } /** * Generate response specification */ static generateResponse(schema, options = {}) { const schemaObject = this.convertSchema(schema); return { description: options.description || "Successful response", content: { "application/json": { schema: schemaObject, examples: options.examples } }, headers: options.headers }; } } exports.OpenAPIConverter = OpenAPIConverter; //# sourceMappingURL=openapi-converter.js.map