Coverage for src/lexigram/web/cli/generators/controller.py: 39%
28 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 04:37 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 04:37 +0800
1"""Controller generator."""
3from __future__ import annotations
5from pathlib import Path
7from lexigram.codegen import GenerationResult, GeneratorBase, parse_fields
10class ControllerGenerator(GeneratorBase):
11 """Generate a controller class with CRUD endpoints."""
13 def __init__(self, output_dir: str | Path = "src/controllers") -> None:
14 super().__init__(output_dir=output_dir)
16 def generate(
17 self,
18 name: str,
19 *,
20 fields_str: str | None = None,
21 path: str | None = None,
22 doc: str | None = None,
23 dry_run: bool = False,
24 force: bool = False,
25 **options: object,
26 ) -> GenerationResult:
27 name = self._strip_type_suffix(name, "Controller")
28 model_name = self._to_snake_case(name)
29 resource_name = self._pluralize(model_name)
30 api_path = path or f"/{resource_name}"
31 fields = parse_fields(fields_str or "")
32 file_path = self.output_dir / f"{model_name}_controller.py"
33 content = self.render_template(
34 "controller.py.jinja2",
35 {
36 "class_name": self._to_pascal_case(name),
37 "model_name": model_name,
38 "resource_name": resource_name,
39 "resource_path": api_path.strip("/"),
40 "doc": doc,
41 "required_fields": [field.name for field in fields if field.required],
42 "fields": [
43 {
44 "name": field.name,
45 "type": field.type,
46 "required": field.required,
47 }
48 for field in fields
49 ],
50 },
51 )
52 return self.write_file(file_path, content, dry_run=dry_run, force=force)
54 @staticmethod
55 def _strip_type_suffix(name: str, suffix: str) -> str:
56 if name.endswith(suffix) and len(name) > len(suffix):
57 return name[: -len(suffix)]
58 return name
60 @staticmethod
61 def _pluralize(value: str) -> str:
62 if value.endswith("y") and value[-2:-1] not in {"a", "e", "i", "o", "u"}:
63 return f"{value[:-1]}ies"
64 if value.endswith("s"):
65 return value
66 return f"{value}s"
69__all__ = ["ControllerGenerator"]