litestar-vite 0.1.1__py3-none-any.whl → 0.15.0__py3-none-any.whl
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.
- litestar_vite/__init__.py +54 -4
- litestar_vite/__metadata__.py +12 -7
- litestar_vite/cli.py +1048 -10
- litestar_vite/codegen/__init__.py +48 -0
- litestar_vite/codegen/_export.py +229 -0
- litestar_vite/codegen/_inertia.py +619 -0
- litestar_vite/codegen/_openapi.py +280 -0
- litestar_vite/codegen/_routes.py +720 -0
- litestar_vite/codegen/_ts.py +235 -0
- litestar_vite/codegen/_utils.py +141 -0
- litestar_vite/commands.py +73 -0
- litestar_vite/config/__init__.py +997 -0
- litestar_vite/config/_constants.py +97 -0
- litestar_vite/config/_deploy.py +70 -0
- litestar_vite/config/_inertia.py +241 -0
- litestar_vite/config/_paths.py +63 -0
- litestar_vite/config/_runtime.py +235 -0
- litestar_vite/config/_spa.py +93 -0
- litestar_vite/config/_types.py +94 -0
- litestar_vite/deploy.py +366 -0
- litestar_vite/doctor.py +1181 -0
- litestar_vite/exceptions.py +78 -0
- litestar_vite/executor.py +360 -0
- litestar_vite/handler/__init__.py +9 -0
- litestar_vite/handler/_app.py +612 -0
- litestar_vite/handler/_routing.py +130 -0
- litestar_vite/html_transform.py +569 -0
- litestar_vite/inertia/__init__.py +77 -0
- litestar_vite/inertia/_utils.py +119 -0
- litestar_vite/inertia/exception_handler.py +178 -0
- litestar_vite/inertia/helpers.py +1571 -0
- litestar_vite/inertia/middleware.py +54 -0
- litestar_vite/inertia/plugin.py +199 -0
- litestar_vite/inertia/precognition.py +274 -0
- litestar_vite/inertia/request.py +334 -0
- litestar_vite/inertia/response.py +802 -0
- litestar_vite/inertia/types.py +335 -0
- litestar_vite/loader.py +464 -123
- litestar_vite/plugin/__init__.py +687 -0
- litestar_vite/plugin/_process.py +185 -0
- litestar_vite/plugin/_proxy.py +689 -0
- litestar_vite/plugin/_proxy_headers.py +244 -0
- litestar_vite/plugin/_static.py +37 -0
- litestar_vite/plugin/_utils.py +489 -0
- litestar_vite/py.typed +0 -0
- litestar_vite/scaffolding/__init__.py +20 -0
- litestar_vite/scaffolding/generator.py +270 -0
- litestar_vite/scaffolding/templates.py +437 -0
- litestar_vite/templates/__init__.py +0 -0
- litestar_vite/templates/addons/tailwindcss/tailwind.css.j2 +1 -0
- litestar_vite/templates/angular/index.html.j2 +12 -0
- litestar_vite/templates/angular/openapi-ts.config.ts.j2 +18 -0
- litestar_vite/templates/angular/package.json.j2 +36 -0
- litestar_vite/templates/angular/src/app/app.component.css.j2 +3 -0
- litestar_vite/templates/angular/src/app/app.component.html.j2 +1 -0
- litestar_vite/templates/angular/src/app/app.component.ts.j2 +9 -0
- litestar_vite/templates/angular/src/app/app.config.ts.j2 +5 -0
- litestar_vite/templates/angular/src/main.ts.j2 +9 -0
- litestar_vite/templates/angular/src/styles.css.j2 +9 -0
- litestar_vite/templates/angular/tsconfig.app.json.j2 +34 -0
- litestar_vite/templates/angular/tsconfig.json.j2 +20 -0
- litestar_vite/templates/angular/vite.config.ts.j2 +21 -0
- litestar_vite/templates/angular-cli/.postcssrc.json.j2 +5 -0
- litestar_vite/templates/angular-cli/angular.json.j2 +36 -0
- litestar_vite/templates/angular-cli/openapi-ts.config.ts.j2 +18 -0
- litestar_vite/templates/angular-cli/package.json.j2 +28 -0
- litestar_vite/templates/angular-cli/proxy.conf.json.j2 +18 -0
- litestar_vite/templates/angular-cli/src/app/app.component.css.j2 +3 -0
- litestar_vite/templates/angular-cli/src/app/app.component.html.j2 +1 -0
- litestar_vite/templates/angular-cli/src/app/app.component.ts.j2 +9 -0
- litestar_vite/templates/angular-cli/src/app/app.config.ts.j2 +5 -0
- litestar_vite/templates/angular-cli/src/index.html.j2 +13 -0
- litestar_vite/templates/angular-cli/src/main.ts.j2 +6 -0
- litestar_vite/templates/angular-cli/src/styles.css.j2 +10 -0
- litestar_vite/templates/angular-cli/tailwind.config.js.j2 +4 -0
- litestar_vite/templates/angular-cli/tsconfig.app.json.j2 +16 -0
- litestar_vite/templates/angular-cli/tsconfig.json.j2 +26 -0
- litestar_vite/templates/angular-cli/tsconfig.spec.json.j2 +9 -0
- litestar_vite/templates/astro/astro.config.mjs.j2 +28 -0
- litestar_vite/templates/astro/openapi-ts.config.ts.j2 +15 -0
- litestar_vite/templates/astro/src/layouts/Layout.astro.j2 +63 -0
- litestar_vite/templates/astro/src/pages/index.astro.j2 +36 -0
- litestar_vite/templates/astro/src/styles/global.css.j2 +1 -0
- litestar_vite/templates/base/.gitignore.j2 +42 -0
- litestar_vite/templates/base/openapi-ts.config.ts.j2 +15 -0
- litestar_vite/templates/base/package.json.j2 +39 -0
- litestar_vite/templates/base/resources/vite-env.d.ts.j2 +1 -0
- litestar_vite/templates/base/tsconfig.json.j2 +37 -0
- litestar_vite/templates/htmx/src/main.js.j2 +8 -0
- litestar_vite/templates/htmx/templates/base.html.j2.j2 +56 -0
- litestar_vite/templates/htmx/templates/index.html.j2.j2 +13 -0
- litestar_vite/templates/htmx/vite.config.ts.j2 +40 -0
- litestar_vite/templates/nuxt/app.vue.j2 +29 -0
- litestar_vite/templates/nuxt/composables/useApi.ts.j2 +33 -0
- litestar_vite/templates/nuxt/nuxt.config.ts.j2 +31 -0
- litestar_vite/templates/nuxt/openapi-ts.config.ts.j2 +15 -0
- litestar_vite/templates/nuxt/pages/index.vue.j2 +54 -0
- litestar_vite/templates/react/index.html.j2 +13 -0
- litestar_vite/templates/react/src/App.css.j2 +56 -0
- litestar_vite/templates/react/src/App.tsx.j2 +19 -0
- litestar_vite/templates/react/src/main.tsx.j2 +10 -0
- litestar_vite/templates/react/vite.config.ts.j2 +39 -0
- litestar_vite/templates/react-inertia/index.html.j2 +14 -0
- litestar_vite/templates/react-inertia/package.json.j2 +47 -0
- litestar_vite/templates/react-inertia/resources/App.css.j2 +68 -0
- litestar_vite/templates/react-inertia/resources/main.tsx.j2 +17 -0
- litestar_vite/templates/react-inertia/resources/pages/Home.tsx.j2 +18 -0
- litestar_vite/templates/react-inertia/resources/ssr.tsx.j2 +19 -0
- litestar_vite/templates/react-inertia/vite.config.ts.j2 +59 -0
- litestar_vite/templates/react-router/index.html.j2 +12 -0
- litestar_vite/templates/react-router/src/App.css.j2 +17 -0
- litestar_vite/templates/react-router/src/App.tsx.j2 +7 -0
- litestar_vite/templates/react-router/src/main.tsx.j2 +10 -0
- litestar_vite/templates/react-router/vite.config.ts.j2 +39 -0
- litestar_vite/templates/react-tanstack/index.html.j2 +12 -0
- litestar_vite/templates/react-tanstack/openapi-ts.config.ts.j2 +18 -0
- litestar_vite/templates/react-tanstack/src/App.css.j2 +17 -0
- litestar_vite/templates/react-tanstack/src/main.tsx.j2 +21 -0
- litestar_vite/templates/react-tanstack/src/routeTree.gen.ts.j2 +7 -0
- litestar_vite/templates/react-tanstack/src/routes/__root.tsx.j2 +9 -0
- litestar_vite/templates/react-tanstack/src/routes/books.tsx.j2 +9 -0
- litestar_vite/templates/react-tanstack/src/routes/index.tsx.j2 +9 -0
- litestar_vite/templates/react-tanstack/vite.config.ts.j2 +39 -0
- litestar_vite/templates/svelte/index.html.j2 +13 -0
- litestar_vite/templates/svelte/src/App.svelte.j2 +30 -0
- litestar_vite/templates/svelte/src/app.css.j2 +45 -0
- litestar_vite/templates/svelte/src/main.ts.j2 +8 -0
- litestar_vite/templates/svelte/src/vite-env.d.ts.j2 +2 -0
- litestar_vite/templates/svelte/svelte.config.js.j2 +5 -0
- litestar_vite/templates/svelte/vite.config.ts.j2 +39 -0
- litestar_vite/templates/svelte-inertia/index.html.j2 +14 -0
- litestar_vite/templates/svelte-inertia/resources/app.css.j2 +21 -0
- litestar_vite/templates/svelte-inertia/resources/main.ts.j2 +11 -0
- litestar_vite/templates/svelte-inertia/resources/pages/Home.svelte.j2 +43 -0
- litestar_vite/templates/svelte-inertia/resources/vite-env.d.ts.j2 +2 -0
- litestar_vite/templates/svelte-inertia/svelte.config.js.j2 +5 -0
- litestar_vite/templates/svelte-inertia/vite.config.ts.j2 +37 -0
- litestar_vite/templates/sveltekit/openapi-ts.config.ts.j2 +15 -0
- litestar_vite/templates/sveltekit/src/app.css.j2 +40 -0
- litestar_vite/templates/sveltekit/src/app.html.j2 +12 -0
- litestar_vite/templates/sveltekit/src/hooks.server.ts.j2 +55 -0
- litestar_vite/templates/sveltekit/src/routes/+layout.svelte.j2 +12 -0
- litestar_vite/templates/sveltekit/src/routes/+page.svelte.j2 +34 -0
- litestar_vite/templates/sveltekit/svelte.config.js.j2 +12 -0
- litestar_vite/templates/sveltekit/tsconfig.json.j2 +14 -0
- litestar_vite/templates/sveltekit/vite.config.ts.j2 +31 -0
- litestar_vite/templates/vue/env.d.ts.j2 +7 -0
- litestar_vite/templates/vue/index.html.j2 +13 -0
- litestar_vite/templates/vue/src/App.vue.j2 +28 -0
- litestar_vite/templates/vue/src/main.ts.j2 +5 -0
- litestar_vite/templates/vue/src/style.css.j2 +45 -0
- litestar_vite/templates/vue/vite.config.ts.j2 +39 -0
- litestar_vite/templates/vue-inertia/env.d.ts.j2 +7 -0
- litestar_vite/templates/vue-inertia/index.html.j2 +14 -0
- litestar_vite/templates/vue-inertia/package.json.j2 +50 -0
- litestar_vite/templates/vue-inertia/resources/main.ts.j2 +18 -0
- litestar_vite/templates/vue-inertia/resources/pages/Home.vue.j2 +22 -0
- litestar_vite/templates/vue-inertia/resources/ssr.ts.j2 +21 -0
- litestar_vite/templates/vue-inertia/resources/style.css.j2 +21 -0
- litestar_vite/templates/vue-inertia/vite.config.ts.j2 +59 -0
- litestar_vite-0.15.0.dist-info/METADATA +230 -0
- litestar_vite-0.15.0.dist-info/RECORD +164 -0
- {litestar_vite-0.1.1.dist-info → litestar_vite-0.15.0.dist-info}/WHEEL +1 -1
- litestar_vite/config.py +0 -100
- litestar_vite/plugin.py +0 -45
- litestar_vite/template_engine.py +0 -103
- litestar_vite-0.1.1.dist-info/METADATA +0 -68
- litestar_vite-0.1.1.dist-info/RECORD +0 -11
- {litestar_vite-0.1.1.dist-info → litestar_vite-0.15.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""Project scaffolding generator.
|
|
2
|
+
|
|
3
|
+
This module handles the generation of project files from templates.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from litestar_vite.scaffolding.templates import FrameworkTemplate
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _dict_factory() -> dict[str, Any]:
|
|
16
|
+
return {}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_DictStrAnyFactory: Callable[[], dict[str, Any]] = _dict_factory
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class TemplateContext:
|
|
24
|
+
"""Context variables for template rendering.
|
|
25
|
+
|
|
26
|
+
Attributes:
|
|
27
|
+
project_name: Name of the project
|
|
28
|
+
framework: The selected framework template
|
|
29
|
+
use_typescript: Whether to use TypeScript
|
|
30
|
+
use_tailwind: Whether to add TailwindCSS
|
|
31
|
+
vite_port: Vite dev server port
|
|
32
|
+
litestar_port: Litestar server port
|
|
33
|
+
asset_url: Base URL for assets
|
|
34
|
+
resource_dir: Source directory for frontend files
|
|
35
|
+
bundle_dir: Output directory for built files
|
|
36
|
+
enable_ssr: Whether SSR is enabled
|
|
37
|
+
enable_inertia: Whether Inertia.js is used
|
|
38
|
+
enable_types: Whether type generation is enabled
|
|
39
|
+
generate_zod: Whether to generate Zod schemas
|
|
40
|
+
generate_client: Whether to generate API client
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
project_name: str
|
|
44
|
+
framework: "FrameworkTemplate"
|
|
45
|
+
use_typescript: bool = True
|
|
46
|
+
use_tailwind: bool = False
|
|
47
|
+
vite_port: int = 5173
|
|
48
|
+
litestar_port: int = 8000
|
|
49
|
+
asset_url: str = "/static/"
|
|
50
|
+
resource_dir: str = "resources"
|
|
51
|
+
bundle_dir: str = "public"
|
|
52
|
+
static_dir: str = "public"
|
|
53
|
+
base_dir: str = "."
|
|
54
|
+
enable_ssr: bool = False
|
|
55
|
+
enable_inertia: bool = False
|
|
56
|
+
enable_types: bool = True
|
|
57
|
+
generate_zod: bool = False
|
|
58
|
+
generate_client: bool = False
|
|
59
|
+
extra: dict[str, Any] = field(default_factory=_DictStrAnyFactory)
|
|
60
|
+
|
|
61
|
+
def to_dict(self) -> dict[str, Any]:
|
|
62
|
+
"""Convert context to dictionary for Jinja2 rendering.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Dictionary of template variables.
|
|
66
|
+
"""
|
|
67
|
+
return {
|
|
68
|
+
"project_name": self.project_name,
|
|
69
|
+
"framework": self.framework.type.value,
|
|
70
|
+
"framework_name": self.framework.name,
|
|
71
|
+
"use_typescript": self.use_typescript,
|
|
72
|
+
"use_tailwind": self.use_tailwind,
|
|
73
|
+
"vite_port": self.vite_port,
|
|
74
|
+
"litestar_port": self.litestar_port,
|
|
75
|
+
"asset_url": self.asset_url,
|
|
76
|
+
"resource_dir": self.resource_dir,
|
|
77
|
+
"bundle_dir": self.bundle_dir,
|
|
78
|
+
"static_dir": self.static_dir,
|
|
79
|
+
"base_dir": self.base_dir,
|
|
80
|
+
"enable_ssr": self.enable_ssr,
|
|
81
|
+
"enable_inertia": self.enable_inertia,
|
|
82
|
+
"enable_types": self.enable_types,
|
|
83
|
+
"generate_zod": self.generate_zod,
|
|
84
|
+
"generate_client": self.generate_client,
|
|
85
|
+
"dependencies": self.framework.dependencies,
|
|
86
|
+
"dev_dependencies": self.framework.dev_dependencies,
|
|
87
|
+
"vite_plugin": self.framework.vite_plugin,
|
|
88
|
+
"uses_vite": self.framework.uses_vite,
|
|
89
|
+
**self.extra,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_template_dir() -> Path:
|
|
94
|
+
"""Get the directory containing framework templates.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Path to the templates directory.
|
|
98
|
+
"""
|
|
99
|
+
return Path(__file__).parent.parent / "templates"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def render_template(template_path: Path, context: dict[str, Any]) -> str:
|
|
103
|
+
"""Render a Jinja2 template with the given context.
|
|
104
|
+
|
|
105
|
+
Templates are rendered with autoescaping disabled because the output is code
|
|
106
|
+
and configuration files, not HTML.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
template_path: Path to the template file.
|
|
110
|
+
context: Dictionary of template variables.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
Rendered template content.
|
|
114
|
+
"""
|
|
115
|
+
from jinja2 import Environment, FileSystemLoader
|
|
116
|
+
|
|
117
|
+
template_dir = template_path.parent
|
|
118
|
+
env = Environment(
|
|
119
|
+
loader=FileSystemLoader(str(template_dir)),
|
|
120
|
+
keep_trailing_newline=True,
|
|
121
|
+
autoescape=False, # noqa: S701
|
|
122
|
+
)
|
|
123
|
+
template = env.get_template(template_path.name)
|
|
124
|
+
return template.render(**context)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _process_templates(
|
|
128
|
+
template_dir: Path,
|
|
129
|
+
output_dir: Path,
|
|
130
|
+
context_dict: dict[str, Any],
|
|
131
|
+
resource_dir: str,
|
|
132
|
+
*,
|
|
133
|
+
overwrite: bool,
|
|
134
|
+
skip_paths: "set[Path] | None" = None,
|
|
135
|
+
) -> list[Path]:
|
|
136
|
+
"""Process templates from a directory and generate output files.
|
|
137
|
+
|
|
138
|
+
This function rewrites template paths so frameworks can customize the output
|
|
139
|
+
directory layout:
|
|
140
|
+
|
|
141
|
+
- ``resources/`` templates are rewritten to the configured ``resource_dir``.
|
|
142
|
+
- ``public/`` templates can be relocated via ``static_dir`` in the context.
|
|
143
|
+
|
|
144
|
+
SSR entrypoints under ``resources/`` are only generated when SSR is enabled.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
template_dir: Directory containing template files.
|
|
148
|
+
output_dir: Directory to write generated files.
|
|
149
|
+
context_dict: Template context dictionary.
|
|
150
|
+
resource_dir: Resource directory name for path rewriting.
|
|
151
|
+
overwrite: Whether to overwrite existing files.
|
|
152
|
+
skip_paths: Set of relative paths to skip.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
List of generated file paths.
|
|
156
|
+
"""
|
|
157
|
+
from litestar.cli._utils import console # pyright: ignore[reportPrivateImportUsage]
|
|
158
|
+
|
|
159
|
+
generated_files: list[Path] = []
|
|
160
|
+
skip_paths = skip_paths or set()
|
|
161
|
+
enable_ssr = bool(context_dict.get("enable_ssr"))
|
|
162
|
+
|
|
163
|
+
for template_file in template_dir.glob("**/*.j2"):
|
|
164
|
+
relative_path = template_file.relative_to(template_dir)
|
|
165
|
+
|
|
166
|
+
if relative_path in skip_paths:
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
if (
|
|
170
|
+
not enable_ssr
|
|
171
|
+
and relative_path.parts
|
|
172
|
+
and relative_path.parts[0] == "resources"
|
|
173
|
+
and relative_path.name.startswith("ssr.")
|
|
174
|
+
):
|
|
175
|
+
continue
|
|
176
|
+
|
|
177
|
+
if relative_path.parts and relative_path.parts[0] == "resources":
|
|
178
|
+
relative_path = Path(resource_dir, *relative_path.parts[1:])
|
|
179
|
+
|
|
180
|
+
if relative_path.parts and relative_path.parts[0] == "public":
|
|
181
|
+
relative_path = Path(context_dict.get("static_dir", "public"), *relative_path.parts[1:])
|
|
182
|
+
|
|
183
|
+
output_path = output_dir / str(relative_path).replace(".j2", "")
|
|
184
|
+
|
|
185
|
+
if output_path.exists() and not overwrite:
|
|
186
|
+
console.print(f"[yellow]Skipping {output_path} (exists)[/]")
|
|
187
|
+
continue
|
|
188
|
+
|
|
189
|
+
_render_and_write(template_file, output_path, context_dict)
|
|
190
|
+
generated_files.append(output_path)
|
|
191
|
+
|
|
192
|
+
return generated_files
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def generate_project(output_dir: Path, context: TemplateContext, *, overwrite: bool = False) -> list[Path]:
|
|
196
|
+
"""Generate project files from templates.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
output_dir: Directory to generate files in.
|
|
200
|
+
context: Template context with configuration.
|
|
201
|
+
overwrite: Whether to overwrite existing files.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
List of generated file paths.
|
|
205
|
+
"""
|
|
206
|
+
from litestar.cli._utils import console # pyright: ignore[reportPrivateImportUsage]
|
|
207
|
+
|
|
208
|
+
template_dir = get_template_dir()
|
|
209
|
+
framework_dir = template_dir / context.framework.type.value
|
|
210
|
+
base_dir = template_dir / "base"
|
|
211
|
+
context_dict = context.to_dict()
|
|
212
|
+
generated_files: list[Path] = []
|
|
213
|
+
|
|
214
|
+
framework_overrides: set[Path] = set()
|
|
215
|
+
if framework_dir.exists():
|
|
216
|
+
framework_overrides = {
|
|
217
|
+
template_file.relative_to(framework_dir) for template_file in framework_dir.glob("**/*.j2")
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
actual_output_dir = output_dir / context.base_dir if context.base_dir not in {"", "."} else output_dir
|
|
221
|
+
actual_output_dir.mkdir(parents=True, exist_ok=True)
|
|
222
|
+
|
|
223
|
+
if context.framework.uses_vite and base_dir.exists():
|
|
224
|
+
generated_files.extend(
|
|
225
|
+
_process_templates(
|
|
226
|
+
base_dir,
|
|
227
|
+
actual_output_dir,
|
|
228
|
+
context_dict,
|
|
229
|
+
context.resource_dir,
|
|
230
|
+
overwrite=overwrite,
|
|
231
|
+
skip_paths=framework_overrides,
|
|
232
|
+
)
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
if framework_dir.exists():
|
|
236
|
+
generated_files.extend(
|
|
237
|
+
_process_templates(
|
|
238
|
+
framework_dir, actual_output_dir, context_dict, context.resource_dir, overwrite=overwrite
|
|
239
|
+
)
|
|
240
|
+
)
|
|
241
|
+
else:
|
|
242
|
+
console.print(f"[dim]No framework templates for {context.framework.type.value}, using base templates[/]")
|
|
243
|
+
|
|
244
|
+
if context.use_tailwind:
|
|
245
|
+
tailwind_dir = template_dir / "addons" / "tailwindcss"
|
|
246
|
+
if tailwind_dir.exists():
|
|
247
|
+
generated_files.extend(
|
|
248
|
+
_process_templates(
|
|
249
|
+
tailwind_dir, actual_output_dir, context_dict, context.resource_dir, overwrite=overwrite
|
|
250
|
+
)
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
return generated_files
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _render_and_write(template_path: Path, output_path: Path, context: dict[str, Any]) -> None:
|
|
257
|
+
"""Render a template and write to output file.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
template_path: Path to the template file.
|
|
261
|
+
output_path: Path to write the rendered content.
|
|
262
|
+
context: Template context dictionary.
|
|
263
|
+
"""
|
|
264
|
+
from litestar.cli._utils import console # pyright: ignore[reportPrivateImportUsage]
|
|
265
|
+
|
|
266
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
267
|
+
|
|
268
|
+
content = render_template(template_path, context)
|
|
269
|
+
output_path.write_text(content, encoding="utf-8")
|
|
270
|
+
console.print(f"[green]Created {output_path}[/]")
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
"""Framework template definitions for scaffolding.
|
|
2
|
+
|
|
3
|
+
This module defines the available framework templates and their configurations.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from enum import Enum
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _str_list_factory() -> list[str]:
|
|
12
|
+
return []
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FrameworkType(str, Enum):
|
|
16
|
+
"""Supported frontend framework types."""
|
|
17
|
+
|
|
18
|
+
REACT = "react"
|
|
19
|
+
REACT_ROUTER = "react-router"
|
|
20
|
+
REACT_TANSTACK = "react-tanstack"
|
|
21
|
+
REACT_INERTIA = "react-inertia"
|
|
22
|
+
VUE = "vue"
|
|
23
|
+
VUE_INERTIA = "vue-inertia"
|
|
24
|
+
SVELTE = "svelte"
|
|
25
|
+
SVELTE_INERTIA = "svelte-inertia"
|
|
26
|
+
SVELTEKIT = "sveltekit"
|
|
27
|
+
NUXT = "nuxt"
|
|
28
|
+
ASTRO = "astro"
|
|
29
|
+
HTMX = "htmx"
|
|
30
|
+
ANGULAR = "angular"
|
|
31
|
+
ANGULAR_CLI = "angular-cli"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
_ListStrFactory: Callable[[], list[str]] = _str_list_factory
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class FrameworkTemplate:
|
|
39
|
+
"""Configuration for a frontend framework template.
|
|
40
|
+
|
|
41
|
+
Attributes:
|
|
42
|
+
name: Display name for the template
|
|
43
|
+
type: Framework type enum
|
|
44
|
+
description: Brief description shown in selection UI
|
|
45
|
+
vite_plugin: Name of the Vite plugin import (if any)
|
|
46
|
+
dependencies: NPM dependencies to install
|
|
47
|
+
dev_dependencies: NPM dev dependencies to install
|
|
48
|
+
files: List of template files to generate
|
|
49
|
+
uses_typescript: Whether TypeScript is used by default
|
|
50
|
+
has_ssr: Whether SSR is supported
|
|
51
|
+
inertia_compatible: Whether it works with Inertia.js
|
|
52
|
+
uses_vite: Whether the template is Vite-based (skip base files when False)
|
|
53
|
+
resource_dir: Preferred source directory name for the framework
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
name: str
|
|
57
|
+
type: FrameworkType
|
|
58
|
+
description: str
|
|
59
|
+
vite_plugin: "str | None" = None
|
|
60
|
+
dependencies: list[str] = field(default_factory=_ListStrFactory)
|
|
61
|
+
dev_dependencies: list[str] = field(default_factory=_ListStrFactory)
|
|
62
|
+
files: list[str] = field(default_factory=_ListStrFactory)
|
|
63
|
+
uses_typescript: bool = True
|
|
64
|
+
has_ssr: bool = False
|
|
65
|
+
inertia_compatible: bool = False
|
|
66
|
+
uses_vite: bool = True
|
|
67
|
+
resource_dir: str = "resources"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
FRAMEWORK_TEMPLATES: dict[FrameworkType, FrameworkTemplate] = {
|
|
71
|
+
FrameworkType.REACT: FrameworkTemplate(
|
|
72
|
+
name="React",
|
|
73
|
+
type=FrameworkType.REACT,
|
|
74
|
+
description="React 18+ with TypeScript and Vite",
|
|
75
|
+
vite_plugin="@vitejs/plugin-react",
|
|
76
|
+
dependencies=["react", "react-dom"],
|
|
77
|
+
dev_dependencies=["@vitejs/plugin-react", "@types/react", "@types/react-dom", "typescript"],
|
|
78
|
+
files=[
|
|
79
|
+
"vite.config.ts",
|
|
80
|
+
"tsconfig.json",
|
|
81
|
+
"package.json",
|
|
82
|
+
"index.html",
|
|
83
|
+
"src/main.tsx",
|
|
84
|
+
"src/App.tsx",
|
|
85
|
+
"src/App.css",
|
|
86
|
+
],
|
|
87
|
+
uses_typescript=True,
|
|
88
|
+
has_ssr=False,
|
|
89
|
+
inertia_compatible=True,
|
|
90
|
+
resource_dir="src",
|
|
91
|
+
),
|
|
92
|
+
FrameworkType.REACT_ROUTER: FrameworkTemplate(
|
|
93
|
+
name="React + React Router",
|
|
94
|
+
type=FrameworkType.REACT_ROUTER,
|
|
95
|
+
description="React 18+ with React Router for SPA routing",
|
|
96
|
+
vite_plugin="@vitejs/plugin-react",
|
|
97
|
+
dependencies=["react", "react-dom", "react-router-dom"],
|
|
98
|
+
dev_dependencies=["@vitejs/plugin-react", "@types/react", "@types/react-dom", "typescript"],
|
|
99
|
+
files=[
|
|
100
|
+
"vite.config.ts",
|
|
101
|
+
"tsconfig.json",
|
|
102
|
+
"package.json",
|
|
103
|
+
"index.html",
|
|
104
|
+
"src/main.tsx",
|
|
105
|
+
"src/App.tsx",
|
|
106
|
+
"src/App.css",
|
|
107
|
+
],
|
|
108
|
+
uses_typescript=True,
|
|
109
|
+
has_ssr=False,
|
|
110
|
+
inertia_compatible=False,
|
|
111
|
+
resource_dir="src",
|
|
112
|
+
),
|
|
113
|
+
FrameworkType.REACT_TANSTACK: FrameworkTemplate(
|
|
114
|
+
name="React + TanStack Router",
|
|
115
|
+
type=FrameworkType.REACT_TANSTACK,
|
|
116
|
+
description="React 18+ with TanStack Router (file-based), Zod, and API client",
|
|
117
|
+
vite_plugin="@vitejs/plugin-react",
|
|
118
|
+
dependencies=["react", "react-dom", "@tanstack/react-router", "zod"],
|
|
119
|
+
dev_dependencies=[
|
|
120
|
+
"@vitejs/plugin-react",
|
|
121
|
+
"@tanstack/router-plugin",
|
|
122
|
+
"@hey-api/openapi-ts",
|
|
123
|
+
"@types/react",
|
|
124
|
+
"@types/react-dom",
|
|
125
|
+
"typescript",
|
|
126
|
+
],
|
|
127
|
+
files=[
|
|
128
|
+
"vite.config.ts",
|
|
129
|
+
"tsconfig.json",
|
|
130
|
+
"package.json",
|
|
131
|
+
"index.html",
|
|
132
|
+
"src/main.tsx",
|
|
133
|
+
"src/routes/__root.tsx",
|
|
134
|
+
"src/routes/index.tsx",
|
|
135
|
+
"src/routes/books.tsx",
|
|
136
|
+
"src/routeTree.gen.ts",
|
|
137
|
+
"src/App.css",
|
|
138
|
+
"openapi-ts.config.ts",
|
|
139
|
+
],
|
|
140
|
+
uses_typescript=True,
|
|
141
|
+
has_ssr=False,
|
|
142
|
+
inertia_compatible=False,
|
|
143
|
+
resource_dir="src",
|
|
144
|
+
),
|
|
145
|
+
FrameworkType.REACT_INERTIA: FrameworkTemplate(
|
|
146
|
+
name="React + Inertia.js",
|
|
147
|
+
type=FrameworkType.REACT_INERTIA,
|
|
148
|
+
description="React 18+ with Inertia.js for server-side routing",
|
|
149
|
+
vite_plugin="@vitejs/plugin-react",
|
|
150
|
+
dependencies=["react", "react-dom", "@inertiajs/react"],
|
|
151
|
+
dev_dependencies=["@vitejs/plugin-react", "@types/react", "@types/react-dom", "typescript", "vite"],
|
|
152
|
+
files=[
|
|
153
|
+
"vite.config.ts",
|
|
154
|
+
"tsconfig.json",
|
|
155
|
+
"package.json",
|
|
156
|
+
"index.html",
|
|
157
|
+
"resources/main.tsx",
|
|
158
|
+
"resources/ssr.tsx",
|
|
159
|
+
"resources/pages/Home.tsx",
|
|
160
|
+
"resources/App.css",
|
|
161
|
+
],
|
|
162
|
+
uses_typescript=True,
|
|
163
|
+
has_ssr=True,
|
|
164
|
+
inertia_compatible=True,
|
|
165
|
+
resource_dir="resources",
|
|
166
|
+
),
|
|
167
|
+
FrameworkType.VUE: FrameworkTemplate(
|
|
168
|
+
name="Vue 3",
|
|
169
|
+
type=FrameworkType.VUE,
|
|
170
|
+
description="Vue 3 with Composition API and TypeScript",
|
|
171
|
+
vite_plugin="@vitejs/plugin-vue",
|
|
172
|
+
dependencies=["vue"],
|
|
173
|
+
dev_dependencies=["@vitejs/plugin-vue", "vue-tsc", "typescript"],
|
|
174
|
+
files=[
|
|
175
|
+
"vite.config.ts",
|
|
176
|
+
"tsconfig.json",
|
|
177
|
+
"package.json",
|
|
178
|
+
"index.html",
|
|
179
|
+
"env.d.ts",
|
|
180
|
+
"src/main.ts",
|
|
181
|
+
"src/App.vue",
|
|
182
|
+
"src/style.css",
|
|
183
|
+
],
|
|
184
|
+
uses_typescript=True,
|
|
185
|
+
has_ssr=False,
|
|
186
|
+
inertia_compatible=True,
|
|
187
|
+
resource_dir="src",
|
|
188
|
+
),
|
|
189
|
+
FrameworkType.VUE_INERTIA: FrameworkTemplate(
|
|
190
|
+
name="Vue + Inertia.js",
|
|
191
|
+
type=FrameworkType.VUE_INERTIA,
|
|
192
|
+
description="Vue 3 with Inertia.js for server-side routing",
|
|
193
|
+
vite_plugin="@vitejs/plugin-vue",
|
|
194
|
+
dependencies=["vue", "@inertiajs/vue3"],
|
|
195
|
+
dev_dependencies=["@vitejs/plugin-vue", "vue-tsc", "typescript"],
|
|
196
|
+
files=[
|
|
197
|
+
"vite.config.ts",
|
|
198
|
+
"tsconfig.json",
|
|
199
|
+
"package.json",
|
|
200
|
+
"index.html",
|
|
201
|
+
"env.d.ts",
|
|
202
|
+
"resources/main.ts",
|
|
203
|
+
"resources/ssr.ts",
|
|
204
|
+
"resources/pages/Home.vue",
|
|
205
|
+
"resources/style.css",
|
|
206
|
+
],
|
|
207
|
+
uses_typescript=True,
|
|
208
|
+
has_ssr=True,
|
|
209
|
+
inertia_compatible=True,
|
|
210
|
+
resource_dir="resources",
|
|
211
|
+
),
|
|
212
|
+
FrameworkType.SVELTE: FrameworkTemplate(
|
|
213
|
+
name="Svelte 5",
|
|
214
|
+
type=FrameworkType.SVELTE,
|
|
215
|
+
description="Svelte 5 with runes and TypeScript",
|
|
216
|
+
vite_plugin="@sveltejs/vite-plugin-svelte",
|
|
217
|
+
dependencies=["svelte"],
|
|
218
|
+
dev_dependencies=["@sveltejs/vite-plugin-svelte", "svelte-check", "typescript", "tslib"],
|
|
219
|
+
files=[
|
|
220
|
+
"vite.config.ts",
|
|
221
|
+
"svelte.config.js",
|
|
222
|
+
"tsconfig.json",
|
|
223
|
+
"package.json",
|
|
224
|
+
"index.html",
|
|
225
|
+
"src/main.ts",
|
|
226
|
+
"src/App.svelte",
|
|
227
|
+
"src/app.css",
|
|
228
|
+
],
|
|
229
|
+
uses_typescript=True,
|
|
230
|
+
has_ssr=False,
|
|
231
|
+
inertia_compatible=True,
|
|
232
|
+
resource_dir="src",
|
|
233
|
+
),
|
|
234
|
+
FrameworkType.SVELTE_INERTIA: FrameworkTemplate(
|
|
235
|
+
name="Svelte + Inertia.js",
|
|
236
|
+
type=FrameworkType.SVELTE_INERTIA,
|
|
237
|
+
description="Svelte 5 with Inertia.js for server-side routing",
|
|
238
|
+
vite_plugin="@sveltejs/vite-plugin-svelte",
|
|
239
|
+
dependencies=["svelte", "@inertiajs/svelte"],
|
|
240
|
+
dev_dependencies=["@sveltejs/vite-plugin-svelte", "svelte-check", "typescript", "tslib"],
|
|
241
|
+
files=[
|
|
242
|
+
"vite.config.ts",
|
|
243
|
+
"svelte.config.js",
|
|
244
|
+
"tsconfig.json",
|
|
245
|
+
"package.json",
|
|
246
|
+
"index.html",
|
|
247
|
+
"resources/main.ts",
|
|
248
|
+
"resources/pages/Home.svelte",
|
|
249
|
+
"resources/app.css",
|
|
250
|
+
],
|
|
251
|
+
uses_typescript=True,
|
|
252
|
+
has_ssr=False,
|
|
253
|
+
inertia_compatible=True,
|
|
254
|
+
resource_dir="resources",
|
|
255
|
+
),
|
|
256
|
+
FrameworkType.SVELTEKIT: FrameworkTemplate(
|
|
257
|
+
name="SvelteKit",
|
|
258
|
+
type=FrameworkType.SVELTEKIT,
|
|
259
|
+
description="SvelteKit with Litestar API backend",
|
|
260
|
+
vite_plugin="litestar-vite-plugin/sveltekit",
|
|
261
|
+
dependencies=["svelte", "@sveltejs/kit"],
|
|
262
|
+
dev_dependencies=[
|
|
263
|
+
"@sveltejs/vite-plugin-svelte",
|
|
264
|
+
"@sveltejs/adapter-auto",
|
|
265
|
+
"svelte-check",
|
|
266
|
+
"typescript",
|
|
267
|
+
"tslib",
|
|
268
|
+
"litestar-vite-plugin",
|
|
269
|
+
],
|
|
270
|
+
files=[
|
|
271
|
+
"vite.config.ts",
|
|
272
|
+
"svelte.config.js",
|
|
273
|
+
"tsconfig.json",
|
|
274
|
+
"src/app.html",
|
|
275
|
+
"src/app.css",
|
|
276
|
+
"src/hooks.server.ts",
|
|
277
|
+
"src/routes/+page.svelte",
|
|
278
|
+
"src/routes/+layout.svelte",
|
|
279
|
+
],
|
|
280
|
+
uses_typescript=True,
|
|
281
|
+
has_ssr=True,
|
|
282
|
+
inertia_compatible=False,
|
|
283
|
+
),
|
|
284
|
+
FrameworkType.NUXT: FrameworkTemplate(
|
|
285
|
+
name="Nuxt 3",
|
|
286
|
+
type=FrameworkType.NUXT,
|
|
287
|
+
description="Nuxt 3 with Litestar API backend",
|
|
288
|
+
vite_plugin=None,
|
|
289
|
+
dependencies=["nuxt", "vue"],
|
|
290
|
+
dev_dependencies=["typescript", "vue-tsc", "litestar-vite-plugin"],
|
|
291
|
+
files=["nuxt.config.ts", "app.vue", "pages/index.vue", "composables/useApi.ts"],
|
|
292
|
+
uses_typescript=True,
|
|
293
|
+
has_ssr=True,
|
|
294
|
+
inertia_compatible=False,
|
|
295
|
+
),
|
|
296
|
+
FrameworkType.ASTRO: FrameworkTemplate(
|
|
297
|
+
name="Astro",
|
|
298
|
+
type=FrameworkType.ASTRO,
|
|
299
|
+
description="Astro with Litestar API backend",
|
|
300
|
+
vite_plugin="litestar-vite-plugin/astro",
|
|
301
|
+
dependencies=["astro"],
|
|
302
|
+
dev_dependencies=["typescript", "litestar-vite-plugin"],
|
|
303
|
+
files=["astro.config.mjs", "src/pages/index.astro", "src/layouts/Layout.astro", "src/styles/global.css"],
|
|
304
|
+
uses_typescript=True,
|
|
305
|
+
has_ssr=True,
|
|
306
|
+
inertia_compatible=False,
|
|
307
|
+
),
|
|
308
|
+
FrameworkType.HTMX: FrameworkTemplate(
|
|
309
|
+
name="HTMX",
|
|
310
|
+
type=FrameworkType.HTMX,
|
|
311
|
+
description="Server-rendered HTML with HTMX",
|
|
312
|
+
vite_plugin=None,
|
|
313
|
+
dependencies=["htmx.org"],
|
|
314
|
+
dev_dependencies=["typescript"],
|
|
315
|
+
files=["vite.config.ts", "resources/main.js", "templates/base.html.j2", "templates/index.html.j2"],
|
|
316
|
+
uses_typescript=False,
|
|
317
|
+
has_ssr=False,
|
|
318
|
+
inertia_compatible=False,
|
|
319
|
+
resource_dir="resources",
|
|
320
|
+
),
|
|
321
|
+
FrameworkType.ANGULAR: FrameworkTemplate(
|
|
322
|
+
name="Angular (Vite)",
|
|
323
|
+
type=FrameworkType.ANGULAR,
|
|
324
|
+
description="Angular 21+ with Vite (zoneless signals)",
|
|
325
|
+
vite_plugin="@analogjs/vite-plugin-angular",
|
|
326
|
+
dependencies=[
|
|
327
|
+
"@angular/animations",
|
|
328
|
+
"@angular/common",
|
|
329
|
+
"@angular/compiler",
|
|
330
|
+
"@angular/core",
|
|
331
|
+
"@angular/forms",
|
|
332
|
+
"@angular/platform-browser",
|
|
333
|
+
"rxjs",
|
|
334
|
+
],
|
|
335
|
+
dev_dependencies=[
|
|
336
|
+
"@analogjs/vite-plugin-angular",
|
|
337
|
+
"@angular/build",
|
|
338
|
+
"@angular/compiler-cli",
|
|
339
|
+
"@angular/platform-browser-dynamic",
|
|
340
|
+
"typescript",
|
|
341
|
+
"@types/node",
|
|
342
|
+
],
|
|
343
|
+
files=[
|
|
344
|
+
"vite.config.ts",
|
|
345
|
+
"tsconfig.json",
|
|
346
|
+
"tsconfig.app.json",
|
|
347
|
+
"package.json",
|
|
348
|
+
"index.html",
|
|
349
|
+
"src/main.ts",
|
|
350
|
+
"src/styles.css",
|
|
351
|
+
"src/app/app.component.ts",
|
|
352
|
+
"src/app/app.component.html",
|
|
353
|
+
"src/app/app.component.css",
|
|
354
|
+
"src/app/app.config.ts",
|
|
355
|
+
],
|
|
356
|
+
uses_typescript=True,
|
|
357
|
+
has_ssr=False,
|
|
358
|
+
inertia_compatible=False,
|
|
359
|
+
uses_vite=True,
|
|
360
|
+
resource_dir="src",
|
|
361
|
+
),
|
|
362
|
+
FrameworkType.ANGULAR_CLI: FrameworkTemplate(
|
|
363
|
+
name="Angular CLI",
|
|
364
|
+
type=FrameworkType.ANGULAR_CLI,
|
|
365
|
+
description="Angular 21+ with zoneless signals and TailwindCSS (Angular CLI)",
|
|
366
|
+
vite_plugin=None,
|
|
367
|
+
dependencies=[
|
|
368
|
+
"@angular/animations",
|
|
369
|
+
"@angular/common",
|
|
370
|
+
"@angular/compiler",
|
|
371
|
+
"@angular/core",
|
|
372
|
+
"@angular/forms",
|
|
373
|
+
"@angular/platform-browser",
|
|
374
|
+
"@angular/platform-browser-dynamic",
|
|
375
|
+
"rxjs",
|
|
376
|
+
"@tailwindcss/postcss",
|
|
377
|
+
"tailwindcss",
|
|
378
|
+
],
|
|
379
|
+
dev_dependencies=[
|
|
380
|
+
"@angular-devkit/build-angular",
|
|
381
|
+
"@angular/cli",
|
|
382
|
+
"@angular/compiler-cli",
|
|
383
|
+
"@types/node",
|
|
384
|
+
"typescript",
|
|
385
|
+
"postcss",
|
|
386
|
+
"autoprefixer",
|
|
387
|
+
],
|
|
388
|
+
files=[
|
|
389
|
+
"angular.json",
|
|
390
|
+
"tsconfig.json",
|
|
391
|
+
"tsconfig.app.json",
|
|
392
|
+
"tsconfig.spec.json",
|
|
393
|
+
"package.json",
|
|
394
|
+
"proxy.conf.json",
|
|
395
|
+
".postcssrc.json",
|
|
396
|
+
"tailwind.config.js",
|
|
397
|
+
"src/index.html",
|
|
398
|
+
"src/main.ts",
|
|
399
|
+
"src/styles.css",
|
|
400
|
+
"src/app/app.component.ts",
|
|
401
|
+
"src/app/app.component.html",
|
|
402
|
+
"src/app/app.component.css",
|
|
403
|
+
"src/app/app.config.ts",
|
|
404
|
+
],
|
|
405
|
+
uses_typescript=True,
|
|
406
|
+
has_ssr=False,
|
|
407
|
+
inertia_compatible=False,
|
|
408
|
+
uses_vite=False,
|
|
409
|
+
resource_dir="src",
|
|
410
|
+
),
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def get_available_templates() -> list[FrameworkTemplate]:
|
|
415
|
+
"""Get all available framework templates.
|
|
416
|
+
|
|
417
|
+
Returns:
|
|
418
|
+
List of available FrameworkTemplate instances.
|
|
419
|
+
"""
|
|
420
|
+
return list(FRAMEWORK_TEMPLATES.values())
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
def get_template(framework_type: "FrameworkType | str") -> "FrameworkTemplate | None":
|
|
424
|
+
"""Get a specific framework template.
|
|
425
|
+
|
|
426
|
+
Args:
|
|
427
|
+
framework_type: The framework type (enum or string).
|
|
428
|
+
|
|
429
|
+
Returns:
|
|
430
|
+
The FrameworkTemplate if found, None otherwise.
|
|
431
|
+
"""
|
|
432
|
+
if isinstance(framework_type, FrameworkType):
|
|
433
|
+
return FRAMEWORK_TEMPLATES.get(framework_type)
|
|
434
|
+
try:
|
|
435
|
+
return FRAMEWORK_TEMPLATES.get(FrameworkType(framework_type))
|
|
436
|
+
except ValueError:
|
|
437
|
+
return None
|