import { AnalysisResult, MissingDocumentation, Severity, CodeElement } from '../types/index.js';
export class DocDetector {
detectMissingDocs(results: AnalysisResult[]): MissingDocumentation[] {
const missing: MissingDocumentation[] = [];
for (const result of results) {
for (const element of result.elements) {
if (!element.hasDocumentation) {
missing.push({
element,
severity: this.determineSeverity(element),
reason: this.getReason(element)
});
}
}
}
return missing.sort((a, b) => this.severityWeight(b.severity) - this.severityWeight(a.severity));
}
private determineSeverity(element: CodeElement): Severity {
// Public APIs and classes are critical
if (element.type === 'class' || element.type === 'interface') {
return Severity.CRITICAL;
}
// Public functions/methods are critical if exported or not private
if (element.type === 'function' || element.type === 'method') {
const isPrivate = element.name.startsWith('_') || element.name.startsWith('#');
return isPrivate ? Severity.LOW : Severity.CRITICAL;
}
// Types are medium priority
if (element.type === 'type') {
return Severity.MEDIUM;
}
// Variables are generally low priority
return Severity.LOW;
}
private getReason(element: CodeElement): string {
const reasons: Record<CodeElement['type'], string> = {
'class': 'Public class requires documentation for API consumers',
'interface': 'Interface definition requires documentation for proper usage',
'function': 'Public function should document parameters and return value',
'method': 'Public method should document its purpose and usage',
'type': 'Type alias should explain its purpose and structure',
'variable': 'Exported variable should document its purpose'
};
return reasons[element.type];
}
private severityWeight(severity: Severity): number {
const weights = {
[Severity.CRITICAL]: 3,
[Severity.MEDIUM]: 2,
[Severity.LOW]: 1
};
return weights[severity];
}
getSummary(missing: MissingDocumentation[]): {
total: number;
bySeverity: Record<Severity, number>;
byType: Record<string, number>;
} {
const bySeverity: Record<Severity, number> = {
[Severity.CRITICAL]: 0,
[Severity.MEDIUM]: 0,
[Severity.LOW]: 0
};
const byType: Record<string, number> = {};
for (const item of missing) {
bySeverity[item.severity]++;
byType[item.element.type] = (byType[item.element.type] || 0) + 1;
}
return {
total: missing.length,
bySeverity,
byType
};
}
}