tree-sitter-analyzer 0.6.2__tar.gz → 0.7.0__tar.gz

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 (98) hide show
  1. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/CHANGELOG.md +44 -0
  2. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/PKG-INFO +1 -1
  3. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/pyproject.toml +1 -1
  4. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/table_formatter.py +218 -102
  5. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/uv.lock +1 -1
  6. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/.gitignore +0 -0
  7. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/.pre-commit-config.yaml +0 -0
  8. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/AI_COLLABORATION_GUIDE.md +0 -0
  9. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/CODE_STYLE_GUIDE.md +0 -0
  10. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/CONTRIBUTING.md +0 -0
  11. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/DEPLOYMENT_GUIDE.md +0 -0
  12. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/LLM_CODING_GUIDELINES.md +0 -0
  13. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/MCP_SETUP_DEVELOPERS.md +0 -0
  14. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/MCP_SETUP_USERS.md +0 -0
  15. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/README.md +0 -0
  16. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/README_ja.md +0 -0
  17. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/README_zh.md +0 -0
  18. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/build_standalone.py +0 -0
  19. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/check_quality.py +0 -0
  20. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/docs/api.md +0 -0
  21. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/examples/BigService.java +0 -0
  22. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/examples/BigService.json +0 -0
  23. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/examples/BigService.summary.json +0 -0
  24. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/examples/JavaDocTest.java +0 -0
  25. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/examples/MultiClass.java +0 -0
  26. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/examples/Sample.java +0 -0
  27. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/examples/calculate_token_comparison.py +0 -0
  28. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/examples/sample.py +0 -0
  29. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/llm_code_checker.py +0 -0
  30. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/pytest.ini +0 -0
  31. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/__init__.py +0 -0
  32. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/__main__.py +0 -0
  33. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/api.py +0 -0
  34. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli/__init__.py +0 -0
  35. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli/__main__.py +0 -0
  36. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli/commands/__init__.py +0 -0
  37. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli/commands/advanced_command.py +0 -0
  38. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli/commands/base_command.py +0 -0
  39. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli/commands/default_command.py +0 -0
  40. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli/commands/partial_read_command.py +0 -0
  41. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli/commands/query_command.py +0 -0
  42. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli/commands/structure_command.py +0 -0
  43. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli/commands/summary_command.py +0 -0
  44. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli/commands/table_command.py +0 -0
  45. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli/info_commands.py +0 -0
  46. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/cli_main.py +0 -0
  47. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/core/__init__.py +0 -0
  48. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/core/analysis_engine.py +0 -0
  49. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/core/cache_service.py +0 -0
  50. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/core/engine.py +0 -0
  51. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/core/parser.py +0 -0
  52. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/core/query.py +0 -0
  53. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/encoding_utils.py +0 -0
  54. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/exceptions.py +0 -0
  55. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/file_handler.py +0 -0
  56. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/formatters/__init__.py +0 -0
  57. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/formatters/base_formatter.py +0 -0
  58. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/formatters/formatter_factory.py +0 -0
  59. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/formatters/java_formatter.py +0 -0
  60. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/formatters/python_formatter.py +0 -0
  61. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/interfaces/__init__.py +0 -0
  62. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/interfaces/cli.py +0 -0
  63. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/interfaces/cli_adapter.py +0 -0
  64. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/interfaces/mcp_adapter.py +0 -0
  65. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/interfaces/mcp_server.py +0 -0
  66. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/language_detector.py +0 -0
  67. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/language_loader.py +0 -0
  68. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/languages/__init__.py +0 -0
  69. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/languages/java_plugin.py +0 -0
  70. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/languages/javascript_plugin.py +0 -0
  71. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/languages/python_plugin.py +0 -0
  72. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/__init__.py +0 -0
  73. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/resources/__init__.py +0 -0
  74. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/resources/code_file_resource.py +0 -0
  75. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/resources/project_stats_resource.py +0 -0
  76. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/server.py +0 -0
  77. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/tools/__init__.py +0 -0
  78. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +0 -0
  79. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +0 -0
  80. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/tools/base_tool.py +0 -0
  81. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/tools/read_partial_tool.py +0 -0
  82. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/tools/table_format_tool.py +0 -0
  83. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +0 -0
  84. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/utils/__init__.py +0 -0
  85. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/mcp/utils/error_handler.py +0 -0
  86. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/models.py +0 -0
  87. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/output_manager.py +0 -0
  88. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/plugins/__init__.py +0 -0
  89. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/plugins/base.py +0 -0
  90. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/plugins/manager.py +0 -0
  91. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/queries/__init__.py +0 -0
  92. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/queries/java.py +0 -0
  93. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/queries/javascript.py +0 -0
  94. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/queries/python.py +0 -0
  95. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/queries/typescript.py +0 -0
  96. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/query_loader.py +0 -0
  97. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/tree_sitter_analyzer/utils.py +0 -0
  98. {tree_sitter_analyzer-0.6.2 → tree_sitter_analyzer-0.7.0}/upload_to_pypi.py +0 -0
@@ -5,6 +5,50 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.7.0] - 2025-08-04
9
+
10
+ ### 🚀 Added
11
+
12
+ #### Improved Table Output Structure
13
+ - **Enhanced**: Complete restructure of `--table=full` output format
14
+ - **Added**: Class-based organization - each class now has its own section
15
+ - **Added**: Clear separation of fields, constructors, and methods by class
16
+ - **Added**: Proper attribution of methods and fields to their respective classes
17
+ - **Added**: Nested class handling - inner class members no longer appear in outer class sections
18
+
19
+ #### Better Output Organization
20
+ - **Enhanced**: File header now shows filename instead of class name for multi-class files
21
+ - **Enhanced**: Package information displayed in dedicated section with clear formatting
22
+ - **Enhanced**: Methods grouped by visibility (Public, Protected, Package, Private)
23
+ - **Enhanced**: Constructors separated from regular methods
24
+ - **Enhanced**: Fields properly attributed to their containing class
25
+
26
+ #### Improved Readability
27
+ - **Enhanced**: Cleaner section headers with line range information
28
+ - **Enhanced**: Better visual separation between different classes
29
+ - **Enhanced**: More logical information flow from overview to details
30
+
31
+ ### 🔧 Fixed
32
+
33
+ #### Output Structure Issues
34
+ - **Fixed**: Methods and fields now correctly attributed to their containing classes
35
+ - **Fixed**: Inner class methods no longer appear duplicated in outer class sections
36
+ - **Fixed**: Nested class field attribution corrected
37
+ - **Fixed**: Multi-class file handling improved
38
+
39
+ #### Test Updates
40
+ - **Updated**: All tests updated to work with new output format
41
+ - **Updated**: Package name verification tests adapted to new structure
42
+ - **Updated**: MCP tool tests updated for new format compatibility
43
+
44
+ ### 📦 Package Updates
45
+
46
+ - **Updated**: Table formatter completely rewritten for better organization
47
+ - **Updated**: Class-based output structure for improved code navigation
48
+ - **Updated**: Enhanced support for complex class hierarchies and nested classes
49
+
50
+ ---
51
+
8
52
  ## [0.6.2] - 2025-08-04
9
53
 
10
54
  ### 🔧 Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tree-sitter-analyzer
3
- Version: 0.6.2
3
+ Version: 0.7.0
4
4
  Summary: Extensible multi-language code analyzer framework using Tree-sitter with dynamic plugin architecture
5
5
  Project-URL: Homepage, https://github.com/aimasteracc/tree-sitter-analyzer
6
6
  Project-URL: Documentation, https://github.com/aimasteracc/tree-sitter-analyzer#readme
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "tree-sitter-analyzer"
7
- version = "0.6.2"
7
+ version = "0.7.0"
8
8
  description = "Extensible multi-language code analyzer framework using Tree-sitter with dynamic plugin architecture"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -53,25 +53,26 @@ class TableFormatter:
53
53
  return self._convert_to_platform_newlines(result)
54
54
 
55
55
  def _format_full_table(self, data: dict[str, Any]) -> str:
56
- """Full table format"""
56
+ """Full table format - organized by class"""
57
57
  lines = []
58
58
 
59
- # Header - use filename when multiple classes exist
59
+ # Header - use filename for multi-class files
60
60
  classes = data.get("classes", [])
61
61
  if classes is None:
62
62
  classes = []
63
- if len(classes) > 1:
64
- # Use file name when multiple classes exist
65
- file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
66
- lines.append(f"# {file_name}")
67
- else:
68
- # Use class name for single class as before
69
- class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
70
- lines.append(
71
- f"# {(data.get('package') or {}).get('name', 'unknown')}.{class_name}"
72
- )
63
+
64
+ # Always use filename for header to be consistent
65
+ file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
66
+ lines.append(f"# {file_name}")
73
67
  lines.append("")
74
68
 
69
+ # Package info
70
+ package_name = (data.get("package") or {}).get("name", "")
71
+ if package_name:
72
+ lines.append("## Package")
73
+ lines.append(f"`{package_name}`")
74
+ lines.append("")
75
+
75
76
  # Imports
76
77
  imports = data.get("imports", [])
77
78
  if imports:
@@ -82,12 +83,9 @@ class TableFormatter:
82
83
  lines.append("```")
83
84
  lines.append("")
84
85
 
85
- # Class Info - Support for multiple classes
86
- classes = data.get("classes", [])
87
- if classes is None:
88
- classes = []
86
+ # Classes Overview
89
87
  if len(classes) > 1:
90
- lines.append("## Classes")
88
+ lines.append("## Classes Overview")
91
89
  lines.append("| Class | Type | Visibility | Lines | Methods | Fields |")
92
90
  lines.append("|-------|------|------------|-------|---------|--------|")
93
91
 
@@ -99,51 +97,198 @@ class TableFormatter:
99
97
  lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
100
98
 
101
99
  # Calculate method and field counts for this class
102
- class_methods = [
103
- m
104
- for m in data.get("methods", [])
105
- if line_range.get("start", 0)
106
- <= m.get("line_range", {}).get("start", 0)
107
- <= line_range.get("end", 0)
108
- ]
109
- class_fields = [
110
- f
111
- for f in data.get("fields", [])
112
- if line_range.get("start", 0)
113
- <= f.get("line_range", {}).get("start", 0)
114
- <= line_range.get("end", 0)
115
- ]
100
+ class_methods = self._get_class_methods(data, line_range)
101
+ class_fields = self._get_class_fields(data, line_range)
116
102
 
117
103
  lines.append(
118
104
  f"| {name} | {class_type} | {visibility} | {lines_str} | {len(class_methods)} | {len(class_fields)} |"
119
105
  )
120
- else:
121
- # Use traditional format for single class
122
- lines.append("## Class Info")
123
- lines.append("| Property | Value |")
124
- lines.append("|----------|-------|")
125
-
126
- package_name = (data.get("package") or {}).get("name", "unknown")
127
- class_info = data.get("classes", [{}])[0] if data.get("classes") else {}
128
- stats = data.get("statistics") or {}
129
-
130
- lines.append(f"| Package | {package_name} |")
131
- lines.append(f"| Type | {str(class_info.get('type', 'class'))} |")
132
- lines.append(
133
- f"| Visibility | {str(class_info.get('visibility', 'public'))} |"
134
- )
135
- lines.append(
136
- f"| Lines | {class_info.get('line_range', {}).get('start', 0)}-{class_info.get('line_range', {}).get('end', 0)} |"
137
- )
138
- lines.append(f"| Total Methods | {stats.get('method_count', 0)} |")
139
- lines.append(f"| Total Fields | {stats.get('field_count', 0)} |")
106
+ lines.append("")
107
+
108
+ # Detailed class information - organized by class
109
+ for class_info in classes:
110
+ lines.extend(self._format_class_details(class_info, data))
111
+
112
+ # Remove trailing empty lines
113
+ while lines and lines[-1] == "":
114
+ lines.pop()
115
+
116
+ return "\n".join(lines)
117
+
118
+ def _get_class_methods(self, data: dict[str, Any], class_line_range: dict[str, int]) -> list[dict[str, Any]]:
119
+ """Get methods that belong to a specific class based on line range, excluding nested classes."""
120
+ methods = data.get("methods", [])
121
+ classes = data.get("classes", [])
122
+ class_methods = []
123
+
124
+ # Get nested class ranges to exclude their methods
125
+ nested_class_ranges = []
126
+ for cls in classes:
127
+ cls_range = cls.get("line_range", {})
128
+ cls_start = cls_range.get("start", 0)
129
+ cls_end = cls_range.get("end", 0)
130
+
131
+ # If this class is nested within the current class range
132
+ if (class_line_range.get("start", 0) < cls_start and
133
+ cls_end < class_line_range.get("end", 0)):
134
+ nested_class_ranges.append((cls_start, cls_end))
135
+
136
+ for method in methods:
137
+ method_line = method.get("line_range", {}).get("start", 0)
138
+
139
+ # Check if method is within the class range
140
+ if (class_line_range.get("start", 0) <= method_line <= class_line_range.get("end", 0)):
141
+ # Check if method is NOT within any nested class
142
+ in_nested_class = False
143
+ for nested_start, nested_end in nested_class_ranges:
144
+ if nested_start <= method_line <= nested_end:
145
+ in_nested_class = True
146
+ break
147
+
148
+ if not in_nested_class:
149
+ class_methods.append(method)
150
+
151
+ return class_methods
152
+
153
+ def _get_class_fields(self, data: dict[str, Any], class_line_range: dict[str, int]) -> list[dict[str, Any]]:
154
+ """Get fields that belong to a specific class based on line range, excluding nested classes."""
155
+ fields = data.get("fields", [])
156
+ classes = data.get("classes", [])
157
+ class_fields = []
158
+
159
+ # Get nested class ranges to exclude their fields
160
+ nested_class_ranges = []
161
+ for cls in classes:
162
+ cls_range = cls.get("line_range", {})
163
+ cls_start = cls_range.get("start", 0)
164
+ cls_end = cls_range.get("end", 0)
165
+
166
+ # If this class is nested within the current class range
167
+ if (class_line_range.get("start", 0) < cls_start and
168
+ cls_end < class_line_range.get("end", 0)):
169
+ nested_class_ranges.append((cls_start, cls_end))
170
+
171
+ for field in fields:
172
+ field_line = field.get("line_range", {}).get("start", 0)
173
+
174
+ # Check if field is within the class range
175
+ if (class_line_range.get("start", 0) <= field_line <= class_line_range.get("end", 0)):
176
+ # Check if field is NOT within any nested class
177
+ in_nested_class = False
178
+ for nested_start, nested_end in nested_class_ranges:
179
+ if nested_start <= field_line <= nested_end:
180
+ in_nested_class = True
181
+ break
182
+
183
+ if not in_nested_class:
184
+ class_fields.append(field)
185
+
186
+ return class_fields
187
+
188
+ def _format_class_details(self, class_info: dict[str, Any], data: dict[str, Any]) -> list[str]:
189
+ """Format detailed information for a single class."""
190
+ lines = []
191
+
192
+ name = str(class_info.get("name", "Unknown"))
193
+ line_range = class_info.get("line_range", {})
194
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
195
+
196
+ # Class header
197
+ lines.append(f"## {name} ({lines_str})")
198
+
199
+ # Get class-specific methods and fields
200
+ class_methods = self._get_class_methods(data, line_range)
201
+ class_fields = self._get_class_fields(data, line_range)
202
+
203
+ # Fields section
204
+ if class_fields:
205
+ lines.append("### Fields")
206
+ lines.append("| Name | Type | Vis | Modifiers | Line | Doc |")
207
+ lines.append("|------|------|-----|-----------|------|-----|")
208
+
209
+ for field in class_fields:
210
+ name_field = str(field.get("name", ""))
211
+ type_field = str(field.get("type", ""))
212
+ visibility = self._convert_visibility(str(field.get("visibility", "")))
213
+ modifiers = ",".join(field.get("modifiers", []))
214
+ line_num = field.get("line_range", {}).get("start", 0)
215
+ doc = self._extract_doc_summary(str(field.get("javadoc", ""))) if self.include_javadoc else "-"
216
+
217
+ lines.append(f"| {name_field} | {type_field} | {visibility} | {modifiers} | {line_num} | {doc} |")
218
+ lines.append("")
219
+
220
+ # Methods section - separate by type
221
+ constructors = [m for m in class_methods if m.get("is_constructor", False)]
222
+ regular_methods = [m for m in class_methods if not m.get("is_constructor", False)]
223
+
224
+ # Constructors
225
+ if constructors:
226
+ lines.append("### Constructors")
227
+ lines.append("| Constructor | Signature | Vis | Lines | Cx | Doc |")
228
+ lines.append("|-------------|-----------|-----|-------|----|----|")
140
229
 
230
+ for method in constructors:
231
+ lines.append(self._format_method_row_detailed(method))
232
+ lines.append("")
233
+
234
+ # Methods grouped by visibility
235
+ public_methods = [m for m in regular_methods if m.get("visibility", "") == "public"]
236
+ protected_methods = [m for m in regular_methods if m.get("visibility", "") == "protected"]
237
+ package_methods = [m for m in regular_methods if m.get("visibility", "") == "package"]
238
+ private_methods = [m for m in regular_methods if m.get("visibility", "") == "private"]
239
+
240
+ for method_group, title in [
241
+ (public_methods, "Public Methods"),
242
+ (protected_methods, "Protected Methods"),
243
+ (package_methods, "Package Methods"),
244
+ (private_methods, "Private Methods")
245
+ ]:
246
+ if method_group:
247
+ lines.append(f"### {title}")
248
+ lines.append("| Method | Signature | Vis | Lines | Cx | Doc |")
249
+ lines.append("|--------|-----------|-----|-------|----|----|")
250
+
251
+ for method in method_group:
252
+ lines.append(self._format_method_row_detailed(method))
253
+ lines.append("")
254
+
255
+ return lines
256
+
257
+ def _format_method_row_detailed(self, method: dict[str, Any]) -> str:
258
+ """Format method row for detailed class view."""
259
+ name = str(method.get("name", ""))
260
+ signature = self._create_full_signature(method)
261
+ visibility = self._convert_visibility(str(method.get("visibility", "")))
262
+ line_range = method.get("line_range", {})
263
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
264
+ complexity = method.get("complexity_score", 0)
265
+ doc = self._extract_doc_summary(str(method.get("javadoc", ""))) if self.include_javadoc else "-"
266
+
267
+ return f"| {name} | {signature} | {visibility} | {lines_str} | {complexity} | {doc} |"
268
+
269
+ def _format_traditional_sections(self, data: dict[str, Any]) -> list[str]:
270
+ """Format traditional sections when no classes are found."""
271
+ lines = []
272
+
273
+ # Traditional class info
274
+ lines.append("## Class Info")
275
+ lines.append("| Property | Value |")
276
+ lines.append("|----------|-------|")
277
+
278
+ package_name = (data.get("package") or {}).get("name", "unknown")
279
+ class_info = data.get("classes", [{}])[0] if data.get("classes") else {}
280
+ stats = data.get("statistics") or {}
281
+
282
+ lines.append(f"| Package | {package_name} |")
283
+ lines.append(f"| Type | {str(class_info.get('type', 'class'))} |")
284
+ lines.append(f"| Visibility | {str(class_info.get('visibility', 'public'))} |")
285
+ lines.append(f"| Lines | {class_info.get('line_range', {}).get('start', 0)}-{class_info.get('line_range', {}).get('end', 0)} |")
286
+ lines.append(f"| Total Methods | {stats.get('method_count', 0)} |")
287
+ lines.append(f"| Total Fields | {stats.get('field_count', 0)} |")
141
288
  lines.append("")
142
289
 
143
290
  # Fields
144
291
  fields = data.get("fields", [])
145
- if fields is None:
146
- fields = []
147
292
  if fields:
148
293
  lines.append("## Fields")
149
294
  lines.append("| Name | Type | Vis | Modifiers | Line | Doc |")
@@ -155,66 +300,37 @@ class TableFormatter:
155
300
  visibility = self._convert_visibility(str(field.get("visibility", "")))
156
301
  modifiers = ",".join([str(m) for m in field.get("modifiers", [])])
157
302
  line = field.get("line_range", {}).get("start", 0)
158
- if self.include_javadoc:
159
- doc = self._extract_doc_summary(str(field.get("javadoc", "")))
160
- else:
161
- doc = "-"
303
+ doc = self._extract_doc_summary(str(field.get("javadoc", ""))) if self.include_javadoc else "-"
162
304
 
163
- lines.append(
164
- f"| {name} | {field_type} | {visibility} | {modifiers} | {line} | {doc} |"
165
- )
305
+ lines.append(f"| {name} | {field_type} | {visibility} | {modifiers} | {line} | {doc} |")
166
306
  lines.append("")
167
307
 
168
- # Constructor
169
- constructors = [
170
- m for m in (data.get("methods") or []) if m.get("is_constructor", False)
171
- ]
308
+ # Methods by type
309
+ methods = data.get("methods", [])
310
+ constructors = [m for m in methods if m.get("is_constructor", False)]
311
+ regular_methods = [m for m in methods if not m.get("is_constructor", False)]
312
+
313
+ # Constructors
172
314
  if constructors:
173
315
  lines.append("## Constructor")
174
316
  lines.append("| Method | Signature | Vis | Lines | Cols | Cx | Doc |")
175
317
  lines.append("|--------|-----------|-----|-------|------|----|----|")
176
-
177
318
  for method in constructors:
178
319
  lines.append(self._format_method_row(method))
179
320
  lines.append("")
180
321
 
181
- # Public Methods
182
- public_methods = [
183
- m
184
- for m in (data.get("methods") or [])
185
- if not m.get("is_constructor", False)
186
- and str(m.get("visibility")) == "public"
187
- ]
188
- if public_methods:
189
- lines.append("## Public Methods")
190
- lines.append("| Method | Signature | Vis | Lines | Cols | Cx | Doc |")
191
- lines.append("|--------|-----------|-----|-------|------|----|----|")
192
-
193
- for method in public_methods:
194
- lines.append(self._format_method_row(method))
195
- lines.append("")
196
-
197
- # Private Methods
198
- private_methods = [
199
- m
200
- for m in (data.get("methods") or [])
201
- if not m.get("is_constructor", False)
202
- and str(m.get("visibility")) == "private"
203
- ]
204
- if private_methods:
205
- lines.append("## Private Methods")
206
- lines.append("| Method | Signature | Vis | Lines | Cols | Cx | Doc |")
207
- lines.append("|--------|-----------|-----|-------|------|----|----|")
208
-
209
- for method in private_methods:
210
- lines.append(self._format_method_row(method))
211
- lines.append("")
212
-
213
- # Remove trailing empty lines
214
- while lines and lines[-1] == "":
215
- lines.pop()
216
-
217
- return "\n".join(lines)
322
+ # Methods by visibility
323
+ for visibility, title in [("public", "Public Methods"), ("private", "Private Methods")]:
324
+ visibility_methods = [m for m in regular_methods if str(m.get("visibility")) == visibility]
325
+ if visibility_methods:
326
+ lines.append(f"## {title}")
327
+ lines.append("| Method | Signature | Vis | Lines | Cols | Cx | Doc |")
328
+ lines.append("|--------|-----------|-----|-------|------|----|----|")
329
+ for method in visibility_methods:
330
+ lines.append(self._format_method_row(method))
331
+ lines.append("")
332
+
333
+ return lines
218
334
 
219
335
  def _format_compact_table(self, data: dict[str, Any]) -> str:
220
336
  """Compact table format"""
@@ -1496,7 +1496,7 @@ wheels = [
1496
1496
 
1497
1497
  [[package]]
1498
1498
  name = "tree-sitter-analyzer"
1499
- version = "0.6.2"
1499
+ version = "0.7.0"
1500
1500
  source = { editable = "." }
1501
1501
  dependencies = [
1502
1502
  { name = "cachetools" },