litestar-vite 0.1.1__py3-none-any.whl → 0.15.0rc2__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/_codegen/__init__.py +26 -0
- litestar_vite/_codegen/inertia.py +407 -0
- litestar_vite/_codegen/openapi.py +233 -0
- litestar_vite/_codegen/routes.py +653 -0
- litestar_vite/_codegen/ts.py +235 -0
- litestar_vite/_handler/__init__.py +8 -0
- litestar_vite/_handler/app.py +524 -0
- litestar_vite/_handler/routing.py +130 -0
- litestar_vite/cli.py +1147 -10
- litestar_vite/codegen.py +39 -0
- litestar_vite/commands.py +79 -0
- litestar_vite/config.py +1594 -70
- litestar_vite/deploy.py +355 -0
- litestar_vite/doctor.py +1179 -0
- litestar_vite/exceptions.py +78 -0
- litestar_vite/executor.py +316 -0
- litestar_vite/handler.py +9 -0
- litestar_vite/html_transform.py +426 -0
- litestar_vite/inertia/__init__.py +53 -0
- litestar_vite/inertia/_utils.py +114 -0
- litestar_vite/inertia/exception_handler.py +172 -0
- litestar_vite/inertia/helpers.py +1043 -0
- litestar_vite/inertia/middleware.py +54 -0
- litestar_vite/inertia/plugin.py +133 -0
- litestar_vite/inertia/request.py +286 -0
- litestar_vite/inertia/response.py +706 -0
- litestar_vite/inertia/types.py +316 -0
- litestar_vite/loader.py +462 -121
- litestar_vite/plugin.py +2160 -21
- 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 +35 -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 +27 -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 +38 -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 +46 -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 +49 -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.0rc2.dist-info/METADATA +230 -0
- litestar_vite-0.15.0rc2.dist-info/RECORD +151 -0
- {litestar_vite-0.1.1.dist-info → litestar_vite-0.15.0rc2.dist-info}/WHEEL +1 -1
- 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.0rc2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""OpenAPI integration helpers for code generation.
|
|
2
|
+
|
|
3
|
+
This module centralizes Litestar private OpenAPI API usage so that the rest of
|
|
4
|
+
the codegen logic can remain stable and easier to reason about.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import contextlib
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import TYPE_CHECKING, Any, Protocol, cast
|
|
11
|
+
|
|
12
|
+
from litestar._openapi.datastructures import OpenAPIContext # pyright: ignore[reportPrivateUsage]
|
|
13
|
+
from litestar._openapi.schema_generation import SchemaCreator # pyright: ignore[reportPrivateUsage]
|
|
14
|
+
from litestar.handlers import HTTPRouteHandler
|
|
15
|
+
from litestar.openapi.spec import Reference, Schema
|
|
16
|
+
from litestar.response import Response as LitestarResponse
|
|
17
|
+
from litestar.response import Template
|
|
18
|
+
from litestar.response.base import ASGIResponse
|
|
19
|
+
from litestar.types.builtin_types import NoneType
|
|
20
|
+
from litestar.typing import FieldDefinition
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from litestar import Litestar
|
|
24
|
+
from litestar.dto import AbstractDTO
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _SchemaRegistryEntry(Protocol):
|
|
28
|
+
key: tuple[str, ...]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(slots=True)
|
|
32
|
+
class OpenAPISupport:
|
|
33
|
+
"""Best-effort access to Litestar OpenAPI internals.
|
|
34
|
+
|
|
35
|
+
Attributes:
|
|
36
|
+
openapi_schema: Exported OpenAPI schema dict (optional).
|
|
37
|
+
context: Litestar OpenAPIContext (optional).
|
|
38
|
+
schema_creator: Litestar SchemaCreator (optional).
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
openapi_schema: dict[str, Any] | None
|
|
42
|
+
context: OpenAPIContext | None
|
|
43
|
+
schema_creator: SchemaCreator | None
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def from_app(cls, app: "Litestar", openapi_schema: dict[str, Any] | None) -> "OpenAPISupport":
|
|
47
|
+
"""Create OpenAPISupport from a Litestar application.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
app: Litestar application instance.
|
|
51
|
+
openapi_schema: Optional OpenAPI schema dict exported by Litestar.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
OpenAPISupport instance.
|
|
55
|
+
"""
|
|
56
|
+
context, creator = try_create_openapi_context(app)
|
|
57
|
+
return cls(openapi_schema=openapi_schema, context=context, schema_creator=creator)
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def enabled(self) -> bool:
|
|
61
|
+
"""Whether OpenAPI support is available.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
True if OpenAPI support is available, otherwise False.
|
|
65
|
+
"""
|
|
66
|
+
return self.context is not None and self.schema_creator is not None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def try_create_openapi_context(app: "Litestar") -> tuple[OpenAPIContext | None, SchemaCreator | None]:
|
|
70
|
+
"""Create OpenAPIContext and SchemaCreator if available.
|
|
71
|
+
|
|
72
|
+
This mirrors Litestar's internal OpenAPI setup but is tolerant of missing
|
|
73
|
+
configuration or internal API changes.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
app: Litestar application instance.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Tuple of (OpenAPIContext or None, SchemaCreator or None).
|
|
80
|
+
"""
|
|
81
|
+
openapi_config = app.openapi_config
|
|
82
|
+
if openapi_config is None:
|
|
83
|
+
return None, None
|
|
84
|
+
|
|
85
|
+
with contextlib.suppress(AttributeError, TypeError, ValueError):
|
|
86
|
+
openapi_context = OpenAPIContext(
|
|
87
|
+
openapi_config=openapi_config, # pyright: ignore[reportUnknownMemberType]
|
|
88
|
+
plugins=app.plugins.openapi, # pyright: ignore[reportUnknownMemberType]
|
|
89
|
+
)
|
|
90
|
+
return openapi_context, SchemaCreator.from_openapi_context(openapi_context)
|
|
91
|
+
|
|
92
|
+
return None, None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def openapi_components_schemas(openapi_schema: dict[str, Any] | None) -> dict[str, Any]:
|
|
96
|
+
"""Extract OpenAPI components.schemas dict as a concrete mapping.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
The components.schemas mapping, or an empty dict if unavailable.
|
|
100
|
+
"""
|
|
101
|
+
if not isinstance(openapi_schema, dict):
|
|
102
|
+
return {}
|
|
103
|
+
components = openapi_schema.get("components")
|
|
104
|
+
if not isinstance(components, dict):
|
|
105
|
+
return {}
|
|
106
|
+
schemas = cast("dict[str, Any]", components).get("schemas")
|
|
107
|
+
if not isinstance(schemas, dict):
|
|
108
|
+
return {}
|
|
109
|
+
return cast("dict[str, Any]", schemas)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def merge_generated_components_into_openapi(
|
|
113
|
+
openapi_schema: dict[str, Any], generated_components: dict[str, Schema]
|
|
114
|
+
) -> None:
|
|
115
|
+
"""Merge generated component schemas into an OpenAPI document."""
|
|
116
|
+
components_any = openapi_schema.get("components")
|
|
117
|
+
if not isinstance(components_any, dict):
|
|
118
|
+
openapi_schema["components"] = {}
|
|
119
|
+
components_any = openapi_schema["components"]
|
|
120
|
+
|
|
121
|
+
components_dict = cast("dict[str, Any]", components_any)
|
|
122
|
+
schemas_any = components_dict.get("schemas")
|
|
123
|
+
if not isinstance(schemas_any, dict):
|
|
124
|
+
components_dict["schemas"] = {}
|
|
125
|
+
schemas_any = components_dict["schemas"]
|
|
126
|
+
|
|
127
|
+
schemas_dict = cast("dict[str, Any]", schemas_any)
|
|
128
|
+
for component_name, schema in generated_components.items():
|
|
129
|
+
if component_name not in schemas_dict:
|
|
130
|
+
schemas_dict[component_name] = schema.to_schema()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def build_schema_name_map(schema_registry: Any) -> dict[tuple[str, ...], str]:
|
|
134
|
+
"""Build a mapping of schema registry keys to final component names.
|
|
135
|
+
|
|
136
|
+
Uses the same shortening and de-duplication logic as
|
|
137
|
+
``SchemaRegistry.generate_components_schemas()``.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
schema_registry: Litestar schema registry.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Mapping of schema keys to component names.
|
|
144
|
+
"""
|
|
145
|
+
name_map: dict[tuple[str, ...], str] = {}
|
|
146
|
+
try:
|
|
147
|
+
model_name_groups = schema_registry._model_name_groups
|
|
148
|
+
except AttributeError:
|
|
149
|
+
model_name_groups = {}
|
|
150
|
+
if not isinstance(model_name_groups, dict):
|
|
151
|
+
return name_map
|
|
152
|
+
|
|
153
|
+
groups_dict = cast("dict[str, Any]", model_name_groups)
|
|
154
|
+
for name, group_any in groups_dict.items():
|
|
155
|
+
group = cast("list[Any]", group_any)
|
|
156
|
+
if len(group) == 1:
|
|
157
|
+
registered_schema: _SchemaRegistryEntry = group[0]
|
|
158
|
+
name_map[registered_schema.key] = name
|
|
159
|
+
continue
|
|
160
|
+
|
|
161
|
+
full_keys: list[tuple[str, ...]] = []
|
|
162
|
+
for registered_schema_any in group:
|
|
163
|
+
entry_key: _SchemaRegistryEntry = registered_schema_any
|
|
164
|
+
full_keys.append(entry_key.key)
|
|
165
|
+
|
|
166
|
+
shortened_keys: list[tuple[str, ...]] = list(schema_registry.remove_common_prefix(full_keys))
|
|
167
|
+
names = ["_".join(k) for k in shortened_keys]
|
|
168
|
+
|
|
169
|
+
for name_, registered_schema_any in zip(names, group, strict=False):
|
|
170
|
+
entry_name: _SchemaRegistryEntry = registered_schema_any
|
|
171
|
+
name_map[entry_name.key] = name_
|
|
172
|
+
|
|
173
|
+
return name_map
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def schema_name_from_ref(ref: str) -> str:
|
|
177
|
+
"""Return the OpenAPI component name from a schema $ref string.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
The schema name part of the reference.
|
|
181
|
+
"""
|
|
182
|
+
return ref.rsplit("/", maxsplit=1)[-1]
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def resolve_page_props_field_definition(
|
|
186
|
+
handler: HTTPRouteHandler, schema_creator: SchemaCreator
|
|
187
|
+
) -> tuple[FieldDefinition | None, Schema | Reference | None]:
|
|
188
|
+
"""Resolve FieldDefinition and schema result for a handler's response.
|
|
189
|
+
|
|
190
|
+
Mirrors Litestar's response schema generation to ensure consistent schema registration.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
handler: HTTP route handler.
|
|
194
|
+
schema_creator: Litestar SchemaCreator.
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Tuple of (FieldDefinition or None, Schema/Reference or None).
|
|
198
|
+
"""
|
|
199
|
+
field_definition = handler.parsed_fn_signature.return_type
|
|
200
|
+
|
|
201
|
+
if field_definition.is_subclass_of((NoneType, ASGIResponse)):
|
|
202
|
+
return None, None
|
|
203
|
+
|
|
204
|
+
resolve_return_dto: Any = None
|
|
205
|
+
with contextlib.suppress(AttributeError):
|
|
206
|
+
resolve_return_dto = cast("Any", handler).resolve_return_dto
|
|
207
|
+
dto = resolve_return_dto() if callable(resolve_return_dto) else None
|
|
208
|
+
if dto is not None:
|
|
209
|
+
dto_t = cast("type[AbstractDTO[Any]]", dto)
|
|
210
|
+
result = dto_t.create_openapi_schema(
|
|
211
|
+
field_definition=field_definition, handler_id=handler.handler_id, schema_creator=schema_creator
|
|
212
|
+
)
|
|
213
|
+
return field_definition, result
|
|
214
|
+
|
|
215
|
+
if field_definition.is_subclass_of(Template):
|
|
216
|
+
resolved_field = FieldDefinition.from_annotation(str)
|
|
217
|
+
elif field_definition.is_subclass_of(LitestarResponse):
|
|
218
|
+
resolved_field = (
|
|
219
|
+
field_definition.inner_types[0] if field_definition.inner_types else FieldDefinition.from_annotation(Any)
|
|
220
|
+
)
|
|
221
|
+
else:
|
|
222
|
+
resolved_field = field_definition
|
|
223
|
+
|
|
224
|
+
return resolved_field, schema_creator.for_field_definition(resolved_field)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def to_root_path(root_dir: Path, path: Path) -> Path:
|
|
228
|
+
"""Resolve a path relative to ``root_dir`` when it is not absolute.
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
Absolute path.
|
|
232
|
+
"""
|
|
233
|
+
return path if path.is_absolute() else (root_dir / path)
|