Skip to main content
Glama
FrameworkModule.ts5.94 kB
import { FrameworkDetectionResult, FrameworkDetectionContext, ImportPattern } from './FrameworkDetectionTypes.js'; import { ParsedImport } from '../extractors/base/ContentExtractor.js'; /** * Abstract base class for framework modules. * Each framework (e.g., Spring Boot, Angular, Flask) should extend this class. */ export abstract class FrameworkModule { protected frameworkMap: Map<string, string> = new Map(); protected categoryMap: Map<string, string> = new Map(); protected importPatterns: ImportPattern[] = []; /** * Get the name of this framework */ abstract getFrameworkName(): string; /** * Get all supported annotations for this framework */ getSupportedAnnotations(): string[] { return Array.from(this.frameworkMap.keys()); } /** * Get all supported categories for this framework */ getSupportedCategories(): string[] { return Array.from(new Set(this.categoryMap.values())); } /** * Detect if an annotation belongs to this framework */ detectFramework(annotation: string): string | null { return this.frameworkMap.get(annotation) || null; } /** * Get the category for an annotation */ categorizeAnnotation(annotation: string): string | null { return this.categoryMap.get(annotation) || null; } /** * Get the framework map for this module */ getFrameworkMap(): Map<string, string> { return new Map(this.frameworkMap); } /** * Get the category map for this module */ getCategoryMap(): Map<string, string> { return new Map(this.categoryMap); } /** * Initialize the framework mappings * This method should be called in the constructor of concrete implementations */ protected abstract initializeMappings(): void; /** * Detect framework from import patterns */ detectFrameworkFromImports(imports: ParsedImport[]): FrameworkDetectionResult { let bestMatch: { framework: string; confidence: number } | null = null; const matchedImports: string[] = []; for (const importItem of imports) { for (const pattern of this.importPatterns) { if (this.matchesImportPattern(importItem.module, pattern.pattern)) { matchedImports.push(importItem.module); if (!bestMatch || pattern.confidence > bestMatch.confidence) { bestMatch = { framework: pattern.framework, confidence: pattern.confidence }; } } } } if (bestMatch) { return { framework: bestMatch.framework, confidence: bestMatch.confidence, detectionMethod: 'import', details: { matchedImports } }; } return { framework: null, confidence: 0, detectionMethod: 'import' }; } /** * Enhanced framework detection using both annotations and imports */ detectFrameworkWithContext(context: FrameworkDetectionContext): FrameworkDetectionResult { const annotationResult = this.detectFrameworkFromAnnotations(context.annotations); const importResult = this.detectFrameworkFromImports(context.imports); // If both methods agree on the framework, combine confidence if (annotationResult.framework === importResult.framework && annotationResult.framework) { return { framework: annotationResult.framework, confidence: Math.min(100, annotationResult.confidence + importResult.confidence), detectionMethod: 'combined', details: { matchedAnnotations: annotationResult.details?.matchedAnnotations, matchedImports: importResult.details?.matchedImports } }; } // Return the result with higher confidence if (importResult.confidence > annotationResult.confidence) { return importResult; } return annotationResult; } /** * Detect framework from annotations with confidence scoring */ detectFrameworkFromAnnotations(annotations: string[]): FrameworkDetectionResult { const matchedAnnotations: string[] = []; const frameworkCounts = new Map<string, number>(); for (const annotation of annotations) { const framework = this.frameworkMap.get(annotation); if (framework) { matchedAnnotations.push(annotation); frameworkCounts.set(framework, (frameworkCounts.get(framework) || 0) + 1); } } if (frameworkCounts.size === 0) { return { framework: null, confidence: 0, detectionMethod: 'annotation' }; } // Find framework with most matches let bestFramework = ''; let maxCount = 0; for (const [framework, count] of frameworkCounts) { if (count > maxCount) { bestFramework = framework; maxCount = count; } } // Calculate confidence based on number of matches and specificity const confidence = Math.min(90, maxCount * 20); // Cap at 90 to leave room for import boost return { framework: bestFramework, confidence, detectionMethod: 'annotation', details: { matchedAnnotations } }; } /** * Check if an import module matches a pattern */ private matchesImportPattern(module: string, pattern: string): boolean { // Convert pattern to regex (handle wildcards) const regexPattern = pattern .replace(/\./g, '\\.') .replace(/\*/g, '.*') + '$'; const regex = new RegExp(regexPattern); return regex.test(module); } /** * Get import patterns for this framework */ getImportPatterns(): ImportPattern[] { return [...this.importPatterns]; } /** * Add an import pattern for framework detection */ protected addImportPattern(pattern: string, confidence: number, framework?: string): void { this.importPatterns.push({ pattern, confidence, framework: framework || this.getFrameworkName() }); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/JonnoC/CodeRAG'

If you have feedback or need assistance with the MCP directory API, please join our Discord server