woaru
Version:
Universal Project Setup Autopilot - Analyze and automatically configure development tools for ANY programming language
228 lines • 8.12 kB
JavaScript
/**
* TypeScript/JavaScript Parser für SOLID-Analyse
* Verwendet einfache Regex-basierte Parsing für Quick Win Implementation
*/
import fs from 'fs-extra';
export class TypeScriptParser {
/**
* Analysiert eine TypeScript/JavaScript-Datei und extrahiert Klassen-Informationen
*/
async parseFile(filePath) {
const content = await fs.readFile(filePath, 'utf-8');
const lines = content.split('\n');
return {
classes: this.extractClasses(content, lines),
imports: this.extractImports(lines),
totalLines: lines.length,
};
}
/**
* Extrahiert alle Klassen aus dem Code
*/
extractClasses(content, _lines) {
const classes = [];
// Regex für Klassen-Deklarationen (class, export class, abstract class)
const classRegex = /(?:export\s+)?(?:abstract\s+)?class\s+(\w+)/g;
let match;
while ((match = classRegex.exec(content)) !== null) {
const className = match[1];
const classStartIndex = match.index;
// Finde die Zeile der Klassen-Deklaration
const lineNumber = this.getLineNumber(content, classStartIndex);
// Extrahiere die gesamte Klasse (von { bis })
const classContent = this.extractClassContent(content, classStartIndex);
if (classContent) {
const methods = this.extractMethods(classContent);
const classLines = classContent.split('\n');
classes.push({
name: className,
line: lineNumber,
methods: methods,
imports: [], // Wird später gefüllt
complexity: this.calculateClassComplexity(classContent),
linesOfCode: classLines.length,
concerns: [], // Wird später gefüllt
});
}
}
return classes;
}
/**
* Extrahiert alle Import-Statements
*/
extractImports(lines) {
const imports = [];
lines.forEach(line => {
const trimmed = line.trim();
// Standard imports: import ... from '...'
const importMatch = trimmed.match(/import\s+.*?\s+from\s+['"`]([^'"`]+)['"`]/);
if (importMatch) {
imports.push(importMatch[1]);
return;
}
// Require statements: require('...')
const requireMatch = trimmed.match(/require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/);
if (requireMatch) {
imports.push(requireMatch[1]);
return;
}
// Dynamic imports: import('...')
const dynamicImportMatch = trimmed.match(/import\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/);
if (dynamicImportMatch) {
imports.push(dynamicImportMatch[1]);
}
});
return imports;
}
/**
* Extrahiert alle Methoden einer Klasse
*/
extractMethods(classContent) {
const methods = [];
// Regex für Methoden (public/private/protected, async, static, etc.)
const methodRegex = /(?:(?:public|private|protected)\s+)?(?:static\s+)?(?:async\s+)?(\w+)\s*\([^)]*\)\s*[:{]/g;
let match;
while ((match = methodRegex.exec(classContent)) !== null) {
const methodName = match[1];
// Skip constructor and getter/setter patterns
if (methodName === 'constructor' ||
methodName === 'get' ||
methodName === 'set') {
continue;
}
const methodStartIndex = match.index;
const lineNumber = this.getLineNumber(classContent, methodStartIndex);
// Extrahiere Parameter-Anzahl
const paramMatch = match[0].match(/\(([^)]*)\)/);
const paramCount = paramMatch ? this.countParameters(paramMatch[1]) : 0;
// Extrahiere Methoden-Content für Komplexität
const methodContent = this.extractMethodContent(classContent, methodStartIndex);
methods.push({
name: methodName,
line: lineNumber,
parameters: paramCount,
complexity: this.calculateMethodComplexity(methodContent),
linesOfCode: methodContent.split('\n').length,
});
}
return methods;
}
/**
* Berechnet die Zeilen-Nummer basierend auf dem Index im String
*/
getLineNumber(content, index) {
return content.substring(0, index).split('\n').length;
}
/**
* Extrahiert den Inhalt einer Klasse (von öffnender bis schließender Klammer)
*/
extractClassContent(content, startIndex) {
let braceCount = 0;
let inClass = false;
let classStart = -1;
for (let i = startIndex; i < content.length; i++) {
const char = content[i];
if (char === '{') {
if (!inClass) {
inClass = true;
classStart = i;
}
braceCount++;
}
else if (char === '}') {
braceCount--;
if (inClass && braceCount === 0) {
return content.substring(classStart, i + 1);
}
}
}
return '';
}
/**
* Extrahiert den Inhalt einer Methode
*/
extractMethodContent(classContent, methodStartIndex) {
let braceCount = 0;
let inMethod = false;
let methodStart = -1;
for (let i = methodStartIndex; i < classContent.length; i++) {
const char = classContent[i];
if (char === '{') {
if (!inMethod) {
inMethod = true;
methodStart = i;
}
braceCount++;
}
else if (char === '}') {
braceCount--;
if (inMethod && braceCount === 0) {
return classContent.substring(methodStart, i + 1);
}
}
}
return '';
}
/**
* Zählt Parameter in einem Parameter-String
*/
countParameters(paramString) {
if (!paramString.trim())
return 0;
// Einfache Zählung - trennt bei Kommas (nicht perfekt, aber gut für MVP)
return paramString.split(',').filter(p => p.trim()).length;
}
/**
* Berechnet eine einfache Komplexitäts-Metrik für eine Klasse
*/
calculateClassComplexity(classContent) {
let complexity = 1; // Base complexity
// Zähle Kontroll-Strukturen
const controlStructures = [
/\bif\s*\(/g,
/\belse\s+if\s*\(/g,
/\bwhile\s*\(/g,
/\bfor\s*\(/g,
/\bswitch\s*\(/g,
/\bcase\s+/g,
/\bcatch\s*\(/g,
/&&/g,
/\|\|/g,
/\?.*:/g, // Ternary operators
];
controlStructures.forEach(regex => {
const matches = classContent.match(regex);
if (matches) {
complexity += matches.length;
}
});
return complexity;
}
/**
* Berechnet eine einfache Komplexitäts-Metrik für eine Methode
*/
calculateMethodComplexity(methodContent) {
let complexity = 1; // Base complexity
// Zähle Kontroll-Strukturen (gleiche Logik wie bei Klassen)
const controlStructures = [
/\bif\s*\(/g,
/\belse\s+if\s*\(/g,
/\bwhile\s*\(/g,
/\bfor\s*\(/g,
/\bswitch\s*\(/g,
/\bcase\s+/g,
/\bcatch\s*\(/g,
/&&/g,
/\|\|/g,
/\?.*:/g,
];
controlStructures.forEach(regex => {
const matches = methodContent.match(regex);
if (matches) {
complexity += matches.length;
}
});
return complexity;
}
}
//# sourceMappingURL=TypeScriptParser.js.map