swagger-auto-generate
Version:
Automatically generate Swagger JSDoc documentation for Express applications
199 lines • 6.91 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.JSDocGenerator = void 0;
class JSDocGenerator {
/**
* Generate JSDoc comment for a route
*/
static generateJSDoc(route) {
const tags = [];
// Add @swagger tag
tags.push({
name: 'swagger',
description: this.generateSwaggerTag(route),
});
// Add @param tags for each parameter
for (const param of route.parameters) {
tags.push({
name: 'param',
description: `${param.in} ${param.name} - ${param.description || param.type}`,
type: param.type,
optional: !param.required,
});
}
// Add @returns tag
tags.push({
name: 'returns',
description: 'Response object',
type: 'object',
});
const jsdoc = {
description: route.description || `Handle ${route.method.toUpperCase()} request to ${route.path}`,
tags,
};
return this.formatJSDoc(jsdoc);
}
/**
* Generate Swagger tag content
*/
static generateSwaggerTag(route) {
const swaggerObj = {
[`/${route.path}`]: {
[route.method]: {
tags: route.tags || ['api'],
summary: route.summary,
description: route.description,
parameters: route.parameters.map(param => ({
name: param.name,
in: param.in,
required: param.required,
type: param.type,
description: param.description,
schema: param.schema,
})),
responses: route.responses.reduce((acc, response) => {
acc[response.code] = {
description: response.description,
schema: response.schema,
};
return acc;
}, {}),
},
},
};
return JSON.stringify(swaggerObj, null, 2);
}
/**
* Format JSDoc comment
*/
static formatJSDoc(jsdoc) {
let result = '/**\n';
// Add description
if (jsdoc.description) {
result += ` * ${jsdoc.description}\n`;
result += ' *\n';
}
// Add tags
for (const tag of jsdoc.tags) {
if (tag.type) {
result += ` * @${tag.name} {${tag.type}} ${tag.description}\n`;
}
else {
result += ` * @${tag.name} ${tag.description}\n`;
}
}
result += ' */';
return result;
}
/**
* Generate complete Swagger specification
*/
static generateSwaggerSpec(routes, config) {
const paths = {};
for (const route of routes) {
const pathKey = `/${route.path}`;
if (!paths[pathKey]) {
paths[pathKey] = {};
}
paths[pathKey][route.method] = {
tags: route.tags || ['api'],
summary: route.summary,
description: route.description,
parameters: route.parameters.map(param => ({
name: param.name,
in: param.in,
required: param.required,
type: param.type,
description: param.description,
schema: param.schema,
})),
responses: route.responses.reduce((acc, response) => {
acc[response.code] = {
description: response.description,
schema: response.schema,
};
return acc;
}, {}),
};
}
return {
swagger: '2.0',
info: {
title: config.swaggerInfo.title,
version: config.swaggerInfo.version,
description: config.swaggerInfo.description,
host: config.swaggerInfo.host,
basePath: config.swaggerInfo.basePath,
schemes: config.swaggerInfo.schemes || ['http'],
},
paths,
definitions: this.generateDefinitions(routes),
};
}
/**
* Generate model definitions
*/
static generateDefinitions(routes) {
const definitions = {};
// Add common response models
definitions['SuccessResponse'] = {
type: 'object',
properties: {
success: { type: 'boolean' },
data: { type: 'object' },
message: { type: 'string' },
},
};
definitions['ErrorResponse'] = {
type: 'object',
properties: {
success: { type: 'boolean' },
error: { type: 'string' },
message: { type: 'string' },
},
};
// Extract models from route parameters and responses
for (const route of routes) {
for (const param of route.parameters) {
if (param.schema && param.schema.$ref) {
const modelName = param.schema.$ref.replace('#/definitions/', '');
if (!definitions[modelName]) {
definitions[modelName] = {
type: 'object',
properties: {},
};
}
}
}
for (const response of route.responses) {
if (response.schema && response.schema.$ref) {
const modelName = response.schema.$ref.replace('#/definitions/', '');
if (!definitions[modelName]) {
definitions[modelName] = {
type: 'object',
properties: {},
};
}
}
}
}
return definitions;
}
/**
* Inject JSDoc into source code
*/
static injectJSDoc(sourceCode, route, jsdoc) {
const lines = sourceCode.split('\n');
const targetLine = route.lineNumber - 1; // Convert to 0-based index
if (targetLine >= 0 && targetLine < lines.length) {
// Find the function declaration line
const functionLine = lines[targetLine];
// Insert JSDoc before the function
lines.splice(targetLine, 0, jsdoc);
return lines.join('\n');
}
return sourceCode;
}
}
exports.JSDocGenerator = JSDocGenerator;
//# sourceMappingURL=jsdocGenerator.js.map