code2docs 3.0.11__tar.gz → 3.0.13__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.
Files changed (67) hide show
  1. {code2docs-3.0.11 → code2docs-3.0.13}/PKG-INFO +3 -3
  2. {code2docs-3.0.11 → code2docs-3.0.13}/README.md +2 -2
  3. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/__init__.py +1 -1
  4. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/analyzers/dependency_scanner.py +130 -2
  5. code2docs-3.0.13/code2docs/generators/contributing_gen.py +231 -0
  6. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/getting_started_gen.py +38 -9
  7. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/readme_gen.py +17 -3
  8. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs.egg-info/PKG-INFO +3 -3
  9. {code2docs-3.0.11 → code2docs-3.0.13}/pyproject.toml +1 -1
  10. code2docs-3.0.11/code2docs/generators/contributing_gen.py +0 -137
  11. {code2docs-3.0.11 → code2docs-3.0.13}/LICENSE +0 -0
  12. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/__main__.py +0 -0
  13. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/analyzers/__init__.py +0 -0
  14. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/analyzers/docstring_extractor.py +0 -0
  15. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/analyzers/endpoint_detector.py +0 -0
  16. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/analyzers/project_scanner.py +0 -0
  17. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/base.py +0 -0
  18. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/cli.py +0 -0
  19. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/config.py +0 -0
  20. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/examples/advanced_usage.py +0 -0
  21. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/examples/quickstart.py +0 -0
  22. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/formatters/__init__.py +0 -0
  23. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/formatters/badges.py +0 -0
  24. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/formatters/markdown.py +0 -0
  25. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/formatters/toc.py +0 -0
  26. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/__init__.py +0 -0
  27. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/_registry_adapters.py +0 -0
  28. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/_source_links.py +0 -0
  29. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/api_changelog_gen.py +0 -0
  30. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/api_reference_gen.py +0 -0
  31. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/architecture_gen.py +0 -0
  32. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/changelog_gen.py +0 -0
  33. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/code2llm_gen.py +0 -0
  34. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/config_docs_gen.py +0 -0
  35. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/coverage_gen.py +0 -0
  36. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/depgraph_gen.py +0 -0
  37. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/examples_gen.py +0 -0
  38. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/mkdocs_gen.py +0 -0
  39. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/module_docs_gen.py +0 -0
  40. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/generators/org_readme_gen.py +0 -0
  41. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/llm_helper.py +0 -0
  42. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/registry.py +0 -0
  43. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/sync/__init__.py +0 -0
  44. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/sync/differ.py +0 -0
  45. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/sync/updater.py +0 -0
  46. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/sync/watcher.py +0 -0
  47. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/templates/api_module.md.j2 +0 -0
  48. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/templates/architecture.md.j2 +0 -0
  49. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/templates/example_usage.py.j2 +0 -0
  50. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/templates/index.md.j2 +0 -0
  51. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/templates/module_doc.md.j2 +0 -0
  52. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs/templates/readme.md.j2 +0 -0
  53. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs.egg-info/SOURCES.txt +0 -0
  54. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs.egg-info/dependency_links.txt +0 -0
  55. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs.egg-info/entry_points.txt +0 -0
  56. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs.egg-info/requires.txt +0 -0
  57. {code2docs-3.0.11 → code2docs-3.0.13}/code2docs.egg-info/top_level.txt +0 -0
  58. {code2docs-3.0.11 → code2docs-3.0.13}/setup.cfg +0 -0
  59. {code2docs-3.0.11 → code2docs-3.0.13}/tests/test_analyzers.py +0 -0
  60. {code2docs-3.0.11 → code2docs-3.0.13}/tests/test_cli.py +0 -0
  61. {code2docs-3.0.11 → code2docs-3.0.13}/tests/test_code2docs.py +0 -0
  62. {code2docs-3.0.11 → code2docs-3.0.13}/tests/test_config.py +0 -0
  63. {code2docs-3.0.11 → code2docs-3.0.13}/tests/test_formatters.py +0 -0
  64. {code2docs-3.0.11 → code2docs-3.0.13}/tests/test_generators.py +0 -0
  65. {code2docs-3.0.11 → code2docs-3.0.13}/tests/test_llm_helper.py +0 -0
  66. {code2docs-3.0.11 → code2docs-3.0.13}/tests/test_registry.py +0 -0
  67. {code2docs-3.0.11 → code2docs-3.0.13}/tests/test_sync.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code2docs
3
- Version: 3.0.11
3
+ Version: 3.0.13
4
4
  Summary: Auto-generate and sync project documentation from source code analysis
5
5
  Author-email: Tom Sapletta <tom@sapletta.com>
6
6
  License-Expression: Apache-2.0
@@ -50,7 +50,7 @@ Dynamic: license-file
50
50
 
51
51
  # code2docs
52
52
 
53
- ![version](https://img.shields.io/badge/version-3.0.11-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
53
+ ![version](https://img.shields.io/badge/version-3.0.13-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
54
54
 
55
55
  > Auto-generate and sync project documentation from source code analysis.
56
56
 
@@ -190,7 +190,7 @@ code2docs can update only specific sections of an existing README using markers:
190
190
  ```markdown
191
191
  <!-- code2docs:start --># code2docs
192
192
 
193
- ![version](https://img.shields.io/badge/version-3.0.11-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-276-green)
193
+ ![version](https://img.shields.io/badge/version-3.0.13-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-276-green)
194
194
  > **276** functions | **57** classes | **51** files | CC̄ = 3.8
195
195
 
196
196
  > Auto-generated project documentation from source code analysis.
@@ -1,6 +1,6 @@
1
1
  # code2docs
2
2
 
3
- ![version](https://img.shields.io/badge/version-3.0.11-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-3.0.13-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
4
4
 
5
5
  > Auto-generate and sync project documentation from source code analysis.
6
6
 
@@ -140,7 +140,7 @@ code2docs can update only specific sections of an existing README using markers:
140
140
  ```markdown
141
141
  <!-- code2docs:start --># code2docs
142
142
 
143
- ![version](https://img.shields.io/badge/version-3.0.11-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-276-green)
143
+ ![version](https://img.shields.io/badge/version-3.0.13-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-276-green)
144
144
  > **276** functions | **57** classes | **51** files | CC̄ = 3.8
145
145
 
146
146
  > Auto-generated project documentation from source code analysis.
@@ -5,7 +5,7 @@ Uses code2llm's AnalysisResult to produce human-readable documentation:
5
5
  README.md, API references, module docs, examples, and architecture diagrams.
6
6
  """
7
7
 
8
- __version__ = "3.0.11"
8
+ __version__ = "3.0.13"
9
9
  __author__ = "Tom Sapletta"
10
10
 
11
11
  from .config import Code2DocsConfig
@@ -1,4 +1,4 @@
1
- """Scan project dependencies from requirements.txt, pyproject.toml, setup.py."""
1
+ """Scan project dependencies from requirements.txt, pyproject.toml, setup.py, package.json, Cargo.toml, go.mod."""
2
2
 
3
3
  import re
4
4
  from dataclasses import dataclass, field
@@ -26,7 +26,9 @@ class DependencyInfo:
26
26
  @dataclass
27
27
  class ProjectDependencies:
28
28
  """All detected project dependencies."""
29
+ language: str = "python"
29
30
  python_version: str = ""
31
+ runtime_version: str = ""
30
32
  dependencies: List[DependencyInfo] = field(default_factory=list)
31
33
  dev_dependencies: List[DependencyInfo] = field(default_factory=list)
32
34
  optional_groups: Dict[str, List[DependencyInfo]] = field(default_factory=dict)
@@ -47,7 +49,31 @@ class DependencyScanner:
47
49
  project = Path(project_path)
48
50
  deps = ProjectDependencies()
49
51
 
50
- # Priority: pyproject.toml > setup.py > requirements.txt
52
+ # Detect language from dependency files
53
+ # Priority: pyproject.toml > setup.py > requirements.txt (Python)
54
+ # package.json (JS/TS) > Cargo.toml (Rust) > go.mod (Go)
55
+ package_json = project / "package.json"
56
+ if package_json.exists():
57
+ deps = self._parse_package_json(package_json)
58
+ deps.source_file = "package.json"
59
+ # Detect TypeScript
60
+ tsconfig = project / "tsconfig.json"
61
+ if tsconfig.exists():
62
+ deps.language = "typescript"
63
+ return deps
64
+
65
+ cargo_toml = project / "Cargo.toml"
66
+ if cargo_toml.exists():
67
+ deps = self._parse_cargo_toml(cargo_toml)
68
+ deps.source_file = "Cargo.toml"
69
+ return deps
70
+
71
+ go_mod = project / "go.mod"
72
+ if go_mod.exists():
73
+ deps = self._parse_go_mod(go_mod)
74
+ deps.source_file = "go.mod"
75
+ return deps
76
+
51
77
  pyproject = project / "pyproject.toml"
52
78
  if pyproject.exists():
53
79
  deps = self._parse_pyproject(pyproject)
@@ -159,6 +185,108 @@ class DependencyScanner:
159
185
  deps.install_command = "pip install -r requirements.txt"
160
186
  return deps
161
187
 
188
+ def _parse_package_json(self, path: Path) -> ProjectDependencies:
189
+ """Parse package.json for dependencies."""
190
+ import json
191
+ deps = ProjectDependencies(language="javascript")
192
+ try:
193
+ data = json.loads(path.read_text(encoding="utf-8"))
194
+ except (json.JSONDecodeError, OSError):
195
+ return deps
196
+
197
+ deps.version = data.get("version", "")
198
+ name = data.get("name", "")
199
+
200
+ # Node engine version
201
+ engines = data.get("engines", {})
202
+ deps.runtime_version = engines.get("node", "")
203
+
204
+ for dep_name, ver in data.get("dependencies", {}).items():
205
+ deps.dependencies.append(DependencyInfo(name=dep_name, version_spec=ver))
206
+
207
+ for dep_name, ver in data.get("devDependencies", {}).items():
208
+ deps.dev_dependencies.append(DependencyInfo(name=dep_name, version_spec=ver, group="dev"))
209
+
210
+ # Detect install command
211
+ lock_yarn = path.parent / "yarn.lock"
212
+ lock_pnpm = path.parent / "pnpm-lock.yaml"
213
+ if lock_pnpm.exists():
214
+ deps.install_command = "pnpm install"
215
+ elif lock_yarn.exists():
216
+ deps.install_command = "yarn install"
217
+ else:
218
+ deps.install_command = "npm install"
219
+
220
+ if name:
221
+ deps.keywords = data.get("keywords", [])
222
+
223
+ return deps
224
+
225
+ def _parse_cargo_toml(self, path: Path) -> ProjectDependencies:
226
+ """Parse Cargo.toml for Rust dependencies."""
227
+ deps = ProjectDependencies(language="rust")
228
+ content = path.read_text(encoding="utf-8")
229
+
230
+ # Version
231
+ ver_match = re.search(r'^version\s*=\s*"([^"]+)"', content, re.MULTILINE)
232
+ if ver_match:
233
+ deps.version = ver_match.group(1)
234
+
235
+ # Dependencies section
236
+ in_deps = False
237
+ in_dev_deps = False
238
+ for line in content.splitlines():
239
+ stripped = line.strip()
240
+ if stripped == "[dependencies]":
241
+ in_deps, in_dev_deps = True, False
242
+ continue
243
+ elif stripped == "[dev-dependencies]":
244
+ in_deps, in_dev_deps = False, True
245
+ continue
246
+ elif stripped.startswith("["):
247
+ in_deps, in_dev_deps = False, False
248
+ continue
249
+
250
+ dep_match = re.match(r'^([a-zA-Z0-9_-]+)\s*=\s*"?([^"\s]+)"?', stripped)
251
+ if dep_match:
252
+ info = DependencyInfo(name=dep_match.group(1), version_spec=dep_match.group(2))
253
+ if in_dev_deps:
254
+ info.group = "dev"
255
+ deps.dev_dependencies.append(info)
256
+ elif in_deps:
257
+ deps.dependencies.append(info)
258
+
259
+ deps.install_command = "cargo build"
260
+ return deps
261
+
262
+ def _parse_go_mod(self, path: Path) -> ProjectDependencies:
263
+ """Parse go.mod for Go dependencies."""
264
+ deps = ProjectDependencies(language="go")
265
+ content = path.read_text(encoding="utf-8")
266
+
267
+ # Go version
268
+ go_ver = re.search(r'^go\s+(\S+)', content, re.MULTILINE)
269
+ if go_ver:
270
+ deps.runtime_version = go_ver.group(1)
271
+
272
+ # Require block
273
+ require_block = re.search(r'require\s*\((.*?)\)', content, re.DOTALL)
274
+ if require_block:
275
+ for line in require_block.group(1).splitlines():
276
+ line = line.strip()
277
+ if not line or line.startswith("//"):
278
+ continue
279
+ parts = line.split()
280
+ if len(parts) >= 2:
281
+ deps.dependencies.append(DependencyInfo(name=parts[0], version_spec=parts[1]))
282
+
283
+ # Single-line requires
284
+ for match in re.finditer(r'^require\s+(\S+)\s+(\S+)', content, re.MULTILINE):
285
+ deps.dependencies.append(DependencyInfo(name=match.group(1), version_spec=match.group(2)))
286
+
287
+ deps.install_command = "go mod download"
288
+ return deps
289
+
162
290
  @staticmethod
163
291
  def _parse_dep_string(dep_str: str) -> DependencyInfo:
164
292
  """Parse a dependency string like 'package>=1.0'."""
@@ -0,0 +1,231 @@
1
+ """CONTRIBUTING.md generator from project tooling detection."""
2
+
3
+ from typing import Dict, List
4
+
5
+ from code2llm.api import AnalysisResult
6
+
7
+ from ..config import Code2DocsConfig
8
+ from ..analyzers.dependency_scanner import DependencyScanner
9
+
10
+
11
+ class ContributingGenerator:
12
+ """Generate CONTRIBUTING.md by detecting dev tools from pyproject.toml."""
13
+
14
+ def __init__(self, config: Code2DocsConfig, result: AnalysisResult):
15
+ self.config = config
16
+ self.result = result
17
+
18
+ def generate(self) -> str:
19
+ """Generate CONTRIBUTING.md content."""
20
+ project = self.config.project_name or "Project"
21
+ tools = self._detect_dev_tools()
22
+ lines = [
23
+ f"# Contributing to {project}\n",
24
+ self._render_setup(tools),
25
+ "",
26
+ self._render_development(tools),
27
+ "",
28
+ self._render_testing(tools),
29
+ "",
30
+ self._render_code_style(tools),
31
+ "",
32
+ self._render_pull_request(),
33
+ "",
34
+ ]
35
+ return "\n".join(lines)
36
+
37
+ def _detect_dev_tools(self) -> Dict[str, bool]:
38
+ """Detect which dev tools are configured in the project."""
39
+ scanner = DependencyScanner()
40
+ deps = scanner.scan(self.result.project_path)
41
+ all_deps = {d.name.lower() for d in deps.dependencies}
42
+ all_deps |= {d.name.lower() for d in deps.dev_dependencies}
43
+ return {
44
+ "language": deps.language,
45
+ "install_command": deps.install_command,
46
+ # Python tools
47
+ "pytest": "pytest" in all_deps,
48
+ "black": "black" in all_deps,
49
+ "ruff": "ruff" in all_deps,
50
+ "mypy": "mypy" in all_deps,
51
+ "flake8": "flake8" in all_deps,
52
+ "isort": "isort" in all_deps,
53
+ "pre-commit": "pre-commit" in all_deps,
54
+ "tox": "tox" in all_deps,
55
+ # JS/TS tools
56
+ "eslint": "eslint" in all_deps,
57
+ "prettier": "prettier" in all_deps,
58
+ "jest": "jest" in all_deps,
59
+ "vitest": "vitest" in all_deps,
60
+ "typescript": "typescript" in all_deps,
61
+ }
62
+
63
+ def _render_setup(self, tools: Dict[str, bool]) -> str:
64
+ """Render development setup instructions."""
65
+ project = self.config.project_name or "project"
66
+ repo_url = self.config.repo_url or "<repository-url>"
67
+ lang = tools.get("language", "python")
68
+ install_cmd = tools.get("install_command", "pip install -e .")
69
+
70
+ lines = [
71
+ "## Development Setup\n",
72
+ "```bash",
73
+ f"git clone {repo_url}",
74
+ f"cd {project}",
75
+ ]
76
+
77
+ if lang in ("javascript", "typescript"):
78
+ lines.append(install_cmd)
79
+ elif lang == "rust":
80
+ lines.append("cargo build")
81
+ elif lang == "go":
82
+ lines.append("go mod download")
83
+ lines.append("go build ./...")
84
+ else:
85
+ lines.extend([
86
+ "python -m venv .venv",
87
+ "source .venv/bin/activate # or .venv\\Scripts\\activate on Windows",
88
+ 'pip install -e ".[dev]"',
89
+ ])
90
+
91
+ lines.append("```")
92
+ return "\n".join(lines)
93
+
94
+ @staticmethod
95
+ def _render_development(tools: Dict[str, bool]) -> str:
96
+ """Render development workflow."""
97
+ lines = [
98
+ "## Development Workflow\n",
99
+ "1. Create a feature branch from `main`",
100
+ "2. Make your changes",
101
+ "3. Add or update tests",
102
+ "4. Run the test suite",
103
+ "5. Submit a pull request",
104
+ ]
105
+ return "\n".join(lines)
106
+
107
+ @staticmethod
108
+ def _render_testing(tools: Dict[str, bool]) -> str:
109
+ """Render testing instructions."""
110
+ lang = tools.get("language", "python")
111
+ lines = ["## Testing\n"]
112
+
113
+ if lang in ("javascript", "typescript"):
114
+ if tools.get("vitest"):
115
+ lines.extend([
116
+ "```bash",
117
+ "# Run all tests",
118
+ "npx vitest",
119
+ "",
120
+ "# Run with coverage",
121
+ "npx vitest --coverage",
122
+ "",
123
+ "# Watch mode",
124
+ "npx vitest --watch",
125
+ "```",
126
+ ])
127
+ elif tools.get("jest"):
128
+ lines.extend([
129
+ "```bash",
130
+ "# Run all tests",
131
+ "npx jest",
132
+ "",
133
+ "# Run with coverage",
134
+ "npx jest --coverage",
135
+ "```",
136
+ ])
137
+ else:
138
+ lines.extend([
139
+ "```bash",
140
+ "npm test",
141
+ "```",
142
+ ])
143
+ elif lang == "rust":
144
+ lines.extend([
145
+ "```bash",
146
+ "# Run all tests",
147
+ "cargo test",
148
+ "",
149
+ "# Run a specific test",
150
+ "cargo test test_name",
151
+ "```",
152
+ ])
153
+ elif lang == "go":
154
+ lines.extend([
155
+ "```bash",
156
+ "# Run all tests",
157
+ "go test ./...",
158
+ "",
159
+ "# Run with coverage",
160
+ "go test -cover ./...",
161
+ "```",
162
+ ])
163
+ elif tools.get("pytest"):
164
+ lines.extend([
165
+ "```bash",
166
+ "# Run all tests",
167
+ "pytest",
168
+ "",
169
+ "# Run with coverage",
170
+ "pytest --cov --cov-report=term-missing",
171
+ "",
172
+ "# Run a specific test file",
173
+ "pytest tests/test_specific.py -v",
174
+ "```",
175
+ ])
176
+ else:
177
+ lines.extend([
178
+ "```bash",
179
+ "python -m unittest discover tests/",
180
+ "```",
181
+ ])
182
+ return "\n".join(lines)
183
+
184
+ @staticmethod
185
+ def _render_code_style(tools: Dict[str, bool]) -> str:
186
+ """Render code style guidelines."""
187
+ lang = tools.get("language", "python")
188
+ lines = ["## Code Style\n"]
189
+
190
+ if lang in ("javascript", "typescript"):
191
+ if tools.get("eslint"):
192
+ lines.append("- **Linting:** [ESLint](https://eslint.org/) — `npx eslint .`")
193
+ if tools.get("prettier"):
194
+ lines.append("- **Formatting:** [Prettier](https://prettier.io/) — `npx prettier --write .`")
195
+ if tools.get("typescript"):
196
+ lines.append("- **Type checking:** TypeScript — `npx tsc --noEmit`")
197
+ if not any(tools.get(t) for t in ("eslint", "prettier")):
198
+ lines.append("Follow the project's ESLint/Prettier configuration.")
199
+ elif lang == "rust":
200
+ lines.append("- **Formatting:** `cargo fmt`")
201
+ lines.append("- **Linting:** `cargo clippy`")
202
+ elif lang == "go":
203
+ lines.append("- **Formatting:** `gofmt -w .`")
204
+ lines.append("- **Linting:** `go vet ./...`")
205
+ else:
206
+ if tools.get("black"):
207
+ lines.append("- **Formatting:** [Black](https://black.readthedocs.io/) — `black .`")
208
+ if tools.get("ruff"):
209
+ lines.append("- **Linting:** [Ruff](https://docs.astral.sh/ruff/) — `ruff check .`")
210
+ if tools.get("mypy"):
211
+ lines.append("- **Type checking:** [mypy](https://mypy.readthedocs.io/) — `mypy .`")
212
+ if tools.get("flake8"):
213
+ lines.append("- **Linting:** [flake8](https://flake8.pycqa.org/) — `flake8 .`")
214
+ if tools.get("isort"):
215
+ lines.append("- **Imports:** [isort](https://pycqa.github.io/isort/) — `isort .`")
216
+ if not any(tools.get(t) for t in ("black", "ruff", "mypy", "flake8", "isort")):
217
+ lines.append("Follow PEP 8 conventions.")
218
+ return "\n".join(lines)
219
+
220
+ @staticmethod
221
+ def _render_pull_request() -> str:
222
+ """Render pull request guidelines."""
223
+ lines = [
224
+ "## Pull Request Guidelines\n",
225
+ "- Keep PRs focused — one feature or fix per PR",
226
+ "- Include tests for new functionality",
227
+ "- Update documentation if needed",
228
+ "- Ensure all tests pass before submitting",
229
+ "- Use descriptive commit messages",
230
+ ]
231
+ return "\n".join(lines)
@@ -44,12 +44,29 @@ class GettingStartedGenerator:
44
44
  """Render prerequisites section."""
45
45
  dep_scanner = DependencyScanner()
46
46
  deps = dep_scanner.scan(self.result.project_path)
47
- py_ver = deps.python_version or ">=3.9"
48
- lines = [
49
- "## Prerequisites\n",
50
- f"- Python {py_ver}",
51
- "- pip (or your preferred package manager)",
52
- ]
47
+ lines = ["## Prerequisites\n"]
48
+
49
+ lang = deps.language
50
+ if lang in ("javascript", "typescript"):
51
+ node_ver = deps.runtime_version or ">=18"
52
+ lines.append(f"- Node.js {node_ver}")
53
+ if "pnpm" in deps.install_command:
54
+ lines.append("- pnpm")
55
+ elif "yarn" in deps.install_command:
56
+ lines.append("- yarn")
57
+ else:
58
+ lines.append("- npm")
59
+ elif lang == "rust":
60
+ lines.append("- Rust toolchain (rustup)")
61
+ lines.append("- cargo")
62
+ elif lang == "go":
63
+ go_ver = deps.runtime_version or ">=1.21"
64
+ lines.append(f"- Go {go_ver}")
65
+ else:
66
+ py_ver = deps.python_version or ">=3.9"
67
+ lines.append(f"- Python {py_ver}")
68
+ lines.append("- pip (or your preferred package manager)")
69
+
53
70
  if deps.dependencies:
54
71
  lines.append(f"- {len(deps.dependencies)} dependencies (installed automatically)")
55
72
  return "\n".join(lines)
@@ -60,6 +77,9 @@ class GettingStartedGenerator:
60
77
  deps = dep_scanner.scan(self.result.project_path)
61
78
  cmd = deps.install_command or f"pip install {self.config.project_name or '.'}"
62
79
  repo_url = self.config.repo_url or "<repository-url>"
80
+ project = self.config.project_name or "project"
81
+ lang = deps.language
82
+
63
83
  lines = [
64
84
  "## Installation\n",
65
85
  "```bash",
@@ -68,10 +88,19 @@ class GettingStartedGenerator:
68
88
  "To install from source:\n",
69
89
  "```bash",
70
90
  f"git clone {repo_url}",
71
- f"cd {self.config.project_name or 'project'}",
72
- "pip install -e .",
73
- "```",
91
+ f"cd {project}",
74
92
  ]
93
+
94
+ if lang in ("javascript", "typescript"):
95
+ lines.append(cmd)
96
+ elif lang == "rust":
97
+ lines.append("cargo build --release")
98
+ elif lang == "go":
99
+ lines.append("go build ./...")
100
+ else:
101
+ lines.append("pip install -e .")
102
+
103
+ lines.append("```")
75
104
  return "\n".join(lines)
76
105
 
77
106
  def _render_first_usage(self) -> str:
@@ -371,7 +371,16 @@ class ReadmeGenerator:
371
371
  if not deps or not deps.install_command:
372
372
  return ""
373
373
  parts = ["## Installation\n", f"```bash\n{deps.install_command}\n```\n"]
374
- if deps.python_version:
374
+ lang = getattr(deps, 'language', 'python')
375
+ if lang in ('javascript', 'typescript'):
376
+ runtime_ver = getattr(deps, 'runtime_version', '')
377
+ if runtime_ver:
378
+ parts.append(f"Requires Node.js {runtime_ver}\n")
379
+ elif lang == 'go':
380
+ runtime_ver = getattr(deps, 'runtime_version', '')
381
+ if runtime_ver:
382
+ parts.append(f"Requires Go {runtime_ver}\n")
383
+ elif deps.python_version:
375
384
  parts.append(f"Requires Python {deps.python_version}\n")
376
385
  return "\n".join(parts)
377
386
 
@@ -381,8 +390,13 @@ class ReadmeGenerator:
381
390
  parts = ["## Quick Start\n"]
382
391
  entry_points = context.get("entry_points", [])
383
392
  if entry_points:
384
- parts.append("```python")
385
- parts.append(f"# Entry points: {', '.join(entry_points[:3])}")
393
+ deps = context.get("dependencies")
394
+ lang = getattr(deps, 'language', 'python') if deps else 'python'
395
+ lang_map = {'python': 'python', 'javascript': 'javascript', 'typescript': 'typescript',
396
+ 'rust': 'rust', 'go': 'go'}
397
+ code_lang = lang_map.get(lang, lang)
398
+ parts.append(f"```{code_lang}")
399
+ parts.append(f"// Entry points: {', '.join(entry_points[:3])}")
386
400
  parts.append("```\n")
387
401
  return "\n".join(parts)
388
402
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code2docs
3
- Version: 3.0.11
3
+ Version: 3.0.13
4
4
  Summary: Auto-generate and sync project documentation from source code analysis
5
5
  Author-email: Tom Sapletta <tom@sapletta.com>
6
6
  License-Expression: Apache-2.0
@@ -50,7 +50,7 @@ Dynamic: license-file
50
50
 
51
51
  # code2docs
52
52
 
53
- ![version](https://img.shields.io/badge/version-3.0.11-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
53
+ ![version](https://img.shields.io/badge/version-3.0.13-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
54
54
 
55
55
  > Auto-generate and sync project documentation from source code analysis.
56
56
 
@@ -190,7 +190,7 @@ code2docs can update only specific sections of an existing README using markers:
190
190
  ```markdown
191
191
  <!-- code2docs:start --># code2docs
192
192
 
193
- ![version](https://img.shields.io/badge/version-3.0.11-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-276-green)
193
+ ![version](https://img.shields.io/badge/version-3.0.13-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-276-green)
194
194
  > **276** functions | **57** classes | **51** files | CC̄ = 3.8
195
195
 
196
196
  > Auto-generated project documentation from source code analysis.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code2docs"
7
- version = "3.0.11"
7
+ version = "3.0.13"
8
8
  description = "Auto-generate and sync project documentation from source code analysis"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,137 +0,0 @@
1
- """CONTRIBUTING.md generator from project tooling detection."""
2
-
3
- from typing import Dict, List
4
-
5
- from code2llm.api import AnalysisResult
6
-
7
- from ..config import Code2DocsConfig
8
- from ..analyzers.dependency_scanner import DependencyScanner
9
-
10
-
11
- class ContributingGenerator:
12
- """Generate CONTRIBUTING.md by detecting dev tools from pyproject.toml."""
13
-
14
- def __init__(self, config: Code2DocsConfig, result: AnalysisResult):
15
- self.config = config
16
- self.result = result
17
-
18
- def generate(self) -> str:
19
- """Generate CONTRIBUTING.md content."""
20
- project = self.config.project_name or "Project"
21
- tools = self._detect_dev_tools()
22
- lines = [
23
- f"# Contributing to {project}\n",
24
- self._render_setup(tools),
25
- "",
26
- self._render_development(tools),
27
- "",
28
- self._render_testing(tools),
29
- "",
30
- self._render_code_style(tools),
31
- "",
32
- self._render_pull_request(),
33
- "",
34
- ]
35
- return "\n".join(lines)
36
-
37
- def _detect_dev_tools(self) -> Dict[str, bool]:
38
- """Detect which dev tools are configured in the project."""
39
- scanner = DependencyScanner()
40
- deps = scanner.scan(self.result.project_path)
41
- all_deps = {d.name.lower() for d in deps.dependencies}
42
- all_deps |= {d.name.lower() for d in deps.dev_dependencies}
43
- return {
44
- "pytest": "pytest" in all_deps,
45
- "black": "black" in all_deps,
46
- "ruff": "ruff" in all_deps,
47
- "mypy": "mypy" in all_deps,
48
- "flake8": "flake8" in all_deps,
49
- "isort": "isort" in all_deps,
50
- "pre-commit": "pre-commit" in all_deps,
51
- "tox": "tox" in all_deps,
52
- }
53
-
54
- def _render_setup(self, tools: Dict[str, bool]) -> str:
55
- """Render development setup instructions."""
56
- project = self.config.project_name or "project"
57
- repo_url = self.config.repo_url or "<repository-url>"
58
- lines = [
59
- "## Development Setup\n",
60
- "```bash",
61
- f"git clone {repo_url}",
62
- f"cd {project}",
63
- "python -m venv .venv",
64
- "source .venv/bin/activate # or .venv\\Scripts\\activate on Windows",
65
- "pip install -e \".[dev]\"",
66
- "```",
67
- ]
68
- return "\n".join(lines)
69
-
70
- @staticmethod
71
- def _render_development(tools: Dict[str, bool]) -> str:
72
- """Render development workflow."""
73
- lines = [
74
- "## Development Workflow\n",
75
- "1. Create a feature branch from `main`",
76
- "2. Make your changes",
77
- "3. Add or update tests",
78
- "4. Run the test suite",
79
- "5. Submit a pull request",
80
- ]
81
- return "\n".join(lines)
82
-
83
- @staticmethod
84
- def _render_testing(tools: Dict[str, bool]) -> str:
85
- """Render testing instructions."""
86
- lines = ["## Testing\n"]
87
- if tools.get("pytest"):
88
- lines.extend([
89
- "```bash",
90
- "# Run all tests",
91
- "pytest",
92
- "",
93
- "# Run with coverage",
94
- "pytest --cov --cov-report=term-missing",
95
- "",
96
- "# Run a specific test file",
97
- "pytest tests/test_specific.py -v",
98
- "```",
99
- ])
100
- else:
101
- lines.extend([
102
- "```bash",
103
- "python -m unittest discover tests/",
104
- "```",
105
- ])
106
- return "\n".join(lines)
107
-
108
- @staticmethod
109
- def _render_code_style(tools: Dict[str, bool]) -> str:
110
- """Render code style guidelines."""
111
- lines = ["## Code Style\n"]
112
- if tools.get("black"):
113
- lines.append("- **Formatting:** [Black](https://black.readthedocs.io/) — `black .`")
114
- if tools.get("ruff"):
115
- lines.append("- **Linting:** [Ruff](https://docs.astral.sh/ruff/) — `ruff check .`")
116
- if tools.get("mypy"):
117
- lines.append("- **Type checking:** [mypy](https://mypy.readthedocs.io/) — `mypy .`")
118
- if tools.get("flake8"):
119
- lines.append("- **Linting:** [flake8](https://flake8.pycqa.org/) — `flake8 .`")
120
- if tools.get("isort"):
121
- lines.append("- **Imports:** [isort](https://pycqa.github.io/isort/) — `isort .`")
122
- if not any(tools.get(t) for t in ("black", "ruff", "mypy", "flake8", "isort")):
123
- lines.append("Follow PEP 8 conventions.")
124
- return "\n".join(lines)
125
-
126
- @staticmethod
127
- def _render_pull_request() -> str:
128
- """Render pull request guidelines."""
129
- lines = [
130
- "## Pull Request Guidelines\n",
131
- "- Keep PRs focused — one feature or fix per PR",
132
- "- Include tests for new functionality",
133
- "- Update documentation if needed",
134
- "- Ensure all tests pass before submitting",
135
- "- Use descriptive commit messages",
136
- ]
137
- return "\n".join(lines)
File without changes
File without changes
File without changes
File without changes
File without changes