UNPKG

devbuddy

Version:

Developer-friendly runtime toolkit that intercepts JavaScript errors and provides helpful suggestions

127 lines (107 loc) 3.85 kB
/** * Hint Engine for DevBuddy * Maps known error patterns to helpful suggestions */ const fs = require('fs'); const path = require('path'); // Registry of hint providers by error type const hintProviders = {}; // Registry of error code to handler mappings const errorCodeMappings = { // File system error codes 'ENOENT': 'FileSystemError', 'EACCES': 'FileSystemError', 'EEXIST': 'FileSystemError', 'EISDIR': 'FileSystemError', 'ENOTDIR': 'FileSystemError', 'EBUSY': 'FileSystemError', 'EMFILE': 'FileSystemError', 'ENFILE': 'FileSystemError', // Network error codes 'ECONNREFUSED': 'NodeNetworkingError', 'EADDRINUSE': 'NodeNetworkingError', 'ENOTFOUND': 'NodeNetworkingError', 'ETIMEDOUT': 'NodeNetworkingError', 'ECONNRESET': 'NodeNetworkingError', 'EPROTO': 'NodeNetworkingError' }; // Dynamically load all hint providers from the hints directory function loadHintProviders() { const hintsDir = path.join(__dirname, 'hints'); try { // Read all files in the hints directory const files = fs.readdirSync(hintsDir); // Filter for JS files and load each provider files.filter(file => file.endsWith('.js')).forEach(file => { const errorType = path.basename(file, '.js'); try { const provider = require(path.join(hintsDir, file)); hintProviders[errorType] = provider; // Also map common variants of error names (like Error vs. error) if (errorType.endsWith('Error')) { const lowerCaseType = errorType.charAt(0).toLowerCase() + errorType.slice(1); hintProviders[lowerCaseType] = provider; } } catch (err) { console.error(`Failed to load hint provider for ${errorType}:`, err.message); } }); } catch (err) { console.error('Failed to load hint providers:', err.message); } } // Load all hint providers at startup loadHintProviders(); /** * Checks if an error message matches a specific pattern * @param {string} message - The error message to check * @param {string|RegExp} pattern - Pattern to match against * @returns {boolean} Whether the message matches the pattern */ function messageMatches(message, pattern) { if (pattern instanceof RegExp) { return pattern.test(message); } return message.includes(pattern); } /** * Gets a hint for the given error * @param {Object} parsedError - The parsed error object * @returns {string|null} A hint message or null if no hint is available */ function getHint(parsedError) { const { type, message, code } = parsedError; // Check for system errors by error code first if (code && errorCodeMappings[code]) { const errorType = errorCodeMappings[code]; if (hintProviders[errorType]) { return hintProviders[errorType](parsedError); } } // Check for special case: UnhandledPromiseRejection if (message.includes('UnhandledPromiseRejection')) { return hintProviders['UnhandledPromiseRejectionWarning']?.(parsedError) || null; } // Check for special case: Module not found if (message.includes('Cannot find module') || message.includes('Module not found')) { return hintProviders['ModuleNotFoundError']?.(parsedError) || null; } // Check if we have a provider for this error type const provider = hintProviders[type]; if (provider) { return provider(parsedError); } // Try to find a fallback provider based on message patterns for (const [errorType, provider] of Object.entries(hintProviders)) { // Skip if we've already checked this type if (errorType === type) { continue; } // Check if this error type typically appears in the message if (messageMatches(message, new RegExp(`\\b${errorType}\\b`, 'i'))) { return provider(parsedError); } } return null; } module.exports = { getHint };