Coverage for lintro / utils / output / parser_registration.py: 96%
46 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Register all parsers at module load time.
3This module registers all tool parsers with the ParserRegistry,
4providing O(1) lookup for parser dispatch and fixability predicates.
5"""
7# mypy: ignore-errors
8# Note: mypy errors are suppressed because lintro runs mypy from file's directory,
9# breaking package resolution. When run properly (mypy lintro/...), this file passes.
11from __future__ import annotations
13import json
14from typing import Any
16from loguru import logger
18from lintro.enums.tool_name import ToolName
19from lintro.parsers.actionlint.actionlint_parser import parse_actionlint_output
20from lintro.parsers.astro_check.astro_check_parser import parse_astro_check_output
21from lintro.parsers.bandit.bandit_parser import parse_bandit_output
22from lintro.parsers.black.black_issue import BlackIssue
23from lintro.parsers.black.black_parser import parse_black_output
24from lintro.parsers.clippy.clippy_parser import parse_clippy_output
25from lintro.parsers.hadolint.hadolint_parser import parse_hadolint_output
26from lintro.parsers.markdownlint.markdownlint_parser import parse_markdownlint_output
27from lintro.parsers.mypy.mypy_parser import parse_mypy_output
28from lintro.parsers.ruff.ruff_format_issue import RuffFormatIssue
29from lintro.parsers.ruff.ruff_issue import RuffIssue
30from lintro.parsers.ruff.ruff_parser import parse_ruff_output
31from lintro.parsers.svelte_check.svelte_check_parser import parse_svelte_check_output
32from lintro.parsers.vue_tsc.vue_tsc_parser import parse_vue_tsc_output
33from lintro.parsers.yamllint.yamllint_parser import parse_yamllint_output
34from lintro.utils.output.parser_registry import ParserRegistry
36# -----------------------------------------------------------------------------
37# Fixability Predicates
38# -----------------------------------------------------------------------------
41def _ruff_is_fixable(issue: object) -> bool:
42 """Check if a Ruff issue is fixable.
44 Args:
45 issue: The issue object to check.
47 Returns:
48 True if the issue is fixable (format issue or has fixable attribute).
49 """
50 return isinstance(issue, RuffFormatIssue) or (
51 isinstance(issue, RuffIssue) and getattr(issue, "fixable", False)
52 )
55def _black_is_fixable(issue: object) -> bool:
56 """Check if a Black issue is fixable.
58 Args:
59 issue: The issue object to check.
61 Returns:
62 True if the issue is a BlackIssue (all Black issues are fixable).
63 """
64 return isinstance(issue, BlackIssue) and getattr(issue, "fixable", True)
67# -----------------------------------------------------------------------------
68# Special Parsers
69# -----------------------------------------------------------------------------
72class ParserError(Exception):
73 """Exception raised when parsing tool output fails.
75 This exception is raised instead of silently returning empty results,
76 allowing callers to distinguish between "no issues found" and "parsing failed".
77 """
80def _parse_bandit_output(output: str) -> list[Any]:
81 """Parse Bandit output, handling JSON format.
83 Args:
84 output: Raw Bandit output (expected to be JSON).
86 Returns:
87 List of parsed Bandit issues.
89 Raises:
90 ParserError: If the output cannot be parsed as valid JSON.
91 """
92 try:
93 return parse_bandit_output(bandit_data=json.loads(output))
94 except (json.JSONDecodeError, KeyError, TypeError, ValueError) as e:
95 logger.error(f"Failed to parse Bandit output: {e}")
96 raise ParserError(f"Failed to parse Bandit output: {e}") from e
99# -----------------------------------------------------------------------------
100# Registration
101# -----------------------------------------------------------------------------
104def register_all_parsers() -> None:
105 """Register all tool parsers with the registry.
107 This function should be called once during application initialization
108 to populate the ParserRegistry with all available tool parsers.
109 """
110 # Ruff - Python linter/formatter
111 ParserRegistry.register(
112 ToolName.RUFF.value,
113 parse_ruff_output,
114 is_fixable=_ruff_is_fixable,
115 )
117 # Black - Python formatter
118 ParserRegistry.register(
119 ToolName.BLACK.value,
120 parse_black_output,
121 is_fixable=_black_is_fixable,
122 )
124 # Mypy - Python type checker
125 ParserRegistry.register(
126 ToolName.MYPY.value,
127 parse_mypy_output,
128 )
130 # Actionlint - GitHub Actions linter
131 ParserRegistry.register(
132 ToolName.ACTIONLINT.value,
133 parse_actionlint_output,
134 )
136 # Hadolint - Dockerfile linter
137 ParserRegistry.register(
138 ToolName.HADOLINT.value,
139 parse_hadolint_output,
140 )
142 # Yamllint - YAML linter
143 ParserRegistry.register(
144 ToolName.YAMLLINT.value,
145 parse_yamllint_output,
146 )
148 # Markdownlint - Markdown linter
149 ParserRegistry.register(
150 ToolName.MARKDOWNLINT.value,
151 parse_markdownlint_output,
152 )
154 # Bandit - Python security linter (special JSON handling)
155 ParserRegistry.register(
156 ToolName.BANDIT.value,
157 _parse_bandit_output,
158 )
160 # Clippy - Rust linter
161 ParserRegistry.register(
162 ToolName.CLIPPY.value,
163 parse_clippy_output,
164 )
166 # Astro check - Astro type checker
167 ParserRegistry.register(
168 ToolName.ASTRO_CHECK.value,
169 parse_astro_check_output,
170 )
172 # Svelte-check - Svelte type checker
173 ParserRegistry.register(
174 ToolName.SVELTE_CHECK.value,
175 parse_svelte_check_output,
176 )
178 # Vue-tsc - Vue TypeScript type checker
179 ParserRegistry.register(
180 ToolName.VUE_TSC.value,
181 parse_vue_tsc_output,
182 )
185# Auto-register parsers when module is imported
186register_all_parsers()