crackerjack 0.33.0__py3-none-any.whl → 0.33.1__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 crackerjack might be problematic. Click here for more details.

Files changed (198) hide show
  1. crackerjack/__main__.py +1350 -34
  2. crackerjack/adapters/__init__.py +17 -0
  3. crackerjack/adapters/lsp_client.py +358 -0
  4. crackerjack/adapters/rust_tool_adapter.py +194 -0
  5. crackerjack/adapters/rust_tool_manager.py +193 -0
  6. crackerjack/adapters/skylos_adapter.py +231 -0
  7. crackerjack/adapters/zuban_adapter.py +560 -0
  8. crackerjack/agents/base.py +7 -3
  9. crackerjack/agents/coordinator.py +271 -33
  10. crackerjack/agents/documentation_agent.py +9 -15
  11. crackerjack/agents/dry_agent.py +3 -15
  12. crackerjack/agents/formatting_agent.py +1 -1
  13. crackerjack/agents/import_optimization_agent.py +36 -180
  14. crackerjack/agents/performance_agent.py +17 -98
  15. crackerjack/agents/performance_helpers.py +7 -31
  16. crackerjack/agents/proactive_agent.py +1 -3
  17. crackerjack/agents/refactoring_agent.py +16 -85
  18. crackerjack/agents/refactoring_helpers.py +7 -42
  19. crackerjack/agents/security_agent.py +9 -48
  20. crackerjack/agents/test_creation_agent.py +356 -513
  21. crackerjack/agents/test_specialist_agent.py +0 -4
  22. crackerjack/api.py +6 -25
  23. crackerjack/cli/cache_handlers.py +204 -0
  24. crackerjack/cli/cache_handlers_enhanced.py +683 -0
  25. crackerjack/cli/facade.py +100 -0
  26. crackerjack/cli/handlers.py +224 -9
  27. crackerjack/cli/interactive.py +6 -4
  28. crackerjack/cli/options.py +642 -55
  29. crackerjack/cli/utils.py +2 -1
  30. crackerjack/code_cleaner.py +58 -117
  31. crackerjack/config/global_lock_config.py +8 -48
  32. crackerjack/config/hooks.py +53 -62
  33. crackerjack/core/async_workflow_orchestrator.py +24 -34
  34. crackerjack/core/autofix_coordinator.py +3 -17
  35. crackerjack/core/enhanced_container.py +4 -13
  36. crackerjack/core/file_lifecycle.py +12 -89
  37. crackerjack/core/performance.py +2 -2
  38. crackerjack/core/performance_monitor.py +15 -55
  39. crackerjack/core/phase_coordinator.py +104 -204
  40. crackerjack/core/resource_manager.py +14 -90
  41. crackerjack/core/service_watchdog.py +62 -95
  42. crackerjack/core/session_coordinator.py +149 -0
  43. crackerjack/core/timeout_manager.py +14 -72
  44. crackerjack/core/websocket_lifecycle.py +13 -78
  45. crackerjack/core/workflow_orchestrator.py +171 -174
  46. crackerjack/docs/INDEX.md +11 -0
  47. crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
  48. crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
  49. crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
  50. crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
  51. crackerjack/docs/generated/api/SERVICES.md +1252 -0
  52. crackerjack/documentation/__init__.py +31 -0
  53. crackerjack/documentation/ai_templates.py +756 -0
  54. crackerjack/documentation/dual_output_generator.py +765 -0
  55. crackerjack/documentation/mkdocs_integration.py +518 -0
  56. crackerjack/documentation/reference_generator.py +977 -0
  57. crackerjack/dynamic_config.py +55 -50
  58. crackerjack/executors/async_hook_executor.py +10 -15
  59. crackerjack/executors/cached_hook_executor.py +117 -43
  60. crackerjack/executors/hook_executor.py +8 -34
  61. crackerjack/executors/hook_lock_manager.py +26 -183
  62. crackerjack/executors/individual_hook_executor.py +13 -11
  63. crackerjack/executors/lsp_aware_hook_executor.py +270 -0
  64. crackerjack/executors/tool_proxy.py +417 -0
  65. crackerjack/hooks/lsp_hook.py +79 -0
  66. crackerjack/intelligence/adaptive_learning.py +25 -10
  67. crackerjack/intelligence/agent_orchestrator.py +2 -5
  68. crackerjack/intelligence/agent_registry.py +34 -24
  69. crackerjack/intelligence/agent_selector.py +5 -7
  70. crackerjack/interactive.py +17 -6
  71. crackerjack/managers/async_hook_manager.py +0 -1
  72. crackerjack/managers/hook_manager.py +79 -1
  73. crackerjack/managers/publish_manager.py +44 -8
  74. crackerjack/managers/test_command_builder.py +1 -15
  75. crackerjack/managers/test_executor.py +1 -3
  76. crackerjack/managers/test_manager.py +98 -7
  77. crackerjack/managers/test_manager_backup.py +10 -9
  78. crackerjack/mcp/cache.py +2 -2
  79. crackerjack/mcp/client_runner.py +1 -1
  80. crackerjack/mcp/context.py +191 -68
  81. crackerjack/mcp/dashboard.py +7 -5
  82. crackerjack/mcp/enhanced_progress_monitor.py +31 -28
  83. crackerjack/mcp/file_monitor.py +30 -23
  84. crackerjack/mcp/progress_components.py +31 -21
  85. crackerjack/mcp/progress_monitor.py +50 -53
  86. crackerjack/mcp/rate_limiter.py +6 -6
  87. crackerjack/mcp/server_core.py +17 -16
  88. crackerjack/mcp/service_watchdog.py +2 -1
  89. crackerjack/mcp/state.py +4 -7
  90. crackerjack/mcp/task_manager.py +11 -9
  91. crackerjack/mcp/tools/core_tools.py +173 -32
  92. crackerjack/mcp/tools/error_analyzer.py +3 -2
  93. crackerjack/mcp/tools/execution_tools.py +8 -10
  94. crackerjack/mcp/tools/execution_tools_backup.py +42 -30
  95. crackerjack/mcp/tools/intelligence_tool_registry.py +7 -5
  96. crackerjack/mcp/tools/intelligence_tools.py +5 -2
  97. crackerjack/mcp/tools/monitoring_tools.py +33 -70
  98. crackerjack/mcp/tools/proactive_tools.py +24 -11
  99. crackerjack/mcp/tools/progress_tools.py +5 -8
  100. crackerjack/mcp/tools/utility_tools.py +20 -14
  101. crackerjack/mcp/tools/workflow_executor.py +62 -40
  102. crackerjack/mcp/websocket/app.py +8 -0
  103. crackerjack/mcp/websocket/endpoints.py +352 -357
  104. crackerjack/mcp/websocket/jobs.py +40 -57
  105. crackerjack/mcp/websocket/monitoring_endpoints.py +2935 -0
  106. crackerjack/mcp/websocket/server.py +7 -25
  107. crackerjack/mcp/websocket/websocket_handler.py +6 -17
  108. crackerjack/mixins/__init__.py +0 -2
  109. crackerjack/mixins/error_handling.py +1 -70
  110. crackerjack/models/config.py +12 -1
  111. crackerjack/models/config_adapter.py +49 -1
  112. crackerjack/models/protocols.py +122 -122
  113. crackerjack/models/resource_protocols.py +55 -210
  114. crackerjack/monitoring/ai_agent_watchdog.py +13 -13
  115. crackerjack/monitoring/metrics_collector.py +426 -0
  116. crackerjack/monitoring/regression_prevention.py +8 -8
  117. crackerjack/monitoring/websocket_server.py +643 -0
  118. crackerjack/orchestration/advanced_orchestrator.py +11 -6
  119. crackerjack/orchestration/coverage_improvement.py +3 -3
  120. crackerjack/orchestration/execution_strategies.py +26 -6
  121. crackerjack/orchestration/test_progress_streamer.py +8 -5
  122. crackerjack/plugins/base.py +2 -2
  123. crackerjack/plugins/hooks.py +7 -0
  124. crackerjack/plugins/managers.py +11 -8
  125. crackerjack/security/__init__.py +0 -1
  126. crackerjack/security/audit.py +6 -35
  127. crackerjack/services/anomaly_detector.py +392 -0
  128. crackerjack/services/api_extractor.py +615 -0
  129. crackerjack/services/backup_service.py +2 -2
  130. crackerjack/services/bounded_status_operations.py +15 -152
  131. crackerjack/services/cache.py +127 -1
  132. crackerjack/services/changelog_automation.py +395 -0
  133. crackerjack/services/config.py +15 -9
  134. crackerjack/services/config_merge.py +19 -80
  135. crackerjack/services/config_template.py +506 -0
  136. crackerjack/services/contextual_ai_assistant.py +48 -22
  137. crackerjack/services/coverage_badge_service.py +171 -0
  138. crackerjack/services/coverage_ratchet.py +27 -25
  139. crackerjack/services/debug.py +3 -3
  140. crackerjack/services/dependency_analyzer.py +460 -0
  141. crackerjack/services/dependency_monitor.py +14 -11
  142. crackerjack/services/documentation_generator.py +491 -0
  143. crackerjack/services/documentation_service.py +675 -0
  144. crackerjack/services/enhanced_filesystem.py +6 -5
  145. crackerjack/services/enterprise_optimizer.py +865 -0
  146. crackerjack/services/error_pattern_analyzer.py +676 -0
  147. crackerjack/services/file_hasher.py +1 -1
  148. crackerjack/services/git.py +8 -25
  149. crackerjack/services/health_metrics.py +10 -8
  150. crackerjack/services/heatmap_generator.py +735 -0
  151. crackerjack/services/initialization.py +11 -30
  152. crackerjack/services/input_validator.py +5 -97
  153. crackerjack/services/intelligent_commit.py +327 -0
  154. crackerjack/services/log_manager.py +15 -12
  155. crackerjack/services/logging.py +4 -3
  156. crackerjack/services/lsp_client.py +628 -0
  157. crackerjack/services/memory_optimizer.py +19 -87
  158. crackerjack/services/metrics.py +42 -33
  159. crackerjack/services/parallel_executor.py +9 -67
  160. crackerjack/services/pattern_cache.py +1 -1
  161. crackerjack/services/pattern_detector.py +6 -6
  162. crackerjack/services/performance_benchmarks.py +18 -59
  163. crackerjack/services/performance_cache.py +20 -81
  164. crackerjack/services/performance_monitor.py +27 -95
  165. crackerjack/services/predictive_analytics.py +510 -0
  166. crackerjack/services/quality_baseline.py +234 -0
  167. crackerjack/services/quality_baseline_enhanced.py +646 -0
  168. crackerjack/services/quality_intelligence.py +785 -0
  169. crackerjack/services/regex_patterns.py +605 -524
  170. crackerjack/services/regex_utils.py +43 -123
  171. crackerjack/services/secure_path_utils.py +5 -164
  172. crackerjack/services/secure_status_formatter.py +30 -141
  173. crackerjack/services/secure_subprocess.py +11 -92
  174. crackerjack/services/security.py +9 -41
  175. crackerjack/services/security_logger.py +12 -24
  176. crackerjack/services/server_manager.py +124 -16
  177. crackerjack/services/status_authentication.py +16 -159
  178. crackerjack/services/status_security_manager.py +4 -131
  179. crackerjack/services/thread_safe_status_collector.py +19 -125
  180. crackerjack/services/unified_config.py +21 -13
  181. crackerjack/services/validation_rate_limiter.py +5 -54
  182. crackerjack/services/version_analyzer.py +459 -0
  183. crackerjack/services/version_checker.py +1 -1
  184. crackerjack/services/websocket_resource_limiter.py +10 -144
  185. crackerjack/services/zuban_lsp_service.py +390 -0
  186. crackerjack/slash_commands/__init__.py +2 -7
  187. crackerjack/slash_commands/run.md +2 -2
  188. crackerjack/tools/validate_input_validator_patterns.py +14 -40
  189. crackerjack/tools/validate_regex_patterns.py +19 -48
  190. {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/METADATA +196 -25
  191. crackerjack-0.33.1.dist-info/RECORD +229 -0
  192. crackerjack/CLAUDE.md +0 -207
  193. crackerjack/RULES.md +0 -380
  194. crackerjack/py313.py +0 -234
  195. crackerjack-0.33.0.dist-info/RECORD +0 -187
  196. {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/WHEEL +0 -0
  197. {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/entry_points.txt +0 -0
  198. {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,491 @@
1
+ """Service for generating documentation from extracted API data."""
2
+
3
+ import typing as t
4
+ from pathlib import Path
5
+ from string import Template
6
+
7
+ from rich.console import Console
8
+
9
+ from ..models.protocols import DocumentationGeneratorProtocol
10
+
11
+
12
+ class MarkdownTemplateRenderer:
13
+ """Simple template renderer for markdown documentation."""
14
+
15
+ def __init__(self) -> None:
16
+ self.built_in_templates = self._init_builtin_templates()
17
+
18
+ def _init_builtin_templates(self) -> dict[str, Template]:
19
+ """Initialize built-in template strings."""
20
+ return {
21
+ "api_reference": Template(self._get_api_reference_template()),
22
+ "function_doc": Template(self._get_function_doc_template()),
23
+ "class_doc": Template(self._get_class_doc_template()),
24
+ "protocol_doc": Template(self._get_protocol_doc_template()),
25
+ "module_doc": Template(self._get_module_doc_template()),
26
+ }
27
+
28
+ def render_template(self, template_name: str, context: dict[str, t.Any]) -> str:
29
+ """Render a template with the given context."""
30
+ if template_name in self.built_in_templates:
31
+ template = self.built_in_templates[template_name]
32
+ return template.safe_substitute(context)
33
+
34
+ # Try to load external template file
35
+ template_path = Path(f"templates/{template_name}")
36
+ if template_path.exists():
37
+ content = template_path.read_text(encoding="utf-8")
38
+ template = Template(content)
39
+ return template.safe_substitute(context)
40
+
41
+ raise ValueError(f"Template '{template_name}' not found")
42
+
43
+ def _get_api_reference_template(self) -> str:
44
+ """Get the API reference template."""
45
+ return """# API Reference
46
+
47
+ ## Overview
48
+ $overview
49
+
50
+ ## Protocols
51
+ $protocols_section
52
+
53
+ ## Services
54
+ $services_section
55
+
56
+ ## Managers
57
+ $managers_section
58
+
59
+ ## Generated on: $timestamp
60
+ """
61
+
62
+ def _get_function_doc_template(self) -> str:
63
+ """Get the function documentation template."""
64
+ return """### $name
65
+
66
+ $description
67
+
68
+ **Parameters:**
69
+ $parameters
70
+
71
+ **Returns:** $returns
72
+
73
+ **Example:**
74
+ ```python
75
+ $example
76
+ ```
77
+
78
+ """
79
+
80
+ def _get_class_doc_template(self) -> str:
81
+ """Get the class documentation template."""
82
+ return """## $name
83
+
84
+ $description
85
+
86
+ **Base Classes:** $base_classes
87
+
88
+ ### Methods
89
+
90
+ $methods
91
+
92
+ """
93
+
94
+ def _get_protocol_doc_template(self) -> str:
95
+ """Get the protocol documentation template."""
96
+ return """## $name (Protocol)
97
+
98
+ $description
99
+
100
+ **Runtime Checkable:** $runtime_checkable
101
+
102
+ ### Required Methods
103
+
104
+ $methods
105
+
106
+ """
107
+
108
+ def _get_module_doc_template(self) -> str:
109
+ """Get the module documentation template."""
110
+ return """# $module_name
111
+
112
+ $description
113
+
114
+ ## Classes
115
+
116
+ $classes
117
+
118
+ ## Functions
119
+
120
+ $functions
121
+
122
+ """
123
+
124
+
125
+ class DocumentationGeneratorImpl(DocumentationGeneratorProtocol):
126
+ """Implementation of documentation generation from extracted API data."""
127
+
128
+ def __init__(self, console: Console) -> None:
129
+ self.console = console
130
+ self.renderer = MarkdownTemplateRenderer()
131
+
132
+ def generate_api_reference(self, api_data: dict[str, t.Any]) -> str:
133
+ """Generate complete API reference documentation."""
134
+ overview = self._generate_overview(api_data)
135
+ protocols_section = self._generate_protocols_section(
136
+ api_data.get("protocols", {})
137
+ )
138
+ services_section = self._generate_services_section(api_data.get("services", {}))
139
+ managers_section = self._generate_managers_section(api_data.get("managers", {}))
140
+
141
+ from datetime import datetime
142
+
143
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
144
+
145
+ context = {
146
+ "overview": overview,
147
+ "protocols_section": protocols_section,
148
+ "services_section": services_section,
149
+ "managers_section": managers_section,
150
+ "timestamp": timestamp,
151
+ }
152
+
153
+ return self.renderer.render_template("api_reference", context)
154
+
155
+ def generate_user_guide(self, template_context: dict[str, t.Any]) -> str:
156
+ """Generate user guide documentation."""
157
+ sections: list[str] = []
158
+
159
+ # Generate getting started section
160
+ if "installation" in template_context:
161
+ sections.extend(
162
+ ("## Getting Started\n", template_context["installation"], "\n")
163
+ )
164
+
165
+ # Generate usage examples
166
+ if "examples" in template_context:
167
+ sections.append("## Usage Examples\n")
168
+ for example in template_context["examples"]:
169
+ sections.extend(
170
+ (
171
+ f"### {example.get('title', 'Example')}\n",
172
+ f"{example.get('description', '')}\n",
173
+ )
174
+ )
175
+ if "code" in example:
176
+ sections.append(f"```bash\n{example['code']}\n```\n")
177
+ sections.append("\n")
178
+
179
+ # Generate configuration section
180
+ if "configuration" in template_context:
181
+ sections.extend(
182
+ ("## Configuration\n", template_context["configuration"], "\n")
183
+ )
184
+
185
+ return "".join(sections)
186
+
187
+ def generate_changelog_update(self, version: str, changes: dict[str, t.Any]) -> str:
188
+ """Generate changelog entry for a version."""
189
+ from datetime import datetime
190
+
191
+ today = datetime.now().strftime("%Y-%m-%d")
192
+
193
+ lines = [f"## [{version}] - {today}\n"]
194
+
195
+ # Order sections by importance
196
+ section_order = [
197
+ ("Added", "added"),
198
+ ("Changed", "changed"),
199
+ ("Fixed", "fixed"),
200
+ ("Removed", "removed"),
201
+ ("Security", "security"),
202
+ ("Deprecated", "deprecated"),
203
+ ]
204
+
205
+ for section_title, section_key in section_order:
206
+ if section_key in changes and changes[section_key]:
207
+ lines.append(f"### {section_title}\n")
208
+ for change in changes[section_key]:
209
+ lines.append(f"- {change}\n")
210
+ lines.append("\n")
211
+
212
+ return "".join(lines)
213
+
214
+ def render_template(self, template_path: Path, context: dict[str, t.Any]) -> str:
215
+ """Render a template file with the given context."""
216
+ if not template_path.exists():
217
+ raise FileNotFoundError(f"Template not found: {template_path}")
218
+
219
+ content = template_path.read_text(encoding="utf-8")
220
+ template = Template(content)
221
+ return template.safe_substitute(context)
222
+
223
+ def generate_cross_references(
224
+ self, api_data: dict[str, t.Any]
225
+ ) -> dict[str, list[str]]:
226
+ """Generate cross-reference mappings for API components."""
227
+ cross_refs = {}
228
+
229
+ # Extract all API names
230
+ all_names = set()
231
+
232
+ # Add protocol names
233
+ protocols = api_data.get("protocols", {})
234
+ all_names.update(protocols.keys())
235
+
236
+ # Add class names from modules
237
+ modules = api_data.get("modules", {})
238
+ for module_data in modules.values():
239
+ all_names.update(
240
+ class_info["name"] for class_info in module_data.get("classes", [])
241
+ )
242
+ all_names.update(
243
+ func_info["name"] for func_info in module_data.get("functions", [])
244
+ )
245
+
246
+ # Generate cross-references by finding mentions
247
+ for name in all_names:
248
+ refs = self._find_references_to_name(name, api_data)
249
+ if refs:
250
+ cross_refs[name] = refs
251
+
252
+ return cross_refs
253
+
254
+ def _generate_overview(self, api_data: dict[str, t.Any]) -> str:
255
+ """Generate overview section for API documentation."""
256
+ stats = self._calculate_api_stats(api_data)
257
+
258
+ overview_lines = [
259
+ "This document provides comprehensive API reference for all protocols, services, and managers in the codebase.\n",
260
+ f"**Total Protocols:** {stats['protocols']}\n",
261
+ f"**Total Classes:** {stats['classes']}\n",
262
+ f"**Total Functions:** {stats['functions']}\n",
263
+ f"**Total Modules:** {stats['modules']}\n",
264
+ ]
265
+
266
+ return "".join(overview_lines)
267
+
268
+ def _generate_protocols_section(self, protocols: dict[str, t.Any]) -> str:
269
+ """Generate the protocols section of API documentation."""
270
+ if not protocols:
271
+ return "No protocols found.\n"
272
+
273
+ sections = []
274
+ for protocol_name, protocol_info in protocols.items():
275
+ context = {
276
+ "name": protocol_name,
277
+ "description": protocol_info.get("docstring", {}).get(
278
+ "description", "No description provided."
279
+ ),
280
+ "runtime_checkable": "Yes"
281
+ if protocol_info.get("runtime_checkable", False)
282
+ else "No",
283
+ "methods": self._format_methods(protocol_info.get("methods", [])),
284
+ }
285
+ sections.append(self.renderer.render_template("protocol_doc", context))
286
+
287
+ return "".join(sections)
288
+
289
+ def _generate_services_section(self, services: dict[str, t.Any]) -> str:
290
+ """Generate the services section of API documentation."""
291
+ if not services:
292
+ return "No services found.\n"
293
+
294
+ sections: list[str] = []
295
+ for service_name, service_info in services.items():
296
+ sections.extend(
297
+ (
298
+ f"## {service_name}\n",
299
+ f"**Path:** `{service_info.get('path', 'Unknown')}`\n\n",
300
+ )
301
+ )
302
+
303
+ if service_info.get("protocols_implemented"):
304
+ sections.append("**Implements Protocols:**\n")
305
+ for protocol in service_info["protocols_implemented"]:
306
+ sections.append(f"- {protocol}\n")
307
+ sections.append("\n")
308
+
309
+ # Add classes from this service
310
+ for class_info in service_info.get("classes", []):
311
+ context = {
312
+ "name": class_info["name"],
313
+ "description": class_info.get("docstring", {}).get(
314
+ "description", "No description provided."
315
+ ),
316
+ "base_classes": ", ".join(class_info.get("base_classes", []))
317
+ or "None",
318
+ "methods": self._format_methods(class_info.get("methods", [])),
319
+ }
320
+ sections.append(self.renderer.render_template("class_doc", context))
321
+
322
+ return "".join(sections)
323
+
324
+ def _generate_managers_section(self, managers: dict[str, t.Any]) -> str:
325
+ """Generate the managers section of API documentation."""
326
+ # Similar to services but focused on manager-specific functionality
327
+ return self._generate_services_section(managers) # Reuse services logic for now
328
+
329
+ def _format_methods(self, methods: list[dict[str, t.Any]]) -> str:
330
+ """Format method information for documentation."""
331
+ if not methods:
332
+ return "No methods defined.\n"
333
+
334
+ formatted_methods = []
335
+ for method in methods:
336
+ method_lines = [f"#### `{method['name']}`\n"]
337
+
338
+ # Add description
339
+ description = method.get("docstring", {}).get(
340
+ "description", "No description provided."
341
+ )
342
+ method_lines.append(f"{description}\n")
343
+
344
+ # Add parameters
345
+ parameters = method.get("parameters", [])
346
+ if parameters:
347
+ method_lines.append("**Parameters:**\n")
348
+ for param in parameters:
349
+ param_type = param.get("annotation", "Any")
350
+ param_desc = param.get("description", "No description")
351
+ method_lines.append(
352
+ f"- `{param['name']}` ({param_type}): {param_desc}\n"
353
+ )
354
+
355
+ # Add return type
356
+ return_annotation = method.get("return_annotation", "")
357
+ if return_annotation:
358
+ method_lines.append(f"**Returns:** {return_annotation}\n")
359
+
360
+ method_lines.append("\n")
361
+ formatted_methods.append("".join(method_lines))
362
+
363
+ return "".join(formatted_methods)
364
+
365
+ def _calculate_api_stats(self, api_data: dict[str, t.Any]) -> dict[str, int]:
366
+ """Calculate statistics about the API data."""
367
+ stats = {"protocols": 0, "classes": 0, "functions": 0, "modules": 0}
368
+
369
+ # Count protocols
370
+ protocols = api_data.get("protocols", {})
371
+ stats["protocols"] = len(protocols)
372
+
373
+ # Count modules, classes, and functions
374
+ modules = api_data.get("modules", {})
375
+ stats["modules"] = len(modules)
376
+
377
+ for module_data in modules.values():
378
+ stats["classes"] += len(module_data.get("classes", []))
379
+ stats["functions"] += len(module_data.get("functions", []))
380
+
381
+ return stats
382
+
383
+ def _find_references_to_name(
384
+ self, name: str, api_data: dict[str, t.Any]
385
+ ) -> list[str]:
386
+ """Find all places where an API component is referenced."""
387
+ references = []
388
+
389
+ # Search in protocols
390
+ protocol_refs = self._find_protocol_references(
391
+ name, api_data.get("protocols", {})
392
+ )
393
+ references.extend(protocol_refs)
394
+
395
+ # Search in modules/classes
396
+ module_refs = self._find_module_references(name, api_data.get("modules", {}))
397
+ references.extend(module_refs)
398
+
399
+ return references
400
+
401
+ def _find_protocol_references(
402
+ self, name: str, protocols: dict[str, t.Any]
403
+ ) -> list[str]:
404
+ """Find references in protocol definitions."""
405
+ references = []
406
+
407
+ for protocol_name, protocol_info in protocols.items():
408
+ method_refs = self._find_protocol_method_references(
409
+ name, protocol_name, protocol_info.get("methods", [])
410
+ )
411
+ references.extend(method_refs)
412
+
413
+ return references
414
+
415
+ def _find_protocol_method_references(
416
+ self, name: str, protocol_name: str, methods: list[dict[str, t.Any]]
417
+ ) -> list[str]:
418
+ """Find references in protocol method signatures."""
419
+ references = []
420
+
421
+ for method in methods:
422
+ # Check parameters
423
+ param_refs = self._find_method_parameter_references(
424
+ name,
425
+ f"{protocol_name}.{method['name']}()",
426
+ method.get("parameters", []),
427
+ )
428
+ references.extend(param_refs)
429
+
430
+ # Check return type
431
+ if name in method.get("return_annotation", ""):
432
+ references.append(f"{protocol_name}.{method['name']}() return type")
433
+
434
+ return references
435
+
436
+ def _find_module_references(
437
+ self, name: str, modules: dict[str, t.Any]
438
+ ) -> list[str]:
439
+ """Find references in module class definitions."""
440
+ references = []
441
+
442
+ for module_data in modules.values():
443
+ class_refs = self._find_class_references(
444
+ name, module_data.get("classes", [])
445
+ )
446
+ references.extend(class_refs)
447
+
448
+ return references
449
+
450
+ def _find_class_references(
451
+ self, name: str, classes: list[dict[str, t.Any]]
452
+ ) -> list[str]:
453
+ """Find references in class definitions."""
454
+ references = []
455
+
456
+ for class_info in classes:
457
+ # Check base classes
458
+ if name in class_info.get("base_classes", []):
459
+ references.append(f"{class_info['name']} base class")
460
+
461
+ # Check method signatures
462
+ method_refs = self._find_class_method_references(
463
+ name, class_info["name"], class_info.get("methods", [])
464
+ )
465
+ references.extend(method_refs)
466
+
467
+ return references
468
+
469
+ def _find_class_method_references(
470
+ self, name: str, class_name: str, methods: list[dict[str, t.Any]]
471
+ ) -> list[str]:
472
+ """Find references in class method signatures."""
473
+ references = []
474
+
475
+ for method in methods:
476
+ param_refs = self._find_method_parameter_references(
477
+ name, f"{class_name}.{method['name']}()", method.get("parameters", [])
478
+ )
479
+ references.extend(param_refs)
480
+
481
+ return references
482
+
483
+ def _find_method_parameter_references(
484
+ self, name: str, method_name: str, parameters: list[dict[str, t.Any]]
485
+ ) -> list[str]:
486
+ """Find references in method parameters."""
487
+ return [
488
+ f"{method_name} parameter"
489
+ for param in parameters
490
+ if name in param.get("annotation", "")
491
+ ]