chore: run format
This commit is contained in:
@@ -3,234 +3,245 @@ import { join } from 'path';
|
||||
import chalk from 'chalk';
|
||||
|
||||
export class ErrorHandler {
|
||||
constructor(logger) {
|
||||
this.logger = logger;
|
||||
this.errors = [];
|
||||
this.warnings = [];
|
||||
}
|
||||
constructor(logger) {
|
||||
this.logger = logger;
|
||||
this.errors = [];
|
||||
this.warnings = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle and categorize errors
|
||||
*/
|
||||
handleError(error, context = {}) {
|
||||
const errorInfo = {
|
||||
timestamp: new Date().toISOString(),
|
||||
message: error.message || 'Unknown error',
|
||||
stack: error.stack,
|
||||
context,
|
||||
type: this.categorizeError(error)
|
||||
};
|
||||
/**
|
||||
* Handle and categorize errors
|
||||
*/
|
||||
handleError(error, context = {}) {
|
||||
const errorInfo = {
|
||||
timestamp: new Date().toISOString(),
|
||||
message: error.message || 'Unknown error',
|
||||
stack: error.stack,
|
||||
context,
|
||||
type: this.categorizeError(error)
|
||||
};
|
||||
|
||||
this.errors.push(errorInfo);
|
||||
this.logger.error(`[${errorInfo.type}] ${errorInfo.message}`);
|
||||
this.errors.push(errorInfo);
|
||||
this.logger.error(`[${errorInfo.type}] ${errorInfo.message}`);
|
||||
|
||||
if (context.critical) {
|
||||
throw error;
|
||||
}
|
||||
if (context.critical) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return errorInfo;
|
||||
}
|
||||
return errorInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a warning
|
||||
*/
|
||||
addWarning(message, context = {}) {
|
||||
const warning = {
|
||||
timestamp: new Date().toISOString(),
|
||||
message,
|
||||
context
|
||||
};
|
||||
/**
|
||||
* Add a warning
|
||||
*/
|
||||
addWarning(message, context = {}) {
|
||||
const warning = {
|
||||
timestamp: new Date().toISOString(),
|
||||
message,
|
||||
context
|
||||
};
|
||||
|
||||
this.warnings.push(warning);
|
||||
this.logger.warning(message);
|
||||
}
|
||||
this.warnings.push(warning);
|
||||
this.logger.warning(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Categorize error types
|
||||
*/
|
||||
categorizeError(error) {
|
||||
const message = error.message.toLowerCase();
|
||||
/**
|
||||
* Categorize error types
|
||||
*/
|
||||
categorizeError(error) {
|
||||
const message = error.message.toLowerCase();
|
||||
|
||||
if (message.includes('command not found') || message.includes('not found')) {
|
||||
return 'DEPENDENCY_ERROR';
|
||||
}
|
||||
if (message.includes('permission') || message.includes('access denied')) {
|
||||
return 'PERMISSION_ERROR';
|
||||
}
|
||||
if (message.includes('timeout')) {
|
||||
return 'TIMEOUT_ERROR';
|
||||
}
|
||||
if (message.includes('api') || message.includes('rate limit')) {
|
||||
return 'API_ERROR';
|
||||
}
|
||||
if (message.includes('json') || message.includes('parse')) {
|
||||
return 'PARSE_ERROR';
|
||||
}
|
||||
if (message.includes('file') || message.includes('directory')) {
|
||||
return 'FILE_ERROR';
|
||||
}
|
||||
if (
|
||||
message.includes('command not found') ||
|
||||
message.includes('not found')
|
||||
) {
|
||||
return 'DEPENDENCY_ERROR';
|
||||
}
|
||||
if (message.includes('permission') || message.includes('access denied')) {
|
||||
return 'PERMISSION_ERROR';
|
||||
}
|
||||
if (message.includes('timeout')) {
|
||||
return 'TIMEOUT_ERROR';
|
||||
}
|
||||
if (message.includes('api') || message.includes('rate limit')) {
|
||||
return 'API_ERROR';
|
||||
}
|
||||
if (message.includes('json') || message.includes('parse')) {
|
||||
return 'PARSE_ERROR';
|
||||
}
|
||||
if (message.includes('file') || message.includes('directory')) {
|
||||
return 'FILE_ERROR';
|
||||
}
|
||||
|
||||
return 'GENERAL_ERROR';
|
||||
}
|
||||
return 'GENERAL_ERROR';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get error summary
|
||||
*/
|
||||
getSummary() {
|
||||
const errorsByType = {};
|
||||
|
||||
this.errors.forEach(error => {
|
||||
if (!errorsByType[error.type]) {
|
||||
errorsByType[error.type] = [];
|
||||
}
|
||||
errorsByType[error.type].push(error);
|
||||
});
|
||||
/**
|
||||
* Get error summary
|
||||
*/
|
||||
getSummary() {
|
||||
const errorsByType = {};
|
||||
|
||||
return {
|
||||
totalErrors: this.errors.length,
|
||||
totalWarnings: this.warnings.length,
|
||||
errorsByType,
|
||||
criticalErrors: this.errors.filter(e => e.context.critical),
|
||||
recentErrors: this.errors.slice(-5)
|
||||
};
|
||||
}
|
||||
this.errors.forEach((error) => {
|
||||
if (!errorsByType[error.type]) {
|
||||
errorsByType[error.type] = [];
|
||||
}
|
||||
errorsByType[error.type].push(error);
|
||||
});
|
||||
|
||||
/**
|
||||
* Generate error report
|
||||
*/
|
||||
generateReport(outputPath) {
|
||||
const summary = this.getSummary();
|
||||
const report = {
|
||||
generatedAt: new Date().toISOString(),
|
||||
summary: {
|
||||
totalErrors: summary.totalErrors,
|
||||
totalWarnings: summary.totalWarnings,
|
||||
errorTypes: Object.keys(summary.errorsByType)
|
||||
},
|
||||
errors: this.errors,
|
||||
warnings: this.warnings,
|
||||
recommendations: this.generateRecommendations(summary)
|
||||
};
|
||||
return {
|
||||
totalErrors: this.errors.length,
|
||||
totalWarnings: this.warnings.length,
|
||||
errorsByType,
|
||||
criticalErrors: this.errors.filter((e) => e.context.critical),
|
||||
recentErrors: this.errors.slice(-5)
|
||||
};
|
||||
}
|
||||
|
||||
writeFileSync(outputPath, JSON.stringify(report, null, 2));
|
||||
return report;
|
||||
}
|
||||
/**
|
||||
* Generate error report
|
||||
*/
|
||||
generateReport(outputPath) {
|
||||
const summary = this.getSummary();
|
||||
const report = {
|
||||
generatedAt: new Date().toISOString(),
|
||||
summary: {
|
||||
totalErrors: summary.totalErrors,
|
||||
totalWarnings: summary.totalWarnings,
|
||||
errorTypes: Object.keys(summary.errorsByType)
|
||||
},
|
||||
errors: this.errors,
|
||||
warnings: this.warnings,
|
||||
recommendations: this.generateRecommendations(summary)
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate recommendations based on errors
|
||||
*/
|
||||
generateRecommendations(summary) {
|
||||
const recommendations = [];
|
||||
writeFileSync(outputPath, JSON.stringify(report, null, 2));
|
||||
return report;
|
||||
}
|
||||
|
||||
if (summary.errorsByType.DEPENDENCY_ERROR) {
|
||||
recommendations.push({
|
||||
type: 'DEPENDENCY',
|
||||
message: 'Install missing dependencies using npm install or check PATH',
|
||||
errors: summary.errorsByType.DEPENDENCY_ERROR.length
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Generate recommendations based on errors
|
||||
*/
|
||||
generateRecommendations(summary) {
|
||||
const recommendations = [];
|
||||
|
||||
if (summary.errorsByType.PERMISSION_ERROR) {
|
||||
recommendations.push({
|
||||
type: 'PERMISSION',
|
||||
message: 'Check file permissions or run with appropriate privileges',
|
||||
errors: summary.errorsByType.PERMISSION_ERROR.length
|
||||
});
|
||||
}
|
||||
if (summary.errorsByType.DEPENDENCY_ERROR) {
|
||||
recommendations.push({
|
||||
type: 'DEPENDENCY',
|
||||
message: 'Install missing dependencies using npm install or check PATH',
|
||||
errors: summary.errorsByType.DEPENDENCY_ERROR.length
|
||||
});
|
||||
}
|
||||
|
||||
if (summary.errorsByType.API_ERROR) {
|
||||
recommendations.push({
|
||||
type: 'API',
|
||||
message: 'Check API keys, rate limits, or network connectivity',
|
||||
errors: summary.errorsByType.API_ERROR.length
|
||||
});
|
||||
}
|
||||
if (summary.errorsByType.PERMISSION_ERROR) {
|
||||
recommendations.push({
|
||||
type: 'PERMISSION',
|
||||
message: 'Check file permissions or run with appropriate privileges',
|
||||
errors: summary.errorsByType.PERMISSION_ERROR.length
|
||||
});
|
||||
}
|
||||
|
||||
if (summary.errorsByType.TIMEOUT_ERROR) {
|
||||
recommendations.push({
|
||||
type: 'TIMEOUT',
|
||||
message: 'Consider increasing timeout values or optimizing slow operations',
|
||||
errors: summary.errorsByType.TIMEOUT_ERROR.length
|
||||
});
|
||||
}
|
||||
if (summary.errorsByType.API_ERROR) {
|
||||
recommendations.push({
|
||||
type: 'API',
|
||||
message: 'Check API keys, rate limits, or network connectivity',
|
||||
errors: summary.errorsByType.API_ERROR.length
|
||||
});
|
||||
}
|
||||
|
||||
return recommendations;
|
||||
}
|
||||
if (summary.errorsByType.TIMEOUT_ERROR) {
|
||||
recommendations.push({
|
||||
type: 'TIMEOUT',
|
||||
message:
|
||||
'Consider increasing timeout values or optimizing slow operations',
|
||||
errors: summary.errorsByType.TIMEOUT_ERROR.length
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Display error summary in console
|
||||
*/
|
||||
displaySummary() {
|
||||
const summary = this.getSummary();
|
||||
return recommendations;
|
||||
}
|
||||
|
||||
if (summary.totalErrors === 0 && summary.totalWarnings === 0) {
|
||||
console.log(chalk.green('✅ No errors or warnings detected'));
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Display error summary in console
|
||||
*/
|
||||
displaySummary() {
|
||||
const summary = this.getSummary();
|
||||
|
||||
console.log(chalk.red.bold(`\n🚨 Error Summary:`));
|
||||
console.log(chalk.red(` Total Errors: ${summary.totalErrors}`));
|
||||
console.log(chalk.yellow(` Total Warnings: ${summary.totalWarnings}`));
|
||||
if (summary.totalErrors === 0 && summary.totalWarnings === 0) {
|
||||
console.log(chalk.green('✅ No errors or warnings detected'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (summary.totalErrors > 0) {
|
||||
console.log(chalk.red.bold('\n Error Types:'));
|
||||
Object.entries(summary.errorsByType).forEach(([type, errors]) => {
|
||||
console.log(chalk.red(` - ${type}: ${errors.length}`));
|
||||
});
|
||||
console.log(chalk.red.bold(`\n🚨 Error Summary:`));
|
||||
console.log(chalk.red(` Total Errors: ${summary.totalErrors}`));
|
||||
console.log(chalk.yellow(` Total Warnings: ${summary.totalWarnings}`));
|
||||
|
||||
if (summary.criticalErrors.length > 0) {
|
||||
console.log(chalk.red.bold(`\n ⚠️ Critical Errors: ${summary.criticalErrors.length}`));
|
||||
summary.criticalErrors.forEach(error => {
|
||||
console.log(chalk.red(` - ${error.message}`));
|
||||
});
|
||||
}
|
||||
}
|
||||
if (summary.totalErrors > 0) {
|
||||
console.log(chalk.red.bold('\n Error Types:'));
|
||||
Object.entries(summary.errorsByType).forEach(([type, errors]) => {
|
||||
console.log(chalk.red(` - ${type}: ${errors.length}`));
|
||||
});
|
||||
|
||||
const recommendations = this.generateRecommendations(summary);
|
||||
if (recommendations.length > 0) {
|
||||
console.log(chalk.yellow.bold('\n💡 Recommendations:'));
|
||||
recommendations.forEach(rec => {
|
||||
console.log(chalk.yellow(` - ${rec.message}`));
|
||||
});
|
||||
}
|
||||
}
|
||||
if (summary.criticalErrors.length > 0) {
|
||||
console.log(
|
||||
chalk.red.bold(
|
||||
`\n ⚠️ Critical Errors: ${summary.criticalErrors.length}`
|
||||
)
|
||||
);
|
||||
summary.criticalErrors.forEach((error) => {
|
||||
console.log(chalk.red(` - ${error.message}`));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all errors and warnings
|
||||
*/
|
||||
clear() {
|
||||
this.errors = [];
|
||||
this.warnings = [];
|
||||
}
|
||||
const recommendations = this.generateRecommendations(summary);
|
||||
if (recommendations.length > 0) {
|
||||
console.log(chalk.yellow.bold('\n💡 Recommendations:'));
|
||||
recommendations.forEach((rec) => {
|
||||
console.log(chalk.yellow(` - ${rec.message}`));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all errors and warnings
|
||||
*/
|
||||
clear() {
|
||||
this.errors = [];
|
||||
this.warnings = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Global error handler for uncaught exceptions
|
||||
*/
|
||||
export function setupGlobalErrorHandlers(errorHandler, logger) {
|
||||
process.on('uncaughtException', (error) => {
|
||||
logger.error(`Uncaught Exception: ${error.message}`);
|
||||
errorHandler.handleError(error, { critical: true, source: 'uncaughtException' });
|
||||
process.exit(1);
|
||||
});
|
||||
process.on('uncaughtException', (error) => {
|
||||
logger.error(`Uncaught Exception: ${error.message}`);
|
||||
errorHandler.handleError(error, {
|
||||
critical: true,
|
||||
source: 'uncaughtException'
|
||||
});
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
logger.error(`Unhandled Rejection at: ${promise}, reason: ${reason}`);
|
||||
errorHandler.handleError(new Error(String(reason)), {
|
||||
critical: false,
|
||||
source: 'unhandledRejection'
|
||||
});
|
||||
});
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
logger.error(`Unhandled Rejection at: ${promise}, reason: ${reason}`);
|
||||
errorHandler.handleError(new Error(String(reason)), {
|
||||
critical: false,
|
||||
source: 'unhandledRejection'
|
||||
});
|
||||
});
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
logger.info('\nReceived SIGINT, shutting down gracefully...');
|
||||
errorHandler.displaySummary();
|
||||
process.exit(130);
|
||||
});
|
||||
process.on('SIGINT', () => {
|
||||
logger.info('\nReceived SIGINT, shutting down gracefully...');
|
||||
errorHandler.displaySummary();
|
||||
process.exit(130);
|
||||
});
|
||||
|
||||
process.on('SIGTERM', () => {
|
||||
logger.info('\nReceived SIGTERM, shutting down...');
|
||||
errorHandler.displaySummary();
|
||||
process.exit(143);
|
||||
});
|
||||
}
|
||||
process.on('SIGTERM', () => {
|
||||
logger.info('\nReceived SIGTERM, shutting down...');
|
||||
errorHandler.displaySummary();
|
||||
process.exit(143);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user