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.
Files changed (169) hide show
  1. litestar_vite/__init__.py +54 -4
  2. litestar_vite/__metadata__.py +12 -7
  3. litestar_vite/cli.py +1048 -10
  4. litestar_vite/codegen/__init__.py +48 -0
  5. litestar_vite/codegen/_export.py +229 -0
  6. litestar_vite/codegen/_inertia.py +619 -0
  7. litestar_vite/codegen/_openapi.py +280 -0
  8. litestar_vite/codegen/_routes.py +720 -0
  9. litestar_vite/codegen/_ts.py +235 -0
  10. litestar_vite/codegen/_utils.py +141 -0
  11. litestar_vite/commands.py +73 -0
  12. litestar_vite/config/__init__.py +997 -0
  13. litestar_vite/config/_constants.py +97 -0
  14. litestar_vite/config/_deploy.py +70 -0
  15. litestar_vite/config/_inertia.py +241 -0
  16. litestar_vite/config/_paths.py +63 -0
  17. litestar_vite/config/_runtime.py +235 -0
  18. litestar_vite/config/_spa.py +93 -0
  19. litestar_vite/config/_types.py +94 -0
  20. litestar_vite/deploy.py +366 -0
  21. litestar_vite/doctor.py +1181 -0
  22. litestar_vite/exceptions.py +78 -0
  23. litestar_vite/executor.py +360 -0
  24. litestar_vite/handler/__init__.py +9 -0
  25. litestar_vite/handler/_app.py +612 -0
  26. litestar_vite/handler/_routing.py +130 -0
  27. litestar_vite/html_transform.py +569 -0
  28. litestar_vite/inertia/__init__.py +77 -0
  29. litestar_vite/inertia/_utils.py +119 -0
  30. litestar_vite/inertia/exception_handler.py +178 -0
  31. litestar_vite/inertia/helpers.py +1571 -0
  32. litestar_vite/inertia/middleware.py +54 -0
  33. litestar_vite/inertia/plugin.py +199 -0
  34. litestar_vite/inertia/precognition.py +274 -0
  35. litestar_vite/inertia/request.py +334 -0
  36. litestar_vite/inertia/response.py +802 -0
  37. litestar_vite/inertia/types.py +335 -0
  38. litestar_vite/loader.py +464 -123
  39. litestar_vite/plugin/__init__.py +687 -0
  40. litestar_vite/plugin/_process.py +185 -0
  41. litestar_vite/plugin/_proxy.py +689 -0
  42. litestar_vite/plugin/_proxy_headers.py +244 -0
  43. litestar_vite/plugin/_static.py +37 -0
  44. litestar_vite/plugin/_utils.py +489 -0
  45. litestar_vite/py.typed +0 -0
  46. litestar_vite/scaffolding/__init__.py +20 -0
  47. litestar_vite/scaffolding/generator.py +270 -0
  48. litestar_vite/scaffolding/templates.py +437 -0
  49. litestar_vite/templates/__init__.py +0 -0
  50. litestar_vite/templates/addons/tailwindcss/tailwind.css.j2 +1 -0
  51. litestar_vite/templates/angular/index.html.j2 +12 -0
  52. litestar_vite/templates/angular/openapi-ts.config.ts.j2 +18 -0
  53. litestar_vite/templates/angular/package.json.j2 +36 -0
  54. litestar_vite/templates/angular/src/app/app.component.css.j2 +3 -0
  55. litestar_vite/templates/angular/src/app/app.component.html.j2 +1 -0
  56. litestar_vite/templates/angular/src/app/app.component.ts.j2 +9 -0
  57. litestar_vite/templates/angular/src/app/app.config.ts.j2 +5 -0
  58. litestar_vite/templates/angular/src/main.ts.j2 +9 -0
  59. litestar_vite/templates/angular/src/styles.css.j2 +9 -0
  60. litestar_vite/templates/angular/tsconfig.app.json.j2 +34 -0
  61. litestar_vite/templates/angular/tsconfig.json.j2 +20 -0
  62. litestar_vite/templates/angular/vite.config.ts.j2 +21 -0
  63. litestar_vite/templates/angular-cli/.postcssrc.json.j2 +5 -0
  64. litestar_vite/templates/angular-cli/angular.json.j2 +36 -0
  65. litestar_vite/templates/angular-cli/openapi-ts.config.ts.j2 +18 -0
  66. litestar_vite/templates/angular-cli/package.json.j2 +28 -0
  67. litestar_vite/templates/angular-cli/proxy.conf.json.j2 +18 -0
  68. litestar_vite/templates/angular-cli/src/app/app.component.css.j2 +3 -0
  69. litestar_vite/templates/angular-cli/src/app/app.component.html.j2 +1 -0
  70. litestar_vite/templates/angular-cli/src/app/app.component.ts.j2 +9 -0
  71. litestar_vite/templates/angular-cli/src/app/app.config.ts.j2 +5 -0
  72. litestar_vite/templates/angular-cli/src/index.html.j2 +13 -0
  73. litestar_vite/templates/angular-cli/src/main.ts.j2 +6 -0
  74. litestar_vite/templates/angular-cli/src/styles.css.j2 +10 -0
  75. litestar_vite/templates/angular-cli/tailwind.config.js.j2 +4 -0
  76. litestar_vite/templates/angular-cli/tsconfig.app.json.j2 +16 -0
  77. litestar_vite/templates/angular-cli/tsconfig.json.j2 +26 -0
  78. litestar_vite/templates/angular-cli/tsconfig.spec.json.j2 +9 -0
  79. litestar_vite/templates/astro/astro.config.mjs.j2 +28 -0
  80. litestar_vite/templates/astro/openapi-ts.config.ts.j2 +15 -0
  81. litestar_vite/templates/astro/src/layouts/Layout.astro.j2 +63 -0
  82. litestar_vite/templates/astro/src/pages/index.astro.j2 +36 -0
  83. litestar_vite/templates/astro/src/styles/global.css.j2 +1 -0
  84. litestar_vite/templates/base/.gitignore.j2 +42 -0
  85. litestar_vite/templates/base/openapi-ts.config.ts.j2 +15 -0
  86. litestar_vite/templates/base/package.json.j2 +39 -0
  87. litestar_vite/templates/base/resources/vite-env.d.ts.j2 +1 -0
  88. litestar_vite/templates/base/tsconfig.json.j2 +37 -0
  89. litestar_vite/templates/htmx/src/main.js.j2 +8 -0
  90. litestar_vite/templates/htmx/templates/base.html.j2.j2 +56 -0
  91. litestar_vite/templates/htmx/templates/index.html.j2.j2 +13 -0
  92. litestar_vite/templates/htmx/vite.config.ts.j2 +40 -0
  93. litestar_vite/templates/nuxt/app.vue.j2 +29 -0
  94. litestar_vite/templates/nuxt/composables/useApi.ts.j2 +33 -0
  95. litestar_vite/templates/nuxt/nuxt.config.ts.j2 +31 -0
  96. litestar_vite/templates/nuxt/openapi-ts.config.ts.j2 +15 -0
  97. litestar_vite/templates/nuxt/pages/index.vue.j2 +54 -0
  98. litestar_vite/templates/react/index.html.j2 +13 -0
  99. litestar_vite/templates/react/src/App.css.j2 +56 -0
  100. litestar_vite/templates/react/src/App.tsx.j2 +19 -0
  101. litestar_vite/templates/react/src/main.tsx.j2 +10 -0
  102. litestar_vite/templates/react/vite.config.ts.j2 +39 -0
  103. litestar_vite/templates/react-inertia/index.html.j2 +14 -0
  104. litestar_vite/templates/react-inertia/package.json.j2 +47 -0
  105. litestar_vite/templates/react-inertia/resources/App.css.j2 +68 -0
  106. litestar_vite/templates/react-inertia/resources/main.tsx.j2 +17 -0
  107. litestar_vite/templates/react-inertia/resources/pages/Home.tsx.j2 +18 -0
  108. litestar_vite/templates/react-inertia/resources/ssr.tsx.j2 +19 -0
  109. litestar_vite/templates/react-inertia/vite.config.ts.j2 +59 -0
  110. litestar_vite/templates/react-router/index.html.j2 +12 -0
  111. litestar_vite/templates/react-router/src/App.css.j2 +17 -0
  112. litestar_vite/templates/react-router/src/App.tsx.j2 +7 -0
  113. litestar_vite/templates/react-router/src/main.tsx.j2 +10 -0
  114. litestar_vite/templates/react-router/vite.config.ts.j2 +39 -0
  115. litestar_vite/templates/react-tanstack/index.html.j2 +12 -0
  116. litestar_vite/templates/react-tanstack/openapi-ts.config.ts.j2 +18 -0
  117. litestar_vite/templates/react-tanstack/src/App.css.j2 +17 -0
  118. litestar_vite/templates/react-tanstack/src/main.tsx.j2 +21 -0
  119. litestar_vite/templates/react-tanstack/src/routeTree.gen.ts.j2 +7 -0
  120. litestar_vite/templates/react-tanstack/src/routes/__root.tsx.j2 +9 -0
  121. litestar_vite/templates/react-tanstack/src/routes/books.tsx.j2 +9 -0
  122. litestar_vite/templates/react-tanstack/src/routes/index.tsx.j2 +9 -0
  123. litestar_vite/templates/react-tanstack/vite.config.ts.j2 +39 -0
  124. litestar_vite/templates/svelte/index.html.j2 +13 -0
  125. litestar_vite/templates/svelte/src/App.svelte.j2 +30 -0
  126. litestar_vite/templates/svelte/src/app.css.j2 +45 -0
  127. litestar_vite/templates/svelte/src/main.ts.j2 +8 -0
  128. litestar_vite/templates/svelte/src/vite-env.d.ts.j2 +2 -0
  129. litestar_vite/templates/svelte/svelte.config.js.j2 +5 -0
  130. litestar_vite/templates/svelte/vite.config.ts.j2 +39 -0
  131. litestar_vite/templates/svelte-inertia/index.html.j2 +14 -0
  132. litestar_vite/templates/svelte-inertia/resources/app.css.j2 +21 -0
  133. litestar_vite/templates/svelte-inertia/resources/main.ts.j2 +11 -0
  134. litestar_vite/templates/svelte-inertia/resources/pages/Home.svelte.j2 +43 -0
  135. litestar_vite/templates/svelte-inertia/resources/vite-env.d.ts.j2 +2 -0
  136. litestar_vite/templates/svelte-inertia/svelte.config.js.j2 +5 -0
  137. litestar_vite/templates/svelte-inertia/vite.config.ts.j2 +37 -0
  138. litestar_vite/templates/sveltekit/openapi-ts.config.ts.j2 +15 -0
  139. litestar_vite/templates/sveltekit/src/app.css.j2 +40 -0
  140. litestar_vite/templates/sveltekit/src/app.html.j2 +12 -0
  141. litestar_vite/templates/sveltekit/src/hooks.server.ts.j2 +55 -0
  142. litestar_vite/templates/sveltekit/src/routes/+layout.svelte.j2 +12 -0
  143. litestar_vite/templates/sveltekit/src/routes/+page.svelte.j2 +34 -0
  144. litestar_vite/templates/sveltekit/svelte.config.js.j2 +12 -0
  145. litestar_vite/templates/sveltekit/tsconfig.json.j2 +14 -0
  146. litestar_vite/templates/sveltekit/vite.config.ts.j2 +31 -0
  147. litestar_vite/templates/vue/env.d.ts.j2 +7 -0
  148. litestar_vite/templates/vue/index.html.j2 +13 -0
  149. litestar_vite/templates/vue/src/App.vue.j2 +28 -0
  150. litestar_vite/templates/vue/src/main.ts.j2 +5 -0
  151. litestar_vite/templates/vue/src/style.css.j2 +45 -0
  152. litestar_vite/templates/vue/vite.config.ts.j2 +39 -0
  153. litestar_vite/templates/vue-inertia/env.d.ts.j2 +7 -0
  154. litestar_vite/templates/vue-inertia/index.html.j2 +14 -0
  155. litestar_vite/templates/vue-inertia/package.json.j2 +50 -0
  156. litestar_vite/templates/vue-inertia/resources/main.ts.j2 +18 -0
  157. litestar_vite/templates/vue-inertia/resources/pages/Home.vue.j2 +22 -0
  158. litestar_vite/templates/vue-inertia/resources/ssr.ts.j2 +21 -0
  159. litestar_vite/templates/vue-inertia/resources/style.css.j2 +21 -0
  160. litestar_vite/templates/vue-inertia/vite.config.ts.j2 +59 -0
  161. litestar_vite-0.15.0.dist-info/METADATA +230 -0
  162. litestar_vite-0.15.0.dist-info/RECORD +164 -0
  163. {litestar_vite-0.1.1.dist-info → litestar_vite-0.15.0.dist-info}/WHEEL +1 -1
  164. litestar_vite/config.py +0 -100
  165. litestar_vite/plugin.py +0 -45
  166. litestar_vite/template_engine.py +0 -103
  167. litestar_vite-0.1.1.dist-info/METADATA +0 -68
  168. litestar_vite-0.1.1.dist-info/RECORD +0 -11
  169. {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