Skip to content

Commit 77ed7a0

Browse files
refactor(docs): code analysis engine
changes: - file: cli.py area: cli added: [_run_check, _run_diff, check, diff] - file: _registry_adapters.py area: docs added: [ContributingAdapter, GettingStartedAdapter, ConfigDocsAdapter] modified: [run] - file: config_docs_gen.py area: config added: [ConfigDocsGenerator, generate, _render_section, _render_example, __init__] - file: contributing_gen.py area: docs added: [generate, _render_setup, _render_code_style, _render_testing, __init__, _render_pull_request, +3 more] - file: getting_started_gen.py area: docs added: [generate, _render_next_steps, _render_installation, __init__, _render_prerequisites, _render_first_usage, +2 more] - file: test_cli.py area: cli new_tests: 4 modified: [TestCLI] - file: test_generators.py area: test added: [TestGettingStartedGenerator, TestContributingGenerator, TestConfigDocsGenerator] new_tests: 10 - file: test_registry.py area: test added: [TestBaseGenerator, _AlwaysGenerator, TestGeneratorRegistry, should_run, TestAdapters, _DummyGenerator, +6 more] new_tests: 14 testing: new_tests: 28 scenarios: - diff_runs - check_help - diff_help - check_runs - contains_testing - contains_next_steps - contains_example_yaml - contains_nested_sections - contains_prerequisites - contains_top_level_options # +18 more dependencies: flow: "basic_usage→registry, _registry_adapters→getting_started_gen, entry_points→code2docs, cli→config" - cli.py -> config.py - cli.py -> registry.py - basic_usage.py -> registry.py - entry_points.py -> registry.py - entry_points.py -> code2docs.py - _registry_adapters.py -> getting_started_gen.py stats: lines: "+4620/-0 (net +4620)" files: 80 complexity: "Large structural change (normalized)"
1 parent 113c566 commit 77ed7a0

File tree

85 files changed

+4656
-5
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+4656
-5
lines changed

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.2.3] - 2026-03-07
11+
12+
### Docs
13+
- Update code2docs/README.md
14+
- Update code2docs/docs/api-changelog.md
15+
- Update code2docs/docs/api/index.md
16+
- Update code2docs/docs/api/module___main__.md
17+
- Update code2docs/docs/api/module_analyzers.md
18+
- Update code2docs/docs/api/module_analyzers_dependency_scanner.md
19+
- Update code2docs/docs/api/module_analyzers_docstring_extractor.md
20+
- Update code2docs/docs/api/module_analyzers_endpoint_detector.md
21+
- Update code2docs/docs/api/module_analyzers_project_scanner.md
22+
- Update code2docs/docs/api/module_base.md
23+
- ... and 58 more files
24+
25+
### Test
26+
- Update tests/test_cli.py
27+
- Update tests/test_generators.py
28+
- Update tests/test_registry.py
29+
30+
### Other
31+
- Update code2docs/cli.py
32+
- Update code2docs/examples/basic_usage.py
33+
- Update code2docs/examples/class_examples.py
34+
- Update code2docs/examples/entry_points.py
35+
- Update code2docs/generators/__init__.py
36+
- Update code2docs/generators/_registry_adapters.py
37+
- Update code2docs/generators/config_docs_gen.py
38+
- Update code2docs/generators/contributing_gen.py
39+
- Update code2docs/generators/getting_started_gen.py
40+
1041
## [0.2.2] - 2026-03-07
1142

1243
### Other

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# code2docs
22

3-
![version](https://img.shields.io/badge/version-0.2.2-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
3+
![version](https://img.shields.io/badge/version-0.2.3-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
44

55
> Auto-generate and sync project documentation from source code analysis.
66
@@ -140,7 +140,7 @@ code2docs can update only specific sections of an existing README using markers:
140140
```markdown
141141
<!-- code2docs:start --># code2docs
142142

143-
![version](https://img.shields.io/badge/version-0.2.2-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![coverage](https://img.shields.io/badge/coverage-unknown-lightgrey) ![functions](https://img.shields.io/badge/functions-153-green)
143+
![version](https://img.shields.io/badge/version-0.2.3-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![coverage](https://img.shields.io/badge/coverage-unknown-lightgrey) ![functions](https://img.shields.io/badge/functions-153-green)
144144
> **153** functions | **30** classes | **28** files | CC̄ = 0.0
145145

146146
## Installation

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.2.2
1+
0.2.3

code2docs/README.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<!-- code2docs:start --># code2docs
2+
3+
![version](https://img.shields.io/badge/version-0.1.0-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![coverage](https://img.shields.io/badge/coverage-unknown-lightgrey) ![functions](https://img.shields.io/badge/functions-185-green)
4+
> **185** functions | **42** classes | **31** files | CC̄ = 3.8
5+
6+
## Installation
7+
8+
```bash
9+
pip install .
10+
```
11+
12+
13+
## Quick Start
14+
15+
```python
16+
# Entry point: registry.GeneratorRegistry.__init__
17+
# Entry point: registry.GeneratorRegistry.add
18+
# Entry point: registry.GeneratorRegistry.run_all
19+
```
20+
21+
## API Overview
22+
23+
### Classes
24+
25+
- **`GeneratorRegistry`** — Registry of documentation generators.
26+
- **`Updater`** — Apply selective documentation updates based on detected changes.
27+
- **`ChangeInfo`** — Describes a detected change.
28+
- **`Differ`** — Detect changes between current source and previous state.
29+
- **`MarkdownFormatter`** — Helper for constructing Markdown documents.
30+
- **`ReadmeGenerator`** — Generate README.md from AnalysisResult.
31+
- **`CoverageGenerator`** — Generate docs/coverage.md — docstring coverage report.
32+
- **`DepGraphGenerator`** — Generate docs/dependency-graph.md with Mermaid diagrams.
33+
- **`GenerateContext`** — Shared context passed to all generators during a run.
34+
- **`BaseGenerator`** — Abstract base for all documentation generators.
35+
- **`ChangelogEntry`** — A single changelog entry.
36+
- **`ChangelogGenerator`** — Generate CHANGELOG.md from git log and analysis diff.
37+
- **`ApiReferenceGenerator`** — Generate docs/api/ — per-module API reference from signatures.
38+
- **`ModuleDocsGenerator`** — Generate docs/modules/ — detailed per-module documentation.
39+
- **`MkDocsGenerator`** — Generate mkdocs.yml from the docs/ directory structure.
40+
- **`ExamplesGenerator`** — Generate examples/ — usage examples from public API signatures.
41+
- **`ReadmeGeneratorAdapter`**
42+
- **`ApiReferenceAdapter`**
43+
- **`ModuleDocsAdapter`**
44+
- **`ArchitectureAdapter`**
45+
- **`DepGraphAdapter`**
46+
- **`CoverageAdapter`**
47+
- **`ApiChangelogAdapter`**
48+
- **`ExamplesAdapter`**
49+
- **`MkDocsAdapter`**
50+
- **`ArchitectureGenerator`** — Generate docs/architecture.md — architecture overview with diagrams.
51+
- **`ApiChange`** — A single API change between two analysis snapshots.
52+
- **`ApiChangelogGenerator`** — Generate API changelog by diffing current analysis with a saved snapshot.
53+
- **`DefaultGroup`** — Click Group that routes unknown subcommands to 'generate'.
54+
- **`ReadmeConfig`** — Configuration for README generation.
55+
- **`DocsConfig`** — Configuration for docs/ generation.
56+
- **`ExamplesConfig`** — Configuration for examples/ generation.
57+
- **`SyncConfig`** — Configuration for synchronization.
58+
- **`Code2DocsConfig`** — Main configuration for code2docs.
59+
- **`ProjectScanner`** — Wraps code2llm's ProjectAnalyzer with code2docs-specific defaults.
60+
- **`DocstringInfo`** — Parsed docstring with sections.
61+
- **`DocstringExtractor`** — Extract and parse docstrings from AnalysisResult.
62+
- **`DependencyInfo`** — Information about a project dependency.
63+
- **`ProjectDependencies`** — All detected project dependencies.
64+
- **`DependencyScanner`** — Scan and parse project dependency files.
65+
- **`Endpoint`** — Represents a detected web endpoint.
66+
- **`EndpointDetector`** — Detects web endpoints from decorator patterns in source code.
67+
68+
### Functions
69+
70+
- `start_watcher(project_path, config)` — Start watching project for file changes and auto-resync docs.
71+
- `generate_badges(project_name, badge_types, stats, deps)` — Generate shields.io badge Markdown strings.
72+
- `generate_toc(markdown_content, max_depth)` — Generate a table of contents from Markdown headings.
73+
- `extract_headings(content, max_depth)` — Extract headings from Markdown content.
74+
- `generate_readme(project_path, output, sections, sync_markers, config)` — Convenience function to generate a README.
75+
- `generate_docs(project_path, config)` — High-level function to generate all documentation.
76+
- `main()` — code2docs — Auto-generate project documentation from source code.
77+
- `generate(project_path, config_path, readme_only, sections, output, verbose, dry_run)` — Generate documentation (default command).
78+
- `sync(project_path, config_path, verbose, dry_run)` — Synchronize documentation with source code changes.
79+
- `watch(project_path, config_path, verbose)` — Watch for file changes and auto-regenerate docs.
80+
- `init(project_path, output)` — Initialize code2docs.yaml configuration file.
81+
- `analyze_and_document(project_path, config)` — Convenience function: analyze a project in one call.
82+
83+
## Project Structure
84+
85+
📄 `__main__`
86+
📦 `analyzers`
87+
📄 `analyzers.dependency_scanner` (6 functions, 3 classes)
88+
📄 `analyzers.docstring_extractor` (10 functions, 2 classes)
89+
📄 `analyzers.endpoint_detector` (3 functions, 2 classes)
90+
📄 `analyzers.project_scanner` (4 functions, 1 classes)
91+
📄 `base` (3 functions, 2 classes)
92+
📄 `cli` (10 functions, 1 classes)
93+
📦 `code2docs` (1 functions)
94+
📄 `config` (2 functions, 5 classes)
95+
📦 `formatters`
96+
📄 `formatters.badges` (2 functions)
97+
📄 `formatters.markdown` (13 functions, 1 classes)
98+
📄 `formatters.toc` (3 functions)
99+
📦 `generators` (1 functions)
100+
📄 `generators._registry_adapters` (18 functions, 9 classes)
101+
📄 `generators.api_changelog_gen` (9 functions, 2 classes)
102+
📄 `generators.api_reference_gen` (11 functions, 1 classes)
103+
📄 `generators.architecture_gen` (6 functions, 1 classes)
104+
📄 `generators.changelog_gen` (6 functions, 2 classes)
105+
📄 `generators.coverage_gen` (7 functions, 1 classes)
106+
📄 `generators.depgraph_gen` (9 functions, 1 classes)
107+
📄 `generators.examples_gen` (12 functions, 1 classes)
108+
📄 `generators.mkdocs_gen` (4 functions, 1 classes)
109+
📄 `generators.module_docs_gen` (17 functions, 1 classes)
110+
📄 `generators.readme_gen` (14 functions, 1 classes)
111+
📄 `registry` (4 functions, 1 classes)
112+
📦 `sync`
113+
📄 `sync.differ` (7 functions, 2 classes)
114+
📄 `sync.updater` (2 functions, 1 classes)
115+
📄 `sync.watcher` (1 functions)
116+
117+
118+
<!-- code2docs:end -->

code2docs/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
README.md, API references, module docs, examples, and architecture diagrams.
66
"""
77

8-
__version__ = "0.2.2"
8+
__version__ = "0.2.3"
99
__author__ = "Tom Sapletta"
1010

1111
from .config import Code2DocsConfig

code2docs/cli.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,25 @@ def init(project_path, output):
8888
click.echo(f"Created {out_path}")
8989

9090

91+
@main.command()
92+
@click.argument("project_path", default=".", type=click.Path(exists=True))
93+
@click.option("--config", "-c", "config_path", default=None, help="Path to code2docs.yaml")
94+
@click.option("--target", "-t", default=80, type=int, help="Docstring coverage target (%)")
95+
def check(project_path, config_path, target):
96+
"""Health check — verify documentation completeness."""
97+
config = _load_config(project_path, config_path)
98+
_run_check(project_path, config, target)
99+
100+
101+
@main.command()
102+
@click.argument("project_path", default=".", type=click.Path(exists=True))
103+
@click.option("--config", "-c", "config_path", default=None, help="Path to code2docs.yaml")
104+
def diff(project_path, config_path):
105+
"""Preview what would change without writing anything."""
106+
config = _load_config(project_path, config_path)
107+
_run_diff(project_path, config)
108+
109+
91110
def _load_config(project_path: str, config_path: Optional[str] = None) -> Code2DocsConfig:
92111
"""Load configuration, auto-detecting code2docs.yaml if present."""
93112
project = Path(project_path).resolve()
@@ -184,3 +203,85 @@ def _run_watch(project_path: str, config: Code2DocsConfig):
184203
project = Path(project_path).resolve()
185204
click.echo(f"👁 Watching {project.name} for changes... (Ctrl+C to stop)")
186205
start_watcher(str(project), config)
206+
207+
208+
def _run_check(project_path: str, config: Code2DocsConfig, target: int = 80):
209+
"""Run documentation health check."""
210+
from .analyzers.project_scanner import ProjectScanner
211+
from .analyzers.docstring_extractor import DocstringExtractor
212+
213+
project = Path(project_path).resolve()
214+
click.echo(f"🩺 code2docs check: {project.name}\n")
215+
216+
scanner = ProjectScanner(config)
217+
result = scanner.analyze(str(project))
218+
219+
score = 0
220+
total = 0
221+
222+
# Check README
223+
total += 1
224+
readme = project / config.readme_output
225+
if readme.exists():
226+
click.echo(" ✅ README.md exists")
227+
score += 1
228+
else:
229+
click.echo(" ❌ README.md missing")
230+
231+
# Check docs/
232+
docs_dir = project / config.output
233+
for subdir, label in [("api", "API reference"), ("modules", "Module docs")]:
234+
total += 1
235+
d = docs_dir / subdir
236+
if d.exists() and any(d.iterdir()):
237+
count = sum(1 for f in d.glob("*.md"))
238+
click.echo(f" ✅ {label}: {count} files")
239+
score += 1
240+
else:
241+
click.echo(f" ❌ {label}: missing or empty")
242+
243+
# Check examples/
244+
total += 1
245+
ex_dir = project / "examples"
246+
if ex_dir.exists() and any(ex_dir.iterdir()):
247+
count = sum(1 for f in ex_dir.glob("*.py"))
248+
click.echo(f" ✅ examples/: {count} files")
249+
score += 1
250+
else:
251+
click.echo(f" ❌ examples/: missing or empty")
252+
253+
# Docstring coverage
254+
total += 1
255+
extractor = DocstringExtractor()
256+
report = extractor.coverage_report(result)
257+
coverage = report.get("overall_coverage", 0)
258+
if coverage >= target:
259+
click.echo(f" ✅ Docstring coverage: {coverage:.0f}% (target: {target}%)")
260+
score += 1
261+
else:
262+
click.echo(f" ⚠️ Docstring coverage: {coverage:.0f}% (target: {target}%)")
263+
264+
click.echo(f"\n Score: {score}/{total}")
265+
266+
267+
def _run_diff(project_path: str, config: Code2DocsConfig):
268+
"""Preview documentation changes without writing."""
269+
from .analyzers.project_scanner import ProjectScanner
270+
from .base import GenerateContext
271+
from .registry import GeneratorRegistry
272+
from .generators._registry_adapters import ALL_ADAPTERS
273+
274+
project = Path(project_path).resolve()
275+
click.echo(f"🔍 code2docs diff: {project.name}\n")
276+
277+
scanner = ProjectScanner(config)
278+
result = scanner.analyze(str(project))
279+
280+
docs_dir = project / config.output
281+
ctx = GenerateContext(project=project, docs_dir=docs_dir, dry_run=True)
282+
283+
registry = GeneratorRegistry()
284+
for adapter_cls in ALL_ADAPTERS:
285+
registry.add(adapter_cls(config, result))
286+
287+
registry.run_all(ctx)

code2docs/docs/api-changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# code2docs — API Changelog
2+
3+
> No previous API snapshot found. Run `code2docs generate` to create a baseline.
4+
> Future runs will show changes here.

code2docs/docs/api/index.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# API Reference
2+
3+
> Auto-generated from 31 modules | 185 functions | 42 classes
4+
5+
## Modules
6+
7+
- [`__main__`](module___main__.md) — 0 functions, 0 classes
8+
- [`analyzers`](module_analyzers.md) — 0 functions, 0 classes
9+
- [`analyzers.dependency_scanner`](module_analyzers_dependency_scanner.md) — 6 functions, 3 classes
10+
- [`analyzers.docstring_extractor`](module_analyzers_docstring_extractor.md) — 10 functions, 2 classes
11+
- [`analyzers.endpoint_detector`](module_analyzers_endpoint_detector.md) — 3 functions, 2 classes
12+
- [`analyzers.project_scanner`](module_analyzers_project_scanner.md) — 4 functions, 1 classes
13+
- [`base`](module_base.md) — 3 functions, 2 classes
14+
- [`cli`](module_cli.md) — 10 functions, 1 classes
15+
- [`code2docs`](module_code2docs.md) — 1 functions, 0 classes
16+
- [`config`](module_config.md) — 2 functions, 5 classes
17+
- [`formatters`](module_formatters.md) — 0 functions, 0 classes
18+
- [`formatters.badges`](module_formatters_badges.md) — 2 functions, 0 classes
19+
- [`formatters.markdown`](module_formatters_markdown.md) — 13 functions, 1 classes
20+
- [`formatters.toc`](module_formatters_toc.md) — 3 functions, 0 classes
21+
- [`generators`](module_generators.md) — 1 functions, 0 classes
22+
- [`generators._registry_adapters`](module_generators__registry_adapters.md) — 18 functions, 9 classes
23+
- [`generators.api_changelog_gen`](module_generators_api_changelog_gen.md) — 9 functions, 2 classes
24+
- [`generators.api_reference_gen`](module_generators_api_reference_gen.md) — 11 functions, 1 classes
25+
- [`generators.architecture_gen`](module_generators_architecture_gen.md) — 6 functions, 1 classes
26+
- [`generators.changelog_gen`](module_generators_changelog_gen.md) — 6 functions, 2 classes
27+
- [`generators.coverage_gen`](module_generators_coverage_gen.md) — 7 functions, 1 classes
28+
- [`generators.depgraph_gen`](module_generators_depgraph_gen.md) — 9 functions, 1 classes
29+
- [`generators.examples_gen`](module_generators_examples_gen.md) — 12 functions, 1 classes
30+
- [`generators.mkdocs_gen`](module_generators_mkdocs_gen.md) — 4 functions, 1 classes
31+
- [`generators.module_docs_gen`](module_generators_module_docs_gen.md) — 17 functions, 1 classes
32+
- [`generators.readme_gen`](module_generators_readme_gen.md) — 14 functions, 1 classes
33+
- [`registry`](module_registry.md) — 4 functions, 1 classes
34+
- [`sync`](module_sync.md) — 0 functions, 0 classes
35+
- [`sync.differ`](module_sync_differ.md) — 7 functions, 2 classes
36+
- [`sync.updater`](module_sync_updater.md) — 2 functions, 1 classes
37+
- [`sync.watcher`](module_sync_watcher.md) — 1 functions, 0 classes
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# `__main__`
2+
3+
> Source: `/home/tom/github/wronai/code2docs/code2docs/__main__.py`

0 commit comments

Comments
 (0)