litestar-vite-plugin 0.15.0-beta.5 → 0.15.0-beta.6
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.
- package/dist/js/astro.d.ts +27 -3
- package/dist/js/astro.js +55 -28
- package/dist/js/helpers/htmx.js +48 -15
- package/dist/js/helpers/index.d.ts +1 -1
- package/dist/js/helpers/index.js +1 -1
- package/dist/js/index.d.ts +26 -49
- package/dist/js/index.js +38 -374
- package/dist/js/inertia-helpers/index.d.ts +3 -4
- package/dist/js/inertia-helpers/index.js +3 -8
- package/dist/js/nuxt.d.ts +29 -32
- package/dist/js/nuxt.js +59 -35
- package/dist/js/shared/bridge-schema.d.ts +51 -0
- package/dist/js/shared/bridge-schema.js +178 -0
- package/dist/js/shared/emit-page-props-types.d.ts +4 -0
- package/dist/js/shared/emit-page-props-types.js +209 -0
- package/dist/js/shared/format-path.d.ts +0 -9
- package/dist/js/shared/format-path.js +1 -5
- package/dist/js/shared/typegen-plugin.d.ts +35 -0
- package/dist/js/shared/typegen-plugin.js +178 -0
- package/dist/js/sveltekit.d.ts +30 -6
- package/dist/js/sveltekit.js +35 -26
- package/package.json +3 -5
- package/dist/js/shared/create-type-gen-plugin.d.ts +0 -99
- package/dist/js/shared/create-type-gen-plugin.js +0 -110
- package/dist/js/shared/emit-route-types.d.ts +0 -41
- package/dist/js/shared/emit-route-types.js +0 -151
package/dist/js/nuxt.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import colors from "picocolors";
|
|
4
|
-
import {
|
|
4
|
+
import { readBridgeConfig } from "./shared/bridge-schema.js";
|
|
5
|
+
import { createLitestarTypeGenPlugin } from "./shared/typegen-plugin.js";
|
|
5
6
|
function normalizeHost(host) {
|
|
6
7
|
if (host === "::" || host === "::1" || host === "0.0.0.0") {
|
|
7
8
|
return "localhost";
|
|
@@ -12,10 +13,11 @@ function normalizeHost(host) {
|
|
|
12
13
|
return host;
|
|
13
14
|
}
|
|
14
15
|
function resolveConfig(config = {}) {
|
|
15
|
-
const runtimeConfigPath = process.env.LITESTAR_VITE_CONFIG_PATH;
|
|
16
16
|
let hotFile;
|
|
17
17
|
let proxyMode = "vite";
|
|
18
18
|
let devPort;
|
|
19
|
+
let pythonTypesConfig;
|
|
20
|
+
let hasPythonConfig = false;
|
|
19
21
|
const envPort = process.env.VITE_PORT;
|
|
20
22
|
if (envPort) {
|
|
21
23
|
devPort = Number.parseInt(envPort, 10);
|
|
@@ -24,42 +26,61 @@ function resolveConfig(config = {}) {
|
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
let pythonExecutor;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
pythonExecutor = json.executor;
|
|
38
|
-
} catch {
|
|
39
|
-
hotFile = void 0;
|
|
29
|
+
const runtime = readBridgeConfig();
|
|
30
|
+
if (runtime) {
|
|
31
|
+
hasPythonConfig = true;
|
|
32
|
+
const hot = runtime.hotFile;
|
|
33
|
+
hotFile = path.isAbsolute(hot) ? hot : path.resolve(process.cwd(), runtime.bundleDir, hot);
|
|
34
|
+
proxyMode = runtime.proxyMode;
|
|
35
|
+
devPort = runtime.port;
|
|
36
|
+
pythonExecutor = runtime.executor;
|
|
37
|
+
if (runtime.types) {
|
|
38
|
+
pythonTypesConfig = runtime.types;
|
|
40
39
|
}
|
|
41
40
|
}
|
|
42
41
|
let typesConfig = false;
|
|
43
42
|
if (config.types === true) {
|
|
44
43
|
typesConfig = {
|
|
45
44
|
enabled: true,
|
|
46
|
-
output: "
|
|
47
|
-
openapiPath: "openapi.json",
|
|
48
|
-
routesPath: "routes.json",
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
output: pythonTypesConfig?.output ?? "generated",
|
|
46
|
+
openapiPath: pythonTypesConfig?.openapiPath ?? "openapi.json",
|
|
47
|
+
routesPath: pythonTypesConfig?.routesPath ?? "routes.json",
|
|
48
|
+
pagePropsPath: pythonTypesConfig?.pagePropsPath ?? "inertia-pages.json",
|
|
49
|
+
generateZod: pythonTypesConfig?.generateZod ?? false,
|
|
50
|
+
generateSdk: pythonTypesConfig?.generateSdk ?? true,
|
|
51
|
+
generateRoutes: pythonTypesConfig?.generateRoutes ?? true,
|
|
52
|
+
generatePageProps: pythonTypesConfig?.generatePageProps ?? true,
|
|
53
|
+
globalRoute: pythonTypesConfig?.globalRoute ?? false,
|
|
51
54
|
debounce: 300
|
|
52
55
|
};
|
|
53
56
|
} else if (typeof config.types === "object" && config.types !== null) {
|
|
54
57
|
typesConfig = {
|
|
55
58
|
enabled: config.types.enabled ?? true,
|
|
56
|
-
output: config.types.output ?? "
|
|
57
|
-
openapiPath: config.types.openapiPath ?? "openapi.json",
|
|
58
|
-
routesPath: config.types.routesPath ?? "routes.json",
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
output: config.types.output ?? pythonTypesConfig?.output ?? "generated",
|
|
60
|
+
openapiPath: config.types.openapiPath ?? pythonTypesConfig?.openapiPath ?? "openapi.json",
|
|
61
|
+
routesPath: config.types.routesPath ?? pythonTypesConfig?.routesPath ?? "routes.json",
|
|
62
|
+
pagePropsPath: config.types.pagePropsPath ?? pythonTypesConfig?.pagePropsPath ?? "inertia-pages.json",
|
|
63
|
+
generateZod: config.types.generateZod ?? pythonTypesConfig?.generateZod ?? false,
|
|
64
|
+
generateSdk: config.types.generateSdk ?? pythonTypesConfig?.generateSdk ?? true,
|
|
65
|
+
generateRoutes: config.types.generateRoutes ?? pythonTypesConfig?.generateRoutes ?? true,
|
|
66
|
+
generatePageProps: config.types.generatePageProps ?? pythonTypesConfig?.generatePageProps ?? true,
|
|
67
|
+
globalRoute: config.types.globalRoute ?? pythonTypesConfig?.globalRoute ?? false,
|
|
61
68
|
debounce: config.types.debounce ?? 300
|
|
62
69
|
};
|
|
70
|
+
} else if (config.types !== false && pythonTypesConfig?.enabled) {
|
|
71
|
+
typesConfig = {
|
|
72
|
+
enabled: true,
|
|
73
|
+
output: pythonTypesConfig.output ?? "generated",
|
|
74
|
+
openapiPath: pythonTypesConfig.openapiPath ?? "openapi.json",
|
|
75
|
+
routesPath: pythonTypesConfig.routesPath ?? "routes.json",
|
|
76
|
+
pagePropsPath: pythonTypesConfig.pagePropsPath ?? "inertia-pages.json",
|
|
77
|
+
generateZod: pythonTypesConfig.generateZod ?? false,
|
|
78
|
+
generateSdk: pythonTypesConfig.generateSdk ?? true,
|
|
79
|
+
generateRoutes: pythonTypesConfig.generateRoutes ?? true,
|
|
80
|
+
generatePageProps: pythonTypesConfig.generatePageProps ?? true,
|
|
81
|
+
globalRoute: pythonTypesConfig.globalRoute ?? false,
|
|
82
|
+
debounce: 300
|
|
83
|
+
};
|
|
63
84
|
}
|
|
64
85
|
return {
|
|
65
86
|
apiProxy: config.apiProxy ?? "http://localhost:8000",
|
|
@@ -69,7 +90,8 @@ function resolveConfig(config = {}) {
|
|
|
69
90
|
hotFile,
|
|
70
91
|
proxyMode,
|
|
71
92
|
devPort,
|
|
72
|
-
executor: config.executor ?? pythonExecutor
|
|
93
|
+
executor: config.executor ?? pythonExecutor,
|
|
94
|
+
hasPythonConfig
|
|
73
95
|
};
|
|
74
96
|
}
|
|
75
97
|
async function getPort() {
|
|
@@ -147,26 +169,29 @@ function createProxyPlugin(config) {
|
|
|
147
169
|
}
|
|
148
170
|
};
|
|
149
171
|
}
|
|
150
|
-
function
|
|
151
|
-
const config = resolveConfig(userConfig);
|
|
172
|
+
function litestarPluginsFromResolved(config) {
|
|
152
173
|
const plugins = [createProxyPlugin(config)];
|
|
153
174
|
if (config.types !== false && config.types.enabled) {
|
|
154
175
|
plugins.push(
|
|
155
|
-
|
|
156
|
-
frameworkName: "litestar-nuxt",
|
|
176
|
+
createLitestarTypeGenPlugin(config.types, {
|
|
157
177
|
pluginName: "litestar-nuxt-types",
|
|
158
|
-
|
|
159
|
-
|
|
178
|
+
frameworkName: "litestar-nuxt",
|
|
179
|
+
sdkClientPlugin: "@hey-api/client-nuxt",
|
|
180
|
+
executor: config.executor,
|
|
181
|
+
hasPythonConfig: config.hasPythonConfig
|
|
160
182
|
})
|
|
161
183
|
);
|
|
162
184
|
}
|
|
163
185
|
return plugins;
|
|
164
186
|
}
|
|
187
|
+
function _litestarPlugins(userConfig = {}) {
|
|
188
|
+
return litestarPluginsFromResolved(resolveConfig(userConfig));
|
|
189
|
+
}
|
|
165
190
|
function litestarNuxtModule(userOptions, nuxt) {
|
|
166
191
|
const nuxtConfigOptions = nuxt.options.litestar;
|
|
167
192
|
const mergedOptions = { ...nuxtConfigOptions, ...userOptions };
|
|
168
193
|
const config = resolveConfig(mergedOptions);
|
|
169
|
-
const plugins =
|
|
194
|
+
const plugins = litestarPluginsFromResolved(config);
|
|
170
195
|
nuxt.options.vite = nuxt.options.vite || {};
|
|
171
196
|
nuxt.options.vite.plugins = nuxt.options.vite.plugins || [];
|
|
172
197
|
nuxt.options.vite.plugins.push(...plugins);
|
|
@@ -231,6 +256,5 @@ const litestarModule = litestarNuxtModule;
|
|
|
231
256
|
var nuxt_default = litestarModule;
|
|
232
257
|
export {
|
|
233
258
|
nuxt_default as default,
|
|
234
|
-
litestarModule
|
|
235
|
-
litestarPlugins
|
|
259
|
+
litestarModule
|
|
236
260
|
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical bridge schema for `.litestar.json`.
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth on the TypeScript side for the config
|
|
5
|
+
* contract emitted by the Python VitePlugin.
|
|
6
|
+
*
|
|
7
|
+
* The project is pre-1.0: no legacy keys, no fallbacks, fail-fast on mismatch.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
export type BridgeMode = "spa" | "template" | "htmx" | "hybrid" | "inertia" | "ssr" | "ssg" | "external";
|
|
12
|
+
export type BridgeProxyMode = "vite" | "direct" | "proxy" | null;
|
|
13
|
+
export type BridgeExecutor = "node" | "bun" | "deno" | "yarn" | "pnpm";
|
|
14
|
+
export interface BridgeTypesConfig {
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
output: string;
|
|
17
|
+
openapiPath: string;
|
|
18
|
+
routesPath: string;
|
|
19
|
+
pagePropsPath: string;
|
|
20
|
+
generateZod: boolean;
|
|
21
|
+
generateSdk: boolean;
|
|
22
|
+
generateRoutes: boolean;
|
|
23
|
+
generatePageProps: boolean;
|
|
24
|
+
globalRoute: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface BridgeSchema {
|
|
27
|
+
assetUrl: string;
|
|
28
|
+
bundleDir: string;
|
|
29
|
+
resourceDir: string;
|
|
30
|
+
staticDir: string;
|
|
31
|
+
hotFile: string;
|
|
32
|
+
manifest: string;
|
|
33
|
+
mode: BridgeMode;
|
|
34
|
+
proxyMode: BridgeProxyMode;
|
|
35
|
+
host: string;
|
|
36
|
+
port: number;
|
|
37
|
+
ssrEnabled: boolean;
|
|
38
|
+
ssrOutDir: string | null;
|
|
39
|
+
types: BridgeTypesConfig | null;
|
|
40
|
+
executor: BridgeExecutor;
|
|
41
|
+
logging: {
|
|
42
|
+
level: "quiet" | "normal" | "verbose";
|
|
43
|
+
showPathsAbsolute: boolean;
|
|
44
|
+
suppressNpmOutput: boolean;
|
|
45
|
+
suppressViteBanner: boolean;
|
|
46
|
+
timestamps: boolean;
|
|
47
|
+
} | null;
|
|
48
|
+
litestarVersion: string;
|
|
49
|
+
}
|
|
50
|
+
export declare function parseBridgeSchema(value: unknown): BridgeSchema;
|
|
51
|
+
export declare function readBridgeConfig(explicitPath?: string): BridgeSchema | null;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const allowedTopLevelKeys = /* @__PURE__ */ new Set([
|
|
4
|
+
"assetUrl",
|
|
5
|
+
"bundleDir",
|
|
6
|
+
"resourceDir",
|
|
7
|
+
"staticDir",
|
|
8
|
+
"hotFile",
|
|
9
|
+
"manifest",
|
|
10
|
+
"mode",
|
|
11
|
+
"proxyMode",
|
|
12
|
+
"host",
|
|
13
|
+
"port",
|
|
14
|
+
"ssrEnabled",
|
|
15
|
+
"ssrOutDir",
|
|
16
|
+
"types",
|
|
17
|
+
"executor",
|
|
18
|
+
"logging",
|
|
19
|
+
"litestarVersion"
|
|
20
|
+
]);
|
|
21
|
+
const allowedModes = /* @__PURE__ */ new Set(["spa", "template", "htmx", "hybrid", "inertia", "ssr", "ssg", "external"]);
|
|
22
|
+
const allowedProxyModes = /* @__PURE__ */ new Set(["vite", "direct", "proxy"]);
|
|
23
|
+
const allowedExecutors = /* @__PURE__ */ new Set(["node", "bun", "deno", "yarn", "pnpm"]);
|
|
24
|
+
const allowedLogLevels = /* @__PURE__ */ new Set(["quiet", "normal", "verbose"]);
|
|
25
|
+
function fail(message) {
|
|
26
|
+
throw new Error(`litestar-vite-plugin: invalid .litestar.json - ${message}`);
|
|
27
|
+
}
|
|
28
|
+
function assertObject(value, label) {
|
|
29
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
30
|
+
fail(`${label} must be an object`);
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
function assertString(obj, key) {
|
|
35
|
+
const value = obj[key];
|
|
36
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
37
|
+
fail(`"${key}" must be a non-empty string`);
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
function assertBoolean(obj, key) {
|
|
42
|
+
const value = obj[key];
|
|
43
|
+
if (typeof value !== "boolean") {
|
|
44
|
+
fail(`"${key}" must be a boolean`);
|
|
45
|
+
}
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
function assertNumber(obj, key) {
|
|
49
|
+
const value = obj[key];
|
|
50
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
51
|
+
fail(`"${key}" must be a number`);
|
|
52
|
+
}
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
function assertNullableString(obj, key) {
|
|
56
|
+
const value = obj[key];
|
|
57
|
+
if (value === null) return null;
|
|
58
|
+
if (typeof value !== "string") {
|
|
59
|
+
fail(`"${key}" must be a string or null`);
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
function assertEnum(value, key, allowed) {
|
|
64
|
+
if (typeof value !== "string" || !allowed.has(value)) {
|
|
65
|
+
fail(`"${key}" must be one of: ${Array.from(allowed).join(", ")}`);
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
function assertProxyMode(value) {
|
|
70
|
+
if (value === null) return null;
|
|
71
|
+
return assertEnum(value, "proxyMode", allowedProxyModes);
|
|
72
|
+
}
|
|
73
|
+
function parseTypesConfig(value) {
|
|
74
|
+
if (value === null) return null;
|
|
75
|
+
const obj = assertObject(value, "types");
|
|
76
|
+
const enabled = assertBoolean(obj, "enabled");
|
|
77
|
+
const output = assertString(obj, "output");
|
|
78
|
+
const openapiPath = assertString(obj, "openapiPath");
|
|
79
|
+
const routesPath = assertString(obj, "routesPath");
|
|
80
|
+
const pagePropsPath = assertString(obj, "pagePropsPath");
|
|
81
|
+
const generateZod = assertBoolean(obj, "generateZod");
|
|
82
|
+
const generateSdk = assertBoolean(obj, "generateSdk");
|
|
83
|
+
const generateRoutes = assertBoolean(obj, "generateRoutes");
|
|
84
|
+
const generatePageProps = assertBoolean(obj, "generatePageProps");
|
|
85
|
+
const globalRoute = assertBoolean(obj, "globalRoute");
|
|
86
|
+
return {
|
|
87
|
+
enabled,
|
|
88
|
+
output,
|
|
89
|
+
openapiPath,
|
|
90
|
+
routesPath,
|
|
91
|
+
pagePropsPath,
|
|
92
|
+
generateZod,
|
|
93
|
+
generateSdk,
|
|
94
|
+
generateRoutes,
|
|
95
|
+
generatePageProps,
|
|
96
|
+
globalRoute
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function parseLogging(value) {
|
|
100
|
+
if (value === null) return null;
|
|
101
|
+
const obj = assertObject(value, "logging");
|
|
102
|
+
const level = assertEnum(obj.level, "logging.level", allowedLogLevels);
|
|
103
|
+
const showPathsAbsolute = assertBoolean(obj, "showPathsAbsolute");
|
|
104
|
+
const suppressNpmOutput = assertBoolean(obj, "suppressNpmOutput");
|
|
105
|
+
const suppressViteBanner = assertBoolean(obj, "suppressViteBanner");
|
|
106
|
+
const timestamps = assertBoolean(obj, "timestamps");
|
|
107
|
+
return { level, showPathsAbsolute, suppressNpmOutput, suppressViteBanner, timestamps };
|
|
108
|
+
}
|
|
109
|
+
function parseBridgeSchema(value) {
|
|
110
|
+
const obj = assertObject(value, "root");
|
|
111
|
+
for (const key of Object.keys(obj)) {
|
|
112
|
+
if (!allowedTopLevelKeys.has(key)) {
|
|
113
|
+
fail(`unknown top-level key "${key}"`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const assetUrl = assertString(obj, "assetUrl");
|
|
117
|
+
const bundleDir = assertString(obj, "bundleDir");
|
|
118
|
+
const resourceDir = assertString(obj, "resourceDir");
|
|
119
|
+
const staticDir = assertString(obj, "staticDir");
|
|
120
|
+
const hotFile = assertString(obj, "hotFile");
|
|
121
|
+
const manifest = assertString(obj, "manifest");
|
|
122
|
+
const mode = assertEnum(obj.mode, "mode", allowedModes);
|
|
123
|
+
const proxyMode = assertProxyMode(obj.proxyMode);
|
|
124
|
+
const host = assertString(obj, "host");
|
|
125
|
+
const port = assertNumber(obj, "port");
|
|
126
|
+
const ssrEnabled = assertBoolean(obj, "ssrEnabled");
|
|
127
|
+
const ssrOutDir = assertNullableString(obj, "ssrOutDir");
|
|
128
|
+
const types = parseTypesConfig(obj.types);
|
|
129
|
+
const executor = assertEnum(obj.executor, "executor", allowedExecutors);
|
|
130
|
+
const logging = parseLogging(obj.logging);
|
|
131
|
+
const litestarVersion = assertString(obj, "litestarVersion");
|
|
132
|
+
return {
|
|
133
|
+
assetUrl,
|
|
134
|
+
bundleDir,
|
|
135
|
+
resourceDir,
|
|
136
|
+
staticDir,
|
|
137
|
+
hotFile,
|
|
138
|
+
manifest,
|
|
139
|
+
mode,
|
|
140
|
+
proxyMode,
|
|
141
|
+
host,
|
|
142
|
+
port,
|
|
143
|
+
ssrEnabled,
|
|
144
|
+
ssrOutDir,
|
|
145
|
+
types,
|
|
146
|
+
executor,
|
|
147
|
+
logging,
|
|
148
|
+
litestarVersion
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function readBridgeConfig(explicitPath) {
|
|
152
|
+
const envPath = explicitPath ?? process.env.LITESTAR_VITE_CONFIG_PATH;
|
|
153
|
+
if (envPath) {
|
|
154
|
+
if (!fs.existsSync(envPath)) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
return readBridgeConfigFile(envPath);
|
|
158
|
+
}
|
|
159
|
+
const defaultPath = path.join(process.cwd(), ".litestar.json");
|
|
160
|
+
if (fs.existsSync(defaultPath)) {
|
|
161
|
+
return readBridgeConfigFile(defaultPath);
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
function readBridgeConfigFile(filePath) {
|
|
166
|
+
let raw;
|
|
167
|
+
try {
|
|
168
|
+
raw = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
169
|
+
} catch (e) {
|
|
170
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
171
|
+
fail(`failed to parse JSON (${msg})`);
|
|
172
|
+
}
|
|
173
|
+
return parseBridgeSchema(raw);
|
|
174
|
+
}
|
|
175
|
+
export {
|
|
176
|
+
parseBridgeSchema,
|
|
177
|
+
readBridgeConfig
|
|
178
|
+
};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
async function emitPagePropsTypes(pagesPath, outputDir) {
|
|
4
|
+
const contents = await fs.promises.readFile(pagesPath, "utf-8");
|
|
5
|
+
const json = JSON.parse(contents);
|
|
6
|
+
const outDir = path.resolve(process.cwd(), outputDir);
|
|
7
|
+
await fs.promises.mkdir(outDir, { recursive: true });
|
|
8
|
+
const outFile = path.join(outDir, "page-props.ts");
|
|
9
|
+
const { includeDefaultAuth, includeDefaultFlash } = json.typeGenConfig;
|
|
10
|
+
const typeImportPaths = json.typeImportPaths ?? {};
|
|
11
|
+
const fallbackType = json.fallbackType ?? "unknown";
|
|
12
|
+
const defaultFallback = fallbackType === "any" ? "Record<string, any>" : "Record<string, unknown>";
|
|
13
|
+
let userTypes = "";
|
|
14
|
+
let authTypes = "";
|
|
15
|
+
let flashTypes = "";
|
|
16
|
+
if (includeDefaultAuth) {
|
|
17
|
+
userTypes = `/**
|
|
18
|
+
* Default User interface - minimal baseline for common auth patterns.
|
|
19
|
+
* Users extend this via module augmentation with their full user model.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* declare module 'litestar-vite-plugin/inertia' {
|
|
23
|
+
* interface User {
|
|
24
|
+
* avatarUrl?: string | null
|
|
25
|
+
* roles: Role[]
|
|
26
|
+
* teams: Team[]
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
*/
|
|
30
|
+
export interface User {
|
|
31
|
+
id: string
|
|
32
|
+
email: string
|
|
33
|
+
name?: string | null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
`;
|
|
37
|
+
authTypes = `/**
|
|
38
|
+
* Default AuthData interface - mirrors Laravel Jetstream pattern.
|
|
39
|
+
* isAuthenticated + optional user is the universal pattern.
|
|
40
|
+
*/
|
|
41
|
+
export interface AuthData {
|
|
42
|
+
isAuthenticated: boolean
|
|
43
|
+
user?: User
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
`;
|
|
47
|
+
} else {
|
|
48
|
+
userTypes = `/**
|
|
49
|
+
* User interface - define via module augmentation.
|
|
50
|
+
* Default auth types are disabled.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* declare module 'litestar-vite-plugin/inertia' {
|
|
54
|
+
* interface User {
|
|
55
|
+
* uuid: string
|
|
56
|
+
* username: string
|
|
57
|
+
* }
|
|
58
|
+
* }
|
|
59
|
+
*/
|
|
60
|
+
export interface User {}
|
|
61
|
+
|
|
62
|
+
`;
|
|
63
|
+
authTypes = `/**
|
|
64
|
+
* AuthData interface - define via module augmentation.
|
|
65
|
+
* Default auth types are disabled.
|
|
66
|
+
*/
|
|
67
|
+
export interface AuthData {}
|
|
68
|
+
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
71
|
+
if (includeDefaultFlash) {
|
|
72
|
+
flashTypes = `/**
|
|
73
|
+
* Default FlashMessages interface - category to messages mapping.
|
|
74
|
+
* Standard categories: success, error, info, warning.
|
|
75
|
+
*/
|
|
76
|
+
export interface FlashMessages {
|
|
77
|
+
[category: string]: string[]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
`;
|
|
81
|
+
} else {
|
|
82
|
+
flashTypes = `/**
|
|
83
|
+
* FlashMessages interface - define via module augmentation.
|
|
84
|
+
* Default flash types are disabled.
|
|
85
|
+
*/
|
|
86
|
+
export interface FlashMessages {}
|
|
87
|
+
|
|
88
|
+
`;
|
|
89
|
+
}
|
|
90
|
+
const sharedPropsContent = includeDefaultAuth || includeDefaultFlash ? ` auth?: AuthData
|
|
91
|
+
flash?: FlashMessages` : "";
|
|
92
|
+
const allCustomTypes = /* @__PURE__ */ new Set();
|
|
93
|
+
for (const data of Object.values(json.pages)) {
|
|
94
|
+
if (data.tsType) {
|
|
95
|
+
allCustomTypes.add(data.tsType);
|
|
96
|
+
}
|
|
97
|
+
for (const t of data.customTypes ?? []) {
|
|
98
|
+
allCustomTypes.add(t);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const apiTypesPath = path.join(outDir, "api", "types.gen.ts");
|
|
102
|
+
const availableApiTypes = /* @__PURE__ */ new Set();
|
|
103
|
+
if (fs.existsSync(apiTypesPath)) {
|
|
104
|
+
const content = await fs.promises.readFile(apiTypesPath, "utf-8");
|
|
105
|
+
for (const match of content.matchAll(/export (?:type|interface|enum|class) (\\w+)/g)) {
|
|
106
|
+
if (match[1]) {
|
|
107
|
+
availableApiTypes.add(match[1]);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const apiImports = [...allCustomTypes].filter((t) => availableApiTypes.has(t)).sort();
|
|
112
|
+
const remainingTypes = [...allCustomTypes].filter((t) => !availableApiTypes.has(t)).sort();
|
|
113
|
+
const importsByPath = /* @__PURE__ */ new Map();
|
|
114
|
+
const unresolvedTypes = [];
|
|
115
|
+
for (const t of remainingTypes) {
|
|
116
|
+
const importPath = typeImportPaths[t];
|
|
117
|
+
if (importPath) {
|
|
118
|
+
const list = importsByPath.get(importPath) ?? [];
|
|
119
|
+
list.push(t);
|
|
120
|
+
importsByPath.set(importPath, list);
|
|
121
|
+
} else {
|
|
122
|
+
unresolvedTypes.push(t);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (unresolvedTypes.length > 0) {
|
|
126
|
+
console.warn(`litestar-vite: unresolved Inertia props types: ${unresolvedTypes.join(", ")}. Add them to TypeGenConfig.type_import_paths or include them in OpenAPI.`);
|
|
127
|
+
}
|
|
128
|
+
let importStatement = "";
|
|
129
|
+
if (apiImports.length > 0) {
|
|
130
|
+
importStatement += `import type { ${apiImports.join(", ")} } from "./api/types.gen"
|
|
131
|
+
`;
|
|
132
|
+
}
|
|
133
|
+
const sortedImportPaths = [...importsByPath.keys()].sort();
|
|
134
|
+
for (const p of sortedImportPaths) {
|
|
135
|
+
const names = (importsByPath.get(p) ?? []).sort();
|
|
136
|
+
if (names.length > 0) {
|
|
137
|
+
importStatement += `import type { ${names.join(", ")} } from "${p}"
|
|
138
|
+
`;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (importStatement) {
|
|
142
|
+
importStatement += "\n";
|
|
143
|
+
}
|
|
144
|
+
const pageEntries = [];
|
|
145
|
+
for (const [component, data] of Object.entries(json.pages)) {
|
|
146
|
+
const rawType = data.tsType || data.propsType || defaultFallback;
|
|
147
|
+
const propsType = rawType.includes("|") ? `(${rawType})` : rawType;
|
|
148
|
+
pageEntries.push(` "${component}": ${propsType} & FullSharedProps`);
|
|
149
|
+
}
|
|
150
|
+
const body = `// AUTO-GENERATED by litestar-vite. Do not edit.
|
|
151
|
+
/* eslint-disable */
|
|
152
|
+
|
|
153
|
+
${importStatement}${userTypes}${authTypes}${flashTypes}/**
|
|
154
|
+
* Generated shared props (always present).
|
|
155
|
+
* Includes built-in props + static config props.
|
|
156
|
+
*/
|
|
157
|
+
export interface GeneratedSharedProps {
|
|
158
|
+
errors?: Record<string, string[]>
|
|
159
|
+
csrf_token?: string
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* User-defined shared props for dynamic share() calls in guards/middleware.
|
|
164
|
+
* Extend this interface via module augmentation.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* declare module 'litestar-vite-plugin/inertia' {
|
|
168
|
+
* interface User {
|
|
169
|
+
* avatarUrl?: string | null
|
|
170
|
+
* roles: Role[]
|
|
171
|
+
* teams: Team[]
|
|
172
|
+
* }
|
|
173
|
+
* interface SharedProps {
|
|
174
|
+
* locale?: string
|
|
175
|
+
* currentTeam?: CurrentTeam
|
|
176
|
+
* }
|
|
177
|
+
* }
|
|
178
|
+
*/
|
|
179
|
+
export interface SharedProps {
|
|
180
|
+
${sharedPropsContent}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Full shared props = generated + user-defined */
|
|
184
|
+
export type FullSharedProps = GeneratedSharedProps & SharedProps
|
|
185
|
+
|
|
186
|
+
/** Page props mapped by component name */
|
|
187
|
+
export interface PageProps {
|
|
188
|
+
${pageEntries.join("\n")}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Component name union type */
|
|
192
|
+
export type ComponentName = keyof PageProps
|
|
193
|
+
|
|
194
|
+
/** Type-safe props for a specific component */
|
|
195
|
+
export type InertiaPageProps<C extends ComponentName> = PageProps[C]
|
|
196
|
+
|
|
197
|
+
/** Get props type for a specific page component */
|
|
198
|
+
export type PagePropsFor<C extends ComponentName> = PageProps[C]
|
|
199
|
+
|
|
200
|
+
// Re-export for module augmentation
|
|
201
|
+
declare module "litestar-vite-plugin/inertia" {
|
|
202
|
+
export { User, AuthData, FlashMessages, SharedProps, GeneratedSharedProps, FullSharedProps, PageProps, ComponentName, InertiaPageProps, PagePropsFor }
|
|
203
|
+
}
|
|
204
|
+
`;
|
|
205
|
+
await fs.promises.writeFile(outFile, body, "utf-8");
|
|
206
|
+
}
|
|
207
|
+
export {
|
|
208
|
+
emitPagePropsTypes
|
|
209
|
+
};
|
|
@@ -11,12 +11,3 @@
|
|
|
11
11
|
* @returns The path relative to root, or the original path if already relative or on different drive
|
|
12
12
|
*/
|
|
13
13
|
export declare function formatPath(absolutePath: string, root?: string): string;
|
|
14
|
-
/**
|
|
15
|
-
* Format multiple paths, joining them with a separator.
|
|
16
|
-
*
|
|
17
|
-
* @param paths - Array of absolute paths to format
|
|
18
|
-
* @param root - The project root directory (defaults to process.cwd())
|
|
19
|
-
* @param separator - Separator between paths (defaults to ", ")
|
|
20
|
-
* @returns Formatted paths joined by separator
|
|
21
|
-
*/
|
|
22
|
-
export declare function formatPaths(paths: string[], root?: string, separator?: string): string;
|
|
@@ -15,10 +15,6 @@ function formatPath(absolutePath, root) {
|
|
|
15
15
|
return absolutePath;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
function formatPaths(paths, root, separator = ", ") {
|
|
19
|
-
return paths.map((p) => formatPath(p, root)).join(separator);
|
|
20
|
-
}
|
|
21
18
|
export {
|
|
22
|
-
formatPath
|
|
23
|
-
formatPaths
|
|
19
|
+
formatPath
|
|
24
20
|
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
export interface RequiredTypeGenConfig {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
output: string;
|
|
5
|
+
openapiPath: string;
|
|
6
|
+
routesPath: string;
|
|
7
|
+
pagePropsPath: string;
|
|
8
|
+
generateZod: boolean;
|
|
9
|
+
generateSdk: boolean;
|
|
10
|
+
generateRoutes: boolean;
|
|
11
|
+
generatePageProps: boolean;
|
|
12
|
+
globalRoute: boolean;
|
|
13
|
+
debounce: number;
|
|
14
|
+
}
|
|
15
|
+
export interface TypeGenPluginOptions {
|
|
16
|
+
/** Vite plugin name */
|
|
17
|
+
pluginName: string;
|
|
18
|
+
/** Human-friendly prefix for logs */
|
|
19
|
+
frameworkName: string;
|
|
20
|
+
/** @hey-api client plugin (e.g. "@hey-api/client-axios") */
|
|
21
|
+
sdkClientPlugin: string;
|
|
22
|
+
/** JS runtime executor for package commands */
|
|
23
|
+
executor?: string;
|
|
24
|
+
/** Whether .litestar.json was present (used for buildStart warnings) */
|
|
25
|
+
hasPythonConfig?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Unified Litestar type generation Vite plugin.
|
|
29
|
+
*
|
|
30
|
+
* Watches OpenAPI, routes.json, and inertia page props metadata and generates:
|
|
31
|
+
* - API types via @hey-api/openapi-ts (optional)
|
|
32
|
+
* - routes.ts (optional)
|
|
33
|
+
* - page-props.ts (optional)
|
|
34
|
+
*/
|
|
35
|
+
export declare function createLitestarTypeGenPlugin(typesConfig: RequiredTypeGenConfig, options: TypeGenPluginOptions): Plugin;
|