UNPKG

arela

Version:

AI-powered CTO with multi-agent orchestration, code summarization, visual testing (web + mobile) for blazing fast development.

168 lines (167 loc) 5.93 kB
/** * Generate TypeScript interfaces from OpenAPI schemas */ export function generateTypes(spec) { let output = `/** * Auto-generated TypeScript types from OpenAPI spec * DO NOT EDIT - This file is generated by Arela * @see https://swagger.io/specification/ */ `; // Extract all schemas from components const schemas = spec.components?.schemas || {}; for (const [name, schema] of Object.entries(schemas)) { output += generateInterface(name, schema); output += '\n\n'; } // Generate request/response types for each endpoint for (const [path, methods] of Object.entries(spec.paths)) { for (const [method, operation] of Object.entries(methods)) { if (typeof operation !== 'object' || !operation) continue; if (operation.requestBody) { output += generateRequestType(path, method, operation); output += '\n\n'; } if (operation.responses) { output += generateResponseType(path, method, operation); output += '\n\n'; } } } return output; } function generateInterface(name, schema) { const properties = schema.properties || {}; const required = schema.required || []; let output = `export interface ${name} {\n`; for (const [propName, propSchema] of Object.entries(properties)) { const isRequired = required.includes(propName); const tsType = schemaToTypeScript(propSchema); const description = propSchema.description ? ` /** ${propSchema.description} */\n` : ''; output += `${description} ${propName}${isRequired ? '' : '?'}: ${tsType};\n`; } output += '}'; return output; } export function schemaToTypeScript(schema) { if (!schema) return 'any'; // Handle $ref if (schema.$ref) { const refName = schema.$ref.split('/').pop(); return refName || 'any'; } // Handle oneOf, anyOf, allOf if (schema.oneOf) { return schema.oneOf.map((s) => schemaToTypeScript(s)).join(' | '); } if (schema.anyOf) { return schema.anyOf.map((s) => schemaToTypeScript(s)).join(' | '); } if (schema.allOf) { return schema.allOf.map((s) => schemaToTypeScript(s)).join(' & '); } // Handle enum if (schema.enum) { return schema.enum.map((e) => `'${e}'`).join(' | '); } switch (schema.type) { case 'string': if (schema.format === 'date') return 'string'; // or Date if (schema.format === 'date-time') return 'string'; // or Date return 'string'; case 'number': case 'integer': return 'number'; case 'boolean': return 'boolean'; case 'null': return 'null'; case 'array': if (!schema.items) return 'any[]'; return `${schemaToTypeScript(schema.items)}[]`; case 'object': if (schema.additionalProperties === true) { return 'Record<string, any>'; } if (typeof schema.additionalProperties === 'object') { return `Record<string, ${schemaToTypeScript(schema.additionalProperties)}>`; } if (schema.properties) { const props = Object.entries(schema.properties) .map(([key, val]) => `${key}${!schema.required?.includes(key) ? '?' : ''}: ${schemaToTypeScript(val)}`) .join('; '); return `{ ${props} }`; } return '{ [key: string]: any }'; default: return 'any'; } } function generateRequestType(path, method, operation) { const operationId = operation.operationId || generateOperationId(path, method); const typeName = `${capitalize(operationId)}Request`; const requestBody = operation.requestBody; if (!requestBody) return ''; const contentValue = Object.values(requestBody.content)?.[0]; const schema = contentValue?.schema; if (!schema) return ''; const type = schemaToTypeScript(schema); return `export type ${typeName} = ${type};`; } function generateResponseType(path, method, operation) { const operationId = operation.operationId || generateOperationId(path, method); const typeName = `${capitalize(operationId)}Response`; const responses = operation.responses || {}; const successResponse = responses['200'] || responses['201'] || Object.values(responses)[0]; if (!successResponse) return ''; const contentValue = Object.values(successResponse.content)?.[0]; const schema = contentValue?.schema; if (!schema) return ''; const type = schemaToTypeScript(schema); return `export type ${typeName} = ${type};`; } function generateOperationId(path, method) { const parts = path.split('/').filter((p) => p && !p.startsWith('{')); const resource = parts[parts.length - 1] || 'resource'; const action = getActionFromMethod(method); return `${action}${capitalize(singularize(resource))}`; } function getActionFromMethod(method) { const m = method.toLowerCase(); switch (m) { case 'get': return 'get'; case 'post': return 'create'; case 'put': return 'update'; case 'patch': return 'patch'; case 'delete': return 'delete'; default: return 'call'; } } function singularize(word) { if (word.endsWith('ies')) return word.slice(0, -3) + 'y'; if (word.endsWith('es')) return word.slice(0, -2); if (word.endsWith('s')) return word.slice(0, -1); return word; } function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } //# sourceMappingURL=type-generator.js.map