Project-Image-Uploader/backend/src/generate-openapi.js

97 lines
3.0 KiB
JavaScript
Raw Blame History

const swaggerAutogen = require('swagger-autogen')();
const path = require('path');
const fs = require('fs');
const outputFile = path.join(__dirname, '..', 'docs', 'openapi.json');
// Import route mappings (Single Source of Truth - keine Router-Imports!)
const routeMappings = require('./routes/routeMappings');
// Use mappings directly (already has file + prefix)
const routerMappings = routeMappings;
const routesDir = path.join(__dirname, 'routes');
const endpointsFiles = routerMappings.map(r => path.join(routesDir, r.file));
const doc = {
info: {
title: 'Project Image Uploader API',
version: '2.0.1',
description: 'Auto-generated OpenAPI spec with correct mount prefixes'
},
host: 'localhost:5001',
schemes: ['http'],
// Add base path hints per router (swagger-autogen doesn't natively support per-file prefixes,
// so we'll post-process or use @swagger annotations in route files)
};
console.log('Generating OpenAPI spec...');
// Generate specs for each router separately with correct basePath
async function generateWithPrefixes() {
const allPaths = {};
const allTags = new Set();
for (const mapping of routerMappings) {
console.log(`<EFBFBD> Processing ${mapping.file} with prefix: "${mapping.prefix || '/'}"...`);
const uniqueName = mapping.name || mapping.file.replace('.js', '');
const tempOutput = path.join(__dirname, '..', 'docs', `.temp-${uniqueName}.json`);
const routeFile = path.join(routesDir, mapping.file);
const tempDoc = {
...doc,
basePath: mapping.prefix || '/'
};
await swaggerAutogen(tempOutput, [routeFile], tempDoc);
// Read the generated spec
const tempSpec = JSON.parse(fs.readFileSync(tempOutput, 'utf8'));
// Merge paths - prepend prefix to each path
for (const [routePath, pathObj] of Object.entries(tempSpec.paths || {})) {
const fullPath = mapping.prefix + routePath;
allPaths[fullPath] = pathObj;
// Collect tags
Object.values(pathObj).forEach(methodObj => {
if (methodObj.tags) {
methodObj.tags.forEach(tag => allTags.add(tag));
}
});
}
// Clean up temp file
fs.unlinkSync(tempOutput);
}
// Write final merged spec
const finalSpec = {
openapi: '3.0.0',
info: doc.info,
servers: [
{ url: 'http://localhost:5001', description: 'Development server (dev compose backend)' }
],
tags: Array.from(allTags).map(name => ({ name })),
paths: allPaths
};
fs.writeFileSync(outputFile, JSON.stringify(finalSpec, null, 2));
console.log('\n✅ OpenAPI spec generated successfully!');
console.log(`📊 Total paths: ${Object.keys(allPaths).length}`);
console.log(`📋 Tags: ${Array.from(allTags).join(', ')}`);
}
// Export for programmatic usage (e.g., from server.js)
module.exports = generateWithPrefixes;
// Run directly when called from CLI
if (require.main === module) {
generateWithPrefixes().catch(err => {
console.error('❌ Failed to generate OpenAPI spec:', err);
process.exit(1);
});
}