tree-sitter-analyzer 0.3.0__py3-none-any.whl → 0.6.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 (63) hide show
  1. tree_sitter_analyzer/__init__.py +5 -6
  2. tree_sitter_analyzer/__main__.py +2 -2
  3. tree_sitter_analyzer/api.py +4 -2
  4. tree_sitter_analyzer/cli/__init__.py +3 -3
  5. tree_sitter_analyzer/cli/commands/advanced_command.py +1 -1
  6. tree_sitter_analyzer/cli/commands/base_command.py +1 -1
  7. tree_sitter_analyzer/cli/commands/default_command.py +1 -1
  8. tree_sitter_analyzer/cli/commands/partial_read_command.py +2 -2
  9. tree_sitter_analyzer/cli/commands/query_command.py +5 -5
  10. tree_sitter_analyzer/cli/commands/summary_command.py +2 -2
  11. tree_sitter_analyzer/cli/commands/table_command.py +14 -11
  12. tree_sitter_analyzer/cli/info_commands.py +14 -13
  13. tree_sitter_analyzer/cli_main.py +51 -31
  14. tree_sitter_analyzer/core/analysis_engine.py +54 -90
  15. tree_sitter_analyzer/core/cache_service.py +31 -31
  16. tree_sitter_analyzer/core/engine.py +6 -4
  17. tree_sitter_analyzer/core/parser.py +1 -1
  18. tree_sitter_analyzer/core/query.py +502 -494
  19. tree_sitter_analyzer/encoding_utils.py +3 -2
  20. tree_sitter_analyzer/exceptions.py +23 -23
  21. tree_sitter_analyzer/file_handler.py +7 -14
  22. tree_sitter_analyzer/formatters/base_formatter.py +18 -18
  23. tree_sitter_analyzer/formatters/formatter_factory.py +15 -15
  24. tree_sitter_analyzer/formatters/java_formatter.py +291 -287
  25. tree_sitter_analyzer/formatters/python_formatter.py +259 -255
  26. tree_sitter_analyzer/interfaces/cli.py +1 -1
  27. tree_sitter_analyzer/interfaces/cli_adapter.py +62 -41
  28. tree_sitter_analyzer/interfaces/mcp_adapter.py +43 -17
  29. tree_sitter_analyzer/interfaces/mcp_server.py +9 -9
  30. tree_sitter_analyzer/language_detector.py +398 -398
  31. tree_sitter_analyzer/language_loader.py +224 -224
  32. tree_sitter_analyzer/languages/java_plugin.py +1174 -1129
  33. tree_sitter_analyzer/{plugins → languages}/javascript_plugin.py +3 -3
  34. tree_sitter_analyzer/languages/python_plugin.py +26 -8
  35. tree_sitter_analyzer/mcp/resources/code_file_resource.py +0 -3
  36. tree_sitter_analyzer/mcp/resources/project_stats_resource.py +555 -560
  37. tree_sitter_analyzer/mcp/server.py +4 -4
  38. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +63 -30
  39. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +9 -4
  40. tree_sitter_analyzer/mcp/tools/table_format_tool.py +2 -2
  41. tree_sitter_analyzer/mcp/utils/__init__.py +10 -8
  42. tree_sitter_analyzer/models.py +470 -470
  43. tree_sitter_analyzer/output_manager.py +12 -20
  44. tree_sitter_analyzer/plugins/__init__.py +9 -62
  45. tree_sitter_analyzer/plugins/base.py +53 -1
  46. tree_sitter_analyzer/plugins/manager.py +29 -12
  47. tree_sitter_analyzer/queries/java.py +78 -78
  48. tree_sitter_analyzer/queries/javascript.py +7 -7
  49. tree_sitter_analyzer/queries/python.py +18 -18
  50. tree_sitter_analyzer/queries/typescript.py +12 -12
  51. tree_sitter_analyzer/query_loader.py +17 -14
  52. tree_sitter_analyzer/table_formatter.py +24 -19
  53. tree_sitter_analyzer/utils.py +7 -7
  54. {tree_sitter_analyzer-0.3.0.dist-info → tree_sitter_analyzer-0.6.0.dist-info}/METADATA +11 -11
  55. tree_sitter_analyzer-0.6.0.dist-info/RECORD +72 -0
  56. {tree_sitter_analyzer-0.3.0.dist-info → tree_sitter_analyzer-0.6.0.dist-info}/entry_points.txt +2 -1
  57. tree_sitter_analyzer/java_analyzer.py +0 -218
  58. tree_sitter_analyzer/plugins/java_plugin.py +0 -608
  59. tree_sitter_analyzer/plugins/plugin_loader.py +0 -85
  60. tree_sitter_analyzer/plugins/python_plugin.py +0 -606
  61. tree_sitter_analyzer/plugins/registry.py +0 -374
  62. tree_sitter_analyzer-0.3.0.dist-info/RECORD +0 -77
  63. {tree_sitter_analyzer-0.3.0.dist-info → tree_sitter_analyzer-0.6.0.dist-info}/WHEEL +0 -0
@@ -1,255 +1,259 @@
1
- #!/usr/bin/env python3
2
- """
3
- Python-specific table formatter.
4
- """
5
-
6
- from typing import Any
7
-
8
- from .base_formatter import BaseTableFormatter
9
-
10
-
11
- class PythonTableFormatter(BaseTableFormatter):
12
- """Python言語専用のテーブルフォーマッター"""
13
-
14
- def _format_full_table(self, data: dict[str, Any]) -> str:
15
- """Python用完全版テーブル形式"""
16
- lines = []
17
-
18
- # ヘッダー - Python用(複数クラス対応)
19
- classes = data.get("classes", [])
20
- if len(classes) > 1:
21
- # 複数クラスがある場合はファイル名を使用
22
- file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
23
- lines.append(f"# {file_name}")
24
- else:
25
- # 単一クラスの場合はクラス名を使用
26
- class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
27
- lines.append(f"# {class_name}")
28
- lines.append("")
29
-
30
- # Imports
31
- imports = data.get("imports", [])
32
- if imports:
33
- lines.append("## Imports")
34
- lines.append("```python")
35
- for imp in imports:
36
- lines.append(str(imp.get("statement", "")))
37
- lines.append("```")
38
- lines.append("")
39
-
40
- # Classes - Python用(複数クラス対応)
41
- if len(classes) > 1:
42
- lines.append("## Classes")
43
- lines.append("| Class | Type | Visibility | Lines | Methods | Fields |")
44
- lines.append("|-------|------|------------|-------|---------|--------|")
45
-
46
- for class_info in classes:
47
- name = str(class_info.get("name", "Unknown"))
48
- class_type = str(class_info.get("type", "class"))
49
- visibility = str(class_info.get("visibility", "public"))
50
- line_range = class_info.get("line_range", {})
51
- lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
52
-
53
- # このクラスのメソッド数とフィールド数を計算
54
- class_methods = [
55
- m
56
- for m in data.get("methods", [])
57
- if line_range.get("start", 0)
58
- <= m.get("line_range", {}).get("start", 0)
59
- <= line_range.get("end", 0)
60
- ]
61
- class_fields = [
62
- f
63
- for f in data.get("fields", [])
64
- if line_range.get("start", 0)
65
- <= f.get("line_range", {}).get("start", 0)
66
- <= line_range.get("end", 0)
67
- ]
68
-
69
- lines.append(
70
- f"| {name} | {class_type} | {visibility} | {lines_str} | {len(class_methods)} | {len(class_fields)} |"
71
- )
72
- else:
73
- # 単一クラスの場合
74
- lines.append("## Class Info")
75
- lines.append("| Property | Value |")
76
- lines.append("|----------|-------|")
77
-
78
- class_info = data.get("classes", [{}])[0] if data.get("classes") else {}
79
- stats = data.get("statistics") or {}
80
-
81
- lines.append("| Package | (default) |")
82
- lines.append(f"| Type | {str(class_info.get('type', 'class'))} |")
83
- lines.append(
84
- f"| Visibility | {str(class_info.get('visibility', 'public'))} |"
85
- )
86
- lines.append(
87
- f"| Lines | {class_info.get('line_range', {}).get('start', 0)}-{class_info.get('line_range', {}).get('end', 0)} |"
88
- )
89
- lines.append(f"| Total Methods | {stats.get('method_count', 0)} |")
90
- lines.append(f"| Total Fields | {stats.get('field_count', 0)} |")
91
-
92
- lines.append("")
93
-
94
- # Fields
95
- fields = data.get("fields", [])
96
- if fields:
97
- lines.append("## Fields")
98
- lines.append("| Name | Type | Vis | Modifiers | Line | Doc |")
99
- lines.append("|------|------|-----|-----------|------|-----|")
100
-
101
- for field in fields:
102
- name = str(field.get("name", ""))
103
- field_type = str(field.get("type", ""))
104
- visibility = self._convert_visibility(str(field.get("visibility", "")))
105
- modifiers = ",".join([str(m) for m in field.get("modifiers", [])])
106
- line = field.get("line_range", {}).get("start", 0)
107
- doc = str(field.get("javadoc", "")) or "-"
108
- doc = doc.replace("\n", " ").replace("|", "\\|")[:50]
109
-
110
- lines.append(
111
- f"| {name} | {field_type} | {visibility} | {modifiers} | {line} | {doc} |"
112
- )
113
- lines.append("")
114
-
115
- # Methods - Python用(コンストラクタ分離なし)
116
- methods = data.get("methods", [])
117
- if methods:
118
- lines.append("## Methods")
119
- lines.append("| Method | Signature | Vis | Lines | Cols | Cx | Doc |")
120
- lines.append("|--------|-----------|-----|-------|------|----|----|")
121
-
122
- for method in methods:
123
- lines.append(self._format_method_row(method))
124
- lines.append("")
125
-
126
- # 末尾の空行を削除
127
- while lines and lines[-1] == "":
128
- lines.pop()
129
-
130
- return "\n".join(lines)
131
-
132
- def _format_compact_table(self, data: dict[str, Any]) -> str:
133
- """Python用コンパクト版テーブル形式"""
134
- lines = []
135
-
136
- # ヘッダー
137
- classes = data.get("classes", [])
138
- if len(classes) > 1:
139
- file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
140
- lines.append(f"# {file_name}")
141
- else:
142
- class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
143
- lines.append(f"# {class_name}")
144
- lines.append("")
145
-
146
- # 基本情報
147
- stats = data.get("statistics") or {}
148
- lines.append("## Info")
149
- lines.append("| Property | Value |")
150
- lines.append("|----------|-------|")
151
- lines.append(f"| Classes | {len(classes)} |")
152
- lines.append(f"| Methods | {stats.get('method_count', 0)} |")
153
- lines.append(f"| Fields | {stats.get('field_count', 0)} |")
154
- lines.append("")
155
-
156
- # メソッド(簡略版)
157
- methods = data.get("methods", [])
158
- if methods:
159
- lines.append("## Methods")
160
- lines.append("| Method | Sig | V | L | Cx | Doc |")
161
- lines.append("|--------|-----|---|---|----|----|")
162
-
163
- for method in methods:
164
- name = str(method.get("name", ""))
165
- signature = self._create_compact_signature(method)
166
- visibility = self._convert_visibility(str(method.get("visibility", "")))
167
- line_range = method.get("line_range", {})
168
- lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
169
- complexity = method.get("complexity_score", 0)
170
- doc = self._clean_csv_text(
171
- self._extract_doc_summary(str(method.get("javadoc", "")))
172
- )
173
-
174
- lines.append(
175
- f"| {name} | {signature} | {visibility} | {lines_str} | {complexity} | {doc} |"
176
- )
177
- lines.append("")
178
-
179
- # 末尾の空行を削除
180
- while lines and lines[-1] == "":
181
- lines.pop()
182
-
183
- return "\n".join(lines)
184
-
185
- def _format_method_row(self, method: dict[str, Any]) -> str:
186
- """Python用メソッド行のフォーマット"""
187
- name = str(method.get("name", ""))
188
- signature = self._create_full_signature(method)
189
- visibility = self._convert_visibility(str(method.get("visibility", "")))
190
- line_range = method.get("line_range", {})
191
- lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
192
- cols_str = "5-6" # デフォルト値
193
- complexity = method.get("complexity_score", 0)
194
- doc = self._clean_csv_text(
195
- self._extract_doc_summary(str(method.get("javadoc", "")))
196
- )
197
-
198
- return f"| {name} | {signature} | {visibility} | {lines_str} | {cols_str} | {complexity} | {doc} |"
199
-
200
- def _create_compact_signature(self, method: dict[str, Any]) -> str:
201
- """Python用コンパクトなメソッドシグネチャを作成"""
202
- params = method.get("parameters", [])
203
- param_types = []
204
-
205
- for p in params:
206
- if isinstance(p, dict):
207
- param_types.append(self._shorten_type(p.get("type", "Any")))
208
- else:
209
- param_types.append("Any")
210
-
211
- params_str = ",".join(param_types)
212
- return_type = self._shorten_type(method.get("return_type", "Any"))
213
-
214
- return f"({params_str}):{return_type}"
215
-
216
- def _shorten_type(self, type_name: Any) -> str:
217
- """Python用型名を短縮"""
218
- if type_name is None:
219
- return "Any"
220
-
221
- if not isinstance(type_name, str):
222
- type_name = str(type_name)
223
-
224
- type_mapping = {
225
- "str": "s",
226
- "int": "i",
227
- "float": "f",
228
- "bool": "b",
229
- "None": "N",
230
- "Any": "A",
231
- "List": "L",
232
- "Dict": "D",
233
- "Optional": "O",
234
- "Union": "U",
235
- }
236
-
237
- # List[str] -> L[s]
238
- if "List[" in type_name:
239
- return (
240
- type_name.replace("List[", "L[").replace("str", "s").replace("int", "i")
241
- )
242
-
243
- # Dict[str, int] -> D[s,i]
244
- if "Dict[" in type_name:
245
- return (
246
- type_name.replace("Dict[", "D[").replace("str", "s").replace("int", "i")
247
- )
248
-
249
- # Optional[str] -> O[s]
250
- if "Optional[" in type_name:
251
- return type_name.replace("Optional[", "O[").replace("str", "s")
252
-
253
- return type_mapping.get(
254
- type_name, type_name[:3] if len(type_name) > 3 else type_name
255
- )
1
+ #!/usr/bin/env python3
2
+ """
3
+ Python-specific table formatter.
4
+ """
5
+
6
+ from typing import Any
7
+
8
+ from .base_formatter import BaseTableFormatter
9
+
10
+
11
+ class PythonTableFormatter(BaseTableFormatter):
12
+ """Python言語専用のテーブルフォーマッター"""
13
+
14
+ def _format_full_table(self, data: dict[str, Any]) -> str:
15
+ """Python用完全版テーブル形式"""
16
+ lines = []
17
+
18
+ # ヘッダー - Python用(複数クラス対応)
19
+ classes = data.get("classes", [])
20
+ if len(classes) > 1:
21
+ # 複数クラスがある場合はファイル名を使用
22
+ file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
23
+ lines.append(f"# {file_name}")
24
+ else:
25
+ # 単一クラスの場合はクラス名を使用
26
+ class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
27
+ lines.append(f"# {class_name}")
28
+ lines.append("")
29
+
30
+ # Imports
31
+ imports = data.get("imports", [])
32
+ if imports:
33
+ lines.append("## Imports")
34
+ lines.append("```python")
35
+ for imp in imports:
36
+ lines.append(str(imp.get("statement", "")))
37
+ lines.append("```")
38
+ lines.append("")
39
+
40
+ # Classes - Python用(複数クラス対応)
41
+ if len(classes) > 1:
42
+ lines.append("## Classes")
43
+ lines.append("| Class | Type | Visibility | Lines | Methods | Fields |")
44
+ lines.append("|-------|------|------------|-------|---------|--------|")
45
+
46
+ for class_info in classes:
47
+ name = str(class_info.get("name", "Unknown"))
48
+ class_type = str(class_info.get("type", "class"))
49
+ visibility = str(class_info.get("visibility", "public"))
50
+ line_range = class_info.get("line_range", {})
51
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
52
+
53
+ # このクラスのメソッド数とフィールド数を計算
54
+ class_methods = [
55
+ m
56
+ for m in data.get("methods", [])
57
+ if line_range.get("start", 0)
58
+ <= m.get("line_range", {}).get("start", 0)
59
+ <= line_range.get("end", 0)
60
+ ]
61
+ class_fields = [
62
+ f
63
+ for f in data.get("fields", [])
64
+ if line_range.get("start", 0)
65
+ <= f.get("line_range", {}).get("start", 0)
66
+ <= line_range.get("end", 0)
67
+ ]
68
+
69
+ lines.append(
70
+ f"| {name} | {class_type} | {visibility} | {lines_str} | {len(class_methods)} | {len(class_fields)} |"
71
+ )
72
+ else:
73
+ # 単一クラスの場合
74
+ lines.append("## Class Info")
75
+ lines.append("| Property | Value |")
76
+ lines.append("|----------|-------|")
77
+
78
+ class_info = data.get("classes", [{}])[0] if data.get("classes") else {}
79
+ stats = data.get("statistics") or {}
80
+
81
+ lines.append("| Package | (default) |")
82
+ lines.append(f"| Type | {str(class_info.get('type', 'class'))} |")
83
+ lines.append(
84
+ f"| Visibility | {str(class_info.get('visibility', 'public'))} |"
85
+ )
86
+ lines.append(
87
+ f"| Lines | {class_info.get('line_range', {}).get('start', 0)}-{class_info.get('line_range', {}).get('end', 0)} |"
88
+ )
89
+ lines.append(f"| Total Methods | {stats.get('method_count', 0)} |")
90
+ lines.append(f"| Total Fields | {stats.get('field_count', 0)} |")
91
+
92
+ lines.append("")
93
+
94
+ # Fields
95
+ fields = data.get("fields", [])
96
+ if fields:
97
+ lines.append("## Fields")
98
+ lines.append("| Name | Type | Vis | Modifiers | Line | Doc |")
99
+ lines.append("|------|------|-----|-----------|------|-----|")
100
+
101
+ for field in fields:
102
+ name = str(field.get("name", ""))
103
+ field_type = str(field.get("type", ""))
104
+ visibility = self._convert_visibility(str(field.get("visibility", "")))
105
+ modifiers = ",".join([str(m) for m in field.get("modifiers", [])])
106
+ line = field.get("line_range", {}).get("start", 0)
107
+ doc = str(field.get("javadoc", "")) or "-"
108
+ doc = doc.replace("\n", " ").replace("|", "\\|")[:50]
109
+
110
+ lines.append(
111
+ f"| {name} | {field_type} | {visibility} | {modifiers} | {line} | {doc} |"
112
+ )
113
+ lines.append("")
114
+
115
+ # Methods - Python用(コンストラクタ分離なし)
116
+ methods = data.get("methods", [])
117
+ if methods:
118
+ lines.append("## Methods")
119
+ lines.append("| Method | Signature | Vis | Lines | Cols | Cx | Doc |")
120
+ lines.append("|--------|-----------|-----|-------|------|----|----|")
121
+
122
+ for method in methods:
123
+ lines.append(self._format_method_row(method))
124
+ lines.append("")
125
+
126
+ # 末尾の空行を削除
127
+ while lines and lines[-1] == "":
128
+ lines.pop()
129
+
130
+ return "\n".join(lines)
131
+
132
+ def _format_compact_table(self, data: dict[str, Any]) -> str:
133
+ """Python用コンパクト版テーブル形式"""
134
+ lines = []
135
+
136
+ # ヘッダー
137
+ classes = data.get("classes", [])
138
+ if len(classes) > 1:
139
+ file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
140
+ lines.append(f"# {file_name}")
141
+ else:
142
+ class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
143
+ lines.append(f"# {class_name}")
144
+ lines.append("")
145
+
146
+ # 基本情報
147
+ stats = data.get("statistics") or {}
148
+ lines.append("## Info")
149
+ lines.append("| Property | Value |")
150
+ lines.append("|----------|-------|")
151
+ lines.append(f"| Classes | {len(classes)} |")
152
+ lines.append(f"| Methods | {stats.get('method_count', 0)} |")
153
+ lines.append(f"| Fields | {stats.get('field_count', 0)} |")
154
+ lines.append("")
155
+
156
+ # メソッド(簡略版)
157
+ methods = data.get("methods", [])
158
+ if methods:
159
+ lines.append("## Methods")
160
+ lines.append("| Method | Sig | V | L | Cx | Doc |")
161
+ lines.append("|--------|-----|---|---|----|----|")
162
+
163
+ for method in methods:
164
+ name = str(method.get("name", ""))
165
+ signature = self._create_compact_signature(method)
166
+ visibility = self._convert_visibility(str(method.get("visibility", "")))
167
+ line_range = method.get("line_range", {})
168
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
169
+ complexity = method.get("complexity_score", 0)
170
+ doc = self._clean_csv_text(
171
+ self._extract_doc_summary(str(method.get("javadoc", "")))
172
+ )
173
+
174
+ lines.append(
175
+ f"| {name} | {signature} | {visibility} | {lines_str} | {complexity} | {doc} |"
176
+ )
177
+ lines.append("")
178
+
179
+ # 末尾の空行を削除
180
+ while lines and lines[-1] == "":
181
+ lines.pop()
182
+
183
+ return "\n".join(lines)
184
+
185
+ def _format_method_row(self, method: dict[str, Any]) -> str:
186
+ """Python用メソッド行のフォーマット"""
187
+ name = str(method.get("name", ""))
188
+ signature = self._create_full_signature(method)
189
+ visibility = self._convert_visibility(str(method.get("visibility", "")))
190
+ line_range = method.get("line_range", {})
191
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
192
+ cols_str = "5-6" # デフォルト値
193
+ complexity = method.get("complexity_score", 0)
194
+ doc = self._clean_csv_text(
195
+ self._extract_doc_summary(str(method.get("javadoc", "")))
196
+ )
197
+
198
+ return f"| {name} | {signature} | {visibility} | {lines_str} | {cols_str} | {complexity} | {doc} |"
199
+
200
+ def _create_compact_signature(self, method: dict[str, Any]) -> str:
201
+ """Python用コンパクトなメソッドシグネチャを作成"""
202
+ params = method.get("parameters", [])
203
+ param_types = []
204
+
205
+ for p in params:
206
+ if isinstance(p, dict):
207
+ param_types.append(self._shorten_type(p.get("type", "Any")))
208
+ else:
209
+ param_types.append("Any")
210
+
211
+ params_str = ",".join(param_types)
212
+ return_type = self._shorten_type(method.get("return_type", "Any"))
213
+
214
+ return f"({params_str}):{return_type}"
215
+
216
+ def _shorten_type(self, type_name: Any) -> str:
217
+ """Python用型名を短縮"""
218
+ if type_name is None:
219
+ return "Any"
220
+
221
+ if not isinstance(type_name, str):
222
+ type_name = str(type_name)
223
+
224
+ type_mapping = {
225
+ "str": "s",
226
+ "int": "i",
227
+ "float": "f",
228
+ "bool": "b",
229
+ "None": "N",
230
+ "Any": "A",
231
+ "List": "L",
232
+ "Dict": "D",
233
+ "Optional": "O",
234
+ "Union": "U",
235
+ }
236
+
237
+ # List[str] -> L[s]
238
+ if "List[" in type_name:
239
+ result = (
240
+ type_name.replace("List[", "L[").replace("str", "s").replace("int", "i")
241
+ )
242
+ return str(result)
243
+
244
+ # Dict[str, int] -> D[s,i]
245
+ if "Dict[" in type_name:
246
+ result = (
247
+ type_name.replace("Dict[", "D[").replace("str", "s").replace("int", "i")
248
+ )
249
+ return str(result)
250
+
251
+ # Optional[str] -> O[s]
252
+ if "Optional[" in type_name:
253
+ result = type_name.replace("Optional[", "O[").replace("str", "s")
254
+ return str(result)
255
+
256
+ result = type_mapping.get(
257
+ type_name, type_name[:3] if len(type_name) > 3 else type_name
258
+ )
259
+ return str(result)
@@ -407,7 +407,7 @@ def format_analysis_output(result: dict[str, Any], output_format: str) -> None:
407
407
  elements = result.get("elements", [])
408
408
  if elements:
409
409
  print(f"\nCode Elements: {len(elements)} found")
410
- element_types = {}
410
+ element_types: dict[str, int] = {}
411
411
  for element in elements:
412
412
  elem_type = element.get("type", "unknown")
413
413
  element_types[elem_type] = element_types.get(elem_type, 0) + 1