Files
patternforge/src/patternforge/generator.py
7000pctAUTO 165db96129
Some checks failed
CI / test (3.10) (push) Has been cancelled
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / build (push) Has been cancelled
fix: resolve CI mypy type checking issues
2026-02-02 22:57:31 +00:00

158 lines
5.0 KiB
Python

import json
import re
from pathlib import Path
from typing import Any
from patternforge.analyzer import CodeAnalyzer
from patternforge.config import Config
from patternforge.template import TemplateManager
class BoilerplateGenerator:
def __init__(self, config: Config) -> None:
self.config = config
self.analyzer = CodeAnalyzer("python", config)
self.template_manager = TemplateManager(config)
def _to_camel_case(self, snake: str) -> str:
if "_" not in snake:
return snake.lower()
parts = snake.split("_")
return parts[0].lower() + "".join(p.title() for p in parts[1:])
def _to_pascal_case(self, camel: str) -> str:
if "_" not in camel:
return camel[0].upper() + camel[1:] if camel else ""
parts = camel.split("_")
return "".join(p.title() for p in parts)
def _to_snake_case(self, name: str) -> str:
if "_" in name:
return name.lower()
result = re.sub(r"(?<!^)(?=[A-Z])", "_", name)
return result.lower()
def _infer_context(
self,
template_name: str,
entity_name: str | None,
) -> dict[str, Any]:
template = self.template_manager.get_template(template_name)
if not template:
raise ValueError(f"Template not found: {template_name}")
name = entity_name or template_name
patterns = template.get("patterns", {})
primary_naming = patterns.get("summary", {}).get("primary_naming", "snake_case")
context: dict[str, Any] = {
"project_name": "generated-project",
"entity_name": name,
"class_name": "",
"function_name": "",
"fields": [],
"methods": [],
"params": "",
"docstring": f"Generated {name}",
"class_docstring": f"Auto-generated class for {name}",
}
if primary_naming == "PascalCase":
context["class_name"] = self._to_pascal_case(name)
context["function_name"] = self._to_camel_case(name)
elif primary_naming == "camelCase":
context["class_name"] = self._to_pascal_case(name)
context["function_name"] = self._to_camel_case(name)
else:
context["class_name"] = self._to_pascal_case(name)
context["function_name"] = name
context["fields"] = [
f"{self._to_camel_case(name)}Id",
f"{self._to_camel_case(name)}Name",
"createdAt",
"updatedAt",
]
context["methods"] = [
{"name": "validate", "params": "", "docstring": "Validate the entity"},
{"name": "to_dict", "params": "", "docstring": "Convert to dictionary"},
{"name": "to_json", "params": "", "docstring": "Convert to JSON string"},
]
context["init_params"] = ", ".join(
f"{self._to_camel_case(name)}{field}"
for field in context["fields"]
)
context["params"] = ", ".join(
f"{self._to_camel_case(name)}{field}" for field in context["fields"][:2]
)
return context
def _get_file_extension(self, template_name: str) -> str:
template = self.template_manager.get_template(template_name)
if not template:
return ".txt"
lang = template.get("language", "")
extensions = {
"python": ".py",
"javascript": ".js",
"typescript": ".ts",
"java": ".java",
"cpp": ".cpp",
"c": ".c",
"rust": ".rs",
"go": ".go",
"ruby": ".rb",
}
return extensions.get(lang, ".txt")
def generate(
self,
template_name: str,
output_dir: str,
data_file: str | None = None,
entity_name: str | None = None,
) -> list[Path]:
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
context = self._infer_context(template_name, entity_name)
if data_file:
with open(data_file) as f:
data = json.load(f)
context.update(data)
try:
content = self.template_manager.render_template(template_name, context)
except ValueError as e:
raise RuntimeError(f"Failed to render template: {e}")
ext = self._get_file_extension(template_name)
filename = f"{entity_name or template_name}{ext}"
file_path = output_path / filename
file_path.write_text(content)
return [file_path]
def generate_multiple(
self,
template_name: str,
output_dir: str,
entities: list[dict[str, Any]],
) -> list[Path]:
generated: list[Path] = []
for entity in entities:
name = entity.get("name", "untitled")
paths = self.generate(
template_name,
output_dir,
entity.get("data_file"),
name,
)
generated.extend(paths)
return generated