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.
- crackerjack/__main__.py +1350 -34
- crackerjack/adapters/__init__.py +17 -0
- crackerjack/adapters/lsp_client.py +358 -0
- crackerjack/adapters/rust_tool_adapter.py +194 -0
- crackerjack/adapters/rust_tool_manager.py +193 -0
- crackerjack/adapters/skylos_adapter.py +231 -0
- crackerjack/adapters/zuban_adapter.py +560 -0
- crackerjack/agents/base.py +7 -3
- crackerjack/agents/coordinator.py +271 -33
- crackerjack/agents/documentation_agent.py +9 -15
- crackerjack/agents/dry_agent.py +3 -15
- crackerjack/agents/formatting_agent.py +1 -1
- crackerjack/agents/import_optimization_agent.py +36 -180
- crackerjack/agents/performance_agent.py +17 -98
- crackerjack/agents/performance_helpers.py +7 -31
- crackerjack/agents/proactive_agent.py +1 -3
- crackerjack/agents/refactoring_agent.py +16 -85
- crackerjack/agents/refactoring_helpers.py +7 -42
- crackerjack/agents/security_agent.py +9 -48
- crackerjack/agents/test_creation_agent.py +356 -513
- crackerjack/agents/test_specialist_agent.py +0 -4
- crackerjack/api.py +6 -25
- crackerjack/cli/cache_handlers.py +204 -0
- crackerjack/cli/cache_handlers_enhanced.py +683 -0
- crackerjack/cli/facade.py +100 -0
- crackerjack/cli/handlers.py +224 -9
- crackerjack/cli/interactive.py +6 -4
- crackerjack/cli/options.py +642 -55
- crackerjack/cli/utils.py +2 -1
- crackerjack/code_cleaner.py +58 -117
- crackerjack/config/global_lock_config.py +8 -48
- crackerjack/config/hooks.py +53 -62
- crackerjack/core/async_workflow_orchestrator.py +24 -34
- crackerjack/core/autofix_coordinator.py +3 -17
- crackerjack/core/enhanced_container.py +4 -13
- crackerjack/core/file_lifecycle.py +12 -89
- crackerjack/core/performance.py +2 -2
- crackerjack/core/performance_monitor.py +15 -55
- crackerjack/core/phase_coordinator.py +104 -204
- crackerjack/core/resource_manager.py +14 -90
- crackerjack/core/service_watchdog.py +62 -95
- crackerjack/core/session_coordinator.py +149 -0
- crackerjack/core/timeout_manager.py +14 -72
- crackerjack/core/websocket_lifecycle.py +13 -78
- crackerjack/core/workflow_orchestrator.py +171 -174
- crackerjack/docs/INDEX.md +11 -0
- crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
- crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
- crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
- crackerjack/docs/generated/api/SERVICES.md +1252 -0
- crackerjack/documentation/__init__.py +31 -0
- crackerjack/documentation/ai_templates.py +756 -0
- crackerjack/documentation/dual_output_generator.py +765 -0
- crackerjack/documentation/mkdocs_integration.py +518 -0
- crackerjack/documentation/reference_generator.py +977 -0
- crackerjack/dynamic_config.py +55 -50
- crackerjack/executors/async_hook_executor.py +10 -15
- crackerjack/executors/cached_hook_executor.py +117 -43
- crackerjack/executors/hook_executor.py +8 -34
- crackerjack/executors/hook_lock_manager.py +26 -183
- crackerjack/executors/individual_hook_executor.py +13 -11
- crackerjack/executors/lsp_aware_hook_executor.py +270 -0
- crackerjack/executors/tool_proxy.py +417 -0
- crackerjack/hooks/lsp_hook.py +79 -0
- crackerjack/intelligence/adaptive_learning.py +25 -10
- crackerjack/intelligence/agent_orchestrator.py +2 -5
- crackerjack/intelligence/agent_registry.py +34 -24
- crackerjack/intelligence/agent_selector.py +5 -7
- crackerjack/interactive.py +17 -6
- crackerjack/managers/async_hook_manager.py +0 -1
- crackerjack/managers/hook_manager.py +79 -1
- crackerjack/managers/publish_manager.py +44 -8
- crackerjack/managers/test_command_builder.py +1 -15
- crackerjack/managers/test_executor.py +1 -3
- crackerjack/managers/test_manager.py +98 -7
- crackerjack/managers/test_manager_backup.py +10 -9
- crackerjack/mcp/cache.py +2 -2
- crackerjack/mcp/client_runner.py +1 -1
- crackerjack/mcp/context.py +191 -68
- crackerjack/mcp/dashboard.py +7 -5
- crackerjack/mcp/enhanced_progress_monitor.py +31 -28
- crackerjack/mcp/file_monitor.py +30 -23
- crackerjack/mcp/progress_components.py +31 -21
- crackerjack/mcp/progress_monitor.py +50 -53
- crackerjack/mcp/rate_limiter.py +6 -6
- crackerjack/mcp/server_core.py +17 -16
- crackerjack/mcp/service_watchdog.py +2 -1
- crackerjack/mcp/state.py +4 -7
- crackerjack/mcp/task_manager.py +11 -9
- crackerjack/mcp/tools/core_tools.py +173 -32
- crackerjack/mcp/tools/error_analyzer.py +3 -2
- crackerjack/mcp/tools/execution_tools.py +8 -10
- crackerjack/mcp/tools/execution_tools_backup.py +42 -30
- crackerjack/mcp/tools/intelligence_tool_registry.py +7 -5
- crackerjack/mcp/tools/intelligence_tools.py +5 -2
- crackerjack/mcp/tools/monitoring_tools.py +33 -70
- crackerjack/mcp/tools/proactive_tools.py +24 -11
- crackerjack/mcp/tools/progress_tools.py +5 -8
- crackerjack/mcp/tools/utility_tools.py +20 -14
- crackerjack/mcp/tools/workflow_executor.py +62 -40
- crackerjack/mcp/websocket/app.py +8 -0
- crackerjack/mcp/websocket/endpoints.py +352 -357
- crackerjack/mcp/websocket/jobs.py +40 -57
- crackerjack/mcp/websocket/monitoring_endpoints.py +2935 -0
- crackerjack/mcp/websocket/server.py +7 -25
- crackerjack/mcp/websocket/websocket_handler.py +6 -17
- crackerjack/mixins/__init__.py +0 -2
- crackerjack/mixins/error_handling.py +1 -70
- crackerjack/models/config.py +12 -1
- crackerjack/models/config_adapter.py +49 -1
- crackerjack/models/protocols.py +122 -122
- crackerjack/models/resource_protocols.py +55 -210
- crackerjack/monitoring/ai_agent_watchdog.py +13 -13
- crackerjack/monitoring/metrics_collector.py +426 -0
- crackerjack/monitoring/regression_prevention.py +8 -8
- crackerjack/monitoring/websocket_server.py +643 -0
- crackerjack/orchestration/advanced_orchestrator.py +11 -6
- crackerjack/orchestration/coverage_improvement.py +3 -3
- crackerjack/orchestration/execution_strategies.py +26 -6
- crackerjack/orchestration/test_progress_streamer.py +8 -5
- crackerjack/plugins/base.py +2 -2
- crackerjack/plugins/hooks.py +7 -0
- crackerjack/plugins/managers.py +11 -8
- crackerjack/security/__init__.py +0 -1
- crackerjack/security/audit.py +6 -35
- crackerjack/services/anomaly_detector.py +392 -0
- crackerjack/services/api_extractor.py +615 -0
- crackerjack/services/backup_service.py +2 -2
- crackerjack/services/bounded_status_operations.py +15 -152
- crackerjack/services/cache.py +127 -1
- crackerjack/services/changelog_automation.py +395 -0
- crackerjack/services/config.py +15 -9
- crackerjack/services/config_merge.py +19 -80
- crackerjack/services/config_template.py +506 -0
- crackerjack/services/contextual_ai_assistant.py +48 -22
- crackerjack/services/coverage_badge_service.py +171 -0
- crackerjack/services/coverage_ratchet.py +27 -25
- crackerjack/services/debug.py +3 -3
- crackerjack/services/dependency_analyzer.py +460 -0
- crackerjack/services/dependency_monitor.py +14 -11
- crackerjack/services/documentation_generator.py +491 -0
- crackerjack/services/documentation_service.py +675 -0
- crackerjack/services/enhanced_filesystem.py +6 -5
- crackerjack/services/enterprise_optimizer.py +865 -0
- crackerjack/services/error_pattern_analyzer.py +676 -0
- crackerjack/services/file_hasher.py +1 -1
- crackerjack/services/git.py +8 -25
- crackerjack/services/health_metrics.py +10 -8
- crackerjack/services/heatmap_generator.py +735 -0
- crackerjack/services/initialization.py +11 -30
- crackerjack/services/input_validator.py +5 -97
- crackerjack/services/intelligent_commit.py +327 -0
- crackerjack/services/log_manager.py +15 -12
- crackerjack/services/logging.py +4 -3
- crackerjack/services/lsp_client.py +628 -0
- crackerjack/services/memory_optimizer.py +19 -87
- crackerjack/services/metrics.py +42 -33
- crackerjack/services/parallel_executor.py +9 -67
- crackerjack/services/pattern_cache.py +1 -1
- crackerjack/services/pattern_detector.py +6 -6
- crackerjack/services/performance_benchmarks.py +18 -59
- crackerjack/services/performance_cache.py +20 -81
- crackerjack/services/performance_monitor.py +27 -95
- crackerjack/services/predictive_analytics.py +510 -0
- crackerjack/services/quality_baseline.py +234 -0
- crackerjack/services/quality_baseline_enhanced.py +646 -0
- crackerjack/services/quality_intelligence.py +785 -0
- crackerjack/services/regex_patterns.py +605 -524
- crackerjack/services/regex_utils.py +43 -123
- crackerjack/services/secure_path_utils.py +5 -164
- crackerjack/services/secure_status_formatter.py +30 -141
- crackerjack/services/secure_subprocess.py +11 -92
- crackerjack/services/security.py +9 -41
- crackerjack/services/security_logger.py +12 -24
- crackerjack/services/server_manager.py +124 -16
- crackerjack/services/status_authentication.py +16 -159
- crackerjack/services/status_security_manager.py +4 -131
- crackerjack/services/thread_safe_status_collector.py +19 -125
- crackerjack/services/unified_config.py +21 -13
- crackerjack/services/validation_rate_limiter.py +5 -54
- crackerjack/services/version_analyzer.py +459 -0
- crackerjack/services/version_checker.py +1 -1
- crackerjack/services/websocket_resource_limiter.py +10 -144
- crackerjack/services/zuban_lsp_service.py +390 -0
- crackerjack/slash_commands/__init__.py +2 -7
- crackerjack/slash_commands/run.md +2 -2
- crackerjack/tools/validate_input_validator_patterns.py +14 -40
- crackerjack/tools/validate_regex_patterns.py +19 -48
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/METADATA +196 -25
- crackerjack-0.33.1.dist-info/RECORD +229 -0
- crackerjack/CLAUDE.md +0 -207
- crackerjack/RULES.md +0 -380
- crackerjack/py313.py +0 -234
- crackerjack-0.33.0.dist-info/RECORD +0 -187
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/WHEEL +0 -0
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
"""MkDocs integration system for crackerjack documentation generation.
|
|
2
|
+
|
|
3
|
+
This module provides seamless integration with MkDocs for generating comprehensive
|
|
4
|
+
documentation websites with automatic configuration and content management.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import typing as t
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import yaml
|
|
13
|
+
|
|
14
|
+
from ..models.protocols import (
|
|
15
|
+
ConfigManagerProtocol,
|
|
16
|
+
FileSystemServiceProtocol,
|
|
17
|
+
LoggerProtocol,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class MkDocsConfig:
|
|
23
|
+
"""Configuration for MkDocs site generation."""
|
|
24
|
+
|
|
25
|
+
site_name: str
|
|
26
|
+
site_description: str
|
|
27
|
+
site_author: str
|
|
28
|
+
site_url: str | None = None
|
|
29
|
+
repo_url: str | None = None
|
|
30
|
+
theme: str = "material"
|
|
31
|
+
nav_structure: dict[str, str] | None = None
|
|
32
|
+
plugins: list[str] | None = None
|
|
33
|
+
extra_css: list[str] | None = None
|
|
34
|
+
extra_javascript: list[str] | None = None
|
|
35
|
+
markdown_extensions: list[str] | None = None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class DocumentationSite:
|
|
40
|
+
"""Represents a complete documentation site."""
|
|
41
|
+
|
|
42
|
+
config: MkDocsConfig
|
|
43
|
+
pages: dict[str, str]
|
|
44
|
+
assets: dict[str, bytes]
|
|
45
|
+
generated_at: datetime
|
|
46
|
+
build_path: Path | None = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class MkDocsIntegrationService:
|
|
50
|
+
"""Service for integrating with MkDocs documentation generation."""
|
|
51
|
+
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
config_manager: ConfigManagerProtocol,
|
|
55
|
+
filesystem: FileSystemServiceProtocol,
|
|
56
|
+
logger: LoggerProtocol,
|
|
57
|
+
):
|
|
58
|
+
self.config_manager = config_manager
|
|
59
|
+
self.filesystem = filesystem
|
|
60
|
+
self.logger = logger
|
|
61
|
+
self._default_theme_config = self._get_default_theme_config()
|
|
62
|
+
|
|
63
|
+
async def generate_site(
|
|
64
|
+
self,
|
|
65
|
+
docs_content: dict[str, str],
|
|
66
|
+
config: MkDocsConfig,
|
|
67
|
+
output_dir: Path,
|
|
68
|
+
) -> DocumentationSite:
|
|
69
|
+
"""Generate a complete MkDocs site from documentation content.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
docs_content: Dictionary mapping file paths to content
|
|
73
|
+
config: MkDocs configuration settings
|
|
74
|
+
output_dir: Directory to generate site in
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Generated documentation site information
|
|
78
|
+
"""
|
|
79
|
+
self.logger.info(f"Generating MkDocs site: {config.site_name}")
|
|
80
|
+
|
|
81
|
+
# Create site structure
|
|
82
|
+
site_dir = output_dir / "site"
|
|
83
|
+
docs_dir = site_dir / "docs"
|
|
84
|
+
|
|
85
|
+
self.filesystem.ensure_directory(site_dir)
|
|
86
|
+
self.filesystem.ensure_directory(docs_dir)
|
|
87
|
+
|
|
88
|
+
# Generate mkdocs.yml
|
|
89
|
+
mkdocs_config = self._create_mkdocs_config(config, docs_content)
|
|
90
|
+
config_path = site_dir / "mkdocs.yml"
|
|
91
|
+
self.filesystem.write_file(
|
|
92
|
+
config_path,
|
|
93
|
+
yaml.dump(mkdocs_config, default_flow_style=False, sort_keys=False),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Write documentation files
|
|
97
|
+
pages = {}
|
|
98
|
+
for file_path, content in docs_content.items():
|
|
99
|
+
doc_path = docs_dir / file_path
|
|
100
|
+
self.filesystem.ensure_directory(doc_path.parent)
|
|
101
|
+
self.filesystem.write_file(doc_path, content)
|
|
102
|
+
pages[file_path] = content
|
|
103
|
+
|
|
104
|
+
# Copy theme assets if needed
|
|
105
|
+
assets = await self._copy_theme_assets(site_dir, config.theme)
|
|
106
|
+
|
|
107
|
+
site = DocumentationSite(
|
|
108
|
+
config=config,
|
|
109
|
+
pages=pages,
|
|
110
|
+
assets=assets,
|
|
111
|
+
generated_at=datetime.now(),
|
|
112
|
+
build_path=site_dir,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
self.logger.info(f"Generated MkDocs site at: {site_dir}")
|
|
116
|
+
return site
|
|
117
|
+
|
|
118
|
+
async def build_site(self, site: DocumentationSite, serve: bool = False) -> bool:
|
|
119
|
+
"""Build the MkDocs site to static HTML.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
site: Documentation site to build
|
|
123
|
+
serve: Whether to start development server
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
True if build successful, False otherwise
|
|
127
|
+
"""
|
|
128
|
+
if not site.build_path:
|
|
129
|
+
self.logger.error("Site has no build path set[t.Any]")
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
# Build command
|
|
134
|
+
build_cmd = ["mkdocs", "build"]
|
|
135
|
+
if serve:
|
|
136
|
+
build_cmd = ["mkdocs", "serve", "--dev-addr", "127.0.0.1:8000"]
|
|
137
|
+
|
|
138
|
+
# Run in site directory
|
|
139
|
+
import subprocess
|
|
140
|
+
|
|
141
|
+
result = subprocess.run(
|
|
142
|
+
build_cmd,
|
|
143
|
+
cwd=site.build_path,
|
|
144
|
+
capture_output=True,
|
|
145
|
+
text=True,
|
|
146
|
+
check=False,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
if result.returncode != 0:
|
|
150
|
+
self.logger.error(f"MkDocs build failed: {result.stderr}")
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
if serve:
|
|
154
|
+
self.logger.info(
|
|
155
|
+
"MkDocs development server started at http://127.0.0.1:8000"
|
|
156
|
+
)
|
|
157
|
+
else:
|
|
158
|
+
self.logger.info("MkDocs site built successfully")
|
|
159
|
+
|
|
160
|
+
return True
|
|
161
|
+
|
|
162
|
+
except Exception as e:
|
|
163
|
+
self.logger.error(f"Failed to build MkDocs site: {e}")
|
|
164
|
+
return False
|
|
165
|
+
|
|
166
|
+
def create_config_from_project(
|
|
167
|
+
self,
|
|
168
|
+
project_name: str,
|
|
169
|
+
project_description: str,
|
|
170
|
+
author: str,
|
|
171
|
+
repo_url: str | None = None,
|
|
172
|
+
) -> MkDocsConfig:
|
|
173
|
+
"""Create MkDocs configuration from project metadata.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
project_name: Name of the project
|
|
177
|
+
project_description: Description of the project
|
|
178
|
+
author: Project author
|
|
179
|
+
repo_url: Repository URL if available
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
Configured MkDocsConfig instance
|
|
183
|
+
"""
|
|
184
|
+
return MkDocsConfig(
|
|
185
|
+
site_name=project_name,
|
|
186
|
+
site_description=project_description,
|
|
187
|
+
site_author=author,
|
|
188
|
+
repo_url=repo_url,
|
|
189
|
+
theme="material",
|
|
190
|
+
nav_structure=self._get_default_nav_structure(),
|
|
191
|
+
plugins=self._get_default_plugins(),
|
|
192
|
+
markdown_extensions=self._get_default_extensions(),
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
def _create_mkdocs_config(
|
|
196
|
+
self,
|
|
197
|
+
config: MkDocsConfig,
|
|
198
|
+
docs_content: dict[str, str],
|
|
199
|
+
) -> dict[str, t.Any]:
|
|
200
|
+
"""Create mkdocs.yml configuration dictionary.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
config: MkDocs configuration
|
|
204
|
+
docs_content: Documentation content for nav generation
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
Configuration dictionary for mkdocs.yml
|
|
208
|
+
"""
|
|
209
|
+
mkdocs_config: dict[str, t.Any] = {
|
|
210
|
+
"site_name": config.site_name,
|
|
211
|
+
"site_description": config.site_description,
|
|
212
|
+
"site_author": config.site_author,
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if config.site_url:
|
|
216
|
+
mkdocs_config["site_url"] = config.site_url
|
|
217
|
+
|
|
218
|
+
if config.repo_url:
|
|
219
|
+
mkdocs_config["repo_url"] = config.repo_url
|
|
220
|
+
mkdocs_config["repo_name"] = self._extract_repo_name(config.repo_url)
|
|
221
|
+
|
|
222
|
+
# Theme configuration
|
|
223
|
+
if config.theme == "material":
|
|
224
|
+
mkdocs_config["theme"] = {
|
|
225
|
+
"name": "material",
|
|
226
|
+
"features": [
|
|
227
|
+
"navigation.sections",
|
|
228
|
+
"navigation.expand",
|
|
229
|
+
"navigation.top",
|
|
230
|
+
"search.highlight",
|
|
231
|
+
"search.share",
|
|
232
|
+
],
|
|
233
|
+
"palette": [
|
|
234
|
+
{
|
|
235
|
+
"scheme": "default",
|
|
236
|
+
"primary": "blue",
|
|
237
|
+
"accent": "blue",
|
|
238
|
+
"toggle": {
|
|
239
|
+
"icon": "material/brightness-7",
|
|
240
|
+
"name": "Switch to dark mode",
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"scheme": "slate",
|
|
245
|
+
"primary": "blue",
|
|
246
|
+
"accent": "blue",
|
|
247
|
+
"toggle": {
|
|
248
|
+
"icon": "material/brightness-4",
|
|
249
|
+
"name": "Switch to light mode",
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
}
|
|
254
|
+
else:
|
|
255
|
+
mkdocs_config["theme"] = {"name": config.theme}
|
|
256
|
+
|
|
257
|
+
# Navigation
|
|
258
|
+
nav = config.nav_structure or self._generate_nav_from_content(docs_content)
|
|
259
|
+
if nav:
|
|
260
|
+
mkdocs_config["nav"] = nav
|
|
261
|
+
|
|
262
|
+
# Plugins
|
|
263
|
+
plugins = config.plugins or self._get_default_plugins()
|
|
264
|
+
if plugins:
|
|
265
|
+
mkdocs_config["plugins"] = plugins
|
|
266
|
+
|
|
267
|
+
# Markdown extensions
|
|
268
|
+
extensions = config.markdown_extensions or self._get_default_extensions()
|
|
269
|
+
if extensions:
|
|
270
|
+
mkdocs_config["markdown_extensions"] = extensions
|
|
271
|
+
|
|
272
|
+
# Extra CSS/JS
|
|
273
|
+
if config.extra_css:
|
|
274
|
+
mkdocs_config["extra_css"] = config.extra_css
|
|
275
|
+
|
|
276
|
+
if config.extra_javascript:
|
|
277
|
+
mkdocs_config["extra_javascript"] = config.extra_javascript
|
|
278
|
+
|
|
279
|
+
return mkdocs_config
|
|
280
|
+
|
|
281
|
+
def _get_default_theme_config(self) -> dict[str, t.Any]:
|
|
282
|
+
"""Get default theme configuration."""
|
|
283
|
+
return {
|
|
284
|
+
"material": {
|
|
285
|
+
"features": [
|
|
286
|
+
"navigation.sections",
|
|
287
|
+
"navigation.expand",
|
|
288
|
+
"navigation.top",
|
|
289
|
+
"search.highlight",
|
|
290
|
+
"search.share",
|
|
291
|
+
],
|
|
292
|
+
"palette": {
|
|
293
|
+
"scheme": "default",
|
|
294
|
+
"primary": "blue",
|
|
295
|
+
"accent": "blue",
|
|
296
|
+
},
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
def _get_default_nav_structure(self) -> dict[str, str]:
|
|
301
|
+
"""Get default navigation structure."""
|
|
302
|
+
return {
|
|
303
|
+
"Home": "index.md",
|
|
304
|
+
"Getting Started": "getting-started.md",
|
|
305
|
+
"User Guide": "user-guide.md",
|
|
306
|
+
"API Reference": "api-reference.md",
|
|
307
|
+
"Development": "development.md",
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
def _get_default_plugins(self) -> list[str]:
|
|
311
|
+
"""Get default MkDocs plugins."""
|
|
312
|
+
return [
|
|
313
|
+
"search",
|
|
314
|
+
"autorefs",
|
|
315
|
+
"mkdocstrings",
|
|
316
|
+
]
|
|
317
|
+
|
|
318
|
+
def _get_default_extensions(self) -> list[str]:
|
|
319
|
+
"""Get default Markdown extensions."""
|
|
320
|
+
return [
|
|
321
|
+
"markdown.extensions.toc",
|
|
322
|
+
"markdown.extensions.tables",
|
|
323
|
+
"markdown.extensions.fenced_code",
|
|
324
|
+
"markdown.extensions.codehilite",
|
|
325
|
+
"markdown.extensions.admonition",
|
|
326
|
+
"pymdownx.details",
|
|
327
|
+
"pymdownx.superfences",
|
|
328
|
+
"pymdownx.highlight",
|
|
329
|
+
"pymdownx.inlinehilite",
|
|
330
|
+
"pymdownx.snippets",
|
|
331
|
+
]
|
|
332
|
+
|
|
333
|
+
def _generate_nav_from_content(
|
|
334
|
+
self, docs_content: dict[str, str]
|
|
335
|
+
) -> list[dict[str, str]]:
|
|
336
|
+
"""Generate navigation structure from documentation content.
|
|
337
|
+
|
|
338
|
+
Args:
|
|
339
|
+
docs_content: Dictionary of file paths to content
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
Navigation structure list[t.Any]
|
|
343
|
+
"""
|
|
344
|
+
nav = []
|
|
345
|
+
|
|
346
|
+
# Sort files by logical order
|
|
347
|
+
sorted_files = sorted(docs_content.keys())
|
|
348
|
+
|
|
349
|
+
# Special handling for common files
|
|
350
|
+
priority_files = ["index.md", "README.md", "getting-started.md"]
|
|
351
|
+
regular_files = [f for f in sorted_files if f not in priority_files]
|
|
352
|
+
|
|
353
|
+
for priority_file in priority_files:
|
|
354
|
+
if priority_file in docs_content:
|
|
355
|
+
title = self._file_to_title(priority_file)
|
|
356
|
+
nav.append({title: priority_file})
|
|
357
|
+
|
|
358
|
+
for file_path in regular_files:
|
|
359
|
+
title = self._file_to_title(file_path)
|
|
360
|
+
nav.append({title: file_path})
|
|
361
|
+
|
|
362
|
+
return nav
|
|
363
|
+
|
|
364
|
+
def _file_to_title(self, file_path: str) -> str:
|
|
365
|
+
"""Convert file path to navigation title.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
file_path: File path to convert
|
|
369
|
+
|
|
370
|
+
Returns:
|
|
371
|
+
Human-readable title
|
|
372
|
+
"""
|
|
373
|
+
# Remove extension and directory path
|
|
374
|
+
name = Path(file_path).stem
|
|
375
|
+
|
|
376
|
+
# Convert various formats to title case
|
|
377
|
+
if name in ("index", "README"):
|
|
378
|
+
return "Home"
|
|
379
|
+
|
|
380
|
+
# Convert snake_case and kebab-case to Title Case
|
|
381
|
+
title = name.replace("_", " ").replace("-", " ")
|
|
382
|
+
title = " ".join(word.capitalize() for word in title.split())
|
|
383
|
+
|
|
384
|
+
return title
|
|
385
|
+
|
|
386
|
+
def _extract_repo_name(self, repo_url: str) -> str:
|
|
387
|
+
"""Extract repository name from URL.
|
|
388
|
+
|
|
389
|
+
Args:
|
|
390
|
+
repo_url: Repository URL
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
Repository name
|
|
394
|
+
"""
|
|
395
|
+
repo_url = repo_url.removesuffix(".git")
|
|
396
|
+
|
|
397
|
+
return repo_url.split("/")[-1]
|
|
398
|
+
|
|
399
|
+
async def _copy_theme_assets(
|
|
400
|
+
self,
|
|
401
|
+
site_dir: Path,
|
|
402
|
+
theme: str,
|
|
403
|
+
) -> dict[str, bytes]:
|
|
404
|
+
"""Copy theme-specific assets to site directory.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
site_dir: Site directory path
|
|
408
|
+
theme: Theme name
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
Dictionary of copied assets
|
|
412
|
+
"""
|
|
413
|
+
assets = {}
|
|
414
|
+
|
|
415
|
+
# For material theme, we might want to copy custom CSS
|
|
416
|
+
if theme == "material":
|
|
417
|
+
custom_css_content = self._get_material_custom_css()
|
|
418
|
+
if custom_css_content:
|
|
419
|
+
css_dir = site_dir / "docs" / "stylesheets"
|
|
420
|
+
self.filesystem.ensure_directory(css_dir)
|
|
421
|
+
css_path = css_dir / "extra.css"
|
|
422
|
+
self.filesystem.write_file(css_path, custom_css_content)
|
|
423
|
+
assets["stylesheets/extra.css"] = custom_css_content.encode()
|
|
424
|
+
|
|
425
|
+
return assets
|
|
426
|
+
|
|
427
|
+
def _get_material_custom_css(self) -> str:
|
|
428
|
+
"""Get custom CSS for Material theme.
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
Custom CSS content
|
|
432
|
+
"""
|
|
433
|
+
return """
|
|
434
|
+
/* Custom CSS for Crackerjack documentation */
|
|
435
|
+
.md-header {
|
|
436
|
+
background-color: var(--md-primary-fg-color--dark);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.md-nav__title {
|
|
440
|
+
font-weight: 700;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/* Code block improvements */
|
|
444
|
+
.md-typeset .codehilite,
|
|
445
|
+
.md-typeset .highlight {
|
|
446
|
+
margin: 1em 0;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/* Admonition styling */
|
|
450
|
+
.md-typeset .admonition {
|
|
451
|
+
border-radius: 0.2rem;
|
|
452
|
+
margin: 1.5625em 0;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/* Table improvements */
|
|
456
|
+
.md-typeset table:not([class]) {
|
|
457
|
+
font-size: 0.8rem;
|
|
458
|
+
}
|
|
459
|
+
"""
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
class MkDocsSiteBuilder:
|
|
463
|
+
"""High-level builder for MkDocs documentation sites."""
|
|
464
|
+
|
|
465
|
+
def __init__(self, integration_service: MkDocsIntegrationService) -> None:
|
|
466
|
+
self.integration = integration_service
|
|
467
|
+
|
|
468
|
+
async def build_documentation_site(
|
|
469
|
+
self,
|
|
470
|
+
project_name: str,
|
|
471
|
+
project_description: str,
|
|
472
|
+
author: str,
|
|
473
|
+
documentation_content: dict[str, str],
|
|
474
|
+
output_dir: Path,
|
|
475
|
+
repo_url: str | None = None,
|
|
476
|
+
serve: bool = False,
|
|
477
|
+
) -> DocumentationSite | None:
|
|
478
|
+
"""Build a complete documentation site.
|
|
479
|
+
|
|
480
|
+
Args:
|
|
481
|
+
project_name: Name of the project
|
|
482
|
+
project_description: Project description
|
|
483
|
+
author: Project author
|
|
484
|
+
documentation_content: Documentation content by file path
|
|
485
|
+
output_dir: Output directory for site
|
|
486
|
+
repo_url: Repository URL if available
|
|
487
|
+
serve: Whether to start development server
|
|
488
|
+
|
|
489
|
+
Returns:
|
|
490
|
+
Built documentation site or None if failed
|
|
491
|
+
"""
|
|
492
|
+
try:
|
|
493
|
+
# Create configuration
|
|
494
|
+
config = self.integration.create_config_from_project(
|
|
495
|
+
project_name=project_name,
|
|
496
|
+
project_description=project_description,
|
|
497
|
+
author=author,
|
|
498
|
+
repo_url=repo_url,
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
# Generate site
|
|
502
|
+
site = await self.integration.generate_site(
|
|
503
|
+
docs_content=documentation_content,
|
|
504
|
+
config=config,
|
|
505
|
+
output_dir=output_dir,
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
# Build site
|
|
509
|
+
success = await self.integration.build_site(site, serve=serve)
|
|
510
|
+
|
|
511
|
+
if success:
|
|
512
|
+
return site
|
|
513
|
+
else:
|
|
514
|
+
return None
|
|
515
|
+
|
|
516
|
+
except Exception as e:
|
|
517
|
+
self.integration.logger.error(f"Failed to build documentation site: {e}")
|
|
518
|
+
return None
|