classNames); if (empty($classNames)) { return new ComponentDetectionResult( totalComponents: 0, bemComponents: [], utilityComponents: [], traditionalComponents: [], patternStatistics: [], recommendations: ['No CSS classes found to analyze for component patterns.'] ); } // Pattern-Erkennung $patterns = $this->classNameParser->detectPatterns($classNames); // Gruppierung nach Pattern-Typ $bemComponents = []; $utilityComponents = []; $traditionalComponents = []; foreach ($patterns as $pattern) { switch ($pattern->type) { case ComponentPatternType::BEM: $bemComponents[] = $pattern; break; case ComponentPatternType::UTILITY: $utilityComponents[] = $pattern; break; case ComponentPatternType::COMPONENT: $traditionalComponents[] = $pattern; break; } } // Statistiken erstellen $statistics = $this->generatePatternStatistics($patterns, $classNames); // Empfehlungen generieren $recommendations = $this->generateRecommendations($bemComponents, $utilityComponents, $traditionalComponents, $classNames); return new ComponentDetectionResult( totalComponents: count($patterns), bemComponents: $bemComponents, utilityComponents: $utilityComponents, traditionalComponents: $traditionalComponents, patternStatistics: $statistics, recommendations: $recommendations ); } /** * Analysiert spezifisch BEM-Patterns */ public function analyzeBemPatterns(CssParseResult $parseResult): array { $bemClasses = $parseResult->getBemClasses(); $analysis = []; foreach ($bemClasses as $className) { $block = $className->getBemBlock(); if (! isset($analysis[$block])) { $analysis[$block] = [ 'block' => $block, 'elements' => [], 'modifiers' => [], 'total_classes' => 0, 'completeness' => 'unknown', ]; } $analysis[$block]['total_classes']++; if ($className->isBemElement()) { $element = $className->getBemElement(); if ($element && ! in_array($element, $analysis[$block]['elements'])) { $analysis[$block]['elements'][] = $element; } } if ($className->isBemModifier()) { $modifier = $className->getBemModifier(); if ($modifier && ! in_array($modifier, $analysis[$block]['modifiers'])) { $analysis[$block]['modifiers'][] = $modifier; } } } // Completeness-Bewertung foreach ($analysis as $block => &$data) { $hasElements = ! empty($data['elements']); $hasModifiers = ! empty($data['modifiers']); if (! $hasElements && ! $hasModifiers) { $data['completeness'] = 'block_only'; } elseif ($hasElements && ! $hasModifiers) { $data['completeness'] = 'block_with_elements'; } elseif (! $hasElements && $hasModifiers) { $data['completeness'] = 'block_with_modifiers'; } else { $data['completeness'] = 'full_bem'; } } return $analysis; } /** * Analysiert Utility-Class-Patterns */ public function analyzeUtilityPatterns(CssParseResult $parseResult): array { $utilityClasses = $parseResult->getUtilityClasses(); $analysis = []; foreach ($utilityClasses as $className) { $category = $className->getUtilityCategory(); if (! $category) { continue; } if (! isset($analysis[$category])) { $analysis[$category] = [ 'category' => $category, 'classes' => [], 'count' => 0, 'coverage' => 'unknown', ]; } $analysis[$category]['classes'][] = $className->name; $analysis[$category]['count']++; } // Coverage-Bewertung für verschiedene Kategorien foreach ($analysis as $category => &$data) { $data['coverage'] = $this->assessUtilityCoverage($category, $data['classes']); } return $analysis; } /** * Findet potenzielle Component-Candidates */ public function findComponentCandidates(CssParseResult $parseResult): array { $candidates = []; $selectorFrequency = []; // Analysiere Selektor-Häufigkeiten foreach ($parseResult->rules as $rule) { foreach ($rule->selectors as $selector) { if ($selector->getType()->value === 'class') { $classes = $selector->extractClasses(); foreach ($classes as $class) { if (! isset($selectorFrequency[$class])) { $selectorFrequency[$class] = 0; } $selectorFrequency[$class]++; } } } } // Finde Klassen mit hoher Verwendung (potenzielle Components) foreach ($selectorFrequency as $className => $frequency) { if ($frequency >= 3) { // Threshold für Component-Candidate $candidates[] = [ 'class' => $className, 'frequency' => $frequency, 'potential' => $this->assessComponentPotential($className, $frequency), 'suggestions' => $this->getComponentSuggestions($className, $frequency), ]; } } // Sortiere nach Häufigkeit usort($candidates, fn ($a, $b) => $b['frequency'] <=> $a['frequency']); return $candidates; } /** * Generiert Pattern-Statistiken */ private function generatePatternStatistics(array $patterns, array $classNames): array { $totalClasses = count($classNames); $statistics = [ 'total_patterns' => count($patterns), 'total_classes' => $totalClasses, 'pattern_distribution' => [], 'complexity_analysis' => [], ]; $patternTypes = []; foreach ($patterns as $pattern) { $type = $pattern->type->value; if (! isset($patternTypes[$type])) { $patternTypes[$type] = 0; } $patternTypes[$type]++; } foreach ($patternTypes as $type => $count) { $percentage = $totalClasses > 0 ? round(($count / $totalClasses) * 100, 1) : 0; $statistics['pattern_distribution'][$type] = [ 'count' => $count, 'percentage' => $percentage, ]; } // Complexity Analysis foreach ($patterns as $pattern) { $complexity = $pattern->getComplexity(); if (! isset($statistics['complexity_analysis'][$complexity])) { $statistics['complexity_analysis'][$complexity] = 0; } $statistics['complexity_analysis'][$complexity]++; } return $statistics; } /** * Generiert Empfehlungen */ private function generateRecommendations(array $bemComponents, array $utilityComponents, array $traditionalComponents, array $classNames): array { $recommendations = []; $totalClasses = count($classNames); // BEM-Empfehlungen if (empty($bemComponents) && $totalClasses > 10) { $recommendations[] = 'Consider adopting BEM methodology for better component organization and naming consistency.'; } elseif (! empty($bemComponents)) { $blocksWithoutElements = 0; foreach ($bemComponents as $component) { if (empty($component->metadata['elements'])) { $blocksWithoutElements++; } } if ($blocksWithoutElements > count($bemComponents) / 2) { $recommendations[] = 'Many BEM blocks lack elements. Consider breaking down components into smaller, reusable parts.'; } } // Utility-Empfehlungen if (! empty($utilityComponents)) { $utilityCount = array_sum(array_map(fn ($comp) => $comp->metadata['class_count'], $utilityComponents)); $utilityPercentage = round(($utilityCount / $totalClasses) * 100, 1); if ($utilityPercentage > 70) { $recommendations[] = 'High percentage of utility classes detected. Consider consolidating repetitive patterns into components.'; } elseif ($utilityPercentage < 10 && $totalClasses > 20) { $recommendations[] = 'Low usage of utility classes. Consider adding utility classes for common spacing, colors, and typography.'; } } // Mixed Pattern Empfehlungen $hasMultiplePatterns = (! empty($bemComponents) ? 1 : 0) + (! empty($utilityComponents) ? 1 : 0) + (! empty($traditionalComponents) ? 1 : 0); if ($hasMultiplePatterns >= 3) { $recommendations[] = 'Multiple CSS methodologies detected. Consider standardizing on one primary approach for consistency.'; } // Spezifische Pattern-Empfehlungen if (! empty($traditionalComponents)) { $componentTypes = array_unique(array_map(fn ($comp) => $comp->metadata['component_type'], $traditionalComponents)); if (in_array('button', $componentTypes) && in_array('form', $componentTypes)) { $recommendations[] = 'Consider creating a design system with consistent button and form component patterns.'; } } if (empty($recommendations)) { $recommendations[] = 'Component patterns look well organized. Consider documenting the design system for team consistency.'; } return $recommendations; } /** * Bewertet Utility-Coverage */ private function assessUtilityCoverage(string $category, array $classes): string { $expectedCoverage = [ 'spacing' => ['xs', 'sm', 'md', 'lg', 'xl'], 'color' => ['primary', 'secondary', 'success', 'warning', 'error'], 'typography' => ['xs', 'sm', 'base', 'lg', 'xl'], 'sizing' => ['sm', 'md', 'lg', 'full'], ]; if (! isset($expectedCoverage[$category])) { return 'unknown'; } $expected = $expectedCoverage[$category]; $hasExpected = 0; foreach ($expected as $expectedClass) { foreach ($classes as $actualClass) { if (str_contains($actualClass, $expectedClass)) { $hasExpected++; break; } } } $percentage = count($expected) > 0 ? ($hasExpected / count($expected)) : 0; if ($percentage >= 0.8) { return 'excellent'; } elseif ($percentage >= 0.6) { return 'good'; } elseif ($percentage >= 0.4) { return 'fair'; } else { return 'poor'; } } /** * Bewertet Component-Potenzial */ private function assessComponentPotential(string $className, int $frequency): string { if ($frequency >= 10) { return 'high'; } elseif ($frequency >= 6) { return 'medium'; } else { return 'low'; } } /** * Gibt Component-Verbesserungsvorschläge */ private function getComponentSuggestions(string $className, int $frequency): array { $suggestions = []; if ($frequency >= 8) { $suggestions[] = 'Consider extracting into a reusable component or design token.'; } if (str_contains($className, 'btn') || str_contains($className, 'button')) { $suggestions[] = 'Consider creating button variants (primary, secondary, outline).'; } if (str_contains($className, 'card')) { $suggestions[] = 'Consider standardizing card padding, borders, and shadows.'; } return $suggestions; } }