UNPKG

userpravah

Version:

UserPravah is an extensible, framework-agnostic tool for analyzing user flows and navigation patterns in web applications. It supports multiple frameworks (Angular, React) and output formats (DOT/Graphviz, JSON) with a plugin-based architecture for easy e

73 lines (72 loc) 4.1 kB
import { BasicPatternCollector } from './core/pattern-collector.interface.js'; import * as path from 'path'; // For potential output path construction export class MainAnalyzer { constructor(adapters, formatters, patternCollector // Allow injecting a shared collector ) { this.frameworkAdapters = []; this.outputFormatters = []; this.frameworkAdapters = adapters; this.outputFormatters = formatters; this.patternCollector = patternCollector || new BasicPatternCollector(); } registerAdapter(adapter) { if (!this.frameworkAdapters.find(a => a.frameworkName.toLowerCase() === adapter.frameworkName.toLowerCase())) { this.frameworkAdapters.push(adapter); } else { console.warn(`[MainAnalyzer] Adapter for framework '${adapter.frameworkName}' already registered.`); } } registerFormatter(formatter) { if (!this.outputFormatters.find(f => f.formatName.toLowerCase() === formatter.formatName.toLowerCase())) { this.outputFormatters.push(formatter); } else { console.warn(`[MainAnalyzer] Formatter for format '${formatter.formatName}' already registered.`); } } async analyzeAndGenerateOutput(projectPath, targetFrameworkName, targetOutputFormat, outputDirectory) { const adapter = this.frameworkAdapters.find(a => a.frameworkName.toLowerCase() === targetFrameworkName.toLowerCase()); if (!adapter) { throw new Error(`[MainAnalyzer] Framework adapter for "${targetFrameworkName}" not found.`); } const formatter = this.outputFormatters.find(f => f.formatName.toLowerCase() === targetOutputFormat.toLowerCase()); if (!formatter) { throw new Error(`[MainAnalyzer] Output formatter for "${targetOutputFormat}" not found.`); } console.log(`🚀 [MainAnalyzer] Starting analysis for ${targetFrameworkName} project at: ${projectPath} using ${adapter.constructor.name}`); // Clear patterns from the central collector before each full analysis run this.patternCollector.clearPatterns(); // The adapter's analyzeProject method should use its *own* pattern collector instance internally // or be passed the main one if designed that way. Here, we assume it might have its own, // and we retrieve patterns afterwards. const analysisResult = await adapter.analyzeProject(projectPath); // The adapter manages its own project instance // After analysis, if the adapter supports getDiscoveredPatterns, merge them into the main collector. // This is useful if adapters have their own collectors or if we want to ensure patterns are sourced correctly. if (adapter.getDiscoveredPatterns) { const adapterPatterns = adapter.getDiscoveredPatterns(); for (const type in adapterPatterns) { adapterPatterns[type].forEach(p => this.patternCollector.addPattern(p)); // Add to central collector } } console.log(`📊 [MainAnalyzer] Generating ${targetOutputFormat} output using ${formatter.constructor.name}...`); // Ensure output directory exists (formatter could also do this) // import * as fs from 'fs'; // if (!fs.existsSync(outputDirectory)) { // fs.mkdirSync(outputDirectory, { recursive: true }); // } await formatter.generateOutput(analysisResult, outputDirectory); console.log(`✨ [MainAnalyzer] Analysis and ${targetOutputFormat} generation complete!`); console.log(` Output should be in directory: ${path.resolve(outputDirectory)}`); console.log(` Total patterns collected: ${this.patternCollector.getAllPatterns().length}`); } getCollectedPatterns() { return this.patternCollector.getAllPatterns(); } getPatternsByFramework(framework) { return this.patternCollector.getPatternsByFramework(framework); } getPatternsByType(type) { return this.patternCollector.getPatternsByType(type); } }