140 lines
5.0 KiB
Python
140 lines
5.0 KiB
Python
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))
|