tree-sitter-analyzer 0.7.0__py3-none-any.whl → 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of tree-sitter-analyzer might be problematic. Click here for more details.

Files changed (69) hide show
  1. tree_sitter_analyzer/__init__.py +132 -132
  2. tree_sitter_analyzer/__main__.py +11 -11
  3. tree_sitter_analyzer/api.py +533 -533
  4. tree_sitter_analyzer/cli/__init__.py +39 -39
  5. tree_sitter_analyzer/cli/__main__.py +12 -12
  6. tree_sitter_analyzer/cli/commands/__init__.py +26 -26
  7. tree_sitter_analyzer/cli/commands/advanced_command.py +88 -88
  8. tree_sitter_analyzer/cli/commands/base_command.py +160 -160
  9. tree_sitter_analyzer/cli/commands/default_command.py +18 -18
  10. tree_sitter_analyzer/cli/commands/partial_read_command.py +141 -141
  11. tree_sitter_analyzer/cli/commands/query_command.py +81 -81
  12. tree_sitter_analyzer/cli/commands/structure_command.py +138 -138
  13. tree_sitter_analyzer/cli/commands/summary_command.py +101 -101
  14. tree_sitter_analyzer/cli/commands/table_command.py +235 -235
  15. tree_sitter_analyzer/cli/info_commands.py +121 -121
  16. tree_sitter_analyzer/cli_main.py +297 -297
  17. tree_sitter_analyzer/core/__init__.py +15 -15
  18. tree_sitter_analyzer/core/analysis_engine.py +555 -555
  19. tree_sitter_analyzer/core/cache_service.py +320 -320
  20. tree_sitter_analyzer/core/engine.py +566 -566
  21. tree_sitter_analyzer/core/parser.py +293 -293
  22. tree_sitter_analyzer/encoding_utils.py +459 -459
  23. tree_sitter_analyzer/exceptions.py +406 -337
  24. tree_sitter_analyzer/file_handler.py +210 -210
  25. tree_sitter_analyzer/formatters/__init__.py +1 -1
  26. tree_sitter_analyzer/formatters/base_formatter.py +167 -167
  27. tree_sitter_analyzer/formatters/formatter_factory.py +78 -78
  28. tree_sitter_analyzer/interfaces/__init__.py +9 -9
  29. tree_sitter_analyzer/interfaces/cli.py +528 -528
  30. tree_sitter_analyzer/interfaces/cli_adapter.py +343 -343
  31. tree_sitter_analyzer/interfaces/mcp_adapter.py +206 -206
  32. tree_sitter_analyzer/interfaces/mcp_server.py +425 -405
  33. tree_sitter_analyzer/languages/__init__.py +10 -10
  34. tree_sitter_analyzer/languages/javascript_plugin.py +446 -446
  35. tree_sitter_analyzer/languages/python_plugin.py +755 -755
  36. tree_sitter_analyzer/mcp/__init__.py +31 -31
  37. tree_sitter_analyzer/mcp/resources/__init__.py +44 -44
  38. tree_sitter_analyzer/mcp/resources/code_file_resource.py +209 -209
  39. tree_sitter_analyzer/mcp/server.py +346 -333
  40. tree_sitter_analyzer/mcp/tools/__init__.py +30 -30
  41. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +654 -654
  42. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +247 -247
  43. tree_sitter_analyzer/mcp/tools/base_tool.py +54 -54
  44. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +300 -300
  45. tree_sitter_analyzer/mcp/tools/table_format_tool.py +362 -362
  46. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +543 -543
  47. tree_sitter_analyzer/mcp/utils/__init__.py +107 -107
  48. tree_sitter_analyzer/mcp/utils/error_handler.py +549 -549
  49. tree_sitter_analyzer/output_manager.py +253 -253
  50. tree_sitter_analyzer/plugins/__init__.py +280 -280
  51. tree_sitter_analyzer/plugins/base.py +529 -529
  52. tree_sitter_analyzer/plugins/manager.py +379 -379
  53. tree_sitter_analyzer/queries/__init__.py +26 -26
  54. tree_sitter_analyzer/queries/java.py +391 -391
  55. tree_sitter_analyzer/queries/javascript.py +148 -148
  56. tree_sitter_analyzer/queries/python.py +285 -285
  57. tree_sitter_analyzer/queries/typescript.py +229 -229
  58. tree_sitter_analyzer/query_loader.py +257 -257
  59. tree_sitter_analyzer/security/__init__.py +22 -0
  60. tree_sitter_analyzer/security/boundary_manager.py +237 -0
  61. tree_sitter_analyzer/security/regex_checker.py +292 -0
  62. tree_sitter_analyzer/security/validator.py +224 -0
  63. tree_sitter_analyzer/table_formatter.py +652 -589
  64. tree_sitter_analyzer/utils.py +277 -277
  65. {tree_sitter_analyzer-0.7.0.dist-info → tree_sitter_analyzer-0.8.0.dist-info}/METADATA +4 -1
  66. tree_sitter_analyzer-0.8.0.dist-info/RECORD +76 -0
  67. tree_sitter_analyzer-0.7.0.dist-info/RECORD +0 -72
  68. {tree_sitter_analyzer-0.7.0.dist-info → tree_sitter_analyzer-0.8.0.dist-info}/WHEEL +0 -0
  69. {tree_sitter_analyzer-0.7.0.dist-info → tree_sitter_analyzer-0.8.0.dist-info}/entry_points.txt +0 -0
@@ -1,39 +1,39 @@
1
- #!/usr/bin/env python3
2
- """
3
- CLI Package
4
-
5
- Command-line interface components using the Command Pattern.
6
- """
7
-
8
- from .info_commands import (
9
- DescribeQueryCommand,
10
- InfoCommand,
11
- ListQueriesCommand,
12
- ShowExtensionsCommand,
13
- ShowLanguagesCommand,
14
- )
15
-
16
- # Modern framework imports
17
- try:
18
- from ..cli_main import main
19
- from ..core.analysis_engine import get_analysis_engine
20
- from ..query_loader import QueryLoader
21
-
22
- query_loader = QueryLoader()
23
- except ImportError:
24
- # Minimal fallback for import safety
25
- get_analysis_engine = None # type: ignore
26
- main = None # type: ignore
27
- query_loader = None # type: ignore
28
-
29
- __all__ = [
30
- "InfoCommand",
31
- "ListQueriesCommand",
32
- "DescribeQueryCommand",
33
- "ShowLanguagesCommand",
34
- "ShowExtensionsCommand",
35
- # Core framework exports
36
- "query_loader",
37
- "get_analysis_engine",
38
- "main",
39
- ]
1
+ #!/usr/bin/env python3
2
+ """
3
+ CLI Package
4
+
5
+ Command-line interface components using the Command Pattern.
6
+ """
7
+
8
+ from .info_commands import (
9
+ DescribeQueryCommand,
10
+ InfoCommand,
11
+ ListQueriesCommand,
12
+ ShowExtensionsCommand,
13
+ ShowLanguagesCommand,
14
+ )
15
+
16
+ # Modern framework imports
17
+ try:
18
+ from ..cli_main import main
19
+ from ..core.analysis_engine import get_analysis_engine
20
+ from ..query_loader import QueryLoader
21
+
22
+ query_loader = QueryLoader()
23
+ except ImportError:
24
+ # Minimal fallback for import safety
25
+ get_analysis_engine = None # type: ignore
26
+ main = None # type: ignore
27
+ query_loader = None # type: ignore
28
+
29
+ __all__ = [
30
+ "InfoCommand",
31
+ "ListQueriesCommand",
32
+ "DescribeQueryCommand",
33
+ "ShowLanguagesCommand",
34
+ "ShowExtensionsCommand",
35
+ # Core framework exports
36
+ "query_loader",
37
+ "get_analysis_engine",
38
+ "main",
39
+ ]
@@ -1,12 +1,12 @@
1
- #!/usr/bin/env python3
2
- """
3
- CLI Module Entry Point
4
-
5
- This module allows the CLI to be executed as a module with:
6
- python -m tree_sitter_analyzer.cli
7
- """
8
-
9
- from ..cli_main import main
10
-
11
- if __name__ == "__main__":
12
- main()
1
+ #!/usr/bin/env python3
2
+ """
3
+ CLI Module Entry Point
4
+
5
+ This module allows the CLI to be executed as a module with:
6
+ python -m tree_sitter_analyzer.cli
7
+ """
8
+
9
+ from ..cli_main import main
10
+
11
+ if __name__ == "__main__":
12
+ main()
@@ -1,26 +1,26 @@
1
- #!/usr/bin/env python3
2
- """
3
- CLI Commands Package
4
-
5
- This package contains all command implementations for the CLI interface.
6
- """
7
-
8
- from .advanced_command import AdvancedCommand
9
- from .base_command import BaseCommand
10
- from .default_command import DefaultCommand
11
- from .partial_read_command import PartialReadCommand
12
- from .query_command import QueryCommand
13
- from .structure_command import StructureCommand
14
- from .summary_command import SummaryCommand
15
- from .table_command import TableCommand
16
-
17
- __all__ = [
18
- "BaseCommand",
19
- "AdvancedCommand",
20
- "DefaultCommand",
21
- "PartialReadCommand",
22
- "QueryCommand",
23
- "StructureCommand",
24
- "SummaryCommand",
25
- "TableCommand",
26
- ]
1
+ #!/usr/bin/env python3
2
+ """
3
+ CLI Commands Package
4
+
5
+ This package contains all command implementations for the CLI interface.
6
+ """
7
+
8
+ from .advanced_command import AdvancedCommand
9
+ from .base_command import BaseCommand
10
+ from .default_command import DefaultCommand
11
+ from .partial_read_command import PartialReadCommand
12
+ from .query_command import QueryCommand
13
+ from .structure_command import StructureCommand
14
+ from .summary_command import SummaryCommand
15
+ from .table_command import TableCommand
16
+
17
+ __all__ = [
18
+ "BaseCommand",
19
+ "AdvancedCommand",
20
+ "DefaultCommand",
21
+ "PartialReadCommand",
22
+ "QueryCommand",
23
+ "StructureCommand",
24
+ "SummaryCommand",
25
+ "TableCommand",
26
+ ]
@@ -1,88 +1,88 @@
1
- #!/usr/bin/env python3
2
- """
3
- Advanced Command
4
-
5
- Handles advanced analysis functionality.
6
- """
7
-
8
- from typing import TYPE_CHECKING
9
-
10
- from ...output_manager import output_data, output_json, output_section
11
- from .base_command import BaseCommand
12
-
13
- if TYPE_CHECKING:
14
- from ...models import AnalysisResult
15
-
16
-
17
- class AdvancedCommand(BaseCommand):
18
- """Command for advanced analysis."""
19
-
20
- async def execute_async(self, language: str) -> int:
21
- analysis_result = await self.analyze_file(language)
22
- if not analysis_result:
23
- return 1
24
-
25
- if hasattr(self.args, "statistics") and self.args.statistics:
26
- self._output_statistics(analysis_result)
27
- else:
28
- self._output_full_analysis(analysis_result)
29
-
30
- return 0
31
-
32
- def _output_statistics(self, analysis_result: "AnalysisResult") -> None:
33
- """Output statistics only."""
34
- stats = {
35
- "line_count": analysis_result.line_count,
36
- "element_count": len(analysis_result.elements),
37
- "node_count": analysis_result.node_count,
38
- "language": analysis_result.language,
39
- }
40
- output_section("Statistics")
41
- if self.args.output_format == "json":
42
- output_json(stats)
43
- else:
44
- for key, value in stats.items():
45
- output_data(f"{key}: {value}")
46
-
47
- def _output_full_analysis(self, analysis_result: "AnalysisResult") -> None:
48
- """Output full analysis results."""
49
- output_section("Advanced Analysis Results")
50
- if self.args.output_format == "json":
51
- result_dict = {
52
- "file_path": analysis_result.file_path,
53
- "language": analysis_result.language,
54
- "line_count": analysis_result.line_count,
55
- "element_count": len(analysis_result.elements),
56
- "node_count": analysis_result.node_count,
57
- "elements": [
58
- {
59
- "name": getattr(element, "name", str(element)),
60
- "type": getattr(element, "__class__", type(element)).__name__,
61
- "start_line": getattr(element, "start_line", 0),
62
- "end_line": getattr(element, "end_line", 0),
63
- }
64
- for element in analysis_result.elements
65
- ],
66
- "success": analysis_result.success,
67
- "analysis_time": analysis_result.analysis_time,
68
- }
69
- output_json(result_dict)
70
- else:
71
- self._output_text_analysis(analysis_result)
72
-
73
- def _output_text_analysis(self, analysis_result: "AnalysisResult") -> None:
74
- """Output analysis in text format."""
75
- output_data(f"File: {analysis_result.file_path}")
76
- output_data("Package: (default)")
77
- output_data(f"Lines: {analysis_result.line_count}")
78
-
79
- element_counts: dict[str, int] = {}
80
- for element in analysis_result.elements:
81
- element_type = getattr(element, "__class__", type(element)).__name__
82
- element_counts[element_type] = element_counts.get(element_type, 0) + 1
83
-
84
- output_data(f"Classes: {element_counts.get('Class', 0)}")
85
- output_data(f"Methods: {element_counts.get('Function', 0)}")
86
- output_data(f"Fields: {element_counts.get('Variable', 0)}")
87
- output_data(f"Imports: {element_counts.get('Import', 0)}")
88
- output_data("Annotations: 0")
1
+ #!/usr/bin/env python3
2
+ """
3
+ Advanced Command
4
+
5
+ Handles advanced analysis functionality.
6
+ """
7
+
8
+ from typing import TYPE_CHECKING
9
+
10
+ from ...output_manager import output_data, output_json, output_section
11
+ from .base_command import BaseCommand
12
+
13
+ if TYPE_CHECKING:
14
+ from ...models import AnalysisResult
15
+
16
+
17
+ class AdvancedCommand(BaseCommand):
18
+ """Command for advanced analysis."""
19
+
20
+ async def execute_async(self, language: str) -> int:
21
+ analysis_result = await self.analyze_file(language)
22
+ if not analysis_result:
23
+ return 1
24
+
25
+ if hasattr(self.args, "statistics") and self.args.statistics:
26
+ self._output_statistics(analysis_result)
27
+ else:
28
+ self._output_full_analysis(analysis_result)
29
+
30
+ return 0
31
+
32
+ def _output_statistics(self, analysis_result: "AnalysisResult") -> None:
33
+ """Output statistics only."""
34
+ stats = {
35
+ "line_count": analysis_result.line_count,
36
+ "element_count": len(analysis_result.elements),
37
+ "node_count": analysis_result.node_count,
38
+ "language": analysis_result.language,
39
+ }
40
+ output_section("Statistics")
41
+ if self.args.output_format == "json":
42
+ output_json(stats)
43
+ else:
44
+ for key, value in stats.items():
45
+ output_data(f"{key}: {value}")
46
+
47
+ def _output_full_analysis(self, analysis_result: "AnalysisResult") -> None:
48
+ """Output full analysis results."""
49
+ output_section("Advanced Analysis Results")
50
+ if self.args.output_format == "json":
51
+ result_dict = {
52
+ "file_path": analysis_result.file_path,
53
+ "language": analysis_result.language,
54
+ "line_count": analysis_result.line_count,
55
+ "element_count": len(analysis_result.elements),
56
+ "node_count": analysis_result.node_count,
57
+ "elements": [
58
+ {
59
+ "name": getattr(element, "name", str(element)),
60
+ "type": getattr(element, "__class__", type(element)).__name__,
61
+ "start_line": getattr(element, "start_line", 0),
62
+ "end_line": getattr(element, "end_line", 0),
63
+ }
64
+ for element in analysis_result.elements
65
+ ],
66
+ "success": analysis_result.success,
67
+ "analysis_time": analysis_result.analysis_time,
68
+ }
69
+ output_json(result_dict)
70
+ else:
71
+ self._output_text_analysis(analysis_result)
72
+
73
+ def _output_text_analysis(self, analysis_result: "AnalysisResult") -> None:
74
+ """Output analysis in text format."""
75
+ output_data(f"File: {analysis_result.file_path}")
76
+ output_data("Package: (default)")
77
+ output_data(f"Lines: {analysis_result.line_count}")
78
+
79
+ element_counts: dict[str, int] = {}
80
+ for element in analysis_result.elements:
81
+ element_type = getattr(element, "__class__", type(element)).__name__
82
+ element_counts[element_type] = element_counts.get(element_type, 0) + 1
83
+
84
+ output_data(f"Classes: {element_counts.get('Class', 0)}")
85
+ output_data(f"Methods: {element_counts.get('Function', 0)}")
86
+ output_data(f"Fields: {element_counts.get('Variable', 0)}")
87
+ output_data(f"Imports: {element_counts.get('Import', 0)}")
88
+ output_data("Annotations: 0")
@@ -1,160 +1,160 @@
1
- #!/usr/bin/env python3
2
- """
3
- Base Command Class
4
-
5
- Abstract base class for all CLI commands implementing the Command Pattern.
6
- """
7
-
8
- import asyncio
9
- from abc import ABC, abstractmethod
10
- from argparse import Namespace
11
- from typing import Optional
12
-
13
- from ...core.analysis_engine import AnalysisRequest, get_analysis_engine
14
- from ...file_handler import read_file_partial
15
- from ...language_detector import detect_language_from_file, is_language_supported
16
- from ...models import AnalysisResult
17
- from ...output_manager import output_error, output_info
18
-
19
-
20
- class BaseCommand(ABC):
21
- """
22
- Base class for all CLI commands.
23
-
24
- Implements common functionality like file validation, language detection,
25
- and analysis engine interaction.
26
- """
27
-
28
- def __init__(self, args: Namespace):
29
- """Initialize command with parsed arguments."""
30
- self.args = args
31
- self.analysis_engine = get_analysis_engine()
32
-
33
- def validate_file(self) -> bool:
34
- """Validate input file exists and is accessible."""
35
- if not hasattr(self.args, "file_path") or not self.args.file_path:
36
- output_error("ERROR: File path not specified.")
37
- return False
38
-
39
- import os
40
-
41
- if not os.path.exists(self.args.file_path):
42
- output_error(f"ERROR: File not found: {self.args.file_path}")
43
- return False
44
-
45
- return True
46
-
47
- def detect_language(self) -> str | None:
48
- """Detect or validate the target language."""
49
- if hasattr(self.args, "language") and self.args.language:
50
- target_language = self.args.language.lower()
51
- if (not hasattr(self.args, "table") or not self.args.table) and (
52
- not hasattr(self.args, "quiet") or not self.args.quiet
53
- ):
54
- output_info(f"INFO: Language explicitly specified: {target_language}")
55
- else:
56
- target_language = detect_language_from_file(self.args.file_path)
57
- if target_language == "unknown":
58
- output_error(
59
- f"ERROR: Could not determine language for file '{self.args.file_path}'."
60
- )
61
- return None
62
- else:
63
- if (not hasattr(self.args, "table") or not self.args.table) and (
64
- not hasattr(self.args, "quiet") or not self.args.quiet
65
- ):
66
- output_info(
67
- f"INFO: Language auto-detected from extension: {target_language}"
68
- )
69
-
70
- # Language support validation
71
- if not is_language_supported(target_language):
72
- if target_language != "java":
73
- if (not hasattr(self.args, "table") or not self.args.table) and (
74
- not hasattr(self.args, "quiet") or not self.args.quiet
75
- ):
76
- output_info(
77
- "INFO: Trying with Java analysis engine. May not work correctly."
78
- )
79
- target_language = "java" # Fallback
80
-
81
- return str(target_language) if target_language else None
82
-
83
- async def analyze_file(self, language: str) -> Optional["AnalysisResult"]:
84
- """Perform file analysis using the unified analysis engine."""
85
- try:
86
- # Handle partial read if enabled
87
- if hasattr(self.args, "partial_read") and self.args.partial_read:
88
- try:
89
- partial_content = read_file_partial(
90
- self.args.file_path,
91
- start_line=self.args.start_line,
92
- end_line=getattr(self.args, "end_line", None),
93
- start_column=getattr(self.args, "start_column", None),
94
- end_column=getattr(self.args, "end_column", None),
95
- )
96
- if partial_content is None:
97
- output_error("ERROR: Failed to read file partially")
98
- return None
99
- except Exception as e:
100
- output_error(f"ERROR: Failed to read file partially: {e}")
101
- return None
102
-
103
- request = AnalysisRequest(
104
- file_path=self.args.file_path,
105
- language=language,
106
- include_complexity=True,
107
- include_details=True,
108
- )
109
- analysis_result = await self.analysis_engine.analyze(request)
110
-
111
- if not analysis_result or not analysis_result.success:
112
- error_msg = (
113
- analysis_result.error_message
114
- if analysis_result
115
- else "Unknown error"
116
- )
117
- output_error(f"ERROR: Analysis failed: {error_msg}")
118
- return None
119
-
120
- return analysis_result
121
-
122
- except Exception as e:
123
- output_error(f"ERROR: An error occurred during analysis: {e}")
124
- return None
125
-
126
- def execute(self) -> int:
127
- """
128
- Execute the command.
129
-
130
- Returns:
131
- int: Exit code (0 for success, 1 for failure)
132
- """
133
- # Validate inputs
134
- if not self.validate_file():
135
- return 1
136
-
137
- # Detect language
138
- language = self.detect_language()
139
- if not language:
140
- return 1
141
-
142
- # Execute the specific command
143
- try:
144
- return asyncio.run(self.execute_async(language))
145
- except Exception as e:
146
- output_error(f"ERROR: An error occurred during command execution: {e}")
147
- return 1
148
-
149
- @abstractmethod
150
- async def execute_async(self, language: str) -> int:
151
- """
152
- Execute the command asynchronously.
153
-
154
- Args:
155
- language: Detected/specified target language
156
-
157
- Returns:
158
- int: Exit code (0 for success, 1 for failure)
159
- """
160
- pass
1
+ #!/usr/bin/env python3
2
+ """
3
+ Base Command Class
4
+
5
+ Abstract base class for all CLI commands implementing the Command Pattern.
6
+ """
7
+
8
+ import asyncio
9
+ from abc import ABC, abstractmethod
10
+ from argparse import Namespace
11
+ from typing import Optional
12
+
13
+ from ...core.analysis_engine import AnalysisRequest, get_analysis_engine
14
+ from ...file_handler import read_file_partial
15
+ from ...language_detector import detect_language_from_file, is_language_supported
16
+ from ...models import AnalysisResult
17
+ from ...output_manager import output_error, output_info
18
+
19
+
20
+ class BaseCommand(ABC):
21
+ """
22
+ Base class for all CLI commands.
23
+
24
+ Implements common functionality like file validation, language detection,
25
+ and analysis engine interaction.
26
+ """
27
+
28
+ def __init__(self, args: Namespace):
29
+ """Initialize command with parsed arguments."""
30
+ self.args = args
31
+ self.analysis_engine = get_analysis_engine()
32
+
33
+ def validate_file(self) -> bool:
34
+ """Validate input file exists and is accessible."""
35
+ if not hasattr(self.args, "file_path") or not self.args.file_path:
36
+ output_error("ERROR: File path not specified.")
37
+ return False
38
+
39
+ import os
40
+
41
+ if not os.path.exists(self.args.file_path):
42
+ output_error(f"ERROR: File not found: {self.args.file_path}")
43
+ return False
44
+
45
+ return True
46
+
47
+ def detect_language(self) -> str | None:
48
+ """Detect or validate the target language."""
49
+ if hasattr(self.args, "language") and self.args.language:
50
+ target_language = self.args.language.lower()
51
+ if (not hasattr(self.args, "table") or not self.args.table) and (
52
+ not hasattr(self.args, "quiet") or not self.args.quiet
53
+ ):
54
+ output_info(f"INFO: Language explicitly specified: {target_language}")
55
+ else:
56
+ target_language = detect_language_from_file(self.args.file_path)
57
+ if target_language == "unknown":
58
+ output_error(
59
+ f"ERROR: Could not determine language for file '{self.args.file_path}'."
60
+ )
61
+ return None
62
+ else:
63
+ if (not hasattr(self.args, "table") or not self.args.table) and (
64
+ not hasattr(self.args, "quiet") or not self.args.quiet
65
+ ):
66
+ output_info(
67
+ f"INFO: Language auto-detected from extension: {target_language}"
68
+ )
69
+
70
+ # Language support validation
71
+ if not is_language_supported(target_language):
72
+ if target_language != "java":
73
+ if (not hasattr(self.args, "table") or not self.args.table) and (
74
+ not hasattr(self.args, "quiet") or not self.args.quiet
75
+ ):
76
+ output_info(
77
+ "INFO: Trying with Java analysis engine. May not work correctly."
78
+ )
79
+ target_language = "java" # Fallback
80
+
81
+ return str(target_language) if target_language else None
82
+
83
+ async def analyze_file(self, language: str) -> Optional["AnalysisResult"]:
84
+ """Perform file analysis using the unified analysis engine."""
85
+ try:
86
+ # Handle partial read if enabled
87
+ if hasattr(self.args, "partial_read") and self.args.partial_read:
88
+ try:
89
+ partial_content = read_file_partial(
90
+ self.args.file_path,
91
+ start_line=self.args.start_line,
92
+ end_line=getattr(self.args, "end_line", None),
93
+ start_column=getattr(self.args, "start_column", None),
94
+ end_column=getattr(self.args, "end_column", None),
95
+ )
96
+ if partial_content is None:
97
+ output_error("ERROR: Failed to read file partially")
98
+ return None
99
+ except Exception as e:
100
+ output_error(f"ERROR: Failed to read file partially: {e}")
101
+ return None
102
+
103
+ request = AnalysisRequest(
104
+ file_path=self.args.file_path,
105
+ language=language,
106
+ include_complexity=True,
107
+ include_details=True,
108
+ )
109
+ analysis_result = await self.analysis_engine.analyze(request)
110
+
111
+ if not analysis_result or not analysis_result.success:
112
+ error_msg = (
113
+ analysis_result.error_message
114
+ if analysis_result
115
+ else "Unknown error"
116
+ )
117
+ output_error(f"ERROR: Analysis failed: {error_msg}")
118
+ return None
119
+
120
+ return analysis_result
121
+
122
+ except Exception as e:
123
+ output_error(f"ERROR: An error occurred during analysis: {e}")
124
+ return None
125
+
126
+ def execute(self) -> int:
127
+ """
128
+ Execute the command.
129
+
130
+ Returns:
131
+ int: Exit code (0 for success, 1 for failure)
132
+ """
133
+ # Validate inputs
134
+ if not self.validate_file():
135
+ return 1
136
+
137
+ # Detect language
138
+ language = self.detect_language()
139
+ if not language:
140
+ return 1
141
+
142
+ # Execute the specific command
143
+ try:
144
+ return asyncio.run(self.execute_async(language))
145
+ except Exception as e:
146
+ output_error(f"ERROR: An error occurred during command execution: {e}")
147
+ return 1
148
+
149
+ @abstractmethod
150
+ async def execute_async(self, language: str) -> int:
151
+ """
152
+ Execute the command asynchronously.
153
+
154
+ Args:
155
+ language: Detected/specified target language
156
+
157
+ Returns:
158
+ int: Exit code (0 for success, 1 for failure)
159
+ """
160
+ pass