package intelligence import ( "context" "fmt" "path/filepath" "regexp" "sort" "strings" "time" slurpContext "chorus.services/bzzz/pkg/slurp/context" ) // DefaultPatternDetector provides comprehensive pattern detection capabilities type DefaultPatternDetector struct { config *EngineConfig codeAnalyzer *CodePatternAnalyzer namingAnalyzer *NamingPatternAnalyzer orgAnalyzer *OrganizationalPatternAnalyzer designAnalyzer *DesignPatternAnalyzer } // CodePatternAnalyzer detects code-level patterns and anti-patterns type CodePatternAnalyzer struct { languagePatterns map[string]*LanguageCodePatterns } // LanguageCodePatterns contains patterns specific to a programming language type LanguageCodePatterns struct { DesignPatterns []*DesignPatternMatcher AntiPatterns []*AntiPatternMatcher ArchPatterns []*ArchitecturalPatternMatcher BestPractices []*BestPracticeMatcher } // DesignPatternMatcher detects specific design patterns type DesignPatternMatcher struct { PatternName string Description string Signatures []*regexp.Regexp StructuralCues []string Confidence func(matches int, totalLines int) float64 } // AntiPatternMatcher detects anti-patterns and code smells type AntiPatternMatcher struct { PatternName string Description string Signatures []*regexp.Regexp Severity string // critical, high, medium, low Recommendation string } // ArchitecturalPatternMatcher detects architectural patterns type ArchitecturalPatternMatcher struct { PatternName string Description string FilePatterns []*regexp.Regexp DirectoryHints []string Dependencies []string } // BestPracticeMatcher detects adherence to best practices type BestPracticeMatcher struct { PracticeName string Description string Indicators []*regexp.Regexp Violations []*regexp.Regexp Impact string } // NamingPatternAnalyzer analyzes naming conventions and patterns type NamingPatternAnalyzer struct { conventionRules map[string]*NamingConventionRule } // NamingConventionRule defines a naming convention rule type NamingConventionRule struct { Language string Scope string // function, variable, class, file, etc. Pattern *regexp.Regexp Description string Examples []string Violations []*regexp.Regexp } // OrganizationalPatternAnalyzer detects organizational and structural patterns type OrganizationalPatternAnalyzer struct { structuralPatterns []*StructuralPatternMatcher } // StructuralPatternMatcher detects structural organization patterns type StructuralPatternMatcher struct { PatternName string Description string DirectoryPatterns []*regexp.Regexp FilePatterns []*regexp.Regexp RequiredFiles []string OptionalFiles []string Depth int Characteristics []string } // DesignPatternAnalyzer detects software design patterns type DesignPatternAnalyzer struct { patternLibrary map[string]*DesignPatternDefinition } // DesignPatternDefinition defines a comprehensive design pattern type DesignPatternDefinition struct { Name string Category string // creational, structural, behavioral Intent string Applicability []string Structure *PatternStructure Participants []string Collaborations []string Consequences []string Implementation *PatternImplementation } // PatternStructure defines the structural elements of a pattern type PatternStructure struct { Classes []string Interfaces []string Relationships []string KeyComponents []string } // PatternImplementation contains implementation-specific details type PatternImplementation struct { Languages []string CodeSignatures []*regexp.Regexp FileStructure []string Dependencies []string } // NewDefaultPatternDetector creates a comprehensive pattern detector func NewDefaultPatternDetector(config *EngineConfig) *DefaultPatternDetector { return &DefaultPatternDetector{ config: config, codeAnalyzer: NewCodePatternAnalyzer(), namingAnalyzer: NewNamingPatternAnalyzer(), orgAnalyzer: NewOrganizationalPatternAnalyzer(), designAnalyzer: NewDesignPatternAnalyzer(), } } // NewCodePatternAnalyzer creates a code pattern analyzer func NewCodePatternAnalyzer() *CodePatternAnalyzer { analyzer := &CodePatternAnalyzer{ languagePatterns: make(map[string]*LanguageCodePatterns), } // Initialize Go patterns goPatterns := &LanguageCodePatterns{ DesignPatterns: []*DesignPatternMatcher{ { PatternName: "Singleton", Description: "Ensures a class has only one instance", Signatures: []*regexp.Regexp{ regexp.MustCompile(`var\s+instance\s+\*\w+`), regexp.MustCompile(`sync\.Once`), regexp.MustCompile(`func\s+GetInstance\s*\(\s*\)\s*\*\w+`), }, StructuralCues: []string{"sync.Once", "private constructor", "static instance"}, Confidence: func(matches, totalLines int) float64 { return float64(matches) / 3.0 }, }, { PatternName: "Factory", Description: "Creates objects without specifying exact class", Signatures: []*regexp.Regexp{ regexp.MustCompile(`func\s+New\w+\s*\(`), regexp.MustCompile(`func\s+Create\w+\s*\(`), regexp.MustCompile(`func\s+Make\w+\s*\(`), }, StructuralCues: []string{"factory method", "object creation"}, }, { PatternName: "Builder", Description: "Constructs complex objects step by step", Signatures: []*regexp.Regexp{ regexp.MustCompile(`func\s+\(\w+\s+\*\w+\)\s+With\w+\(`), regexp.MustCompile(`func\s+\(\w+\s+\*\w+\)\s+Set\w+\(`), regexp.MustCompile(`func\s+\(\w+\s+\*\w+\)\s+Build\s*\(\s*\)`), }, StructuralCues: []string{"fluent interface", "method chaining", "build method"}, }, { PatternName: "Observer", Description: "Notifies multiple objects about state changes", Signatures: []*regexp.Regexp{ regexp.MustCompile(`type\s+\w*Observer\w*\s+interface`), regexp.MustCompile(`func\s+\w*Subscribe\w*\s*\(`), regexp.MustCompile(`func\s+\w*Notify\w*\s*\(`), }, StructuralCues: []string{"observer interface", "subscription", "notification"}, }, }, AntiPatterns: []*AntiPatternMatcher{ { PatternName: "God Object", Description: "Class that does too much", Signatures: []*regexp.Regexp{regexp.MustCompile(`func\s+\(\w+\s+\*\w+\)\s+\w+`)}, Severity: "high", Recommendation: "Split responsibilities into smaller, focused types", }, { PatternName: "Magic Numbers", Description: "Unexplained numeric literals", Signatures: []*regexp.Regexp{regexp.MustCompile(`\b\d{2,}\b`)}, Severity: "medium", Recommendation: "Replace with named constants", }, }, ArchPatterns: []*ArchitecturalPatternMatcher{ { PatternName: "Repository Pattern", Description: "Encapsulates data access logic", FilePatterns: []*regexp.Regexp{regexp.MustCompile(`.*repository.*\.go$`)}, DirectoryHints: []string{"repository", "repo", "storage"}, Dependencies: []string{"database", "storage"}, }, }, BestPractices: []*BestPracticeMatcher{ { PracticeName: "Error Handling", Description: "Proper error handling patterns", Indicators: []*regexp.Regexp{ regexp.MustCompile(`if\s+err\s*!=\s*nil`), regexp.MustCompile(`return.*,\s*err`), }, Violations: []*regexp.Regexp{ regexp.MustCompile(`_\s*,\s*_\s*:=`), }, Impact: "high", }, }, } // Initialize JavaScript/TypeScript patterns jsPatterns := &LanguageCodePatterns{ DesignPatterns: []*DesignPatternMatcher{ { PatternName: "Module Pattern", Description: "Encapsulates functionality in modules", Signatures: []*regexp.Regexp{ regexp.MustCompile(`export\s+default`), regexp.MustCompile(`module\.exports\s*=`), regexp.MustCompile(`export\s+\{.*\}`), }, }, { PatternName: "Singleton", Description: "Single instance pattern in JavaScript", Signatures: []*regexp.Regexp{ regexp.MustCompile(`class\s+\w+\s*\{[\s\S]*static\s+instance`), regexp.MustCompile(`getInstance\s*\(\s*\)`), }, }, { PatternName: "Observer", Description: "Event-driven programming pattern", Signatures: []*regexp.Regexp{ regexp.MustCompile(`addEventListener\s*\(`), regexp.MustCompile(`on\s*\(`), regexp.MustCompile(`subscribe\s*\(`), }, }, }, AntiPatterns: []*AntiPatternMatcher{ { PatternName: "Callback Hell", Description: "Deeply nested callbacks", Signatures: []*regexp.Regexp{regexp.MustCompile(`function\s*\([^)]*\)\s*\{[\s\S]*function\s*\([^)]*\)\s*\{[\s\S]*function`)}, Severity: "high", Recommendation: "Use Promises or async/await", }, }, } // Initialize Python patterns pythonPatterns := &LanguageCodePatterns{ DesignPatterns: []*DesignPatternMatcher{ { PatternName: "Decorator Pattern", Description: "Adds behavior to objects dynamically", Signatures: []*regexp.Regexp{ regexp.MustCompile(`@\w+`), regexp.MustCompile(`def\s+\w+\s*\([^)]*\)\s*->\s*callable`), }, }, { PatternName: "Context Manager", Description: "Resource management pattern", Signatures: []*regexp.Regexp{ regexp.MustCompile(`def\s+__enter__\s*\(`), regexp.MustCompile(`def\s+__exit__\s*\(`), regexp.MustCompile(`with\s+\w+`), }, }, }, } analyzer.languagePatterns["go"] = goPatterns analyzer.languagePatterns["javascript"] = jsPatterns analyzer.languagePatterns["typescript"] = jsPatterns analyzer.languagePatterns["python"] = pythonPatterns return analyzer } // NewNamingPatternAnalyzer creates a naming pattern analyzer func NewNamingPatternAnalyzer() *NamingPatternAnalyzer { analyzer := &NamingPatternAnalyzer{ conventionRules: make(map[string]*NamingConventionRule), } // Go naming conventions goRules := []*NamingConventionRule{ { Language: "go", Scope: "function", Pattern: regexp.MustCompile(`^[A-Z][a-zA-Z0-9]*$`), Description: "Exported functions use PascalCase", Examples: []string{"GetUser", "ProcessData"}, }, { Language: "go", Scope: "variable", Pattern: regexp.MustCompile(`^[a-z][a-zA-Z0-9]*$`), Description: "Variables use camelCase", Examples: []string{"userName", "totalCount"}, }, { Language: "go", Scope: "constant", Pattern: regexp.MustCompile(`^[A-Z][A-Z0-9_]*$`), Description: "Constants use SCREAMING_SNAKE_CASE", Examples: []string{"MAX_SIZE", "DEFAULT_TIMEOUT"}, }, } // JavaScript/TypeScript naming conventions jsRules := []*NamingConventionRule{ { Language: "javascript", Scope: "function", Pattern: regexp.MustCompile(`^[a-z][a-zA-Z0-9]*$`), Description: "Functions use camelCase", Examples: []string{"getUserData", "processResults"}, }, { Language: "javascript", Scope: "class", Pattern: regexp.MustCompile(`^[A-Z][a-zA-Z0-9]*$`), Description: "Classes use PascalCase", Examples: []string{"UserManager", "DataProcessor"}, }, } // Python naming conventions pythonRules := []*NamingConventionRule{ { Language: "python", Scope: "function", Pattern: regexp.MustCompile(`^[a-z][a-z0-9_]*$`), Description: "Functions use snake_case", Examples: []string{"get_user_data", "process_results"}, }, { Language: "python", Scope: "class", Pattern: regexp.MustCompile(`^[A-Z][a-zA-Z0-9]*$`), Description: "Classes use PascalCase", Examples: []string{"UserManager", "DataProcessor"}, }, } // Register all rules for _, rule := range append(append(goRules, jsRules...), pythonRules...) { key := fmt.Sprintf("%s_%s", rule.Language, rule.Scope) analyzer.conventionRules[key] = rule } return analyzer } // NewOrganizationalPatternAnalyzer creates an organizational pattern analyzer func NewOrganizationalPatternAnalyzer() *OrganizationalPatternAnalyzer { analyzer := &OrganizationalPatternAnalyzer{ structuralPatterns: []*StructuralPatternMatcher{}, } // Define common structural patterns patterns := []*StructuralPatternMatcher{ { PatternName: "Hexagonal Architecture", Description: "Ports and adapters architecture", DirectoryPatterns: []*regexp.Regexp{ regexp.MustCompile(`.*/(domain|core)/.*`), regexp.MustCompile(`.*/adapters?/.*`), regexp.MustCompile(`.*/ports?/.*`), }, RequiredFiles: []string{"domain", "adapters"}, Characteristics: []string{"dependency_inversion", "testable", "framework_independent"}, }, { PatternName: "Clean Architecture", Description: "Uncle Bob's clean architecture", DirectoryPatterns: []*regexp.Regexp{ regexp.MustCompile(`.*/entities/.*`), regexp.MustCompile(`.*/usecases/.*`), regexp.MustCompile(`.*/adapters/.*`), regexp.MustCompile(`.*/frameworks?/.*`), }, RequiredFiles: []string{"entities", "usecases"}, Characteristics: []string{"dependency_rule", "testable", "ui_independent"}, }, { PatternName: "Microservices", Description: "Service-oriented architecture", DirectoryPatterns: []*regexp.Regexp{ regexp.MustCompile(`.*/services?/.*`), regexp.MustCompile(`.*/api-gateway/.*`), }, RequiredFiles: []string{"services"}, Characteristics: []string{"distributed", "autonomous", "scalable"}, }, { PatternName: "Monorepo", Description: "Multiple projects in single repository", DirectoryPatterns: []*regexp.Regexp{ regexp.MustCompile(`.*/packages?/.*`), regexp.MustCompile(`.*/apps?/.*`), regexp.MustCompile(`.*/libs?/.*`), }, RequiredFiles: []string{"packages", "apps"}, Characteristics: []string{"shared_dependencies", "atomic_commits", "unified_tooling"}, }, } analyzer.structuralPatterns = patterns return analyzer } // NewDesignPatternAnalyzer creates a design pattern analyzer func NewDesignPatternAnalyzer() *DesignPatternAnalyzer { analyzer := &DesignPatternAnalyzer{ patternLibrary: make(map[string]*DesignPatternDefinition), } // Define comprehensive design patterns patterns := []*DesignPatternDefinition{ { Name: "Singleton", Category: "creational", Intent: "Ensure a class has only one instance and provide global point of access", Applicability: []string{ "exactly one instance needed", "instance must be accessible from well-known access point", "sole instance should be extensible by subclassing", }, Structure: &PatternStructure{ Classes: []string{"Singleton"}, Interfaces: []string{}, Relationships: []string{"self-reference"}, KeyComponents: []string{"private constructor", "static instance", "getInstance method"}, }, Implementation: &PatternImplementation{ Languages: []string{"go", "java", "javascript", "python"}, CodeSignatures: []*regexp.Regexp{ regexp.MustCompile(`getInstance|GetInstance`), regexp.MustCompile(`static.*instance|var.*instance`), }, }, }, { Name: "Factory Method", Category: "creational", Intent: "Create objects without specifying their concrete classes", Structure: &PatternStructure{ Classes: []string{"Creator", "ConcreteCreator", "Product", "ConcreteProduct"}, Interfaces: []string{"Product"}, Relationships: []string{"creator uses product"}, KeyComponents: []string{"factory method", "product hierarchy"}, }, Implementation: &PatternImplementation{ Languages: []string{"go", "java", "javascript", "python"}, CodeSignatures: []*regexp.Regexp{ regexp.MustCompile(`New\w+|Create\w+|Make\w+`), regexp.MustCompile(`factory|Factory`), }, }, }, { Name: "Observer", Category: "behavioral", Intent: "Define a one-to-many dependency between objects", Structure: &PatternStructure{ Classes: []string{"Subject", "Observer", "ConcreteSubject", "ConcreteObserver"}, Interfaces: []string{"Observer", "Subject"}, Relationships: []string{"subject notifies observers"}, KeyComponents: []string{"subscribe", "unsubscribe", "notify"}, }, Implementation: &PatternImplementation{ Languages: []string{"go", "java", "javascript", "python"}, CodeSignatures: []*regexp.Regexp{ regexp.MustCompile(`Subscribe|Unsubscribe|Notify`), regexp.MustCompile(`Observer|Subject`), regexp.MustCompile(`addEventListener|on\(`), }, }, }, } for _, pattern := range patterns { analyzer.patternLibrary[pattern.Name] = pattern } return analyzer } // DetectCodePatterns identifies code patterns and architectural styles func (pd *DefaultPatternDetector) DetectCodePatterns(ctx context.Context, filePath string, content []byte) ([]*CodePattern, error) { patterns := []*CodePattern{} // Detect language language := pd.detectLanguageFromPath(filePath) if language == "" { return patterns, nil } // Get language-specific patterns langPatterns, exists := pd.codeAnalyzer.languagePatterns[language] if !exists { return patterns, nil } contentStr := string(content) // Detect design patterns for _, designPattern := range langPatterns.DesignPatterns { if pattern := pd.analyzeDesignPattern(contentStr, designPattern, language); pattern != nil { patterns = append(patterns, pattern) } } // Detect architectural patterns for _, archPattern := range langPatterns.ArchPatterns { if pattern := pd.analyzeArchitecturalPattern(filePath, contentStr, archPattern, language); pattern != nil { patterns = append(patterns, pattern) } } // Detect anti-patterns for _, antiPattern := range langPatterns.AntiPatterns { if pattern := pd.analyzeAntiPattern(contentStr, antiPattern, language); pattern != nil { patterns = append(patterns, pattern) } } return patterns, nil } // DetectNamingPatterns identifies naming conventions and patterns func (pd *DefaultPatternDetector) DetectNamingPatterns(ctx context.Context, contexts []*slurpContext.ContextNode) ([]*NamingPattern, error) { patterns := []*NamingPattern{} // Group contexts by language langGroups := make(map[string][]*slurpContext.ContextNode) for _, context := range contexts { if analysis, ok := context.Metadata["analysis"].(*FileAnalysis); ok { lang := analysis.Language if lang != "" { langGroups[lang] = append(langGroups[lang], context) } } } // Analyze naming patterns for each language for language, langContexts := range langGroups { langPatterns := pd.analyzeLanguageNamingPatterns(language, langContexts) patterns = append(patterns, langPatterns...) } return patterns, nil } // DetectOrganizationalPatterns identifies organizational patterns func (pd *DefaultPatternDetector) DetectOrganizationalPatterns(ctx context.Context, rootPath string) ([]*OrganizationalPattern, error) { patterns := []*OrganizationalPattern{} for _, matcher := range pd.orgAnalyzer.structuralPatterns { if pattern := pd.analyzeStructuralPattern(rootPath, matcher); pattern != nil { patterns = append(patterns, pattern) } } return patterns, nil } // MatchPatterns matches context against known patterns func (pd *DefaultPatternDetector) MatchPatterns(ctx context.Context, node *slurpContext.ContextNode, patterns []*Pattern) ([]*PatternMatch, error) { matches := []*PatternMatch{} for _, pattern := range patterns { if match := pd.calculatePatternMatch(node, pattern); match != nil { matches = append(matches, match) } } // Sort by match score sort.Slice(matches, func(i, j int) bool { return matches[i].MatchScore > matches[j].MatchScore }) return matches, nil } // LearnPatterns learns new patterns from context examples func (pd *DefaultPatternDetector) LearnPatterns(ctx context.Context, examples []*slurpContext.ContextNode) ([]*Pattern, error) { patterns := []*Pattern{} // Group examples by similarity groups := pd.groupSimilarContexts(examples) // Extract patterns from each group for groupID, group := range groups { if len(group) >= 2 { // Need at least 2 examples to form a pattern pattern := pd.extractPatternFromGroup(groupID, group) if pattern != nil { patterns = append(patterns, pattern) } } } return patterns, nil } // Helper methods func (pd *DefaultPatternDetector) detectLanguageFromPath(filePath string) string { ext := strings.ToLower(filepath.Ext(filePath)) langMap := map[string]string{ ".go": "go", ".py": "python", ".js": "javascript", ".jsx": "javascript", ".ts": "typescript", ".tsx": "typescript", ".java": "java", ".c": "c", ".cpp": "cpp", ".cs": "csharp", ".php": "php", ".rb": "ruby", ".rs": "rust", } return langMap[ext] } func (pd *DefaultPatternDetector) analyzeDesignPattern(content string, matcher *DesignPatternMatcher, language string) *CodePattern { matches := 0 matchedSignatures := []string{} for _, signature := range matcher.Signatures { if signature.MatchString(content) { matches++ matchedSignatures = append(matchedSignatures, signature.String()) } } if matches == 0 { return nil } confidence := 0.0 if matcher.Confidence != nil { lines := strings.Count(content, "\n") + 1 confidence = matcher.Confidence(matches, lines) } else { confidence = float64(matches) / float64(len(matcher.Signatures)) } if confidence < 0.3 { return nil } return &CodePattern{ Pattern: Pattern{ ID: fmt.Sprintf("%s_%s", language, strings.ToLower(matcher.PatternName)), Name: matcher.PatternName, Type: "design_pattern", Description: matcher.Description, Confidence: confidence, Examples: matchedSignatures, DetectedAt: time.Now(), }, Language: language, Complexity: pd.calculatePatternComplexity(matcher.PatternName), Usage: &UsagePattern{ Frequency: pd.determinePatternFrequency(matches), Context: matcher.StructuralCues, }, } } func (pd *DefaultPatternDetector) analyzeArchitecturalPattern(filePath, content string, matcher *ArchitecturalPatternMatcher, language string) *CodePattern { // Check file path patterns pathMatches := false for _, pattern := range matcher.FilePatterns { if pattern.MatchString(filePath) { pathMatches = true break } } if !pathMatches { return nil } // Check for dependencies if specified hasRequiredDeps := len(matcher.Dependencies) == 0 if len(matcher.Dependencies) > 0 { for _, dep := range matcher.Dependencies { if strings.Contains(strings.ToLower(content), strings.ToLower(dep)) { hasRequiredDeps = true break } } } if !hasRequiredDeps { return nil } return &CodePattern{ Pattern: Pattern{ ID: fmt.Sprintf("%s_%s_arch", language, strings.ToLower(matcher.PatternName)), Name: matcher.PatternName, Type: "architectural_pattern", Description: matcher.Description, Confidence: 0.8, Examples: []string{filepath.Base(filePath)}, DetectedAt: time.Now(), }, Language: language, Complexity: 0.7, Usage: &UsagePattern{ Frequency: "common", Context: matcher.DirectoryHints, }, } } func (pd *DefaultPatternDetector) analyzeAntiPattern(content string, matcher *AntiPatternMatcher, language string) *CodePattern { matches := 0 for _, signature := range matcher.Signatures { matches += len(signature.FindAllString(content, -1)) } if matches == 0 { return nil } severity := 0.5 switch matcher.Severity { case "critical": severity = 1.0 case "high": severity = 0.8 case "medium": severity = 0.6 case "low": severity = 0.4 } return &CodePattern{ Pattern: Pattern{ ID: fmt.Sprintf("%s_%s_anti", language, strings.ToLower(matcher.PatternName)), Name: matcher.PatternName, Type: "anti_pattern", Description: matcher.Description, Confidence: severity, Frequency: matches, Drawbacks: []string{matcher.Recommendation}, DetectedAt: time.Now(), }, Language: language, Complexity: severity, } } func (pd *DefaultPatternDetector) analyzeLanguageNamingPatterns(language string, contexts []*slurpContext.ContextNode) []*NamingPattern { patterns := []*NamingPattern{} // Collect all identifiers from contexts identifiers := pd.collectIdentifiers(contexts) // Analyze patterns for different scopes scopes := []string{"function", "variable", "class", "file"} for _, scope := range scopes { if pattern := pd.analyzeNamingPatternForScope(language, scope, identifiers[scope]); pattern != nil { patterns = append(patterns, pattern) } } return patterns } func (pd *DefaultPatternDetector) collectIdentifiers(contexts []*slurpContext.ContextNode) map[string][]string { identifiers := make(map[string][]string) for _, context := range contexts { if analysis, ok := context.Metadata["analysis"].(*FileAnalysis); ok { identifiers["function"] = append(identifiers["function"], analysis.Functions...) identifiers["variable"] = append(identifiers["variable"], analysis.Variables...) identifiers["class"] = append(identifiers["class"], analysis.Classes...) identifiers["file"] = append(identifiers["file"], filepath.Base(context.Path)) } } return identifiers } func (pd *DefaultPatternDetector) analyzeNamingPatternForScope(language, scope string, identifiers []string) *NamingPattern { if len(identifiers) < 2 { return nil } // Detect dominant convention conventions := map[string]int{ "camelCase": 0, "PascalCase": 0, "snake_case": 0, "kebab-case": 0, } for _, identifier := range identifiers { if matched, _ := regexp.MatchString(`^[a-z][a-zA-Z0-9]*$`, identifier); matched { conventions["camelCase"]++ } else if matched, _ := regexp.MatchString(`^[A-Z][a-zA-Z0-9]*$`, identifier); matched { conventions["PascalCase"]++ } else if matched, _ := regexp.MatchString(`^[a-z][a-z0-9_]*$`, identifier); matched { conventions["snake_case"]++ } else if matched, _ := regexp.MatchString(`^[a-z][a-z0-9-]*$`, identifier); matched { conventions["kebab-case"]++ } } // Find dominant convention maxCount := 0 dominantConvention := "mixed" for convention, count := range conventions { if count > maxCount { maxCount = count dominantConvention = convention } } confidence := float64(maxCount) / float64(len(identifiers)) if confidence < 0.5 { return nil } return &NamingPattern{ Pattern: Pattern{ ID: fmt.Sprintf("%s_%s_naming", language, scope), Name: fmt.Sprintf("%s %s Naming", strings.Title(language), strings.Title(scope)), Type: "naming_convention", Description: fmt.Sprintf("Naming convention for %s %ss", language, scope), Confidence: confidence, Examples: identifiers[:min(5, len(identifiers))], DetectedAt: time.Now(), }, Convention: dominantConvention, Scope: scope, CaseStyle: dominantConvention, } } func (pd *DefaultPatternDetector) analyzeStructuralPattern(rootPath string, matcher *StructuralPatternMatcher) *OrganizationalPattern { // Check if pattern directory structure exists matchCount := 0 totalRequired := len(matcher.RequiredFiles) for _, required := range matcher.RequiredFiles { checkPath := filepath.Join(rootPath, required) if pd.pathExists(checkPath) { matchCount++ } } if matchCount < totalRequired { return nil } confidence := float64(matchCount) / float64(totalRequired) return &OrganizationalPattern{ Pattern: Pattern{ ID: strings.ToLower(strings.ReplaceAll(matcher.PatternName, " ", "_")), Name: matcher.PatternName, Type: "organizational", Description: matcher.Description, Confidence: confidence, Examples: matcher.RequiredFiles, Benefits: matcher.Characteristics, DetectedAt: time.Now(), }, Structure: "hierarchical", Depth: matcher.Depth, FanOut: len(matcher.RequiredFiles), Modularity: confidence, Scalability: pd.assessScalability(matcher.Characteristics), } } func (pd *DefaultPatternDetector) calculatePatternMatch(node *slurpContext.ContextNode, pattern *Pattern) *PatternMatch { score := 0.0 matchedFields := []string{} // Check summary match if pd.textContainsKeywords(node.Summary, pattern.Examples) { score += 0.3 matchedFields = append(matchedFields, "summary") } // Check purpose match if pd.textContainsKeywords(node.Purpose, pattern.Examples) { score += 0.3 matchedFields = append(matchedFields, "purpose") } // Check technology match for _, tech := range node.Technologies { if pd.containsIgnoreCase(pattern.Examples, tech) { score += 0.2 matchedFields = append(matchedFields, "technologies") break } } // Check tag match for _, tag := range node.Tags { if pd.containsIgnoreCase(pattern.Examples, tag) { score += 0.2 matchedFields = append(matchedFields, "tags") break } } if score < 0.3 { return nil } return &PatternMatch{ PatternID: pattern.ID, MatchScore: score, Confidence: pattern.Confidence * score, MatchedFields: matchedFields, Explanation: fmt.Sprintf("Pattern %s matched with score %.2f", pattern.Name, score), Suggestions: pd.generatePatternSuggestions(pattern), } } func (pd *DefaultPatternDetector) groupSimilarContexts(contexts []*slurpContext.ContextNode) map[string][]*slurpContext.ContextNode { groups := make(map[string][]*slurpContext.ContextNode) for _, context := range contexts { // Simple grouping by primary technology groupKey := "unknown" if len(context.Technologies) > 0 { groupKey = context.Technologies[0] } groups[groupKey] = append(groups[groupKey], context) } return groups } func (pd *DefaultPatternDetector) extractPatternFromGroup(groupID string, group []*slurpContext.ContextNode) *Pattern { // Find common characteristics commonTechs := pd.findCommonTechnologies(group) commonTags := pd.findCommonTags(group) if len(commonTechs) == 0 && len(commonTags) == 0 { return nil } return &Pattern{ ID: fmt.Sprintf("learned_%s_%d", groupID, time.Now().Unix()), Name: fmt.Sprintf("Learned %s Pattern", strings.Title(groupID)), Type: "learned", Description: fmt.Sprintf("Pattern extracted from %d similar contexts", len(group)), Confidence: pd.calculateLearningConfidence(group), Examples: append(commonTechs, commonTags...), DetectedAt: time.Now(), } } // Additional helper methods func (pd *DefaultPatternDetector) calculatePatternComplexity(patternName string) float64 { complexityMap := map[string]float64{ "Singleton": 0.3, "Factory": 0.5, "Builder": 0.7, "Observer": 0.6, "Strategy": 0.5, "Command": 0.6, "Decorator": 0.8, "Composite": 0.9, "Abstract Factory": 0.9, "Prototype": 0.4, } if complexity, exists := complexityMap[patternName]; exists { return complexity } return 0.5 // Default complexity } func (pd *DefaultPatternDetector) determinePatternFrequency(matches int) string { if matches > 5 { return "frequent" } else if matches > 2 { return "common" } else { return "rare" } } func (pd *DefaultPatternDetector) pathExists(path string) bool { _, err := filepath.Abs(path) return err == nil } func (pd *DefaultPatternDetector) assessScalability(characteristics []string) string { for _, char := range characteristics { if strings.Contains(char, "scalable") { return "excellent" } } return "good" } func (pd *DefaultPatternDetector) textContainsKeywords(text string, keywords []string) bool { lowerText := strings.ToLower(text) for _, keyword := range keywords { if strings.Contains(lowerText, strings.ToLower(keyword)) { return true } } return false } func (pd *DefaultPatternDetector) containsIgnoreCase(slice []string, item string) bool { lowerItem := strings.ToLower(item) for _, s := range slice { if strings.ToLower(s) == lowerItem { return true } } return false } func (pd *DefaultPatternDetector) generatePatternSuggestions(pattern *Pattern) []string { suggestions := []string{} switch pattern.Type { case "design_pattern": suggestions = append(suggestions, "Consider documenting the pattern usage") suggestions = append(suggestions, "Ensure pattern implementation follows best practices") case "anti_pattern": suggestions = append(suggestions, "Refactor to eliminate anti-pattern") suggestions = append(suggestions, "Consider alternative design approaches") case "architectural_pattern": suggestions = append(suggestions, "Document architectural decisions") suggestions = append(suggestions, "Ensure pattern consistency across project") } return suggestions } func (pd *DefaultPatternDetector) findCommonTechnologies(contexts []*slurpContext.ContextNode) []string { techCount := make(map[string]int) for _, context := range contexts { for _, tech := range context.Technologies { techCount[tech]++ } } common := []string{} threshold := len(contexts) / 2 // At least half should have the technology for tech, count := range techCount { if count >= threshold { common = append(common, tech) } } return common } func (pd *DefaultPatternDetector) findCommonTags(contexts []*slurpContext.ContextNode) []string { tagCount := make(map[string]int) for _, context := range contexts { for _, tag := range context.Tags { tagCount[tag]++ } } common := []string{} threshold := len(contexts) / 2 for tag, count := range tagCount { if count >= threshold { common = append(common, tag) } } return common } func (pd *DefaultPatternDetector) calculateLearningConfidence(group []*slurpContext.ContextNode) float64 { // Simple confidence based on group size and consistency baseConfidence := 0.5 groupBonus := float64(len(group)) * 0.1 if groupBonus > 0.3 { groupBonus = 0.3 } return baseConfidence + groupBonus } func min(a, b int) int { if a < b { return a } return b }