breathe-api
Version:
Model Context Protocol server for Breathe HR APIs with Swagger/OpenAPI support - also works with custom APIs
138 lines • 5.55 kB
JavaScript
export async function generateTypesFromSchema(spec) {
const types = [];
const schemas = spec.components?.schemas || spec.definitions || {};
types.push('// Auto-generated TypeScript types from Swagger/OpenAPI spec');
types.push('');
for (const [name, schema] of Object.entries(schemas)) {
types.push(generateInterface(name, schema));
types.push('');
}
if (spec.paths) {
types.push('// API Operation Types');
types.push('');
for (const [path, pathItem] of Object.entries(spec.paths)) {
for (const [method, operation] of Object.entries(pathItem)) {
if (['get', 'post', 'put', 'delete', 'patch'].includes(method.toLowerCase())) {
const opTypes = generateOperationTypes(path, method, operation);
if (opTypes) {
types.push(opTypes);
types.push('');
}
}
}
}
}
return types.join('\n');
}
function generateInterface(name, schema) {
const lines = [];
lines.push(`export interface ${sanitizeName(name)} {`);
if (schema.type === 'object' && schema.properties) {
for (const [propName, propSchema] of Object.entries(schema.properties)) {
const required = schema.required?.includes(propName) || false;
const optional = required ? '' : '?';
const type = getTypeFromSchema(propSchema);
lines.push(` ${propName}${optional}: ${type};`);
}
}
else if (schema.enum) {
return `export type ${sanitizeName(name)} = ${schema.enum.map((v) => `'${v}'`).join(' | ')};`;
}
lines.push('}');
return lines.join('\n');
}
function generateOperationTypes(_path, _method, operation) {
if (!operation.operationId)
return null;
const lines = [];
const opName = sanitizeName(operation.operationId);
const hasParams = operation.parameters && operation.parameters.length > 0;
const hasBody = operation.requestBody?.content;
if (hasParams || hasBody) {
lines.push(`export interface ${opName}Request {`);
if (hasParams) {
const queryParams = operation.parameters.filter((p) => p.in === 'query');
const pathParams = operation.parameters.filter((p) => p.in === 'path');
const headerParams = operation.parameters.filter((p) => p.in === 'header');
if (pathParams.length > 0) {
lines.push(' params: {');
for (const param of pathParams) {
const required = param.required ? '' : '?';
const schema = param.schema || {};
lines.push(` ${param.name}${required}: ${getTypeFromSchema(schema)};`);
}
lines.push(' };');
}
if (queryParams.length > 0) {
lines.push(' query?: {');
for (const param of queryParams) {
const required = param.required ? '' : '?';
const schema = param.schema || {};
lines.push(` ${param.name}${required}: ${getTypeFromSchema(schema)};`);
}
lines.push(' };');
}
if (headerParams.length > 0) {
lines.push(' headers?: {');
for (const param of headerParams) {
const required = param.required ? '' : '?';
const schema = param.schema || {};
lines.push(` ${param.name}${required}: ${getTypeFromSchema(schema)};`);
}
lines.push(' };');
}
}
if (hasBody) {
const content = operation.requestBody.content || {};
const firstContent = Object.values(content)[0];
const bodySchema = firstContent?.schema;
if (bodySchema) {
lines.push(` body: ${getTypeFromSchema(bodySchema)};`);
}
}
lines.push('}');
lines.push('');
}
if (operation.responses) {
const successResponse = operation.responses['200'] || operation.responses['201'];
if (successResponse?.content) {
const content = successResponse.content || {};
const firstContent = Object.values(content)[0];
const responseSchema = firstContent?.schema;
if (responseSchema) {
lines.push(`export type ${opName}Response = ${getTypeFromSchema(responseSchema)};`);
}
}
}
return lines.join('\n');
}
function getTypeFromSchema(schema) {
if (!schema)
return 'any';
if (schema.$ref) {
const refName = schema.$ref.split('/').pop();
return sanitizeName(refName);
}
switch (schema.type) {
case 'string':
return schema.enum ? schema.enum.map((v) => `'${v}'`).join(' | ') : 'string';
case 'number':
case 'integer':
return 'number';
case 'boolean':
return 'boolean';
case 'array':
return `Array<${getTypeFromSchema(schema.items)}>`;
case 'object':
if (schema.additionalProperties) {
return `Record<string, ${getTypeFromSchema(schema.additionalProperties)}>`;
}
return 'any';
default:
return 'any';
}
}
function sanitizeName(name) {
return name.replace(/[^a-zA-Z0-9_]/g, '');
}
//# sourceMappingURL=type-generator.js.map