openapi-spec-generator 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openapi_spec_generator-0.1.0/PKG-INFO +98 -0
- openapi_spec_generator-0.1.0/README.md +79 -0
- openapi_spec_generator-0.1.0/pyproject.toml +29 -0
- openapi_spec_generator-0.1.0/setup.cfg +4 -0
- openapi_spec_generator-0.1.0/src/openapi_generator/__init__.py +1 -0
- openapi_spec_generator-0.1.0/src/openapi_generator/ai_client.py +22 -0
- openapi_spec_generator-0.1.0/src/openapi_generator/cli.py +31 -0
- openapi_spec_generator-0.1.0/src/openapi_generator/file_collector.py +37 -0
- openapi_spec_generator-0.1.0/src/openapi_generator/generator.py +49 -0
- openapi_spec_generator-0.1.0/src/openapi_spec_generator.egg-info/PKG-INFO +98 -0
- openapi_spec_generator-0.1.0/src/openapi_spec_generator.egg-info/SOURCES.txt +14 -0
- openapi_spec_generator-0.1.0/src/openapi_spec_generator.egg-info/dependency_links.txt +1 -0
- openapi_spec_generator-0.1.0/src/openapi_spec_generator.egg-info/entry_points.txt +2 -0
- openapi_spec_generator-0.1.0/src/openapi_spec_generator.egg-info/requires.txt +15 -0
- openapi_spec_generator-0.1.0/src/openapi_spec_generator.egg-info/top_level.txt +1 -0
- openapi_spec_generator-0.1.0/tests/test_generator.py +82 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openapi-spec-generator
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Generate OpenAPI specifications for any REST API project directory.
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: click>=8.0
|
|
9
|
+
Provides-Extra: claude
|
|
10
|
+
Requires-Dist: anthropic>=0.25; extra == "claude"
|
|
11
|
+
Provides-Extra: openai
|
|
12
|
+
Requires-Dist: openai>=1.0; extra == "openai"
|
|
13
|
+
Provides-Extra: all
|
|
14
|
+
Requires-Dist: anthropic>=0.25; extra == "all"
|
|
15
|
+
Requires-Dist: openai>=1.0; extra == "all"
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
18
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
19
|
+
|
|
20
|
+
# OpenAPI Generator
|
|
21
|
+
|
|
22
|
+
A pip-installable CLI tool that uses AI to generate OpenAPI 3.0.3 specifications for any REST API project directory.
|
|
23
|
+
|
|
24
|
+
## Overview
|
|
25
|
+
|
|
26
|
+
Point this tool at any REST API project and it will scan the source files, send them to an AI model (Claude or OpenAI), and produce a valid OpenAPI 3.0.3 JSON specification.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# With Claude support (default)
|
|
32
|
+
pip install "openapi-generator[claude]"
|
|
33
|
+
|
|
34
|
+
# With OpenAI support
|
|
35
|
+
pip install "openapi-generator[openai]"
|
|
36
|
+
|
|
37
|
+
# Both providers
|
|
38
|
+
pip install "openapi-generator[all]"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
openapi-gen <path-to-project> --api-key <your-api-key>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The API key can also be provided via the `OPENAPI_GEN_API_KEY` environment variable:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
export OPENAPI_GEN_API_KEY=sk-ant-...
|
|
51
|
+
openapi-gen <path-to-project>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Options
|
|
55
|
+
|
|
56
|
+
| Option | Default | Description |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| `<path>` | _(required)_ | Path to the REST API project directory |
|
|
59
|
+
| `--api-key` | `OPENAPI_GEN_API_KEY` env var | AI provider API key |
|
|
60
|
+
| `--provider` | `claude` | AI provider: `claude` or `openai` |
|
|
61
|
+
| `--output`, `-o` | `openapi.json` | Output file path |
|
|
62
|
+
| `--title` | `API` | API title in the spec |
|
|
63
|
+
| `--version` | `1.0.0` | API version in the spec |
|
|
64
|
+
|
|
65
|
+
### Examples
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Generate a spec using Claude (default)
|
|
69
|
+
export OPENAPI_GEN_API_KEY=sk-ant-...
|
|
70
|
+
openapi-gen ./my-api
|
|
71
|
+
|
|
72
|
+
# Generate a spec using OpenAI
|
|
73
|
+
openapi-gen ./my-api --provider openai --api-key sk-...
|
|
74
|
+
|
|
75
|
+
# Specify title, version, and output path
|
|
76
|
+
openapi-gen ./my-api --title "My REST API" --version "2.0.0" --output ./docs/openapi.json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Output
|
|
80
|
+
|
|
81
|
+
The generated file follows the [OpenAPI 3.0.3 specification](https://spec.openapis.org/oas/v3.0.3) and can be used directly with tools like Swagger UI, Postman, or any OpenAPI-compatible client generator.
|
|
82
|
+
|
|
83
|
+
## Supported Languages
|
|
84
|
+
|
|
85
|
+
The tool scans files with the following extensions: `.py`, `.js`, `.ts`, `.go`, `.java`, `.rb`, `.php`, `.cs`
|
|
86
|
+
|
|
87
|
+
## Development
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
git clone https://github.com/your-org/openapi-generator
|
|
91
|
+
cd openapi-generator
|
|
92
|
+
pip install -e ".[dev]"
|
|
93
|
+
pytest
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# OpenAPI Generator
|
|
2
|
+
|
|
3
|
+
A pip-installable CLI tool that uses AI to generate OpenAPI 3.0.3 specifications for any REST API project directory.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Point this tool at any REST API project and it will scan the source files, send them to an AI model (Claude or OpenAI), and produce a valid OpenAPI 3.0.3 JSON specification.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# With Claude support (default)
|
|
13
|
+
pip install "openapi-generator[claude]"
|
|
14
|
+
|
|
15
|
+
# With OpenAI support
|
|
16
|
+
pip install "openapi-generator[openai]"
|
|
17
|
+
|
|
18
|
+
# Both providers
|
|
19
|
+
pip install "openapi-generator[all]"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
openapi-gen <path-to-project> --api-key <your-api-key>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The API key can also be provided via the `OPENAPI_GEN_API_KEY` environment variable:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
export OPENAPI_GEN_API_KEY=sk-ant-...
|
|
32
|
+
openapi-gen <path-to-project>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Options
|
|
36
|
+
|
|
37
|
+
| Option | Default | Description |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `<path>` | _(required)_ | Path to the REST API project directory |
|
|
40
|
+
| `--api-key` | `OPENAPI_GEN_API_KEY` env var | AI provider API key |
|
|
41
|
+
| `--provider` | `claude` | AI provider: `claude` or `openai` |
|
|
42
|
+
| `--output`, `-o` | `openapi.json` | Output file path |
|
|
43
|
+
| `--title` | `API` | API title in the spec |
|
|
44
|
+
| `--version` | `1.0.0` | API version in the spec |
|
|
45
|
+
|
|
46
|
+
### Examples
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Generate a spec using Claude (default)
|
|
50
|
+
export OPENAPI_GEN_API_KEY=sk-ant-...
|
|
51
|
+
openapi-gen ./my-api
|
|
52
|
+
|
|
53
|
+
# Generate a spec using OpenAI
|
|
54
|
+
openapi-gen ./my-api --provider openai --api-key sk-...
|
|
55
|
+
|
|
56
|
+
# Specify title, version, and output path
|
|
57
|
+
openapi-gen ./my-api --title "My REST API" --version "2.0.0" --output ./docs/openapi.json
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Output
|
|
61
|
+
|
|
62
|
+
The generated file follows the [OpenAPI 3.0.3 specification](https://spec.openapis.org/oas/v3.0.3) and can be used directly with tools like Swagger UI, Postman, or any OpenAPI-compatible client generator.
|
|
63
|
+
|
|
64
|
+
## Supported Languages
|
|
65
|
+
|
|
66
|
+
The tool scans files with the following extensions: `.py`, `.js`, `.ts`, `.go`, `.java`, `.rb`, `.php`, `.cs`
|
|
67
|
+
|
|
68
|
+
## Development
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
git clone https://github.com/your-org/openapi-generator
|
|
72
|
+
cd openapi-generator
|
|
73
|
+
pip install -e ".[dev]"
|
|
74
|
+
pytest
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## License
|
|
78
|
+
|
|
79
|
+
MIT
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "openapi-spec-generator"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Generate OpenAPI specifications for any REST API project directory."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
dependencies = [
|
|
13
|
+
"click>=8.0",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.optional-dependencies]
|
|
17
|
+
claude = ["anthropic>=0.25"]
|
|
18
|
+
openai = ["openai>=1.0"]
|
|
19
|
+
all = ["anthropic>=0.25", "openai>=1.0"]
|
|
20
|
+
dev = ["pytest>=8.0", "pytest-cov>=5.0"]
|
|
21
|
+
|
|
22
|
+
[project.scripts]
|
|
23
|
+
openapi-gen = "openapi_generator.cli:main"
|
|
24
|
+
|
|
25
|
+
[tool.setuptools.packages.find]
|
|
26
|
+
where = ["src"]
|
|
27
|
+
|
|
28
|
+
[tool.pytest.ini_options]
|
|
29
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
def call_ai(prompt: str, api_key: str, provider: str) -> str:
|
|
2
|
+
if provider == "claude":
|
|
3
|
+
import anthropic
|
|
4
|
+
|
|
5
|
+
client = anthropic.Anthropic(api_key=api_key)
|
|
6
|
+
with client.messages.stream(
|
|
7
|
+
model="claude-sonnet-4-6",
|
|
8
|
+
max_tokens=4096,
|
|
9
|
+
messages=[{"role": "user", "content": prompt}],
|
|
10
|
+
) as stream:
|
|
11
|
+
return stream.get_final_message().content[0].text
|
|
12
|
+
elif provider == "openai":
|
|
13
|
+
import openai
|
|
14
|
+
|
|
15
|
+
client = openai.OpenAI(api_key=api_key)
|
|
16
|
+
response = client.chat.completions.create(
|
|
17
|
+
model="gpt-4o",
|
|
18
|
+
messages=[{"role": "user", "content": prompt}],
|
|
19
|
+
)
|
|
20
|
+
return response.choices[0].message.content
|
|
21
|
+
else:
|
|
22
|
+
raise ValueError(f"Unknown provider '{provider}'. Choose 'claude' or 'openai'.")
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import click
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from .generator import generate_spec
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@click.command()
|
|
8
|
+
@click.argument("path", type=click.Path(exists=True, file_okay=False, path_type=Path))
|
|
9
|
+
@click.option("--output", "-o", default="openapi.json", show_default=True, help="Output file path.")
|
|
10
|
+
@click.option("--title", default="API", show_default=True, help="API title.")
|
|
11
|
+
@click.option("--version", "api_version", default="1.0.0", show_default=True, help="API version.")
|
|
12
|
+
@click.option(
|
|
13
|
+
"--api-key",
|
|
14
|
+
envvar="OPENAPI_GEN_API_KEY",
|
|
15
|
+
required=True,
|
|
16
|
+
help="AI provider API key (or set OPENAPI_GEN_API_KEY).",
|
|
17
|
+
)
|
|
18
|
+
@click.option(
|
|
19
|
+
"--provider",
|
|
20
|
+
type=click.Choice(["claude", "openai"]),
|
|
21
|
+
default="claude",
|
|
22
|
+
show_default=True,
|
|
23
|
+
help="AI provider to use.",
|
|
24
|
+
)
|
|
25
|
+
def main(path: Path, output: str, title: str, api_version: str, api_key: str, provider: str) -> None:
|
|
26
|
+
"""Generate an OpenAPI specification for a REST API project directory."""
|
|
27
|
+
click.echo(f"Scanning {path} ...")
|
|
28
|
+
spec = generate_spec(path, title=title, api_version=api_version, api_key=api_key, provider=provider)
|
|
29
|
+
output_path = Path(output)
|
|
30
|
+
output_path.write_text(json.dumps(spec, indent=2), encoding="utf-8")
|
|
31
|
+
click.echo(f"Wrote JSON spec to {output_path}")
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
_INCLUDE_EXTENSIONS = {".py", ".js", ".ts", ".go", ".java", ".rb", ".php", ".cs"}
|
|
5
|
+
_SKIP_DIRS = {"node_modules", ".git", "__pycache__", "venv", ".venv", "dist", "build", ".eggs"}
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def collect_files(project_dir: Path, max_bytes: int = 400_000) -> list[tuple[str, str]]:
|
|
9
|
+
"""Walk *project_dir* and return (relative_path, content) for each source file.
|
|
10
|
+
|
|
11
|
+
Stops collecting once the total accumulated size exceeds *max_bytes* to
|
|
12
|
+
avoid exceeding AI model context limits.
|
|
13
|
+
"""
|
|
14
|
+
results: list[tuple[str, str]] = []
|
|
15
|
+
total = 0
|
|
16
|
+
|
|
17
|
+
for root, dirs, files in os.walk(project_dir):
|
|
18
|
+
dirs[:] = [d for d in dirs if d not in _SKIP_DIRS]
|
|
19
|
+
|
|
20
|
+
for filename in sorted(files):
|
|
21
|
+
if Path(filename).suffix not in _INCLUDE_EXTENSIONS:
|
|
22
|
+
continue
|
|
23
|
+
|
|
24
|
+
abs_path = Path(root) / filename
|
|
25
|
+
try:
|
|
26
|
+
content = abs_path.read_text(encoding="utf-8")
|
|
27
|
+
except (UnicodeDecodeError, OSError):
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
total += len(content.encode("utf-8"))
|
|
31
|
+
if total > max_bytes:
|
|
32
|
+
return results
|
|
33
|
+
|
|
34
|
+
rel_path = abs_path.relative_to(project_dir).as_posix()
|
|
35
|
+
results.append((rel_path, content))
|
|
36
|
+
|
|
37
|
+
return results
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import re
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from .file_collector import collect_files
|
|
6
|
+
from .ai_client import call_ai
|
|
7
|
+
|
|
8
|
+
_SYSTEM_PROMPT = (
|
|
9
|
+
"You are an expert OpenAPI specification writer. "
|
|
10
|
+
"Given source files from a REST API project, produce a complete, valid "
|
|
11
|
+
"OpenAPI 3.0.3 specification in JSON. "
|
|
12
|
+
"Respond with ONLY the raw JSON — no markdown fences, no explanation, no commentary."
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _build_prompt(files: list[tuple[str, str]], title: str, api_version: str) -> str:
|
|
17
|
+
file_blocks = "\n\n".join(
|
|
18
|
+
f"### {path}\n{content}" for path, content in files
|
|
19
|
+
)
|
|
20
|
+
return (
|
|
21
|
+
f"{_SYSTEM_PROMPT}\n\n"
|
|
22
|
+
f"API title: {title}\n"
|
|
23
|
+
f"API version: {api_version}\n\n"
|
|
24
|
+
f"Source files:\n\n{file_blocks}"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _parse_json(raw: str) -> dict:
|
|
29
|
+
text = raw.strip()
|
|
30
|
+
text = re.sub(r"^```(?:json)?\s*", "", text)
|
|
31
|
+
text = re.sub(r"\s*```$", "", text)
|
|
32
|
+
try:
|
|
33
|
+
return json.loads(text)
|
|
34
|
+
except json.JSONDecodeError as exc:
|
|
35
|
+
raise ValueError(f"AI response was not valid JSON:\n{raw[:500]}") from exc
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def generate_spec(
|
|
39
|
+
project_dir: Path,
|
|
40
|
+
*,
|
|
41
|
+
title: str = "API",
|
|
42
|
+
api_version: str = "1.0.0",
|
|
43
|
+
api_key: str,
|
|
44
|
+
provider: str = "claude",
|
|
45
|
+
) -> dict:
|
|
46
|
+
files = collect_files(project_dir)
|
|
47
|
+
prompt = _build_prompt(files, title, api_version)
|
|
48
|
+
raw = call_ai(prompt, api_key, provider)
|
|
49
|
+
return _parse_json(raw)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openapi-spec-generator
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Generate OpenAPI specifications for any REST API project directory.
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: click>=8.0
|
|
9
|
+
Provides-Extra: claude
|
|
10
|
+
Requires-Dist: anthropic>=0.25; extra == "claude"
|
|
11
|
+
Provides-Extra: openai
|
|
12
|
+
Requires-Dist: openai>=1.0; extra == "openai"
|
|
13
|
+
Provides-Extra: all
|
|
14
|
+
Requires-Dist: anthropic>=0.25; extra == "all"
|
|
15
|
+
Requires-Dist: openai>=1.0; extra == "all"
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
18
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
19
|
+
|
|
20
|
+
# OpenAPI Generator
|
|
21
|
+
|
|
22
|
+
A pip-installable CLI tool that uses AI to generate OpenAPI 3.0.3 specifications for any REST API project directory.
|
|
23
|
+
|
|
24
|
+
## Overview
|
|
25
|
+
|
|
26
|
+
Point this tool at any REST API project and it will scan the source files, send them to an AI model (Claude or OpenAI), and produce a valid OpenAPI 3.0.3 JSON specification.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# With Claude support (default)
|
|
32
|
+
pip install "openapi-generator[claude]"
|
|
33
|
+
|
|
34
|
+
# With OpenAI support
|
|
35
|
+
pip install "openapi-generator[openai]"
|
|
36
|
+
|
|
37
|
+
# Both providers
|
|
38
|
+
pip install "openapi-generator[all]"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
openapi-gen <path-to-project> --api-key <your-api-key>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The API key can also be provided via the `OPENAPI_GEN_API_KEY` environment variable:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
export OPENAPI_GEN_API_KEY=sk-ant-...
|
|
51
|
+
openapi-gen <path-to-project>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Options
|
|
55
|
+
|
|
56
|
+
| Option | Default | Description |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| `<path>` | _(required)_ | Path to the REST API project directory |
|
|
59
|
+
| `--api-key` | `OPENAPI_GEN_API_KEY` env var | AI provider API key |
|
|
60
|
+
| `--provider` | `claude` | AI provider: `claude` or `openai` |
|
|
61
|
+
| `--output`, `-o` | `openapi.json` | Output file path |
|
|
62
|
+
| `--title` | `API` | API title in the spec |
|
|
63
|
+
| `--version` | `1.0.0` | API version in the spec |
|
|
64
|
+
|
|
65
|
+
### Examples
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Generate a spec using Claude (default)
|
|
69
|
+
export OPENAPI_GEN_API_KEY=sk-ant-...
|
|
70
|
+
openapi-gen ./my-api
|
|
71
|
+
|
|
72
|
+
# Generate a spec using OpenAI
|
|
73
|
+
openapi-gen ./my-api --provider openai --api-key sk-...
|
|
74
|
+
|
|
75
|
+
# Specify title, version, and output path
|
|
76
|
+
openapi-gen ./my-api --title "My REST API" --version "2.0.0" --output ./docs/openapi.json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Output
|
|
80
|
+
|
|
81
|
+
The generated file follows the [OpenAPI 3.0.3 specification](https://spec.openapis.org/oas/v3.0.3) and can be used directly with tools like Swagger UI, Postman, or any OpenAPI-compatible client generator.
|
|
82
|
+
|
|
83
|
+
## Supported Languages
|
|
84
|
+
|
|
85
|
+
The tool scans files with the following extensions: `.py`, `.js`, `.ts`, `.go`, `.java`, `.rb`, `.php`, `.cs`
|
|
86
|
+
|
|
87
|
+
## Development
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
git clone https://github.com/your-org/openapi-generator
|
|
91
|
+
cd openapi-generator
|
|
92
|
+
pip install -e ".[dev]"
|
|
93
|
+
pytest
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/openapi_generator/__init__.py
|
|
4
|
+
src/openapi_generator/ai_client.py
|
|
5
|
+
src/openapi_generator/cli.py
|
|
6
|
+
src/openapi_generator/file_collector.py
|
|
7
|
+
src/openapi_generator/generator.py
|
|
8
|
+
src/openapi_spec_generator.egg-info/PKG-INFO
|
|
9
|
+
src/openapi_spec_generator.egg-info/SOURCES.txt
|
|
10
|
+
src/openapi_spec_generator.egg-info/dependency_links.txt
|
|
11
|
+
src/openapi_spec_generator.egg-info/entry_points.txt
|
|
12
|
+
src/openapi_spec_generator.egg-info/requires.txt
|
|
13
|
+
src/openapi_spec_generator.egg-info/top_level.txt
|
|
14
|
+
tests/test_generator.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
openapi_generator
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import pytest
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from unittest.mock import patch
|
|
5
|
+
|
|
6
|
+
from openapi_generator.file_collector import collect_files
|
|
7
|
+
from openapi_generator.generator import generate_spec
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# --- file_collector tests ---
|
|
11
|
+
|
|
12
|
+
def test_collect_files_filters_extensions(tmp_path: Path) -> None:
|
|
13
|
+
(tmp_path / "app.py").write_text("# python")
|
|
14
|
+
(tmp_path / "README.md").write_text("# docs")
|
|
15
|
+
(tmp_path / "logo.png").write_bytes(b"\x89PNG")
|
|
16
|
+
|
|
17
|
+
files = collect_files(tmp_path)
|
|
18
|
+
paths = [p for p, _ in files]
|
|
19
|
+
assert "app.py" in paths
|
|
20
|
+
assert "README.md" not in paths
|
|
21
|
+
assert "logo.png" not in paths
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_collect_files_respects_max_bytes(tmp_path: Path) -> None:
|
|
25
|
+
# "a_small.py" sorts before "z_big.py", so small is collected first;
|
|
26
|
+
# adding big would exceed the budget, so we stop with exactly 1 file.
|
|
27
|
+
(tmp_path / "a_small.py").write_text("y" * 100)
|
|
28
|
+
(tmp_path / "z_big.py").write_text("x" * 300)
|
|
29
|
+
|
|
30
|
+
files = collect_files(tmp_path, max_bytes=250)
|
|
31
|
+
assert len(files) == 1
|
|
32
|
+
assert files[0][0] == "a_small.py"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_collect_files_skips_excluded_dirs(tmp_path: Path) -> None:
|
|
36
|
+
node_modules = tmp_path / "node_modules"
|
|
37
|
+
node_modules.mkdir()
|
|
38
|
+
(node_modules / "dep.js").write_text("module.exports = {}")
|
|
39
|
+
(tmp_path / "index.js").write_text("const x = 1")
|
|
40
|
+
|
|
41
|
+
files = collect_files(tmp_path)
|
|
42
|
+
paths = [p for p, _ in files]
|
|
43
|
+
assert "index.js" in paths
|
|
44
|
+
assert not any("node_modules" in p for p in paths)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# --- generator tests ---
|
|
48
|
+
|
|
49
|
+
def test_generate_spec_calls_ai_and_parses_result(tmp_path: Path) -> None:
|
|
50
|
+
(tmp_path / "app.py").write_text("# flask app")
|
|
51
|
+
fake_spec = {
|
|
52
|
+
"openapi": "3.0.3",
|
|
53
|
+
"info": {"title": "Test API", "version": "0.1.0"},
|
|
54
|
+
"paths": {},
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
with patch("openapi_generator.generator.call_ai", return_value=json.dumps(fake_spec)):
|
|
58
|
+
spec = generate_spec(tmp_path, title="Test API", api_version="0.1.0", api_key="fake", provider="claude")
|
|
59
|
+
|
|
60
|
+
assert spec["openapi"] == "3.0.3"
|
|
61
|
+
assert spec["info"]["title"] == "Test API"
|
|
62
|
+
assert spec["info"]["version"] == "0.1.0"
|
|
63
|
+
assert "paths" in spec
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_generate_spec_strips_markdown_fences(tmp_path: Path) -> None:
|
|
67
|
+
(tmp_path / "app.py").write_text("# flask app")
|
|
68
|
+
fake_spec = {"openapi": "3.0.3", "info": {"title": "A", "version": "1"}, "paths": {}}
|
|
69
|
+
raw = f"```json\n{json.dumps(fake_spec)}\n```"
|
|
70
|
+
|
|
71
|
+
with patch("openapi_generator.generator.call_ai", return_value=raw):
|
|
72
|
+
spec = generate_spec(tmp_path, title="A", api_version="1", api_key="fake", provider="claude")
|
|
73
|
+
|
|
74
|
+
assert spec["openapi"] == "3.0.3"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_generate_spec_raises_on_invalid_json(tmp_path: Path) -> None:
|
|
78
|
+
(tmp_path / "app.py").write_text("# flask app")
|
|
79
|
+
|
|
80
|
+
with patch("openapi_generator.generator.call_ai", return_value="not json at all"):
|
|
81
|
+
with pytest.raises(ValueError, match="not valid JSON"):
|
|
82
|
+
generate_spec(tmp_path, title="A", api_version="1", api_key="fake", provider="claude")
|