crapifyme
Version:
Ultra-fast developer productivity CLI tools - remove comments, logs, and more
336 lines • 12.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorHandler = exports.ErrorCategory = exports.ErrorSeverity = void 0;
const logger_1 = require("./logger");
var ErrorSeverity;
(function (ErrorSeverity) {
ErrorSeverity["LOW"] = "low";
ErrorSeverity["MEDIUM"] = "medium";
ErrorSeverity["HIGH"] = "high";
ErrorSeverity["CRITICAL"] = "critical";
})(ErrorSeverity || (exports.ErrorSeverity = ErrorSeverity = {}));
var ErrorCategory;
(function (ErrorCategory) {
ErrorCategory["PARSING"] = "parsing";
ErrorCategory["TOKENIZATION"] = "tokenization";
ErrorCategory["REGEX"] = "regex";
ErrorCategory["STRING_HANDLING"] = "string_handling";
ErrorCategory["TEMPLATE_LITERAL"] = "template_literal";
ErrorCategory["COMMENT_DETECTION"] = "comment_detection";
ErrorCategory["PRESERVATION"] = "preservation";
ErrorCategory["FILE_PROCESSING"] = "file_processing";
})(ErrorCategory || (exports.ErrorCategory = ErrorCategory = {}));
class ErrorHandler {
constructor(logger, enableRecovery = true) {
this.errors = [];
this.warnings = [];
this.logger = logger || new logger_1.Logger(false, false, false);
this.enableRecovery = enableRecovery;
}
recordError(error) {
const fullError = {
severity: ErrorSeverity.MEDIUM,
position: undefined,
line: undefined,
column: undefined,
context: undefined,
recoveryAction: undefined,
originalError: undefined,
...error
};
this.errors.push(fullError);
switch (fullError.severity) {
case ErrorSeverity.CRITICAL:
this.logger.error(`CRITICAL ${fullError.category}: ${fullError.message}`, fullError.originalError);
break;
case ErrorSeverity.HIGH:
this.logger.error(`${fullError.category}: ${fullError.message}`, fullError.originalError);
break;
case ErrorSeverity.MEDIUM:
this.logger.warn(`${fullError.category}: ${fullError.message}`);
break;
case ErrorSeverity.LOW:
this.logger.info(`${fullError.category}: ${fullError.message}`);
break;
}
}
recordWarning(message) {
this.warnings.push(message);
this.logger.warn(message);
}
attemptRecovery(error, content, position) {
if (!this.enableRecovery) {
return {
recovered: false,
fallbackUsed: false,
errors: [error],
warnings: []
};
}
const recoveryResult = {
recovered: false,
fallbackUsed: false,
errors: [],
warnings: []
};
try {
switch (error.category) {
case ErrorCategory.STRING_HANDLING:
return this.recoverFromStringError(error, content, position);
case ErrorCategory.TEMPLATE_LITERAL:
return this.recoverFromTemplateError(error, content, position);
case ErrorCategory.REGEX:
return this.recoverFromRegexError(error, content, position);
case ErrorCategory.COMMENT_DETECTION:
return this.recoverFromCommentError(error, content, position);
case ErrorCategory.TOKENIZATION:
return this.recoverFromTokenizationError(error, content, position);
default:
return this.recoverFromGenericError(error, content, position);
}
}
catch (recoveryError) {
recoveryResult.errors.push({
category: ErrorCategory.PARSING,
severity: ErrorSeverity.HIGH,
message: `Recovery attempt failed: ${recoveryError instanceof Error ? recoveryError.message : 'Unknown error'}`,
position,
originalError: recoveryError instanceof Error ? recoveryError : undefined
});
return recoveryResult;
}
}
recoverFromStringError(error, content, position) {
const result = {
recovered: false,
fallbackUsed: true,
errors: [],
warnings: ['Attempting string parsing recovery']
};
const quote = this.detectQuoteType(content, position);
if (quote) {
const nextQuote = content.indexOf(quote, position + 1);
if (nextQuote !== -1) {
result.recovered = true;
result.warnings.push(`Recovered unterminated string by finding next ${quote} at position ${nextQuote}`);
return result;
}
}
const nextNewline = content.indexOf('\n', position);
if (nextNewline !== -1) {
result.recovered = true;
result.warnings.push(`Recovered unterminated string by ending at line break at position ${nextNewline}`);
return result;
}
result.recovered = true;
result.warnings.push('Recovered unterminated string by ending at end of content');
return result;
}
recoverFromTemplateError(error, content, position) {
const result = {
recovered: false,
fallbackUsed: true,
errors: [],
warnings: ['Attempting template literal recovery']
};
const nextBacktick = content.indexOf('`', position + 1);
if (nextBacktick !== -1) {
result.recovered = true;
result.warnings.push(`Recovered unterminated template literal by finding next backtick at position ${nextBacktick}`);
return result;
}
const nextQuote = this.findNextQuote(content, position + 1);
if (nextQuote !== -1) {
result.recovered = true;
result.warnings.push(`Recovered template literal by treating as string ending at position ${nextQuote}`);
return result;
}
result.recovered = true;
result.warnings.push('Recovered template literal by ending at end of content');
return result;
}
recoverFromRegexError(error, content, position) {
const result = {
recovered: false,
fallbackUsed: true,
errors: [],
warnings: ['Attempting regex parsing recovery']
};
let i = position + 1;
while (i < content.length) {
if (content[i] === '/' && (i === 0 || content[i - 1] !== '\\')) {
result.recovered = true;
result.warnings.push(`Recovered unterminated regex by finding next unescaped / at position ${i}`);
return result;
}
i++;
}
i = position + 1;
while (i < content.length && !/[\s;,)}]/.test(content[i])) {
i++;
}
if (i < content.length) {
result.recovered = true;
result.warnings.push(`Recovered regex by ending at whitespace/operator at position ${i}`);
return result;
}
result.recovered = true;
result.warnings.push('Recovered regex by ending at end of content');
return result;
}
recoverFromCommentError(error, content, position) {
const result = {
recovered: false,
fallbackUsed: true,
errors: [],
warnings: ['Attempting comment parsing recovery']
};
if (content.substring(position, position + 2) === '/*') {
const endComment = content.indexOf('*/', position + 2);
if (endComment !== -1) {
result.recovered = true;
result.warnings.push(`Recovered unterminated block comment by finding */ at position ${endComment}`);
return result;
}
}
if (content.substring(position, position + 2) === '//') {
const nextNewline = content.indexOf('\n', position);
if (nextNewline !== -1) {
result.recovered = true;
result.warnings.push(`Recovered line comment by finding newline at position ${nextNewline}`);
return result;
}
}
if (content.substring(position, position + 4) === '<!--') {
const endComment = content.indexOf('-->', position + 4);
if (endComment !== -1) {
result.recovered = true;
result.warnings.push(`Recovered unterminated HTML comment by finding --> at position ${endComment}`);
return result;
}
}
result.recovered = true;
result.warnings.push('Recovered comment by ending at end of content');
return result;
}
recoverFromTokenizationError(error, content, position) {
const result = {
recovered: true,
fallbackUsed: true,
errors: [],
warnings: ['Recovered from tokenization error by skipping problematic character']
};
return result;
}
recoverFromGenericError(error, content, position) {
const result = {
recovered: true,
fallbackUsed: true,
errors: [],
warnings: ['Applied generic recovery strategy']
};
return result;
}
detectQuoteType(content, position) {
if (position >= content.length)
return null;
const char = content[position];
if (char === '"' || char === "'" || char === '`') {
return char;
}
return null;
}
findNextQuote(content, startPosition) {
for (let i = startPosition; i < content.length; i++) {
const char = content[i];
if (char === '"' || char === "'" || char === '`') {
return i;
}
}
return -1;
}
calculateLineColumn(content, position) {
let line = 1;
let column = 1;
for (let i = 0; i < position && i < content.length; i++) {
if (content[i] === '\n') {
line++;
column = 1;
}
else {
column++;
}
}
return { line, column };
}
getContext(content, position, contextSize = 50) {
const start = Math.max(0, position - contextSize);
const end = Math.min(content.length, position + contextSize);
const context = content.substring(start, end);
const relativePos = position - start;
return context.substring(0, relativePos) + '<<<ERROR>>>' + context.substring(relativePos);
}
validateParsingCompletion(originalLength, processedLength, tokensProcessed) {
const lengthDifference = Math.abs(originalLength - processedLength);
const maxAllowedDifference = originalLength * 0.5;
if (lengthDifference > maxAllowedDifference) {
this.recordError({
category: ErrorCategory.PARSING,
severity: ErrorSeverity.HIGH,
message: `Significant content length difference detected: original=${originalLength}, processed=${processedLength}, difference=${lengthDifference}`
});
return false;
}
if (tokensProcessed === 0 && originalLength > 0) {
this.recordError({
category: ErrorCategory.TOKENIZATION,
severity: ErrorSeverity.CRITICAL,
message: 'No tokens were processed despite non-empty input'
});
return false;
}
return true;
}
getErrors() {
return [...this.errors];
}
getWarnings() {
return [...this.warnings];
}
hasCriticalErrors() {
return this.errors.some(error => error.severity === ErrorSeverity.CRITICAL);
}
getErrorSummary() {
const bySeverity = {
[ErrorSeverity.LOW]: 0,
[ErrorSeverity.MEDIUM]: 0,
[ErrorSeverity.HIGH]: 0,
[ErrorSeverity.CRITICAL]: 0
};
const byCategory = {
[ErrorCategory.PARSING]: 0,
[ErrorCategory.TOKENIZATION]: 0,
[ErrorCategory.REGEX]: 0,
[ErrorCategory.STRING_HANDLING]: 0,
[ErrorCategory.TEMPLATE_LITERAL]: 0,
[ErrorCategory.COMMENT_DETECTION]: 0,
[ErrorCategory.PRESERVATION]: 0,
[ErrorCategory.FILE_PROCESSING]: 0
};
this.errors.forEach(error => {
bySeverity[error.severity]++;
byCategory[error.category]++;
});
return {
total: this.errors.length,
bySeverity,
byCategory
};
}
clear() {
this.errors = [];
this.warnings = [];
}
}
exports.ErrorHandler = ErrorHandler;
//# sourceMappingURL=error-handler.js.map