From e671b764525dd35255a517b87d45940743b2543b Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Sun, 1 Feb 2026 03:56:25 +0000 Subject: [PATCH] Initial upload: ErrorFix CLI with rule engine and pattern matching --- errorfix/formatters/__init__.py | 139 ++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 errorfix/formatters/__init__.py diff --git a/errorfix/formatters/__init__.py b/errorfix/formatters/__init__.py new file mode 100644 index 0000000..a2a06c0 --- /dev/null +++ b/errorfix/formatters/__init__.py @@ -0,0 +1,139 @@ +from abc import ABC, abstractmethod +from typing import List, TextIO, Dict, Any + +from errorfix.patterns import MatchResult + + +class Formatter(ABC): + @abstractmethod + def format(self, results: List[MatchResult], error_text: str) -> str: + pass + + @abstractmethod + def write(self, results: List[MatchResult], error_text: str, output: TextIO): + pass + + +class TextFormatter(Formatter): + def __init__(self, use_colors: bool = True): + self.use_colors = use_colors + self._colors = { + 'reset': '\033[0m', + 'red': '\033[31m', + 'green': '\033[32m', + 'yellow': '\033[33m', + 'blue': '\033[34m', + 'magenta': '\033[35m', + } + + def _color(self, text: str, color: str) -> str: + if not self.use_colors: + return text + return f"{self._colors.get(color, '')}{text}{self._colors['reset']}" + + def format(self, results: List[MatchResult], error_text: str) -> str: + if not results: + return self._format_no_match(error_text) + + output = [] + for i, result in enumerate(results, 1): + output.append(self._format_result(i, result)) + + return '\n'.join(output) + + def _format_result(self, index: int, result: MatchResult) -> str: + lines = [] + lines.append(self._color(f"Fix #{index}: {result.rule.name}", 'magenta')) + lines.append(self._color("-" * 50, 'blue')) + lines.append(f"Rule ID: {result.rule.id}") + lines.append(f"Description: {result.rule.description}") + lines.append(f"Severity: {result.rule.severity.value}") + if result.rule.language: + lines.append(f"Language: {result.rule.language}") + if result.rule.tool: + lines.append(f"Tool: {result.rule.tool}") + lines.append("") + lines.append(self._color("Matched:", 'yellow')) + lines.append(result.matched_text) + lines.append("") + lines.append(self._color("Suggested Fix:", 'green')) + fix = result.apply_fix() + lines.append(fix) + if result.groups: + lines.append("") + lines.append(self._color("Captured Variables:", 'yellow')) + for key, value in result.groups.items(): + lines.append(f" {key} = {value}") + return '\n'.join(lines) + + def _format_no_match(self, error_text: str) -> str: + lines = [] + lines.append(self._color("No matching rules found", 'yellow')) + lines.append("-" * 50) + lines.append("Error text:") + lines.append(error_text[:200] + "..." if len(error_text) > 200 else error_text) + lines.append("") + lines.append("Suggestions:") + lines.append(" - Check if the correct rule files are loaded") + lines.append(" - Verify the error pattern matches any known rules") + lines.append(" - Add a custom rule for this error type") + return '\n'.join(lines) + + def write(self, results: List[MatchResult], error_text: str, output: TextIO): + output.write(self.format(results, error_text)) + + +class JSONFormatter(Formatter): + def __init__(self, pretty: bool = True): + self.pretty = pretty + + def format(self, results: List[MatchResult], error_text: str) -> str: + data = self._to_dict(results, error_text) + if self.pretty: + import json + return json.dumps(data, indent=2) + import json + return json.dumps(data) + + def _to_dict(self, results: List[MatchResult], error_text: str) -> Dict[str, Any]: + return { + 'input_text': error_text, + 'match_count': len(results), + 'matches': [ + { + 'rule': { + 'id': r.rule.id, + 'name': r.rule.name, + 'description': r.rule.description, + 'severity': r.rule.severity.value if hasattr(r.rule.severity, 'value') else str(r.rule.severity), + 'language': r.rule.language, + 'tool': r.rule.tool, + 'tags': r.rule.tags, + }, + 'matched_text': r.matched_text, + 'captured_variables': r.groups, + 'suggested_fix': r.apply_fix(), + } + for r in results + ] + } + + def write(self, results: List[MatchResult], error_text: str, output: TextIO): + output.write(self.format(results, error_text)) + + +class StructuredFormatter(Formatter): + def format(self, results: List[MatchResult], error_text: str) -> str: + output = [] + for result in results: + output.append({ + 'rule_id': result.rule.id, + 'rule_name': result.rule.name, + 'match': result.matched_text, + 'fix': result.apply_fix(), + 'variables': result.groups, + }) + return str(output) + + def write(self, results: List[MatchResult], error_text: str, output: TextIO): + output.write(self.format(results, error_text))