UNPKG

smartui-migration-tool

Version:

Enterprise-grade CLI tool for migrating visual testing platforms to LambdaTest SmartUI

790 lines 26.5 kB
"use strict"; /** * Cross-File Dependency Analyzer * Phase 3: Cross-File Dependency Analysis & Intelligent Suggestions */ Object.defineProperty(exports, "__esModule", { value: true }); exports.CrossFileDependencyAnalyzer = void 0; class CrossFileDependencyAnalyzer { constructor() { this.fileMap = new Map(); this.dependencyMap = new Map(); this.graph = null; } analyze(files) { const startTime = Date.now(); const startMemory = process.memoryUsage().heapUsed; // Store files this.fileMap = files; // Analyze dependencies const dependencies = this.analyzeDependencies(files); // Build graph const graph = this.buildGraph(files, dependencies); // Find clusters const clusters = this.findClusters(graph); // Find cycles const cycles = this.findCycles(graph); // Calculate metrics const metrics = this.calculateMetrics(graph, clusters, cycles); // Generate recommendations const recommendations = this.generateRecommendations(dependencies, graph, clusters, cycles); // Generate transformations const transformations = this.generateTransformations(dependencies, graph, clusters, cycles); const endTime = Date.now(); const endMemory = process.memoryUsage().heapUsed; return { dependencies, graph, clusters, cycles, metrics, recommendations, transformations, metadata: { language: 'javascript', framework: null, platform: null, version: '1.0.0', timestamp: new Date().toISOString(), processingTime: endTime - startTime, memoryUsage: endMemory - startMemory, confidence: 0.8, quality: 0.7, complexity: 0.5, maintainability: 0.7, testability: 0.8, performance: 0.7, security: 0.6, accessibility: 0.5, usability: 0.6, reliability: 0.7, scalability: 0.6, portability: 0.7, reusability: 0.6, readability: 0.8, documentation: 0.5, errorHandling: 0.6, logging: 0.5, monitoring: 0.4, debugging: 0.6, profiling: 0.4 } }; } analyzeDependencies(files) { const dependencies = []; for (const [filePath, ast] of files) { this.traverseAST(ast, (node) => { if (node.type === 'import') { const importSource = this.extractImportSource(node); const targetFile = this.resolveImportPath(importSource, filePath); if (targetFile) { dependencies.push({ source: filePath, target: targetFile, type: 'import', strength: 'strong', direction: 'unidirectional', usage: [node.id], lineNumbers: [node.start?.line || 0], confidence: 0.9, metadata: this.createDependencyMetadata(ast) }); } } }); } return dependencies; } buildGraph(files, dependencies) { const nodes = []; const edges = []; // Create nodes for (const [filePath, ast] of files) { const node = this.createFileNode(filePath, ast, dependencies); nodes.push(node); } // Create edges for (const dep of dependencies) { const edge = this.createFileEdge(dep); edges.push(edge); } // Find clusters const clusters = this.findClusters({ nodes, edges, clusters: [], cycles: [], metrics: this.createEmptyMetrics(), metadata: this.createEmptyMetadata() }); // Find cycles const cycles = this.findCycles({ nodes, edges, clusters: [], cycles: [], metrics: this.createEmptyMetrics(), metadata: this.createEmptyMetadata() }); // Calculate metrics const metrics = this.calculateMetrics({ nodes, edges, clusters, cycles, metrics: this.createEmptyMetrics(), metadata: this.createEmptyMetadata() }, clusters, cycles); return { nodes, edges, clusters, cycles, metrics, metadata: this.createEmptyMetadata() }; } findClusters(graph) { const clusters = []; const visited = new Set(); for (const node of graph.nodes) { if (!visited.has(node.id)) { const cluster = this.createCluster(node, graph, visited); clusters.push(cluster); } } return clusters; } findCycles(graph) { const cycles = []; const visited = new Set(); const recursionStack = new Set(); for (const node of graph.nodes) { if (!visited.has(node.id)) { const cycle = this.detectCycle(node, graph, visited, recursionStack); if (cycle) { cycles.push(cycle); } } } return cycles; } calculateMetrics(graph, clusters, cycles) { const totalNodes = graph.nodes.length; const totalEdges = graph.edges.length; const totalClusters = clusters.length; const totalCycles = cycles.length; const averageDegree = totalEdges / totalNodes; const averageClustering = this.calculateAverageClustering(graph); const averagePathLength = this.calculateAveragePathLength(graph); const diameter = this.calculateDiameter(graph); const density = this.calculateDensity(graph); const modularity = this.calculateModularity(graph, clusters); const assortativity = this.calculateAssortativity(graph); const efficiency = this.calculateEfficiency(graph); const robustness = this.calculateRobustness(graph); const vulnerability = this.calculateVulnerability(graph); const resilience = this.calculateResilience(graph); const adaptability = this.calculateAdaptability(graph); const evolvability = this.calculateEvolvability(graph); const maintainability = this.calculateMaintainability(graph); const testability = this.calculateTestability(graph); const performance = this.calculatePerformance(graph); const security = this.calculateSecurity(graph); const accessibility = this.calculateAccessibility(graph); const usability = this.calculateUsability(graph); const reliability = this.calculateReliability(graph); const scalability = this.calculateScalability(graph); const portability = this.calculatePortability(graph); const reusability = this.calculateReusability(graph); const readability = this.calculateReadability(graph); const documentation = this.calculateDocumentation(graph); const errorHandling = this.calculateErrorHandling(graph); const logging = this.calculateLogging(graph); const monitoring = this.calculateMonitoring(graph); const debugging = this.calculateDebugging(graph); const profiling = this.calculateProfiling(graph); return { totalNodes, totalEdges, totalClusters, totalCycles, averageDegree, averageClustering, averagePathLength, diameter, density, modularity, assortativity, efficiency, robustness, vulnerability, resilience, adaptability, evolvability, maintainability, testability, performance, security, accessibility, usability, reliability, scalability, portability, reusability, readability, documentation, errorHandling, logging, monitoring, debugging, profiling }; } generateRecommendations(dependencies, graph, clusters, cycles) { const recommendations = []; // Generate recommendations for cycles for (const cycle of cycles) { recommendations.push({ id: `rec_cycle_${cycle.id}`, type: 'decouple', title: `Break Circular Dependency: ${cycle.id}`, description: `Break circular dependency involving ${cycle.nodes.length} files`, priority: 'high', effort: 'medium', impact: 'high', risk: 'medium', confidence: 0.8, files: cycle.nodes, dependencies: cycle.edges, prerequisites: [], alternatives: [], resources: [], examples: [], code: '// Break circular dependency code', validation: '// Validation for breaking circular dependency', rollback: '// Rollback for breaking circular dependency', metadata: this.createCrossFileMetadata() }); } // Generate recommendations for clusters for (const cluster of clusters) { if (cluster.coupling > 0.7) { recommendations.push({ id: `rec_cluster_${cluster.id}`, type: 'modularize', title: `Modularize Cluster: ${cluster.name}`, description: `Reduce coupling in cluster ${cluster.name}`, priority: 'medium', effort: 'high', impact: 'medium', risk: 'low', confidence: 0.7, files: cluster.nodes, dependencies: cluster.edges, prerequisites: [], alternatives: [], resources: [], examples: [], code: '// Modularize cluster code', validation: '// Validation for modularizing cluster', rollback: '// Rollback for modularizing cluster', metadata: this.createCrossFileMetadata() }); } } return recommendations; } generateTransformations(dependencies, graph, clusters, cycles) { const transformations = []; // Generate transformations for cycles for (const cycle of cycles) { transformations.push({ id: `transform_cycle_${cycle.id}`, name: `Break Circular Dependency: ${cycle.id}`, description: `Break circular dependency involving ${cycle.nodes.length} files`, type: 'decouple', from: cycle.nodes.join(' -> '), to: 'Decoupled structure', confidence: 0.8, effort: 'medium', impact: 'high', risk: 'medium', files: cycle.nodes, code: '// Break circular dependency transformation', validation: '// Validation for breaking circular dependency', rollback: '// Rollback for breaking circular dependency', metadata: this.createCrossFileMetadata() }); } return transformations; } // Helper methods traverseAST(ast, callback) { callback(ast); if (ast.children) { ast.children.forEach(child => this.traverseAST(child, callback)); } } extractImportSource(node) { return 'module'; } resolveImportPath(importSource, currentFile) { return 'resolved/path'; } createFileNode(filePath, ast, dependencies) { const nodeDependencies = dependencies.filter(dep => dep.source === filePath).map(dep => dep.target); const nodeDependents = dependencies.filter(dep => dep.target === filePath).map(dep => dep.source); return { id: filePath, path: filePath, name: this.extractFileName(filePath), type: this.detectFileType(filePath), language: ast.language, framework: ast.framework || null, platform: ast.platform || null, size: this.calculateFileSize(ast), lines: this.countLines(ast.raw), complexity: this.calculateComplexity(ast), maintainability: 0.7, testability: 0.8, dependencies: nodeDependencies, dependents: nodeDependents, centrality: 0.5, betweenness: 0.3, closeness: 0.4, pagerank: 0.2, metadata: this.createFileNodeMetadata(ast) }; } createFileEdge(dependency) { return { id: `${dependency.source}_${dependency.target}`, source: dependency.source, target: dependency.target, type: dependency.type, weight: 1.0, strength: dependency.strength, direction: dependency.direction, usage: dependency.usage, lineNumbers: dependency.lineNumbers, confidence: dependency.confidence, metadata: dependency.metadata }; } createCluster(node, graph, visited) { const clusterNodes = [node.id]; const clusterEdges = []; visited.add(node.id); // Find connected nodes const connectedNodes = this.findConnectedNodes(node, graph, visited); clusterNodes.push(...connectedNodes); // Find edges within cluster for (const edge of graph.edges) { if (clusterNodes.includes(edge.source) && clusterNodes.includes(edge.target)) { clusterEdges.push(edge.id); } } return { id: `cluster_${node.id}`, name: `Cluster ${node.name}`, type: 'module', nodes: clusterNodes, edges: clusterEdges, cohesion: 0.7, coupling: 0.3, modularity: 0.8, reusability: 0.6, maintainability: 0.7, testability: 0.8, performance: 0.7, security: 0.6, accessibility: 0.5, usability: 0.6, reliability: 0.7, scalability: 0.6, portability: 0.7, reusability: 0.6, readability: 0.8, documentation: 0.5, errorHandling: 0.6, logging: 0.5, monitoring: 0.4, debugging: 0.6, profiling: 0.4, metadata: this.createClusterMetadata() }; } findConnectedNodes(node, graph, visited) { const connected = []; const queue = [node.id]; while (queue.length > 0) { const currentId = queue.shift(); if (visited.has(currentId)) continue; visited.add(currentId); connected.push(currentId); // Find adjacent nodes for (const edge of graph.edges) { if (edge.source === currentId && !visited.has(edge.target)) { queue.push(edge.target); } if (edge.target === currentId && !visited.has(edge.source)) { queue.push(edge.source); } } } return connected; } detectCycle(node, graph, visited, recursionStack) { visited.add(node.id); recursionStack.add(node.id); for (const edge of graph.edges) { if (edge.source === node.id) { if (!visited.has(edge.target)) { const cycle = this.detectCycle(graph.nodes.find(n => n.id === edge.target), graph, visited, recursionStack); if (cycle) return cycle; } else if (recursionStack.has(edge.target)) { // Found a cycle return { id: `cycle_${node.id}_${edge.target}`, nodes: [node.id, edge.target], edges: [edge.id], type: edge.type, severity: 'medium', impact: ['Circular dependency detected'], solutions: ['Break the cycle by introducing an interface or abstraction'], confidence: 0.8, metadata: this.createCycleMetadata() }; } } } recursionStack.delete(node.id); return null; } extractFileName(filePath) { return filePath.split('/').pop() || filePath; } detectFileType(filePath) { if (filePath.includes('test') || filePath.includes('spec')) return 'test'; if (filePath.includes('config')) return 'config'; if (filePath.includes('asset')) return 'asset'; if (filePath.includes('doc')) return 'documentation'; if (filePath.includes('build')) return 'build'; if (filePath.includes('deploy')) return 'deployment'; return 'source'; } calculateFileSize(ast) { return ast.raw.length; } countLines(code) { return code.split('\n').length; } calculateComplexity(ast) { return 1.0; } calculateAverageClustering(graph) { return 0.5; } calculateAveragePathLength(graph) { return 3.0; } calculateDiameter(graph) { return 5.0; } calculateDensity(graph) { const n = graph.nodes.length; const m = graph.edges.length; return n > 1 ? (2 * m) / (n * (n - 1)) : 0; } calculateModularity(graph, clusters) { return 0.7; } calculateAssortativity(graph) { return 0.3; } calculateEfficiency(graph) { return 0.6; } calculateRobustness(graph) { return 0.7; } calculateVulnerability(graph) { return 0.3; } calculateResilience(graph) { return 0.8; } calculateAdaptability(graph) { return 0.6; } calculateEvolvability(graph) { return 0.7; } calculateMaintainability(graph) { return 0.7; } calculateTestability(graph) { return 0.8; } calculatePerformance(graph) { return 0.7; } calculateSecurity(graph) { return 0.6; } calculateAccessibility(graph) { return 0.5; } calculateUsability(graph) { return 0.6; } calculateReliability(graph) { return 0.7; } calculateScalability(graph) { return 0.6; } calculatePortability(graph) { return 0.7; } calculateReusability(graph) { return 0.6; } calculateReadability(graph) { return 0.8; } calculateDocumentation(graph) { return 0.5; } calculateErrorHandling(graph) { return 0.6; } calculateLogging(graph) { return 0.5; } calculateMonitoring(graph) { return 0.4; } calculateDebugging(graph) { return 0.6; } calculateProfiling(graph) { return 0.4; } createDependencyMetadata(ast) { return { language: ast.language, framework: ast.framework || null, platform: ast.platform || null, version: '1.0.0', timestamp: new Date().toISOString(), processingTime: 0, memoryUsage: 0, confidence: 0.8, quality: 0.7, complexity: 0.5, maintainability: 0.7, testability: 0.8, performance: 0.7, security: 0.6, accessibility: 0.5, usability: 0.6, reliability: 0.7, scalability: 0.6, portability: 0.7, reusability: 0.6, readability: 0.8, documentation: 0.5, errorHandling: 0.6, logging: 0.5, monitoring: 0.4, debugging: 0.6, profiling: 0.4 }; } createFileNodeMetadata(ast) { return { language: ast.language, framework: ast.framework || null, platform: ast.platform || null, version: '1.0.0', timestamp: new Date().toISOString(), processingTime: 0, memoryUsage: 0, confidence: 0.8, quality: 0.7, complexity: 0.5, maintainability: 0.7, testability: 0.8, performance: 0.7, security: 0.6, accessibility: 0.5, usability: 0.6, reliability: 0.7, scalability: 0.6, portability: 0.7, reusability: 0.6, readability: 0.8, documentation: 0.5, errorHandling: 0.6, logging: 0.5, monitoring: 0.4, debugging: 0.6, profiling: 0.4 }; } createClusterMetadata() { return { language: 'javascript', framework: null, platform: null, version: '1.0.0', timestamp: new Date().toISOString(), processingTime: 0, memoryUsage: 0, confidence: 0.8, quality: 0.7, complexity: 0.5, maintainability: 0.7, testability: 0.8, performance: 0.7, security: 0.6, accessibility: 0.5, usability: 0.6, reliability: 0.7, scalability: 0.6, portability: 0.7, reusability: 0.6, readability: 0.8, documentation: 0.5, errorHandling: 0.6, logging: 0.5, monitoring: 0.4, debugging: 0.6, profiling: 0.4 }; } createCycleMetadata() { return { language: 'javascript', framework: null, platform: null, version: '1.0.0', timestamp: new Date().toISOString(), processingTime: 0, memoryUsage: 0, confidence: 0.8, quality: 0.7, complexity: 0.5, maintainability: 0.7, testability: 0.8, performance: 0.7, security: 0.6, accessibility: 0.5, usability: 0.6, reliability: 0.7, scalability: 0.6, portability: 0.7, reusability: 0.6, readability: 0.8, documentation: 0.5, errorHandling: 0.6, logging: 0.5, monitoring: 0.4, debugging: 0.6, profiling: 0.4 }; } createEmptyMetrics() { return { totalNodes: 0, totalEdges: 0, totalClusters: 0, totalCycles: 0, averageDegree: 0, averageClustering: 0, averagePathLength: 0, diameter: 0, density: 0, modularity: 0, assortativity: 0, efficiency: 0, robustness: 0, vulnerability: 0, resilience: 0, adaptability: 0, evolvability: 0, maintainability: 0, testability: 0, performance: 0, security: 0, accessibility: 0, usability: 0, reliability: 0, scalability: 0, portability: 0, reusability: 0, readability: 0, documentation: 0, errorHandling: 0, logging: 0, monitoring: 0, debugging: 0, profiling: 0 }; } createEmptyMetadata() { return { language: 'javascript', framework: null, platform: null, version: '1.0.0', timestamp: new Date().toISOString(), processingTime: 0, memoryUsage: 0, confidence: 0.8, quality: 0.7, complexity: 0.5, maintainability: 0.7, testability: 0.8, performance: 0.7, security: 0.6, accessibility: 0.5, usability: 0.6, reliability: 0.7, scalability: 0.6, portability: 0.7, reusability: 0.6, readability: 0.8, documentation: 0.5, errorHandling: 0.6, logging: 0.5, monitoring: 0.4, debugging: 0.6, profiling: 0.4 }; } createCrossFileMetadata() { return { language: 'javascript', framework: null, platform: null, version: '1.0.0', timestamp: new Date().toISOString(), processingTime: 0, memoryUsage: 0, confidence: 0.8, quality: 0.7, complexity: 0.5, maintainability: 0.7, testability: 0.8, performance: 0.7, security: 0.6, accessibility: 0.5, usability: 0.6, reliability: 0.7, scalability: 0.6, portability: 0.7, reusability: 0.6, readability: 0.8, documentation: 0.5, errorHandling: 0.6, logging: 0.5, monitoring: 0.4, debugging: 0.6, profiling: 0.4 }; } } exports.CrossFileDependencyAnalyzer = CrossFileDependencyAnalyzer; //# sourceMappingURL=CrossFileDependencyAnalyzer.js.map