UNPKG

snes-disassembler

Version:

A Super Nintendo (SNES) ROM disassembler for 65816 assembly

407 lines 17.7 kB
"use strict"; /** * Error and Warning Consolidation Manager * * Implements a comprehensive system to consolidate error and warning messages * into summaries, reducing repetition and providing users with clear overviews * of issues that occurred during their session. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ErrorWarningManager = exports.MessageCategory = exports.MessageSeverity = void 0; const logger_1 = require("./utils/logger"); // Enhanced error types for better categorization var MessageSeverity; (function (MessageSeverity) { MessageSeverity["FATAL"] = "fatal"; MessageSeverity["ERROR"] = "error"; MessageSeverity["WARNING"] = "warning"; MessageSeverity["INFO"] = "info"; MessageSeverity["DEBUG"] = "debug"; })(MessageSeverity || (exports.MessageSeverity = MessageSeverity = {})); var MessageCategory; (function (MessageCategory) { MessageCategory["ROM_PARSING"] = "rom_parsing"; MessageCategory["INSTRUCTION_DECODE"] = "instruction_decode"; MessageCategory["MEMORY_ACCESS"] = "memory_access"; MessageCategory["ASSET_EXTRACTION"] = "asset_extraction"; MessageCategory["OUTPUT_GENERATION"] = "output_generation"; MessageCategory["VALIDATION"] = "validation"; MessageCategory["CONFIGURATION"] = "configuration"; MessageCategory["PERFORMANCE"] = "performance"; MessageCategory["AUDIO_PROCESSING"] = "audio_processing"; MessageCategory["AI_ANALYSIS"] = "ai_analysis"; })(MessageCategory || (exports.MessageCategory = MessageCategory = {})); // Pre-defined message patterns for common issues const MESSAGE_PATTERNS = [ { pattern: /Invalid instruction at address 0x([0-9A-Fa-f]+)/, category: MessageCategory.INSTRUCTION_DECODE, consolidationKey: (match) => 'invalid_instruction', generateTitle: () => 'Invalid Instructions Detected', generateSummary: (count, matches) => { const addresses = matches.map(m => `0x${m[1]}`).slice(0, 5); const remaining = Math.max(0, count - 5); return `Found ${count} invalid instruction${count > 1 ? 's' : ''} at addresses: ${addresses.join(', ')}${remaining > 0 ? ` and ${remaining} more` : ''}`; }, suggestions: [ 'Verify ROM file integrity', 'Check if the address range is correct', 'Consider using bank-aware addressing mode' ] }, { pattern: /Memory access out of bounds at 0x([0-9A-Fa-f]+)/, category: MessageCategory.MEMORY_ACCESS, consolidationKey: (match) => 'memory_oob', generateTitle: () => 'Memory Access Violations', generateSummary: (count, matches) => `${count} memory access violation${count > 1 ? 's' : ''} detected`, suggestions: [ 'Review ROM mapping configuration', 'Check memory region definitions', 'Verify address calculation logic' ] }, { pattern: /Failed to extract (graphics|audio|text) from offset 0x([0-9A-Fa-f]+)/, category: MessageCategory.ASSET_EXTRACTION, consolidationKey: (match) => `asset_extraction_${match[1]}`, generateTitle: (matches) => `${matches[0][1].charAt(0).toUpperCase() + matches[0][1].slice(1)} Extraction Issues`, generateSummary: (count) => `${count} asset extraction failure${count > 1 ? 's' : ''} occurred`, suggestions: [ 'Verify asset format specifications', 'Check offset calculations', 'Consider alternative extraction methods' ] }, { pattern: /BRR decoding error: (.+)/, category: MessageCategory.AUDIO_PROCESSING, consolidationKey: (match) => 'brr_decode_error', generateTitle: () => 'BRR Audio Processing Issues', generateSummary: (count) => `${count} BRR audio processing error${count > 1 ? 's' : ''} encountered`, suggestions: [ 'Verify BRR file format', 'Check sample rate configuration', 'Review loop point settings' ] } ]; class ErrorWarningManager { constructor(sessionId) { this.rawMessages = new Map(); this.consolidatedMessages = new Map(); this.messageCounter = 0; this.performanceMetrics = { processingTime: 0, memoryUsage: 0, operationsCompleted: 0 }; this.logger = (0, logger_1.createLogger)('ErrorWarningManager'); this.sessionId = sessionId || this.generateSessionId(); this.sessionStartTime = new Date(); this.logger.info('Error and Warning Manager initialized', { sessionId: this.sessionId }); } generateSessionId() { return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * Add a message to the manager for consolidation */ addMessage(severity, category, message, context) { const timestamp = new Date(); const messageId = this.generateMessageId(severity, category, message); // Store raw message if (!this.rawMessages.has(messageId)) { this.rawMessages.set(messageId, []); } this.rawMessages.get(messageId).push({ timestamp, context }); // Consolidate message this.consolidateMessage(messageId, severity, category, message, timestamp, context); this.messageCounter++; this.logger.debug('Message added for consolidation', { severity, category, messageId, totalMessages: this.messageCounter }); } /** * Add an error (convenience method) */ addError(category, message, context) { this.addMessage(MessageSeverity.ERROR, category, message, context); } /** * Add a warning (convenience method) */ addWarning(category, message, context) { this.addMessage(MessageSeverity.WARNING, category, message, context); } /** * Add a fatal error (convenience method) */ addFatalError(category, message, context) { this.addMessage(MessageSeverity.FATAL, category, message, context); } generateMessageId(severity, category, message) { // Try to match against known patterns first for (const pattern of MESSAGE_PATTERNS) { const match = message.match(pattern.pattern); if (match && pattern.category === category) { return pattern.consolidationKey(match); } } // Fallback to generating ID from message content const normalized = message.toLowerCase() .replace(/0x[0-9a-f]+/g, '0xXXXX') // Normalize hex addresses .replace(/\d+/g, 'N') // Normalize numbers .replace(/[^a-z0-9]/g, '_') // Replace special chars .replace(/_+/g, '_') // Collapse multiple underscores .replace(/^_|_$/g, ''); // Remove leading/trailing underscores return `${category}_${normalized}`; } consolidateMessage(messageId, severity, category, message, timestamp, context) { let consolidated = this.consolidatedMessages.get(messageId); if (!consolidated) { // Create new consolidated message const pattern = this.findMatchingPattern(message, category); consolidated = { id: messageId, severity, category, title: pattern?.generateTitle ? pattern.generateTitle([message.match(pattern.pattern)]) : this.generateTitle(message), message: pattern?.generateSummary ? pattern.generateSummary(1, [message.match(pattern.pattern)]) : message, count: 1, firstOccurrence: timestamp, lastOccurrence: timestamp, context: [{ timestamp, ...context }], suggestions: pattern?.suggestions || this.generateSuggestions(category, message), relatedMessages: [] }; this.consolidatedMessages.set(messageId, consolidated); } else { // Update existing consolidated message consolidated.count++; consolidated.lastOccurrence = timestamp; consolidated.context.push({ timestamp, ...context }); // Update message summary if using pattern const pattern = this.findMatchingPattern(message, category); if (pattern?.generateSummary) { const matches = this.rawMessages.get(messageId)?.map(raw => message.match(pattern.pattern)) || []; consolidated.message = pattern.generateSummary(consolidated.count, matches); } // Update severity if more severe if (this.getSeverityWeight(severity) > this.getSeverityWeight(consolidated.severity)) { consolidated.severity = severity; } } } findMatchingPattern(message, category) { return MESSAGE_PATTERNS.find(pattern => pattern.category === category && pattern.pattern.test(message)); } getSeverityWeight(severity) { switch (severity) { case MessageSeverity.DEBUG: return 1; case MessageSeverity.INFO: return 2; case MessageSeverity.WARNING: return 3; case MessageSeverity.ERROR: return 4; case MessageSeverity.FATAL: return 5; default: return 0; } } generateTitle(message) { // Extract key terms for title generation const words = message.split(' '); if (words.length <= 3) return message; return words.slice(0, 3).join(' ') + '...'; } generateSuggestions(category, message) { const suggestions = { [MessageCategory.ROM_PARSING]: [ 'Verify ROM file format and integrity', 'Check file permissions and accessibility', 'Try a different ROM dump if available' ], [MessageCategory.INSTRUCTION_DECODE]: [ 'Verify the address range being disassembled', 'Check processor mode settings (8-bit vs 16-bit)', 'Review memory mapping configuration' ], [MessageCategory.MEMORY_ACCESS]: [ 'Review ROM mapping settings', 'Check memory region boundaries', 'Verify address calculations' ], [MessageCategory.ASSET_EXTRACTION]: [ 'Verify asset format specifications', 'Check data offset calculations', 'Review compression settings if applicable' ], [MessageCategory.OUTPUT_GENERATION]: [ 'Check output directory permissions', 'Verify disk space availability', 'Review output format settings' ], [MessageCategory.VALIDATION]: [ 'Review validation rules', 'Check input data format', 'Verify configuration parameters' ], [MessageCategory.CONFIGURATION]: [ 'Check configuration file syntax', 'Verify all required parameters are set', 'Review parameter value ranges' ], [MessageCategory.PERFORMANCE]: [ 'Consider increasing memory allocation', 'Review processing complexity', 'Check system resources' ], [MessageCategory.AUDIO_PROCESSING]: [ 'Verify audio format specifications', 'Check sample rate settings', 'Review compression parameters' ], [MessageCategory.AI_ANALYSIS]: [ 'Check AI model availability', 'Verify network connectivity if required', 'Review analysis parameters' ] }; return suggestions[category] || ['Review the error details and configuration']; } /** * Generate a comprehensive session summary */ generateSessionSummary() { const endTime = new Date(); const consolidatedArray = Array.from(this.consolidatedMessages.values()); // Calculate severity counts const severityCounts = Object.values(MessageSeverity).reduce((acc, severity) => { acc[severity] = consolidatedArray.filter(msg => msg.severity === severity).length; return acc; }, {}); // Calculate category counts const categoryCounts = Object.values(MessageCategory).reduce((acc, category) => { acc[category] = consolidatedArray.filter(msg => msg.category === category).length; return acc; }, {}); // Identify critical issues (fatal errors and high-count errors/warnings) const criticalIssues = consolidatedArray.filter(msg => msg.severity === MessageSeverity.FATAL || (msg.severity === MessageSeverity.ERROR && msg.count >= 5) || (msg.severity === MessageSeverity.WARNING && msg.count >= 10)); // Generate recommendations based on the issues found const recommendations = this.generateRecommendations(consolidatedArray); return { sessionId: this.sessionId, startTime: this.sessionStartTime, endTime, totalMessages: this.messageCounter, severityCounts, categoryCounts, consolidatedMessages: consolidatedArray.sort((a, b) => this.getSeverityWeight(b.severity) - this.getSeverityWeight(a.severity) || b.count - a.count), criticalIssues, recommendations, performanceMetrics: this.performanceMetrics }; } generateRecommendations(messages) { const recommendations = []; // Check for common patterns and generate recommendations const errorCount = messages.filter(m => m.severity === MessageSeverity.ERROR).length; const warningCount = messages.filter(m => m.severity === MessageSeverity.WARNING).length; if (errorCount > 0) { recommendations.push('Review and address the errors found during processing'); } if (warningCount > 10) { recommendations.push('Consider reviewing configuration to reduce warnings'); } // Category-specific recommendations const instructionErrors = messages.filter(m => m.category === MessageCategory.INSTRUCTION_DECODE && m.severity === MessageSeverity.ERROR); if (instructionErrors.length > 0) { recommendations.push('Verify ROM integrity and disassembly address ranges'); } const memoryErrors = messages.filter(m => m.category === MessageCategory.MEMORY_ACCESS && m.severity === MessageSeverity.ERROR); if (memoryErrors.length > 0) { recommendations.push('Review memory mapping configuration'); } const assetErrors = messages.filter(m => m.category === MessageCategory.ASSET_EXTRACTION && m.severity === MessageSeverity.ERROR); if (assetErrors.length > 0) { recommendations.push('Check asset extraction parameters and ROM format'); } if (recommendations.length === 0) { recommendations.push('Processing completed with no major issues detected'); } return recommendations; } /** * Get messages by severity */ getMessagesBySeverity(severity) { return Array.from(this.consolidatedMessages.values()) .filter(msg => msg.severity === severity) .sort((a, b) => b.count - a.count); } /** * Get messages by category */ getMessagesByCategory(category) { return Array.from(this.consolidatedMessages.values()) .filter(msg => msg.category === category) .sort((a, b) => b.count - a.count); } /** * Get critical issues that need immediate attention */ getCriticalIssues() { return Array.from(this.consolidatedMessages.values()) .filter(msg => msg.severity === MessageSeverity.FATAL || (msg.severity === MessageSeverity.ERROR && msg.count >= 5)) .sort((a, b) => this.getSeverityWeight(b.severity) - this.getSeverityWeight(a.severity) || b.count - a.count); } /** * Update performance metrics */ updatePerformanceMetrics(metrics) { this.performanceMetrics = { ...this.performanceMetrics, ...metrics }; } /** * Clear all messages and reset the session */ reset() { this.rawMessages.clear(); this.consolidatedMessages.clear(); this.messageCounter = 0; this.sessionStartTime = new Date(); this.performanceMetrics = { processingTime: 0, memoryUsage: 0, operationsCompleted: 0 }; this.logger.info('Error and Warning Manager reset', { sessionId: this.sessionId }); } /** * Get session statistics */ getSessionStats() { const duration = Date.now() - this.sessionStartTime.getTime(); const consolidated = Array.from(this.consolidatedMessages.values()); const mostCommon = consolidated.sort((a, b) => b.count - a.count)[0]; return { sessionId: this.sessionId, duration, totalMessages: this.messageCounter, uniqueMessages: consolidated.length, mostCommonIssue: mostCommon }; } } exports.ErrorWarningManager = ErrorWarningManager; //# sourceMappingURL=error-warning-manager.js.map