diff --git a/devctl/commands/add.py b/devctl/commands/add.py index a0a2c1d..d3947db 100644 --- a/devctl/commands/add.py +++ b/devctl/commands/add.py @@ -7,9 +7,9 @@ import typer -from devctl.generators.scaffold_angular import generate_angular_resource -from devctl.generators.scaffold_spring import generate_spring_resource -from devctl.generators.scaffold_vue import generate_vue_resource +from devctl.generators.angular.scaffold import generate_angular_resource +from devctl.generators.spring.scaffold import generate_spring_resource +from devctl.generators.vue.scaffold import generate_vue_resource from devctl.orchestrator.scanner import detect_environment app = typer.Typer(help="Adds resources to the current project (Scaffolding).") diff --git a/devctl/commands/init.py b/devctl/commands/init.py index bc819fe..8f93999 100644 --- a/devctl/commands/init.py +++ b/devctl/commands/init.py @@ -5,12 +5,13 @@ import typer -# Angular generator -from devctl.generators.angular import generate_angular_boilerplate +# Angular Generator +from devctl.generators.angular.init import generate_angular_boilerplate + +# Spring Generator +from devctl.generators.spring.init import download_spring_boilerplate +from devctl.generators.vue.init import generate_vue_boilerplate -# Spring generator -from devctl.generators.spring import download_spring_boilerplate -from devctl.generators.vue import generate_vue_boilerplate from devctl.orchestrator.config_builder import generate_config from devctl.utils.dependencies import check_tool diff --git a/devctl/generators/angular/__init__.py b/devctl/generators/angular/__init__.py new file mode 100644 index 0000000..16e3bcb --- /dev/null +++ b/devctl/generators/angular/__init__.py @@ -0,0 +1,2 @@ +from .init import generate_angular_boilerplate, setup_angular_environments +from .scaffold import generate_angular_resource, parse_ts_fields diff --git a/devctl/generators/angular.py b/devctl/generators/angular/init.py similarity index 94% rename from devctl/generators/angular.py rename to devctl/generators/angular/init.py index 9cf0a46..55f5c76 100644 --- a/devctl/generators/angular.py +++ b/devctl/generators/angular/init.py @@ -8,7 +8,7 @@ import subprocess import typer -from jinja2 import Environment, FileSystemLoader +from devctl.utils.templates import get_jinja_env def setup_angular_environments(project_path: str): @@ -23,8 +23,7 @@ def setup_angular_environments(project_path: str): os.makedirs(env_dir, exist_ok=True) # 2. Template rendering via Jinja2 - templates_dir = os.path.join(os.path.dirname(__file__), "..", "templates", "angular", "config") - env = Environment(loader=FileSystemLoader(templates_dir)) + env = get_jinja_env("angular/config") files_to_generate = { "proxy.conf.json.j2": os.path.join(project_path, "src", "proxy.conf.json"), diff --git a/devctl/generators/scaffold_angular.py b/devctl/generators/angular/scaffold.py similarity index 96% rename from devctl/generators/scaffold_angular.py rename to devctl/generators/angular/scaffold.py index 06f4255..92870aa 100644 --- a/devctl/generators/scaffold_angular.py +++ b/devctl/generators/angular/scaffold.py @@ -6,9 +6,9 @@ import os import typer -from jinja2 import Environment, FileSystemLoader from devctl.orchestrator.scanner import detect_environment +from devctl.utils.templates import get_jinja_env # Dictionary mapping CLI types to TypeScript types TS_TYPE_MAP = { @@ -117,8 +117,7 @@ def generate_angular_resource(resource_name: str, fields_str: str, root_path: st }, ] - templates_dir = os.path.join(os.path.dirname(__file__), "..", "templates", "angular", "feature") - env = Environment(loader=FileSystemLoader(templates_dir)) + env = get_jinja_env("angular/feature") typer.secho(f"⚙️ Generating Angular feature '{entity_name}'...", fg=typer.colors.CYAN) diff --git a/devctl/generators/spring/__init__.py b/devctl/generators/spring/__init__.py new file mode 100644 index 0000000..c8154cb --- /dev/null +++ b/devctl/generators/spring/__init__.py @@ -0,0 +1,2 @@ +from .init import patch_pom_xml, download_spring_boilerplate +from .scaffold import generate_spring_resource, generate_spring_security diff --git a/devctl/generators/spring.py b/devctl/generators/spring/init.py similarity index 99% rename from devctl/generators/spring.py rename to devctl/generators/spring/init.py index 39cdade..acce45e 100644 --- a/devctl/generators/spring.py +++ b/devctl/generators/spring/init.py @@ -12,7 +12,7 @@ import requests import typer -from devctl.generators.scaffold_spring import generate_spring_security +from devctl.generators.spring.scaffold import generate_spring_security def patch_pom_xml(project_path: str): diff --git a/devctl/generators/scaffold_spring.py b/devctl/generators/spring/scaffold.py similarity index 93% rename from devctl/generators/scaffold_spring.py rename to devctl/generators/spring/scaffold.py index 92fb5ed..6d7ba26 100644 --- a/devctl/generators/scaffold_spring.py +++ b/devctl/generators/spring/scaffold.py @@ -6,7 +6,8 @@ import os import typer -from jinja2 import Environment, FileSystemLoader + +from devctl.utils.templates import get_jinja_env # Dictionary mapping CLI types to Java types JAVA_TYPE_MAP = { @@ -87,8 +88,7 @@ def generate_spring_resource(resource_name: str, fields_str: str): {"dir": "mapper", "suffix": "Mapper", "template": "mapper/Mapper.java.j2"}, ] - templates_dir = os.path.join(os.path.dirname(__file__), "..", "templates", "spring") - env = Environment(loader=FileSystemLoader(templates_dir)) + env = get_jinja_env("spring") typer.secho( f"⚙️ Generating Spring resource '{entity_name}' (with MapStruct & DTOs)...", @@ -143,8 +143,7 @@ def generate_spring_security(_root_path: str = "."): os.makedirs(target_dir, exist_ok=True) # Setup Jinja2 - templates_dir = os.path.join(os.path.dirname(__file__), "..", "templates", "spring", "config") - env = Environment(loader=FileSystemLoader(templates_dir)) + env = get_jinja_env("spring/config") security_files = [ "JwtService.java", diff --git a/devctl/generators/vue/__init__.py b/devctl/generators/vue/__init__.py new file mode 100644 index 0000000..a582f3b --- /dev/null +++ b/devctl/generators/vue/__init__.py @@ -0,0 +1,2 @@ +from .init import generate_vue_boilerplate, setup_vue_proxy, setup_vue_router +from .scaffold import generate_vue_resource diff --git a/devctl/generators/vue.py b/devctl/generators/vue/init.py similarity index 90% rename from devctl/generators/vue.py rename to devctl/generators/vue/init.py index 439d581..309e4c7 100644 --- a/devctl/generators/vue.py +++ b/devctl/generators/vue/init.py @@ -7,7 +7,8 @@ import subprocess import typer -from jinja2 import Environment, FileSystemLoader + +from devctl.utils.templates import get_jinja_env def setup_vue_proxy(project_path: str): @@ -16,8 +17,7 @@ def setup_vue_proxy(project_path: str): """ typer.secho("⚙️ Configuring Vite Proxy for Spring Boot...", fg=typer.colors.CYAN) - templates_dir = os.path.join(os.path.dirname(__file__), "..", "templates", "vue", "config") - env = Environment(loader=FileSystemLoader(templates_dir)) + env = get_jinja_env("vue/config") target_path = os.path.join(project_path, "vite.config.ts") @@ -52,8 +52,7 @@ def setup_vue_router(project_path: str): os.makedirs(router_dir, exist_ok=True) # 3. Jinja2 template rendering - templates_dir = os.path.join(os.path.dirname(__file__), "..", "templates", "vue", "config") - env = Environment(loader=FileSystemLoader(templates_dir)) + env = get_jinja_env("vue/config") files_to_generate = { "router.ts.j2": os.path.join(router_dir, "index.ts"), diff --git a/devctl/generators/scaffold_vue.py b/devctl/generators/vue/scaffold.py similarity index 89% rename from devctl/generators/scaffold_vue.py rename to devctl/generators/vue/scaffold.py index 414c071..84667cf 100644 --- a/devctl/generators/scaffold_vue.py +++ b/devctl/generators/vue/scaffold.py @@ -6,10 +6,10 @@ import os import typer -from jinja2 import Environment, FileSystemLoader, select_autoescape -from devctl.generators.scaffold_angular import parse_ts_fields +from devctl.generators.angular.scaffold import parse_ts_fields from devctl.orchestrator.scanner import detect_environment +from devctl.utils.templates import get_jinja_env def generate_vue_resource(resource_name: str, fields_str: str, root_path: str = "."): @@ -68,11 +68,7 @@ def generate_vue_resource(resource_name: str, fields_str: str, root_path: str = }, ] - templates_dir = os.path.join(os.path.dirname(__file__), "..", "templates", "vue", "feature") - env = Environment( - loader=FileSystemLoader(templates_dir), - autoescape=select_autoescape(["html", "xml"]), - ) + env = get_jinja_env("vue/feature") typer.secho(f"⚙️ Generating Vue.js feature '{entity_name}'...", fg=typer.colors.CYAN) diff --git a/devctl/utils/templates.py b/devctl/utils/templates.py new file mode 100644 index 0000000..1bedebf --- /dev/null +++ b/devctl/utils/templates.py @@ -0,0 +1,21 @@ +import os +from pathlib import Path +from jinja2 import Environment, FileSystemLoader + + +def get_jinja_env(template_subdir: str) -> Environment: + """ + Returns a Jinja2 environment for a specific template subdirectory. + """ + base_dir = Path(__file__).resolve().parent.parent / "templates" + template_path = base_dir / template_subdir + + if not template_path.exists(): + raise FileNotFoundError(f"Template directory not found: {template_path}") + + return Environment( + loader=FileSystemLoader(str(template_path)), + trim_blocks=True, + lstrip_blocks=True, + keep_trailing_newline=True, + )