tree-sitter-analyzer 0.1.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.
- tree_sitter_analyzer/__init__.py +121 -0
- tree_sitter_analyzer/__main__.py +12 -0
- tree_sitter_analyzer/api.py +539 -0
- tree_sitter_analyzer/cli/__init__.py +39 -0
- tree_sitter_analyzer/cli/__main__.py +13 -0
- tree_sitter_analyzer/cli/commands/__init__.py +27 -0
- tree_sitter_analyzer/cli/commands/advanced_command.py +88 -0
- tree_sitter_analyzer/cli/commands/base_command.py +155 -0
- tree_sitter_analyzer/cli/commands/default_command.py +19 -0
- tree_sitter_analyzer/cli/commands/partial_read_command.py +133 -0
- tree_sitter_analyzer/cli/commands/query_command.py +82 -0
- tree_sitter_analyzer/cli/commands/structure_command.py +121 -0
- tree_sitter_analyzer/cli/commands/summary_command.py +93 -0
- tree_sitter_analyzer/cli/commands/table_command.py +233 -0
- tree_sitter_analyzer/cli/info_commands.py +121 -0
- tree_sitter_analyzer/cli_main.py +276 -0
- tree_sitter_analyzer/core/__init__.py +20 -0
- tree_sitter_analyzer/core/analysis_engine.py +574 -0
- tree_sitter_analyzer/core/cache_service.py +330 -0
- tree_sitter_analyzer/core/engine.py +560 -0
- tree_sitter_analyzer/core/parser.py +288 -0
- tree_sitter_analyzer/core/query.py +502 -0
- tree_sitter_analyzer/encoding_utils.py +460 -0
- tree_sitter_analyzer/exceptions.py +340 -0
- tree_sitter_analyzer/file_handler.py +222 -0
- tree_sitter_analyzer/formatters/__init__.py +1 -0
- tree_sitter_analyzer/formatters/base_formatter.py +168 -0
- tree_sitter_analyzer/formatters/formatter_factory.py +74 -0
- tree_sitter_analyzer/formatters/java_formatter.py +270 -0
- tree_sitter_analyzer/formatters/python_formatter.py +235 -0
- tree_sitter_analyzer/interfaces/__init__.py +10 -0
- tree_sitter_analyzer/interfaces/cli.py +557 -0
- tree_sitter_analyzer/interfaces/cli_adapter.py +319 -0
- tree_sitter_analyzer/interfaces/mcp_adapter.py +170 -0
- tree_sitter_analyzer/interfaces/mcp_server.py +416 -0
- tree_sitter_analyzer/java_analyzer.py +219 -0
- tree_sitter_analyzer/language_detector.py +400 -0
- tree_sitter_analyzer/language_loader.py +228 -0
- tree_sitter_analyzer/languages/__init__.py +11 -0
- tree_sitter_analyzer/languages/java_plugin.py +1113 -0
- tree_sitter_analyzer/languages/python_plugin.py +712 -0
- tree_sitter_analyzer/mcp/__init__.py +32 -0
- tree_sitter_analyzer/mcp/resources/__init__.py +47 -0
- tree_sitter_analyzer/mcp/resources/code_file_resource.py +213 -0
- tree_sitter_analyzer/mcp/resources/project_stats_resource.py +550 -0
- tree_sitter_analyzer/mcp/server.py +319 -0
- tree_sitter_analyzer/mcp/tools/__init__.py +36 -0
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +558 -0
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +245 -0
- tree_sitter_analyzer/mcp/tools/base_tool.py +55 -0
- tree_sitter_analyzer/mcp/tools/get_positions_tool.py +448 -0
- tree_sitter_analyzer/mcp/tools/read_partial_tool.py +302 -0
- tree_sitter_analyzer/mcp/tools/table_format_tool.py +359 -0
- tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +476 -0
- tree_sitter_analyzer/mcp/utils/__init__.py +106 -0
- tree_sitter_analyzer/mcp/utils/error_handler.py +549 -0
- tree_sitter_analyzer/models.py +481 -0
- tree_sitter_analyzer/output_manager.py +264 -0
- tree_sitter_analyzer/plugins/__init__.py +334 -0
- tree_sitter_analyzer/plugins/base.py +446 -0
- tree_sitter_analyzer/plugins/java_plugin.py +625 -0
- tree_sitter_analyzer/plugins/javascript_plugin.py +439 -0
- tree_sitter_analyzer/plugins/manager.py +355 -0
- tree_sitter_analyzer/plugins/plugin_loader.py +83 -0
- tree_sitter_analyzer/plugins/python_plugin.py +598 -0
- tree_sitter_analyzer/plugins/registry.py +366 -0
- tree_sitter_analyzer/queries/__init__.py +27 -0
- tree_sitter_analyzer/queries/java.py +394 -0
- tree_sitter_analyzer/queries/javascript.py +149 -0
- tree_sitter_analyzer/queries/python.py +286 -0
- tree_sitter_analyzer/queries/typescript.py +230 -0
- tree_sitter_analyzer/query_loader.py +260 -0
- tree_sitter_analyzer/table_formatter.py +448 -0
- tree_sitter_analyzer/utils.py +201 -0
- tree_sitter_analyzer-0.1.0.dist-info/METADATA +581 -0
- tree_sitter_analyzer-0.1.0.dist-info/RECORD +78 -0
- tree_sitter_analyzer-0.1.0.dist-info/WHEEL +4 -0
- tree_sitter_analyzer-0.1.0.dist-info/entry_points.txt +8 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Base formatter for language-specific table formatting.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import csv
|
|
8
|
+
import io
|
|
9
|
+
import os
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from typing import Any, Dict, List
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BaseTableFormatter(ABC):
|
|
15
|
+
"""Base class for language-specific table formatters"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, format_type: str = "full"):
|
|
18
|
+
self.format_type = format_type
|
|
19
|
+
|
|
20
|
+
def _get_platform_newline(self) -> str:
|
|
21
|
+
"""プラットフォーム固有の改行コードを取得"""
|
|
22
|
+
return os.linesep
|
|
23
|
+
|
|
24
|
+
def _convert_to_platform_newlines(self, text: str) -> str:
|
|
25
|
+
"""通常の\nをプラットフォーム固有の改行コードに変換"""
|
|
26
|
+
if os.linesep != "\n":
|
|
27
|
+
return text.replace("\n", os.linesep)
|
|
28
|
+
return text
|
|
29
|
+
|
|
30
|
+
def format_structure(self, structure_data: Dict[str, Any]) -> str:
|
|
31
|
+
"""構造データをテーブル形式でフォーマット"""
|
|
32
|
+
if self.format_type == "full":
|
|
33
|
+
result = self._format_full_table(structure_data)
|
|
34
|
+
elif self.format_type == "compact":
|
|
35
|
+
result = self._format_compact_table(structure_data)
|
|
36
|
+
elif self.format_type == "csv":
|
|
37
|
+
result = self._format_csv(structure_data)
|
|
38
|
+
else:
|
|
39
|
+
raise ValueError(f"Unsupported format type: {self.format_type}")
|
|
40
|
+
|
|
41
|
+
# 最終的にプラットフォーム固有の改行コードに変換
|
|
42
|
+
if self.format_type == "csv":
|
|
43
|
+
return result
|
|
44
|
+
|
|
45
|
+
return self._convert_to_platform_newlines(result)
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def _format_full_table(self, data: Dict[str, Any]) -> str:
|
|
49
|
+
"""完全版テーブル形式(言語固有実装)"""
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
def _format_compact_table(self, data: Dict[str, Any]) -> str:
|
|
54
|
+
"""コンパクト版テーブル形式(言語固有実装)"""
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
def _format_csv(self, data: Dict[str, Any]) -> str:
|
|
58
|
+
"""CSV形式(共通実装)"""
|
|
59
|
+
output = io.StringIO()
|
|
60
|
+
writer = csv.writer(output, lineterminator="\n")
|
|
61
|
+
|
|
62
|
+
# ヘッダー
|
|
63
|
+
writer.writerow(
|
|
64
|
+
["Type", "Name", "Signature", "Visibility", "Lines", "Complexity", "Doc"]
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# フィールド
|
|
68
|
+
for field in data.get("fields", []):
|
|
69
|
+
writer.writerow(
|
|
70
|
+
[
|
|
71
|
+
"Field",
|
|
72
|
+
str(field.get("name", "")),
|
|
73
|
+
f"{str(field.get('name', ''))}:{str(field.get('type', ''))}",
|
|
74
|
+
str(field.get("visibility", "")),
|
|
75
|
+
f"{field.get('line_range', {}).get('start', 0)}-{field.get('line_range', {}).get('end', 0)}",
|
|
76
|
+
"",
|
|
77
|
+
self._clean_csv_text(
|
|
78
|
+
self._extract_doc_summary(str(field.get("javadoc", "")))
|
|
79
|
+
),
|
|
80
|
+
]
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# メソッド
|
|
84
|
+
for method in data.get("methods", []):
|
|
85
|
+
writer.writerow(
|
|
86
|
+
[
|
|
87
|
+
"Constructor" if method.get("is_constructor", False) else "Method",
|
|
88
|
+
str(method.get("name", "")),
|
|
89
|
+
self._clean_csv_text(self._create_full_signature(method)),
|
|
90
|
+
str(method.get("visibility", "")),
|
|
91
|
+
f"{method.get('line_range', {}).get('start', 0)}-{method.get('line_range', {}).get('end', 0)}",
|
|
92
|
+
method.get("complexity_score", 0),
|
|
93
|
+
self._clean_csv_text(
|
|
94
|
+
self._extract_doc_summary(str(method.get("javadoc", "")))
|
|
95
|
+
),
|
|
96
|
+
]
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
csv_content = output.getvalue()
|
|
100
|
+
csv_content = csv_content.replace("\r\n", "\n").replace("\r", "\n")
|
|
101
|
+
csv_content = csv_content.rstrip("\n")
|
|
102
|
+
output.close()
|
|
103
|
+
|
|
104
|
+
return csv_content
|
|
105
|
+
|
|
106
|
+
# 共通ヘルパーメソッド
|
|
107
|
+
def _create_full_signature(self, method: Dict[str, Any]) -> str:
|
|
108
|
+
"""完全なメソッドシグネチャを作成"""
|
|
109
|
+
params = method.get("parameters", [])
|
|
110
|
+
param_strs = []
|
|
111
|
+
for param in params:
|
|
112
|
+
if isinstance(param, dict):
|
|
113
|
+
param_type = str(param.get("type", "Object"))
|
|
114
|
+
param_name = str(param.get("name", "param"))
|
|
115
|
+
param_strs.append(f"{param_name}:{param_type}")
|
|
116
|
+
else:
|
|
117
|
+
param_strs.append(str(param))
|
|
118
|
+
|
|
119
|
+
params_str = ", ".join(param_strs)
|
|
120
|
+
return_type = str(method.get("return_type", "void"))
|
|
121
|
+
|
|
122
|
+
modifiers = []
|
|
123
|
+
if method.get("is_static", False):
|
|
124
|
+
modifiers.append("[static]")
|
|
125
|
+
|
|
126
|
+
modifier_str = " ".join(modifiers)
|
|
127
|
+
signature = f"({params_str}):{return_type}"
|
|
128
|
+
|
|
129
|
+
if modifier_str:
|
|
130
|
+
signature += f" {modifier_str}"
|
|
131
|
+
|
|
132
|
+
return signature
|
|
133
|
+
|
|
134
|
+
def _convert_visibility(self, visibility: str) -> str:
|
|
135
|
+
"""可視性を記号に変換"""
|
|
136
|
+
mapping = {"public": "+", "private": "-", "protected": "#", "package": "~"}
|
|
137
|
+
return mapping.get(visibility, visibility)
|
|
138
|
+
|
|
139
|
+
def _extract_doc_summary(self, javadoc: str) -> str:
|
|
140
|
+
"""ドキュメントから要約を抽出"""
|
|
141
|
+
if not javadoc:
|
|
142
|
+
return "-"
|
|
143
|
+
|
|
144
|
+
# コメント記号を除去
|
|
145
|
+
clean_doc = (
|
|
146
|
+
javadoc.replace("/**", "").replace("*/", "").replace("*", "").strip()
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# 最初の行を取得
|
|
150
|
+
lines = clean_doc.split("\n")
|
|
151
|
+
first_line = lines[0].strip()
|
|
152
|
+
|
|
153
|
+
# 長すぎる場合は切り詰め
|
|
154
|
+
if len(first_line) > 50:
|
|
155
|
+
first_line = first_line[:47] + "..."
|
|
156
|
+
|
|
157
|
+
return first_line.replace("|", "\\|").replace("\n", " ")
|
|
158
|
+
|
|
159
|
+
def _clean_csv_text(self, text: str) -> str:
|
|
160
|
+
"""CSV形式用のテキストクリーニング"""
|
|
161
|
+
if not text:
|
|
162
|
+
return ""
|
|
163
|
+
|
|
164
|
+
cleaned = text.replace("\r\n", " ").replace("\r", " ").replace("\n", " ")
|
|
165
|
+
cleaned = " ".join(cleaned.split())
|
|
166
|
+
cleaned = cleaned.replace('"', '""')
|
|
167
|
+
|
|
168
|
+
return cleaned
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Factory for creating language-specific table formatters.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, Type
|
|
8
|
+
from .base_formatter import BaseTableFormatter
|
|
9
|
+
from .java_formatter import JavaTableFormatter
|
|
10
|
+
from .python_formatter import PythonTableFormatter
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TableFormatterFactory:
|
|
14
|
+
"""言語固有のテーブルフォーマッターを作成するファクトリー"""
|
|
15
|
+
|
|
16
|
+
_formatters: Dict[str, Type[BaseTableFormatter]] = {
|
|
17
|
+
"java": JavaTableFormatter,
|
|
18
|
+
"python": PythonTableFormatter,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def create_formatter(cls, language: str, format_type: str = "full") -> BaseTableFormatter:
|
|
23
|
+
"""
|
|
24
|
+
指定された言語用のテーブルフォーマッターを作成
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
language: プログラミング言語名
|
|
28
|
+
format_type: フォーマットタイプ(full, compact, csv)
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
言語固有のテーブルフォーマッター
|
|
32
|
+
"""
|
|
33
|
+
formatter_class = cls._formatters.get(language.lower())
|
|
34
|
+
|
|
35
|
+
if formatter_class is None:
|
|
36
|
+
# デフォルトとしてJavaフォーマッターを使用
|
|
37
|
+
formatter_class = JavaTableFormatter
|
|
38
|
+
|
|
39
|
+
return formatter_class(format_type)
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def register_formatter(cls, language: str, formatter_class: Type[BaseTableFormatter]) -> None:
|
|
43
|
+
"""
|
|
44
|
+
新しい言語フォーマッターを登録
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
language: プログラミング言語名
|
|
48
|
+
formatter_class: フォーマッタークラス
|
|
49
|
+
"""
|
|
50
|
+
cls._formatters[language.lower()] = formatter_class
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def get_supported_languages(cls) -> list[str]:
|
|
54
|
+
"""
|
|
55
|
+
サポートされている言語一覧を取得
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
サポートされている言語のリスト
|
|
59
|
+
"""
|
|
60
|
+
return list(cls._formatters.keys())
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def create_table_formatter(format_type: str, language: str = "java") -> BaseTableFormatter:
|
|
64
|
+
"""
|
|
65
|
+
テーブルフォーマッターを作成(互換性のための関数)
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
format_type: フォーマットタイプ
|
|
69
|
+
language: プログラミング言語名
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
テーブルフォーマッター
|
|
73
|
+
"""
|
|
74
|
+
return TableFormatterFactory.create_formatter(language, format_type)
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Java-specific table formatter.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Dict, List
|
|
8
|
+
from .base_formatter import BaseTableFormatter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class JavaTableFormatter(BaseTableFormatter):
|
|
12
|
+
"""Java言語専用のテーブルフォーマッター"""
|
|
13
|
+
|
|
14
|
+
def _format_full_table(self, data: Dict[str, Any]) -> str:
|
|
15
|
+
"""Java用完全版テーブル形式"""
|
|
16
|
+
lines = []
|
|
17
|
+
|
|
18
|
+
# ヘッダー - Java用(複数クラス対応)
|
|
19
|
+
classes = data.get("classes", [])
|
|
20
|
+
package_name = (data.get("package") or {}).get("name", "unknown")
|
|
21
|
+
|
|
22
|
+
if len(classes) > 1:
|
|
23
|
+
# 複数クラスがある場合はファイル名を使用
|
|
24
|
+
file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
|
|
25
|
+
lines.append(f"# {package_name}.{file_name}")
|
|
26
|
+
else:
|
|
27
|
+
# 単一クラスの場合は従来通り
|
|
28
|
+
class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
|
|
29
|
+
lines.append(f"# {package_name}.{class_name}")
|
|
30
|
+
lines.append("")
|
|
31
|
+
|
|
32
|
+
# Imports
|
|
33
|
+
imports = data.get("imports", [])
|
|
34
|
+
if imports:
|
|
35
|
+
lines.append("## Imports")
|
|
36
|
+
lines.append("```java")
|
|
37
|
+
for imp in imports:
|
|
38
|
+
lines.append(str(imp.get("statement", "")))
|
|
39
|
+
lines.append("```")
|
|
40
|
+
lines.append("")
|
|
41
|
+
|
|
42
|
+
# Class Info - Java用(複数クラス対応)
|
|
43
|
+
if len(classes) > 1:
|
|
44
|
+
lines.append("## Classes")
|
|
45
|
+
lines.append("| Class | Type | Visibility | Lines | Methods | Fields |")
|
|
46
|
+
lines.append("|-------|------|------------|-------|---------|--------|")
|
|
47
|
+
|
|
48
|
+
for class_info in classes:
|
|
49
|
+
name = str(class_info.get("name", "Unknown"))
|
|
50
|
+
class_type = str(class_info.get("type", "class"))
|
|
51
|
+
visibility = str(class_info.get("visibility", "public"))
|
|
52
|
+
line_range = class_info.get("line_range", {})
|
|
53
|
+
lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
|
|
54
|
+
|
|
55
|
+
# このクラスのメソッド数とフィールド数を計算
|
|
56
|
+
class_methods = [m for m in data.get("methods", [])
|
|
57
|
+
if line_range.get('start', 0) <= m.get('line_range', {}).get('start', 0) <= line_range.get('end', 0)]
|
|
58
|
+
class_fields = [f for f in data.get("fields", [])
|
|
59
|
+
if line_range.get('start', 0) <= f.get('line_range', {}).get('start', 0) <= line_range.get('end', 0)]
|
|
60
|
+
|
|
61
|
+
lines.append(f"| {name} | {class_type} | {visibility} | {lines_str} | {len(class_methods)} | {len(class_fields)} |")
|
|
62
|
+
else:
|
|
63
|
+
# 単一クラスの場合は従来通り
|
|
64
|
+
lines.append("## Class Info")
|
|
65
|
+
lines.append("| Property | Value |")
|
|
66
|
+
lines.append("|----------|-------|")
|
|
67
|
+
|
|
68
|
+
class_info = data.get("classes", [{}])[0] if data.get("classes") else {}
|
|
69
|
+
stats = data.get("statistics") or {}
|
|
70
|
+
|
|
71
|
+
lines.append(f"| Package | {package_name} |")
|
|
72
|
+
lines.append(f"| Type | {str(class_info.get('type', 'class'))} |")
|
|
73
|
+
lines.append(f"| Visibility | {str(class_info.get('visibility', 'public'))} |")
|
|
74
|
+
lines.append(
|
|
75
|
+
f"| Lines | {class_info.get('line_range', {}).get('start', 0)}-{class_info.get('line_range', {}).get('end', 0)} |"
|
|
76
|
+
)
|
|
77
|
+
lines.append(f"| Total Methods | {stats.get('method_count', 0)} |")
|
|
78
|
+
lines.append(f"| Total Fields | {stats.get('field_count', 0)} |")
|
|
79
|
+
|
|
80
|
+
lines.append("")
|
|
81
|
+
|
|
82
|
+
# Fields
|
|
83
|
+
fields = data.get("fields", [])
|
|
84
|
+
if fields:
|
|
85
|
+
lines.append("## Fields")
|
|
86
|
+
lines.append("| Name | Type | Vis | Modifiers | Line | Doc |")
|
|
87
|
+
lines.append("|------|------|-----|-----------|------|-----|")
|
|
88
|
+
|
|
89
|
+
for field in fields:
|
|
90
|
+
name = str(field.get("name", ""))
|
|
91
|
+
field_type = str(field.get("type", ""))
|
|
92
|
+
visibility = self._convert_visibility(str(field.get("visibility", "")))
|
|
93
|
+
modifiers = ",".join([str(m) for m in field.get("modifiers", [])])
|
|
94
|
+
line = field.get("line_range", {}).get("start", 0)
|
|
95
|
+
doc = str(field.get("javadoc", "")) or "-"
|
|
96
|
+
doc = doc.replace("\n", " ").replace("|", "\\|")[:50]
|
|
97
|
+
|
|
98
|
+
lines.append(
|
|
99
|
+
f"| {name} | {field_type} | {visibility} | {modifiers} | {line} | {doc} |"
|
|
100
|
+
)
|
|
101
|
+
lines.append("")
|
|
102
|
+
|
|
103
|
+
# Constructor
|
|
104
|
+
constructors = [
|
|
105
|
+
m for m in (data.get("methods") or []) if m.get("is_constructor", False)
|
|
106
|
+
]
|
|
107
|
+
if constructors:
|
|
108
|
+
lines.append("## Constructor")
|
|
109
|
+
lines.append("| Method | Signature | Vis | Lines | Cols | Cx | Doc |")
|
|
110
|
+
lines.append("|--------|-----------|-----|-------|------|----|----|")
|
|
111
|
+
|
|
112
|
+
for method in constructors:
|
|
113
|
+
lines.append(self._format_method_row(method))
|
|
114
|
+
lines.append("")
|
|
115
|
+
|
|
116
|
+
# Public Methods
|
|
117
|
+
public_methods = [
|
|
118
|
+
m
|
|
119
|
+
for m in (data.get("methods") or [])
|
|
120
|
+
if not m.get("is_constructor", False)
|
|
121
|
+
and str(m.get("visibility")) == "public"
|
|
122
|
+
]
|
|
123
|
+
if public_methods:
|
|
124
|
+
lines.append("## Public Methods")
|
|
125
|
+
lines.append("| Method | Signature | Vis | Lines | Cols | Cx | Doc |")
|
|
126
|
+
lines.append("|--------|-----------|-----|-------|------|----|----|")
|
|
127
|
+
|
|
128
|
+
for method in public_methods:
|
|
129
|
+
lines.append(self._format_method_row(method))
|
|
130
|
+
lines.append("")
|
|
131
|
+
|
|
132
|
+
# Private Methods
|
|
133
|
+
private_methods = [
|
|
134
|
+
m
|
|
135
|
+
for m in (data.get("methods") or [])
|
|
136
|
+
if not m.get("is_constructor", False)
|
|
137
|
+
and str(m.get("visibility")) == "private"
|
|
138
|
+
]
|
|
139
|
+
if private_methods:
|
|
140
|
+
lines.append("## Private Methods")
|
|
141
|
+
lines.append("| Method | Signature | Vis | Lines | Cols | Cx | Doc |")
|
|
142
|
+
lines.append("|--------|-----------|-----|-------|------|----|----|")
|
|
143
|
+
|
|
144
|
+
for method in private_methods:
|
|
145
|
+
lines.append(self._format_method_row(method))
|
|
146
|
+
lines.append("")
|
|
147
|
+
|
|
148
|
+
# 末尾の空行を削除
|
|
149
|
+
while lines and lines[-1] == "":
|
|
150
|
+
lines.pop()
|
|
151
|
+
|
|
152
|
+
return "\n".join(lines)
|
|
153
|
+
|
|
154
|
+
def _format_compact_table(self, data: Dict[str, Any]) -> str:
|
|
155
|
+
"""Java用コンパクト版テーブル形式"""
|
|
156
|
+
lines = []
|
|
157
|
+
|
|
158
|
+
# ヘッダー
|
|
159
|
+
package_name = (data.get("package") or {}).get("name", "unknown")
|
|
160
|
+
classes = data.get("classes", [])
|
|
161
|
+
class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
|
|
162
|
+
lines.append(f"# {package_name}.{class_name}")
|
|
163
|
+
lines.append("")
|
|
164
|
+
|
|
165
|
+
# 基本情報
|
|
166
|
+
stats = data.get("statistics") or {}
|
|
167
|
+
lines.append("## Info")
|
|
168
|
+
lines.append("| Property | Value |")
|
|
169
|
+
lines.append("|----------|-------|")
|
|
170
|
+
lines.append(f"| Package | {package_name} |")
|
|
171
|
+
lines.append(f"| Methods | {stats.get('method_count', 0)} |")
|
|
172
|
+
lines.append(f"| Fields | {stats.get('field_count', 0)} |")
|
|
173
|
+
lines.append("")
|
|
174
|
+
|
|
175
|
+
# メソッド(簡略版)
|
|
176
|
+
methods = data.get("methods", [])
|
|
177
|
+
if methods:
|
|
178
|
+
lines.append("## Methods")
|
|
179
|
+
lines.append("| Method | Sig | V | L | Cx | Doc |")
|
|
180
|
+
lines.append("|--------|-----|---|---|----|----|")
|
|
181
|
+
|
|
182
|
+
for method in methods:
|
|
183
|
+
name = str(method.get("name", ""))
|
|
184
|
+
signature = self._create_compact_signature(method)
|
|
185
|
+
visibility = self._convert_visibility(str(method.get("visibility", "")))
|
|
186
|
+
line_range = method.get("line_range", {})
|
|
187
|
+
lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
|
|
188
|
+
complexity = method.get("complexity_score", 0)
|
|
189
|
+
doc = self._clean_csv_text(
|
|
190
|
+
self._extract_doc_summary(str(method.get("javadoc", "")))
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
lines.append(
|
|
194
|
+
f"| {name} | {signature} | {visibility} | {lines_str} | {complexity} | {doc} |"
|
|
195
|
+
)
|
|
196
|
+
lines.append("")
|
|
197
|
+
|
|
198
|
+
# 末尾の空行を削除
|
|
199
|
+
while lines and lines[-1] == "":
|
|
200
|
+
lines.pop()
|
|
201
|
+
|
|
202
|
+
return "\n".join(lines)
|
|
203
|
+
|
|
204
|
+
def _format_method_row(self, method: Dict[str, Any]) -> str:
|
|
205
|
+
"""Java用メソッド行のフォーマット"""
|
|
206
|
+
name = str(method.get("name", ""))
|
|
207
|
+
signature = self._create_full_signature(method)
|
|
208
|
+
visibility = self._convert_visibility(str(method.get("visibility", "")))
|
|
209
|
+
line_range = method.get("line_range", {})
|
|
210
|
+
lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
|
|
211
|
+
cols_str = "5-6" # デフォルト値
|
|
212
|
+
complexity = method.get("complexity_score", 0)
|
|
213
|
+
doc = self._clean_csv_text(
|
|
214
|
+
self._extract_doc_summary(str(method.get("javadoc", "")))
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
return f"| {name} | {signature} | {visibility} | {lines_str} | {cols_str} | {complexity} | {doc} |"
|
|
218
|
+
|
|
219
|
+
def _create_compact_signature(self, method: Dict[str, Any]) -> str:
|
|
220
|
+
"""Java用コンパクトなメソッドシグネチャを作成"""
|
|
221
|
+
params = method.get("parameters", [])
|
|
222
|
+
param_types = [self._shorten_type(p.get("type", "O") if isinstance(p, dict) else str(p)) for p in params]
|
|
223
|
+
params_str = ",".join(param_types)
|
|
224
|
+
return_type = self._shorten_type(method.get("return_type", "void"))
|
|
225
|
+
|
|
226
|
+
return f"({params_str}):{return_type}"
|
|
227
|
+
|
|
228
|
+
def _shorten_type(self, type_name: Any) -> str:
|
|
229
|
+
"""Java用型名を短縮"""
|
|
230
|
+
if type_name is None:
|
|
231
|
+
return "O"
|
|
232
|
+
|
|
233
|
+
if not isinstance(type_name, str):
|
|
234
|
+
type_name = str(type_name)
|
|
235
|
+
|
|
236
|
+
type_mapping = {
|
|
237
|
+
"String": "S",
|
|
238
|
+
"int": "i",
|
|
239
|
+
"long": "l",
|
|
240
|
+
"double": "d",
|
|
241
|
+
"boolean": "b",
|
|
242
|
+
"void": "void",
|
|
243
|
+
"Object": "O",
|
|
244
|
+
"Exception": "E",
|
|
245
|
+
"SQLException": "SE",
|
|
246
|
+
"IllegalArgumentException": "IAE",
|
|
247
|
+
"RuntimeException": "RE",
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
# Map<String,Object> -> M<S,O>
|
|
251
|
+
if "Map<" in type_name:
|
|
252
|
+
return (
|
|
253
|
+
type_name.replace("Map<", "M<")
|
|
254
|
+
.replace("String", "S")
|
|
255
|
+
.replace("Object", "O")
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
# List<String> -> L<S>
|
|
259
|
+
if "List<" in type_name:
|
|
260
|
+
return type_name.replace("List<", "L<").replace("String", "S")
|
|
261
|
+
|
|
262
|
+
# String[] -> S[]
|
|
263
|
+
if "[]" in type_name:
|
|
264
|
+
base_type = type_name.replace("[]", "")
|
|
265
|
+
if base_type:
|
|
266
|
+
return type_mapping.get(base_type, base_type[0].upper()) + "[]"
|
|
267
|
+
else:
|
|
268
|
+
return "O[]"
|
|
269
|
+
|
|
270
|
+
return type_mapping.get(type_name, type_name)
|