UNPKG

@aaswe/codebase-ai

Version:

AI-Assisted Software Engineering (AASWE) - Rich codebase context for IDE LLMs

272 lines 9.12 kB
"use strict"; /** * Base AST Analyzer * Abstract base class for language-specific AST analyzers */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseAnalyzer = void 0; const fs_1 = require("fs"); const logger_1 = __importDefault(require("../../../utils/logger")); class BaseAnalyzer { language; defaultOptions = { includeComments: false, calculateComplexity: true, extractDependencies: true, includePrivateMembers: true, maxDepth: 10, timeout: 30000 }; constructor(language) { this.language = language; } /** * Analyze a single file */ async analyzeFile(filePath, options) { const startTime = Date.now(); const context = this.createContext(filePath, options); try { logger_1.default.debug(`Starting AST analysis for ${filePath}`); // Read file content const content = (0, fs_1.readFileSync)(filePath, 'utf-8'); // Parse AST const ast = await this.parseAST(content, context); // Extract information const nodes = await this.extractNodes(ast, context); const functions = await this.extractFunctions(ast, context); const classes = await this.extractClasses(ast, context); const imports = await this.extractImports(ast, context); const exports = await this.extractExports(ast, context); const dependencies = await this.extractDependencies(ast, context); // Calculate complexity const complexity = context.options.calculateComplexity ? await this.calculateComplexity(ast, context) : this.getDefaultComplexity(); const result = { filePath, language: context.language, nodes, functions, classes, imports, exports, dependencies, complexity, errors: [], timestamp: new Date() }; const processingTime = Date.now() - startTime; logger_1.default.debug(`AST analysis completed for ${filePath} in ${processingTime}ms`); return result; } catch (error) { logger_1.default.error(`AST analysis failed for ${filePath}:`, error); return { filePath, language: context.language, nodes: [], functions: [], classes: [], imports: [], exports: [], dependencies: [], complexity: this.getDefaultComplexity(), errors: [{ type: 'analysis', message: error instanceof Error ? error.message : 'Unknown analysis error', severity: 'error' }], timestamp: new Date() }; } } /** * Analyze multiple files */ async analyzeFiles(filePaths, options) { const results = []; for (const filePath of filePaths) { try { const result = await this.analyzeFile(filePath, options); results.push(result); } catch (error) { logger_1.default.error(`Failed to analyze ${filePath}:`, error); const context = this.createContext(filePath, options); results.push({ filePath, language: context.language, nodes: [], functions: [], classes: [], imports: [], exports: [], dependencies: [], complexity: this.getDefaultComplexity(), errors: [{ type: 'analysis', message: error instanceof Error ? error.message : 'Unknown analysis error', severity: 'error' }], timestamp: new Date() }); } } return results; } /** * Build dependency graph from analysis results */ buildDependencyGraph(results) { const nodes = new Map(); const edges = []; // Create nodes for each file, function, and class for (const result of results) { // File node nodes.set(result.filePath, { id: result.filePath, name: result.filePath.split('/').pop() || result.filePath, type: 'file', filePath: result.filePath, exported: result.exports.length > 0 }); // Function nodes for (const func of result.functions) { nodes.set(func.id, { id: func.id, name: func.name, type: 'function', filePath: result.filePath, exported: func.isExported }); } // Class nodes for (const cls of result.classes) { nodes.set(cls.id, { id: cls.id, name: cls.name, type: 'class', filePath: result.filePath, exported: cls.isExported }); } } // Create edges for dependencies for (const result of results) { // Import edges for (const imp of result.imports) { edges.push({ from: result.filePath, to: imp.source, type: 'imports', weight: imp.imports.length }); } // Function call edges for (const func of result.functions) { for (const call of func.calls) { edges.push({ from: func.id, to: call, type: 'calls', weight: 1 }); } } // Class inheritance edges for (const cls of result.classes) { if (cls.extends) { edges.push({ from: cls.id, to: cls.extends, type: 'extends', weight: 1 }); } for (const impl of cls.implements) { edges.push({ from: cls.id, to: impl, type: 'implements', weight: 1 }); } } } return { nodes: Array.from(nodes.values()), edges }; } /** * Create analysis context */ createContext(filePath, options) { // Detect language from file extension instead of using hardcoded language const detectedLanguage = this.detectLanguageFromPath(filePath); return { filePath, projectRoot: process.cwd(), language: detectedLanguage, options: { ...this.defaultOptions, ...options }, config: this.getParserConfig() }; } /** * Detect language from file path */ detectLanguageFromPath(filePath) { const extension = filePath.split('.').pop()?.toLowerCase(); switch (extension) { case 'ts': case 'tsx': return 'typescript'; case 'js': case 'jsx': case 'mjs': return 'javascript'; case 'py': return 'python'; case 'java': return 'java'; case 'go': return 'go'; case 'rs': return 'rust'; case 'cpp': case 'cc': case 'cxx': case 'c++': case 'hpp': case 'h': return 'cpp'; default: // Fallback to analyzer's language if detection fails return this.language; } } /** * Generate unique ID */ generateId() { return Math.random().toString(36).substring(2) + Date.now().toString(36); } /** * Get default complexity metrics */ getDefaultComplexity() { return { cyclomaticComplexity: 0, cognitiveComplexity: 0, linesOfCode: 0, maintainabilityIndex: 100, technicalDebt: 0 }; } } exports.BaseAnalyzer = BaseAnalyzer; //# sourceMappingURL=BaseAnalyzer.js.map