import { AnalysisResult, ImprovementSuggestion, Severity, CodeElement } from '../types/index.js';
export class ImprovementSuggester {
generateSuggestions(results: AnalysisResult[]): ImprovementSuggestion[] {
const suggestions: ImprovementSuggestion[] = [];
for (const result of results) {
for (const element of result.elements) {
const suggestion = this.analyzElement(element);
if (suggestion) {
suggestions.push(suggestion);
}
}
}
return suggestions;
}
private analyzElement(element: CodeElement): ImprovementSuggestion | null {
// Missing documentation
if (!element.hasDocumentation) {
return {
element,
suggestedDoc: this.generateDocTemplate(element),
reason: 'Missing documentation',
severity: this.getSeverity(element, 'missing')
};
}
// Poor documentation quality
const quality = this.assessDocQuality(element);
if (quality.needsImprovement) {
return {
element,
currentDoc: element.documentation,
suggestedDoc: this.improveDoc(element),
reason: quality.reason,
severity: Severity.MEDIUM
};
}
return null;
}
private generateDocTemplate(element: CodeElement): string {
const templates: Record<CodeElement['type'], string> = {
'function': `/**\n * ${element.name} - Brief description\n * \n * @param {type} paramName - Parameter description\n * @returns {type} Return value description\n */`,
'method': `/**\n * ${element.name} - Brief description of the method\n * \n * @param {type} paramName - Parameter description\n * @returns {type} Return value description\n */`,
'class': `/**\n * ${element.name} class\n * \n * Brief description of the class purpose and functionality\n */`,
'interface': `/**\n * ${element.name} interface\n * \n * Description of the interface and its properties\n */`,
'type': `/**\n * ${element.name} type\n * \n * Description of the type definition\n */`,
'variable': `/** ${element.name} - Brief description of the variable purpose */`
};
return templates[element.type];
}
private assessDocQuality(element: CodeElement): { needsImprovement: boolean; reason: string } {
if (!element.documentation) {
return { needsImprovement: false, reason: '' };
}
const doc = element.documentation;
const wordCount = doc.split(/\s+/).length;
// Too short
if (wordCount < 3) {
return {
needsImprovement: true,
reason: 'Documentation is too brief (less than 3 words)'
};
}
// Missing parameter documentation for functions/methods
if ((element.type === 'function' || element.type === 'method') && element.signature) {
const hasParams = /\(.*\w+.*\)/.test(element.signature);
const hasParamDocs = /@param|@arg|:param/.test(doc);
if (hasParams && !hasParamDocs) {
return {
needsImprovement: true,
reason: 'Missing parameter documentation'
};
}
}
// Missing return documentation
if ((element.type === 'function' || element.type === 'method')) {
const hasReturnDocs = /@returns?|@return|:return/.test(doc);
if (!hasReturnDocs && !doc.toLowerCase().includes('return')) {
return {
needsImprovement: true,
reason: 'Missing return value documentation'
};
}
}
return { needsImprovement: false, reason: '' };
}
private improveDoc(element: CodeElement): string {
const current = element.documentation || '';
if ((element.type === 'function' || element.type === 'method')) {
const lines = [current];
if (!/@param/.test(current)) {
lines.push(' * @param {type} paramName - Parameter description');
}
if (!/@returns?/.test(current)) {
lines.push(' * @returns {type} Return value description');
}
return lines.join('\n');
}
return current + '\n * [Add more detailed description here]';
}
private getSeverity(element: CodeElement, issue: 'missing' | 'poor'): Severity {
if (issue === 'missing') {
if (element.type === 'class' || element.type === 'interface') {
return Severity.CRITICAL;
}
if (element.type === 'function' || element.type === 'method') {
const isPrivate = element.name.startsWith('_') || element.name.startsWith('#');
return isPrivate ? Severity.LOW : Severity.CRITICAL;
}
return Severity.MEDIUM;
}
return Severity.MEDIUM;
}
}