sicua
Version:
A tool for analyzing project structure and dependencies
287 lines (286 loc) • 10.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorHandler = exports.ErrorCategory = exports.ErrorSeverity = void 0;
/**
* Error severity levels
*/
var ErrorSeverity;
(function (ErrorSeverity) {
ErrorSeverity["LOW"] = "low";
ErrorSeverity["MEDIUM"] = "medium";
ErrorSeverity["HIGH"] = "high";
ErrorSeverity["CRITICAL"] = "critical";
})(ErrorSeverity || (exports.ErrorSeverity = ErrorSeverity = {}));
/**
* Error categories for function analysis
*/
var ErrorCategory;
(function (ErrorCategory) {
ErrorCategory["PARSING"] = "parsing";
ErrorCategory["TYPE_RESOLUTION"] = "type_resolution";
ErrorCategory["AST_TRAVERSAL"] = "ast_traversal";
ErrorCategory["FILE_ACCESS"] = "file_access";
ErrorCategory["FUNCTION_EXTRACTION"] = "function_extraction";
ErrorCategory["CLASSIFICATION"] = "classification";
ErrorCategory["DEPENDENCY_ANALYSIS"] = "dependency_analysis";
})(ErrorCategory || (exports.ErrorCategory = ErrorCategory = {}));
/**
* Utility class for structured error handling in function analysis
*/
class ErrorHandler {
constructor(config = {}) {
this.errors = [];
this.defaultFallbacks = {
functionName: "Unknown Function",
returnType: "unknown",
params: [],
body: "// Error parsing function body",
dependencies: [],
calledFunctions: [],
isAsync: false,
};
this.config = {
logErrors: true,
throwOnCritical: false,
maxErrorsPerFile: 50,
includeStackTrace: false,
enableRecovery: true,
...config,
};
}
/**
* Safely executes a function with error handling and fallback
*/
safeExecute(operation, fallbackValue, context, category = ErrorCategory.PARSING, severity = ErrorSeverity.MEDIUM, filePath, functionName) {
try {
return operation();
}
catch (error) {
this.handleError(error, context, category, severity, filePath, functionName);
return fallbackValue;
}
}
/**
* Safely extracts function name with fallback
*/
safeFunctionName(node, extractor, filePath) {
return this.safeExecute(() => extractor(node), this.defaultFallbacks.functionName, "function name extraction", ErrorCategory.FUNCTION_EXTRACTION, ErrorSeverity.LOW, filePath);
}
/**
* Safely extracts return type with fallback
*/
safeReturnType(node, extractor, filePath, functionName) {
return this.safeExecute(() => extractor(node), this.defaultFallbacks.returnType, "return type extraction", ErrorCategory.TYPE_RESOLUTION, ErrorSeverity.LOW, filePath, functionName);
}
/**
* Safely extracts parameters with fallback
*/
safeParameters(node, extractor, filePath, functionName) {
return this.safeExecute(() => extractor(node), this.defaultFallbacks.params, "parameter extraction", ErrorCategory.FUNCTION_EXTRACTION, ErrorSeverity.LOW, filePath, functionName);
}
/**
* Safely extracts function body with fallback
*/
safeFunctionBody(node, extractor, filePath, functionName) {
return this.safeExecute(() => extractor(node), this.defaultFallbacks.body, "function body extraction", ErrorCategory.FUNCTION_EXTRACTION, ErrorSeverity.MEDIUM, filePath, functionName);
}
/**
* Safely extracts dependencies with fallback
*/
safeDependencies(node, extractor, filePath, functionName) {
return this.safeExecute(() => extractor(node), this.defaultFallbacks.dependencies, "dependency extraction", ErrorCategory.DEPENDENCY_ANALYSIS, ErrorSeverity.LOW, filePath, functionName);
}
/**
* Safely extracts called functions with fallback
*/
safeCalledFunctions(node, extractor, filePath, functionName) {
return this.safeExecute(() => extractor(node), this.defaultFallbacks.calledFunctions, "called functions extraction", ErrorCategory.FUNCTION_EXTRACTION, ErrorSeverity.LOW, filePath, functionName);
}
/**
* Safely detects async status with fallback
*/
safeAsyncDetection(node, detector, filePath, functionName) {
return this.safeExecute(() => detector(node), this.defaultFallbacks.isAsync, "async detection", ErrorCategory.FUNCTION_EXTRACTION, ErrorSeverity.LOW, filePath, functionName);
}
/**
* Safely performs classification with fallback
*/
safeClassification(node, classifier, fallbackValue, filePath, functionName) {
return this.safeExecute(() => classifier(node), fallbackValue, "function classification", ErrorCategory.CLASSIFICATION, ErrorSeverity.MEDIUM, filePath, functionName);
}
/**
* Safely traverses AST with error recovery
*/
safeASTTraversal(node, traverser, fallbackValue, filePath) {
return this.safeExecute(() => traverser(node), fallbackValue, "AST traversal", ErrorCategory.AST_TRAVERSAL, ErrorSeverity.HIGH, filePath);
}
/**
* Handles file access errors
*/
handleFileError(filePath, operation, error) {
this.handleError(error, `File ${operation}: ${filePath}`, ErrorCategory.FILE_ACCESS, ErrorSeverity.HIGH, filePath);
}
/**
* Core error handling method
*/
handleError(error, context, category, severity, filePath, functionName) {
const analysisError = {
category,
severity,
message: this.extractErrorMessage(error),
context,
filePath,
functionName,
nodeKind: this.extractNodeKind(error),
stackTrace: this.config.includeStackTrace
? this.extractStackTrace(error)
: undefined,
timestamp: new Date(),
recoverable: this.config.enableRecovery && severity !== ErrorSeverity.CRITICAL,
};
this.errors.push(analysisError);
// Log error if configured
if (this.config.logErrors) {
this.logError(analysisError);
}
// Check if we should throw on critical errors
if (this.config.throwOnCritical && severity === ErrorSeverity.CRITICAL) {
throw new Error(`Critical error in ${context}: ${analysisError.message}`);
}
// Check if we've exceeded max errors per file
if (filePath &&
this.getErrorCountForFile(filePath) > this.config.maxErrorsPerFile) {
console.warn(`Max errors exceeded for file: ${filePath}. Some errors may be suppressed.`);
}
}
/**
* Extracts error message from various error types
*/
extractErrorMessage(error) {
if (error instanceof Error) {
return error.message;
}
if (typeof error === "string") {
return error;
}
if (error && typeof error === "object" && "message" in error) {
return String(error.message);
}
return "Unknown error occurred";
}
/**
* Extracts stack trace from error
*/
extractStackTrace(error) {
if (error instanceof Error && error.stack) {
return error.stack;
}
return undefined;
}
/**
* Attempts to extract TypeScript node kind from error context
*/
extractNodeKind(error) {
if (error instanceof Error && error.message.includes("SyntaxKind")) {
const match = error.message.match(/SyntaxKind\.(\w+)/);
return match ? match[1] : undefined;
}
return undefined;
}
/**
* Logs error with appropriate level
*/
logError(error) {
const prefix = `[${error.severity.toUpperCase()}] ${error.category}:`;
const message = `${prefix} ${error.message} (${error.context})`;
const location = error.filePath ? ` in ${error.filePath}` : "";
const functionContext = error.functionName
? ` at function ${error.functionName}`
: "";
const fullMessage = `${message}${location}${functionContext}`;
switch (error.severity) {
case ErrorSeverity.CRITICAL:
console.error(fullMessage);
break;
case ErrorSeverity.HIGH:
console.error(fullMessage);
break;
case ErrorSeverity.MEDIUM:
console.warn(fullMessage);
break;
case ErrorSeverity.LOW:
console.log(fullMessage);
break;
}
if (error.stackTrace && error.severity === ErrorSeverity.CRITICAL) {
console.error("Stack trace:", error.stackTrace);
}
}
/**
* Gets error count for a specific file
*/
getErrorCountForFile(filePath) {
return this.errors.filter((error) => error.filePath === filePath).length;
}
/**
* Gets all errors
*/
getErrors() {
return [...this.errors];
}
/**
* Gets errors by category
*/
getErrorsByCategory(category) {
return this.errors.filter((error) => error.category === category);
}
/**
* Gets errors by severity
*/
getErrorsBySeverity(severity) {
return this.errors.filter((error) => error.severity === severity);
}
/**
* Gets errors for a specific file
*/
getErrorsForFile(filePath) {
return this.errors.filter((error) => error.filePath === filePath);
}
/**
* Clears all errors
*/
clearErrors() {
this.errors = [];
}
/**
* Gets error summary statistics
*/
getErrorSummary() {
const bySeverity = Object.values(ErrorSeverity).reduce((acc, severity) => {
acc[severity] = this.getErrorsBySeverity(severity).length;
return acc;
}, {});
const byCategory = Object.values(ErrorCategory).reduce((acc, category) => {
acc[category] = this.getErrorsByCategory(category).length;
return acc;
}, {});
const filesWithErrors = new Set(this.errors
.filter((error) => error.filePath)
.map((error) => error.filePath)).size;
return {
total: this.errors.length,
bySeverity,
byCategory,
filesWithErrors,
};
}
/**
* Checks if analysis can continue based on error state
*/
canContinueAnalysis() {
const criticalErrors = this.getErrorsBySeverity(ErrorSeverity.CRITICAL).length;
const highErrors = this.getErrorsBySeverity(ErrorSeverity.HIGH).length;
return criticalErrors === 0 && highErrors < 10; // Configurable threshold
}
}
exports.ErrorHandler = ErrorHandler;