woaru
Version:
Universal Project Setup Autopilot - Analyze and automatically configure development tools for ANY programming language
249 lines • 10.5 kB
JavaScript
/**
* Single Responsibility Principle (SRP) Checker
* Erkennt Klassen und Methoden, die zu viele Verantwortlichkeiten haben
*/
import { BaseSOLIDChecker } from './BaseSOLIDChecker.js';
import { TypeScriptParser } from '../parsers/TypeScriptParser.js';
import { APP_CONFIG } from '../../config/constants.js';
import { t } from '../../config/i18n.js';
export class SRPChecker extends BaseSOLIDChecker {
principle = 'SRP';
supportedLanguages = ['typescript', 'javascript'];
parser;
constructor() {
super();
this.parser = new TypeScriptParser();
}
/**
* Führt SRP-Analyse für eine Datei durch
*/
async check(filePath, language) {
if (!this.supportsLanguage(language)) {
return [];
}
const violations = [];
try {
// Parse die Datei
const analysis = await this.parser.parseFile(filePath);
// Analysiere jede Klasse
for (const classAnalysis of analysis.classes) {
// Füge Import-Concerns zur Klassen-Analyse hinzu
classAnalysis.concerns = this.analyzeImportConcerns(analysis.imports);
// 1. Check für zu viele Methoden (High Method Count)
violations.push(...this.checkMethodCount(filePath, classAnalysis));
// 2. Check für zu hohe Komplexität
violations.push(...this.checkComplexity(filePath, classAnalysis));
// 3. Check für zu viele verschiedene Concerns
violations.push(...this.checkConcernDiversity(filePath, classAnalysis));
// 4. Check für zu große Klassen (Lines of Code)
violations.push(...this.checkClassSize(filePath, classAnalysis));
// 5. Check für Methoden mit zu vielen Parametern
violations.push(...this.checkMethodParameters(filePath, classAnalysis));
}
// 6. File-Level Check: Zu viele Klassen in einer Datei
violations.push(...this.checkFileClassCount(filePath, analysis.classes));
}
catch (error) {
// Log error with more context for debugging
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
console.warn(t('solid.srp.analysis_error', { filePath }), {
error: errorMessage,
stack: error instanceof Error ? error.stack : undefined,
});
}
return violations;
}
/**
* Prüft auf zu viele Methoden in einer Klasse
*/
checkMethodCount(filePath, classAnalysis) {
const violations = [];
const methodCount = classAnalysis.methods.length;
// Thresholds für Method Count
const thresholds = APP_CONFIG.SOLID_THRESHOLDS.METHODS_PER_CLASS;
if (methodCount >= thresholds.low) {
const severity = this.calculateSeverity(methodCount, thresholds);
violations.push(this.createViolation({
file: filePath,
line: classAnalysis.line,
class: classAnalysis.name,
description: t('solid.srp.method_count.description', {
className: classAnalysis.name,
count: methodCount,
}),
explanation: t('solid.srp.method_count.explanation'),
impact: t('solid.srp.method_count.impact'),
suggestion: t('solid.srp.method_count.suggestion', {
className: classAnalysis.name,
}),
severity,
metrics: {
methodCount: methodCount,
complexity: classAnalysis.complexity,
},
}));
}
return violations;
}
/**
* Prüft auf zu hohe Klassen-Komplexität
*/
checkComplexity(filePath, classAnalysis) {
const violations = [];
const complexity = classAnalysis.complexity;
// Thresholds für Complexity
const thresholds = APP_CONFIG.SOLID_THRESHOLDS.LINES_PER_METHOD;
if (complexity >= thresholds.low) {
const severity = this.calculateSeverity(complexity, thresholds);
violations.push(this.createViolation({
file: filePath,
line: classAnalysis.line,
class: classAnalysis.name,
description: t('solid.srp.complexity.description', {
className: classAnalysis.name,
complexity,
}),
explanation: t('solid.srp.complexity.explanation'),
impact: t('solid.srp.complexity.impact'),
suggestion: t('solid.srp.complexity.suggestion'),
severity,
metrics: {
complexity: complexity,
methodCount: classAnalysis.methods.length,
},
}));
}
return violations;
}
/**
* Prüft auf zu viele verschiedene Concerns (Verantwortlichkeiten)
*/
checkConcernDiversity(filePath, classAnalysis) {
const violations = [];
const concernCount = classAnalysis.concerns.length;
// Thresholds für Concern Diversity
const thresholds = APP_CONFIG.SOLID_THRESHOLDS.CONSTRUCTOR_PARAMS;
if (concernCount >= thresholds.low) {
const severity = this.calculateSeverity(concernCount, thresholds);
violations.push(this.createViolation({
file: filePath,
line: classAnalysis.line,
class: classAnalysis.name,
description: t('solid.srp.concern_diversity.description', {
className: classAnalysis.name,
concernCount,
concerns: classAnalysis.concerns.join(', '),
}),
explanation: t('solid.srp.concern_diversity.explanation'),
impact: t('solid.srp.concern_diversity.impact'),
suggestion: t('solid.srp.concern_diversity.suggestion', {
concernServices: classAnalysis.concerns
.map((c) => `${c}Service`)
.join(', '),
}),
severity,
metrics: {
dependencies: concernCount,
importConcerns: classAnalysis.concerns,
},
}));
}
return violations;
}
/**
* Prüft auf zu große Klassen (Lines of Code)
*/
checkClassSize(filePath, classAnalysis) {
const violations = [];
const linesOfCode = classAnalysis.linesOfCode;
// Thresholds für Class Size
const thresholds = APP_CONFIG.SOLID_THRESHOLDS.CHARACTERS_PER_LINE;
if (linesOfCode >= thresholds.low) {
const severity = this.calculateSeverity(linesOfCode, thresholds);
violations.push(this.createViolation({
file: filePath,
line: classAnalysis.line,
class: classAnalysis.name,
description: t('solid.srp.class_size.description', {
className: classAnalysis.name,
linesOfCode,
}),
explanation: t('solid.srp.class_size.explanation'),
impact: t('solid.srp.class_size.impact'),
suggestion: t('solid.srp.class_size.suggestion', {
className: classAnalysis.name,
}),
severity,
metrics: {
linesOfCode: linesOfCode,
methodCount: classAnalysis.methods.length,
},
}));
}
return violations;
}
/**
* Prüft auf Methoden mit zu vielen Parametern
*/
checkMethodParameters(filePath, classAnalysis) {
const violations = [];
classAnalysis.methods.forEach((method) => {
// Thresholds für Parameter Count
const thresholds = APP_CONFIG.SOLID_THRESHOLDS.METHODS_PER_INTERFACE;
if (method.parameters >= thresholds.low) {
const severity = this.calculateSeverity(method.parameters, thresholds);
violations.push(this.createViolation({
file: filePath,
line: method.line,
class: classAnalysis.name,
method: method.name,
description: t('solid.srp.method_parameters.description', {
methodName: method.name,
parameterCount: method.parameters,
}),
explanation: t('solid.srp.method_parameters.explanation'),
impact: t('solid.srp.method_parameters.impact'),
suggestion: t('solid.srp.method_parameters.suggestion', {
methodName: method.name,
}),
severity,
metrics: {
parameters: method.parameters,
complexity: method.complexity,
},
}));
}
});
return violations;
}
/**
* Prüft auf zu viele Klassen in einer Datei
*/
checkFileClassCount(filePath, classes) {
const violations = [];
const classCount = classes.length;
// Thresholds für Class Count per File
const thresholds = APP_CONFIG.SOLID_THRESHOLDS.ABSTRACT_METHODS;
if (classCount >= thresholds.low) {
const severity = this.calculateSeverity(classCount, thresholds);
violations.push(this.createViolation({
file: filePath,
description: t('solid.srp.file_class_count.description', {
classCount,
classList: classes.map(c => c.name).join(', '),
}),
explanation: t('solid.srp.file_class_count.explanation'),
impact: t('solid.srp.file_class_count.impact'),
suggestion: t('solid.srp.file_class_count.suggestion', {
fileName: this.getFileName(filePath),
}),
severity,
metrics: {
classCount: classCount,
},
}));
}
return violations;
}
}
//# sourceMappingURL=SRPChecker.js.map