litestar-vite-plugin 0.15.0-alpha.4 → 0.15.0-alpha.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 +6 -0
- package/dist/js/astro.js +42 -7
- package/dist/js/helpers/htmx.d.ts +68 -0
- package/dist/js/helpers/htmx.js +494 -0
- package/dist/js/helpers/index.d.ts +12 -4
- package/dist/js/helpers/index.js +13 -5
- package/dist/js/index.d.ts +33 -8
- package/dist/js/index.js +227 -54
- package/dist/js/inertia-helpers/index.d.ts +6 -1
- package/dist/js/inertia-helpers/index.js +7 -4
- package/dist/js/litestar-meta.js +20 -4
- package/dist/js/nuxt.d.ts +6 -0
- package/dist/js/nuxt.js +39 -4
- package/dist/js/sveltekit.d.ts +6 -0
- package/dist/js/sveltekit.js +34 -4
- package/package.json +7 -7
- package/dist/js/helpers/routes.d.ts +0 -159
- package/dist/js/helpers/routes.js +0 -302
package/dist/js/nuxt.js
CHANGED
|
@@ -51,6 +51,7 @@ function resolveConfig(config = {}) {
|
|
|
51
51
|
openapiPath: "openapi.json",
|
|
52
52
|
routesPath: "routes.json",
|
|
53
53
|
generateZod: false,
|
|
54
|
+
generateSdk: true,
|
|
54
55
|
debounce: 300
|
|
55
56
|
};
|
|
56
57
|
} else if (typeof config.types === "object" && config.types !== null) {
|
|
@@ -60,6 +61,7 @@ function resolveConfig(config = {}) {
|
|
|
60
61
|
openapiPath: config.types.openapiPath ?? "openapi.json",
|
|
61
62
|
routesPath: config.types.routesPath ?? "routes.json",
|
|
62
63
|
generateZod: config.types.generateZod ?? false,
|
|
64
|
+
generateSdk: config.types.generateSdk ?? true,
|
|
63
65
|
debounce: config.types.debounce ?? 300
|
|
64
66
|
};
|
|
65
67
|
}
|
|
@@ -96,6 +98,15 @@ function createProxyPlugin(config) {
|
|
|
96
98
|
hmrPort = await getPort();
|
|
97
99
|
return {
|
|
98
100
|
server: {
|
|
101
|
+
// Force IPv4 binding for consistency with Python proxy configuration
|
|
102
|
+
// Without this, Nuxt/Nitro might bind to IPv6 localhost which the proxy can't reach
|
|
103
|
+
host: "127.0.0.1",
|
|
104
|
+
// Set the port from Python config/env to ensure Nuxt uses the expected port
|
|
105
|
+
// strictPort: true prevents auto-incrementing to a different port
|
|
106
|
+
...config.devPort !== void 0 ? {
|
|
107
|
+
port: config.devPort,
|
|
108
|
+
strictPort: true
|
|
109
|
+
} : {},
|
|
99
110
|
// Avoid HMR port collisions by letting Vite pick a free port for WS
|
|
100
111
|
hmr: {
|
|
101
112
|
port: hmrPort,
|
|
@@ -281,12 +292,28 @@ function createTypeGenerationPlugin(typesConfig, executor) {
|
|
|
281
292
|
return false;
|
|
282
293
|
}
|
|
283
294
|
console.log(colors.cyan("[litestar-nuxt]"), colors.dim("Generating TypeScript types..."));
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
295
|
+
const projectRoot = process.cwd();
|
|
296
|
+
const candidates = [path.resolve(projectRoot, "openapi-ts.config.ts"), path.resolve(projectRoot, "hey-api.config.ts"), path.resolve(projectRoot, ".hey-api.config.ts")];
|
|
297
|
+
const configPath = candidates.find((p) => fs.existsSync(p)) || null;
|
|
298
|
+
let args;
|
|
299
|
+
if (configPath) {
|
|
300
|
+
console.log(colors.cyan("[litestar-nuxt]"), colors.dim("Using config:"), configPath);
|
|
301
|
+
args = ["@hey-api/openapi-ts", "--file", configPath];
|
|
302
|
+
} else {
|
|
303
|
+
args = ["@hey-api/openapi-ts", "-i", typesConfig.openapiPath, "-o", typesConfig.output];
|
|
304
|
+
const plugins = ["@hey-api/typescript", "@hey-api/schemas"];
|
|
305
|
+
if (typesConfig.generateSdk) {
|
|
306
|
+
plugins.push("@hey-api/sdk", "@hey-api/client-nuxt");
|
|
307
|
+
}
|
|
308
|
+
if (typesConfig.generateZod) {
|
|
309
|
+
plugins.push("zod");
|
|
310
|
+
}
|
|
311
|
+
if (plugins.length) {
|
|
312
|
+
args.push("--plugins", ...plugins);
|
|
313
|
+
}
|
|
287
314
|
}
|
|
288
315
|
await execAsync(resolvePackageExecutor(args.join(" "), executor), {
|
|
289
|
-
cwd:
|
|
316
|
+
cwd: projectRoot
|
|
290
317
|
});
|
|
291
318
|
const routesPath = path.resolve(process.cwd(), typesConfig.routesPath);
|
|
292
319
|
if (fs.existsSync(routesPath)) {
|
|
@@ -325,6 +352,14 @@ function createTypeGenerationPlugin(typesConfig, executor) {
|
|
|
325
352
|
server = devServer;
|
|
326
353
|
console.log(colors.cyan("[litestar-nuxt]"), colors.dim("Watching for schema changes:"), colors.yellow(typesConfig.openapiPath));
|
|
327
354
|
},
|
|
355
|
+
async buildStart() {
|
|
356
|
+
if (typesConfig.enabled) {
|
|
357
|
+
const openapiPath = path.resolve(process.cwd(), typesConfig.openapiPath);
|
|
358
|
+
if (fs.existsSync(openapiPath)) {
|
|
359
|
+
await runTypeGeneration();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
},
|
|
328
363
|
handleHotUpdate({ file }) {
|
|
329
364
|
if (!typesConfig.enabled) {
|
|
330
365
|
return;
|
package/dist/js/sveltekit.d.ts
CHANGED
|
@@ -66,6 +66,12 @@ export interface SvelteKitTypesConfig {
|
|
|
66
66
|
* @default false
|
|
67
67
|
*/
|
|
68
68
|
generateZod?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Generate SDK client functions for API calls.
|
|
71
|
+
*
|
|
72
|
+
* @default true
|
|
73
|
+
*/
|
|
74
|
+
generateSdk?: boolean;
|
|
69
75
|
/**
|
|
70
76
|
* Debounce time in milliseconds for type regeneration.
|
|
71
77
|
*
|
package/dist/js/sveltekit.js
CHANGED
|
@@ -46,6 +46,7 @@ function resolveConfig(config = {}) {
|
|
|
46
46
|
openapiPath: pythonTypesConfig?.openapiPath ?? "openapi.json",
|
|
47
47
|
routesPath: pythonTypesConfig?.routesPath ?? "routes.json",
|
|
48
48
|
generateZod: pythonTypesConfig?.generateZod ?? false,
|
|
49
|
+
generateSdk: pythonTypesConfig?.generateSdk ?? true,
|
|
49
50
|
debounce: 300
|
|
50
51
|
};
|
|
51
52
|
} else if (typeof config.types === "object" && config.types !== null) {
|
|
@@ -55,6 +56,7 @@ function resolveConfig(config = {}) {
|
|
|
55
56
|
openapiPath: config.types.openapiPath ?? pythonTypesConfig?.openapiPath ?? "openapi.json",
|
|
56
57
|
routesPath: config.types.routesPath ?? pythonTypesConfig?.routesPath ?? "routes.json",
|
|
57
58
|
generateZod: config.types.generateZod ?? pythonTypesConfig?.generateZod ?? false,
|
|
59
|
+
generateSdk: config.types.generateSdk ?? pythonTypesConfig?.generateSdk ?? true,
|
|
58
60
|
debounce: config.types.debounce ?? 300
|
|
59
61
|
};
|
|
60
62
|
} else if (config.types !== false && pythonTypesConfig?.enabled) {
|
|
@@ -64,6 +66,7 @@ function resolveConfig(config = {}) {
|
|
|
64
66
|
openapiPath: pythonTypesConfig.openapiPath ?? "openapi.json",
|
|
65
67
|
routesPath: pythonTypesConfig.routesPath ?? "routes.json",
|
|
66
68
|
generateZod: pythonTypesConfig.generateZod ?? false,
|
|
69
|
+
generateSdk: pythonTypesConfig.generateSdk ?? true,
|
|
67
70
|
debounce: 300
|
|
68
71
|
};
|
|
69
72
|
}
|
|
@@ -87,6 +90,9 @@ function litestarSvelteKit(userConfig = {}) {
|
|
|
87
90
|
config() {
|
|
88
91
|
return {
|
|
89
92
|
server: {
|
|
93
|
+
// Force IPv4 binding for consistency with Python proxy configuration
|
|
94
|
+
// Without this, SvelteKit might bind to IPv6 localhost which the proxy can't reach
|
|
95
|
+
host: "127.0.0.1",
|
|
90
96
|
// Set the port from Python config/env to ensure SvelteKit uses the expected port
|
|
91
97
|
// strictPort: true prevents SvelteKit from auto-incrementing to a different port
|
|
92
98
|
...config.port !== void 0 ? {
|
|
@@ -294,12 +300,28 @@ function createTypeGenerationPlugin(typesConfig, executor) {
|
|
|
294
300
|
return false;
|
|
295
301
|
}
|
|
296
302
|
console.log(colors.cyan("[litestar-sveltekit]"), colors.dim("Generating TypeScript types..."));
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
303
|
+
const projectRoot = process.cwd();
|
|
304
|
+
const candidates = [path.resolve(projectRoot, "openapi-ts.config.ts"), path.resolve(projectRoot, "hey-api.config.ts"), path.resolve(projectRoot, ".hey-api.config.ts")];
|
|
305
|
+
const configPath = candidates.find((p) => fs.existsSync(p)) || null;
|
|
306
|
+
let args;
|
|
307
|
+
if (configPath) {
|
|
308
|
+
console.log(colors.cyan("[litestar-sveltekit]"), colors.dim("Using config:"), configPath);
|
|
309
|
+
args = ["@hey-api/openapi-ts", "--file", configPath];
|
|
310
|
+
} else {
|
|
311
|
+
args = ["@hey-api/openapi-ts", "-i", typesConfig.openapiPath, "-o", typesConfig.output];
|
|
312
|
+
const plugins = ["@hey-api/typescript", "@hey-api/schemas"];
|
|
313
|
+
if (typesConfig.generateSdk) {
|
|
314
|
+
plugins.push("@hey-api/sdk", "@hey-api/client-fetch");
|
|
315
|
+
}
|
|
316
|
+
if (typesConfig.generateZod) {
|
|
317
|
+
plugins.push("zod");
|
|
318
|
+
}
|
|
319
|
+
if (plugins.length) {
|
|
320
|
+
args.push("--plugins", ...plugins);
|
|
321
|
+
}
|
|
300
322
|
}
|
|
301
323
|
await execAsync(resolvePackageExecutor(args.join(" "), executor), {
|
|
302
|
-
cwd:
|
|
324
|
+
cwd: projectRoot
|
|
303
325
|
});
|
|
304
326
|
const routesPath = path.resolve(process.cwd(), typesConfig.routesPath);
|
|
305
327
|
if (fs.existsSync(routesPath)) {
|
|
@@ -338,6 +360,14 @@ function createTypeGenerationPlugin(typesConfig, executor) {
|
|
|
338
360
|
server = devServer;
|
|
339
361
|
console.log(colors.cyan("[litestar-sveltekit]"), colors.dim("Watching for schema changes:"), colors.yellow(typesConfig.openapiPath));
|
|
340
362
|
},
|
|
363
|
+
async buildStart() {
|
|
364
|
+
if (typesConfig.enabled) {
|
|
365
|
+
const openapiPath = path.resolve(process.cwd(), typesConfig.openapiPath);
|
|
366
|
+
if (fs.existsSync(openapiPath)) {
|
|
367
|
+
await runTypeGeneration();
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
},
|
|
341
371
|
handleHotUpdate({ file }) {
|
|
342
372
|
if (!typesConfig.enabled) {
|
|
343
373
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "litestar-vite-plugin",
|
|
3
|
-
"version": "0.15.0-alpha.
|
|
3
|
+
"version": "0.15.0-alpha.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Litestar plugin for Vite.",
|
|
6
6
|
"keywords": [
|
|
@@ -18,29 +18,29 @@
|
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
20
|
"types": "./dist/js/index.d.ts",
|
|
21
|
-
"
|
|
21
|
+
"import": "./dist/js/index.js"
|
|
22
22
|
},
|
|
23
23
|
"./helpers": {
|
|
24
24
|
"types": "./dist/js/helpers/index.d.ts",
|
|
25
|
-
"
|
|
25
|
+
"import": "./dist/js/helpers/index.js"
|
|
26
26
|
},
|
|
27
27
|
"./install-hint": "./dist/js/install-hint.js",
|
|
28
28
|
"./litestar-meta": "./dist/js/litestar-meta.js",
|
|
29
29
|
"./inertia-helpers": {
|
|
30
30
|
"types": "./dist/js/inertia-helpers/index.d.ts",
|
|
31
|
-
"
|
|
31
|
+
"import": "./dist/js/inertia-helpers/index.js"
|
|
32
32
|
},
|
|
33
33
|
"./astro": {
|
|
34
34
|
"types": "./dist/js/astro.d.ts",
|
|
35
|
-
"
|
|
35
|
+
"import": "./dist/js/astro.js"
|
|
36
36
|
},
|
|
37
37
|
"./sveltekit": {
|
|
38
38
|
"types": "./dist/js/sveltekit.d.ts",
|
|
39
|
-
"
|
|
39
|
+
"import": "./dist/js/sveltekit.js"
|
|
40
40
|
},
|
|
41
41
|
"./nuxt": {
|
|
42
42
|
"types": "./dist/js/nuxt.d.ts",
|
|
43
|
-
"
|
|
43
|
+
"import": "./dist/js/nuxt.js"
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
"types": "./dist/js/index.d.ts",
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Route utilities for Litestar applications.
|
|
3
|
-
*
|
|
4
|
-
* These helpers work with route metadata injected by Litestar:
|
|
5
|
-
* - window.__LITESTAR_ROUTES__ (SPA mode with route injection)
|
|
6
|
-
* - window.routes (legacy/Inertia mode)
|
|
7
|
-
* - Generated routes from src/generated/routes.ts (typed routing)
|
|
8
|
-
*
|
|
9
|
-
* For typed routing, import from your generated routes instead:
|
|
10
|
-
* ```ts
|
|
11
|
-
* import { route, routes } from '@/generated/routes'
|
|
12
|
-
* ```
|
|
13
|
-
*
|
|
14
|
-
* @module
|
|
15
|
-
*/
|
|
16
|
-
/**
|
|
17
|
-
* Route definition from Litestar.
|
|
18
|
-
*/
|
|
19
|
-
export interface RouteDefinition {
|
|
20
|
-
uri: string;
|
|
21
|
-
methods: string[];
|
|
22
|
-
parameters?: string[];
|
|
23
|
-
parameterTypes?: Record<string, string>;
|
|
24
|
-
queryParameters?: Record<string, string>;
|
|
25
|
-
component?: string;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Routes object mapping route names to definitions.
|
|
29
|
-
*/
|
|
30
|
-
export interface RoutesMap {
|
|
31
|
-
routes: Record<string, RouteDefinition>;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Convenience alias for route names when using injected metadata.
|
|
35
|
-
*/
|
|
36
|
-
export type RouteName = keyof RoutesMap["routes"];
|
|
37
|
-
/**
|
|
38
|
-
* Litestar helpers namespace for clean global access.
|
|
39
|
-
*/
|
|
40
|
-
export interface LitestarHelpers {
|
|
41
|
-
route: typeof route;
|
|
42
|
-
toRoute: typeof toRoute;
|
|
43
|
-
currentRoute: typeof currentRoute;
|
|
44
|
-
isRoute: typeof isRoute;
|
|
45
|
-
isCurrentRoute: typeof isCurrentRoute;
|
|
46
|
-
getRelativeUrlPath: typeof getRelativeUrlPath;
|
|
47
|
-
routes: Record<string, string>;
|
|
48
|
-
}
|
|
49
|
-
declare global {
|
|
50
|
-
interface Window {
|
|
51
|
-
__LITESTAR_ROUTES__?: RoutesMap;
|
|
52
|
-
__LITESTAR__?: LitestarHelpers;
|
|
53
|
-
routes?: Record<string, string>;
|
|
54
|
-
serverRoutes?: Record<string, string>;
|
|
55
|
-
}
|
|
56
|
-
var __LITESTAR__: LitestarHelpers | undefined;
|
|
57
|
-
var routes: Record<string, string>;
|
|
58
|
-
var serverRoutes: Record<string, string>;
|
|
59
|
-
}
|
|
60
|
-
declare global {
|
|
61
|
-
interface ImportMeta {
|
|
62
|
-
hot?: {
|
|
63
|
-
on: (event: string, callback: (...args: unknown[]) => void) => void;
|
|
64
|
-
accept?: (cb?: () => void) => void;
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
type RouteArg = string | number | boolean;
|
|
69
|
-
type RouteArgs = Record<string, RouteArg> | RouteArg[];
|
|
70
|
-
/**
|
|
71
|
-
* Get the routes object from the page.
|
|
72
|
-
*
|
|
73
|
-
* Checks multiple sources:
|
|
74
|
-
* 1. window.__LITESTAR_ROUTES__ (SPA mode with full metadata)
|
|
75
|
-
* 2. window.routes (legacy mode with just paths)
|
|
76
|
-
*
|
|
77
|
-
* @returns Routes map or null if not found
|
|
78
|
-
*/
|
|
79
|
-
export declare function getRoutes(): Record<string, string> | null;
|
|
80
|
-
/**
|
|
81
|
-
* Generate a URL for a named route with parameters.
|
|
82
|
-
*
|
|
83
|
-
* @param routeName - The name of the route
|
|
84
|
-
* @param args - Route parameters (object or array)
|
|
85
|
-
* @returns The generated URL or "#" if route not found
|
|
86
|
-
*
|
|
87
|
-
* @example
|
|
88
|
-
* ```ts
|
|
89
|
-
* import { route } from 'litestar-vite-plugin/helpers'
|
|
90
|
-
*
|
|
91
|
-
* // Named parameters
|
|
92
|
-
* route('user:detail', { user_id: 123 }) // "/users/123"
|
|
93
|
-
*
|
|
94
|
-
* // Positional parameters
|
|
95
|
-
* route('user:detail', [123]) // "/users/123"
|
|
96
|
-
* ```
|
|
97
|
-
*/
|
|
98
|
-
export declare function route(routeName: string, ...args: [RouteArgs?]): string;
|
|
99
|
-
/**
|
|
100
|
-
* Get the relative path portion of a URL.
|
|
101
|
-
*
|
|
102
|
-
* @param url - Full URL or path
|
|
103
|
-
* @returns Relative path with query string and hash
|
|
104
|
-
*/
|
|
105
|
-
export declare function getRelativeUrlPath(url: string): string;
|
|
106
|
-
/**
|
|
107
|
-
* Convert a URL to a route name.
|
|
108
|
-
*
|
|
109
|
-
* @param url - URL to match
|
|
110
|
-
* @returns Route name or null if no match
|
|
111
|
-
*
|
|
112
|
-
* @example
|
|
113
|
-
* ```ts
|
|
114
|
-
* toRoute('/users/123') // "user:detail"
|
|
115
|
-
* ```
|
|
116
|
-
*/
|
|
117
|
-
export declare function toRoute(url: string): string | null;
|
|
118
|
-
/**
|
|
119
|
-
* Get the current route name based on window.location.
|
|
120
|
-
*
|
|
121
|
-
* @returns Current route name or null if no match
|
|
122
|
-
*/
|
|
123
|
-
export declare function currentRoute(): string | null;
|
|
124
|
-
/**
|
|
125
|
-
* Check if a URL matches a route pattern.
|
|
126
|
-
*
|
|
127
|
-
* Supports wildcard patterns like "user:*" to match "user:list", "user:detail", etc.
|
|
128
|
-
*
|
|
129
|
-
* @param url - URL to check
|
|
130
|
-
* @param routeName - Route name or pattern (supports * wildcards)
|
|
131
|
-
* @returns True if the URL matches the route
|
|
132
|
-
*
|
|
133
|
-
* @example
|
|
134
|
-
* ```ts
|
|
135
|
-
* isRoute('/users/123', 'user:detail') // true
|
|
136
|
-
* isRoute('/users/123', 'user:*') // true
|
|
137
|
-
* ```
|
|
138
|
-
*/
|
|
139
|
-
export declare function isRoute(url: string, routeName: string): boolean;
|
|
140
|
-
/**
|
|
141
|
-
* Check if the current URL matches a route pattern.
|
|
142
|
-
*
|
|
143
|
-
* @param routeName - Route name or pattern (supports * wildcards)
|
|
144
|
-
* @returns True if the current URL matches the route
|
|
145
|
-
*
|
|
146
|
-
* @example
|
|
147
|
-
* ```ts
|
|
148
|
-
* // On /users/123
|
|
149
|
-
* isCurrentRoute('user:detail') // true
|
|
150
|
-
* isCurrentRoute('user:*') // true
|
|
151
|
-
* ```
|
|
152
|
-
*/
|
|
153
|
-
export declare function isCurrentRoute(routeName: string): boolean;
|
|
154
|
-
/**
|
|
155
|
-
* Litestar helpers namespace object.
|
|
156
|
-
* Access via window.__LITESTAR__ or import functions directly from this module.
|
|
157
|
-
*/
|
|
158
|
-
export declare const LITESTAR: LitestarHelpers;
|
|
159
|
-
export {};
|
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Route utilities for Litestar applications.
|
|
3
|
-
*
|
|
4
|
-
* These helpers work with route metadata injected by Litestar:
|
|
5
|
-
* - window.__LITESTAR_ROUTES__ (SPA mode with route injection)
|
|
6
|
-
* - window.routes (legacy/Inertia mode)
|
|
7
|
-
* - Generated routes from src/generated/routes.ts (typed routing)
|
|
8
|
-
*
|
|
9
|
-
* For typed routing, import from your generated routes instead:
|
|
10
|
-
* ```ts
|
|
11
|
-
* import { route, routes } from '@/generated/routes'
|
|
12
|
-
* ```
|
|
13
|
-
*
|
|
14
|
-
* @module
|
|
15
|
-
*/
|
|
16
|
-
/**
|
|
17
|
-
* Cache for compiled route patterns to avoid repeated regex compilation.
|
|
18
|
-
*/
|
|
19
|
-
const routePatternCache = new Map();
|
|
20
|
-
/**
|
|
21
|
-
* Compile a route pattern to a regex for URL matching.
|
|
22
|
-
* Results are cached for performance.
|
|
23
|
-
*
|
|
24
|
-
* @param routePattern - Route pattern with optional {param:type} placeholders
|
|
25
|
-
* @returns Compiled regex pattern
|
|
26
|
-
*/
|
|
27
|
-
function compileRoutePattern(routePattern) {
|
|
28
|
-
const cached = routePatternCache.get(routePattern);
|
|
29
|
-
if (cached) {
|
|
30
|
-
return cached;
|
|
31
|
-
}
|
|
32
|
-
const regexPattern = routePattern.replace(/\//g, "\\/").replace(/\{([^}]+)\}/g, (_, paramSpec) => {
|
|
33
|
-
// Handle {param:type} syntax
|
|
34
|
-
const paramType = paramSpec.includes(":") ? paramSpec.split(":")[1] : "str";
|
|
35
|
-
switch (paramType) {
|
|
36
|
-
case "uuid":
|
|
37
|
-
return "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
|
38
|
-
case "path":
|
|
39
|
-
return ".*";
|
|
40
|
-
case "int":
|
|
41
|
-
return "\\d+";
|
|
42
|
-
default:
|
|
43
|
-
return "[^/]+";
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
const compiled = new RegExp(`^${regexPattern}$`);
|
|
47
|
-
routePatternCache.set(routePattern, compiled);
|
|
48
|
-
return compiled;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Get the routes object from the page.
|
|
52
|
-
*
|
|
53
|
-
* Checks multiple sources:
|
|
54
|
-
* 1. window.__LITESTAR_ROUTES__ (SPA mode with full metadata)
|
|
55
|
-
* 2. window.routes (legacy mode with just paths)
|
|
56
|
-
*
|
|
57
|
-
* @returns Routes map or null if not found
|
|
58
|
-
*/
|
|
59
|
-
export function getRoutes() {
|
|
60
|
-
if (typeof window === "undefined") {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
// Check for full route metadata (SPA mode)
|
|
64
|
-
if (window.__LITESTAR_ROUTES__?.routes) {
|
|
65
|
-
const routes = {};
|
|
66
|
-
for (const [name, def] of Object.entries(window.__LITESTAR_ROUTES__.routes)) {
|
|
67
|
-
routes[name] = def.uri;
|
|
68
|
-
}
|
|
69
|
-
// Expose a descriptive alias for consumers
|
|
70
|
-
window.serverRoutes = routes;
|
|
71
|
-
return routes;
|
|
72
|
-
}
|
|
73
|
-
// Check for simple routes object (legacy/Inertia mode)
|
|
74
|
-
if (window.routes) {
|
|
75
|
-
return window.routes;
|
|
76
|
-
}
|
|
77
|
-
// Check globalThis.routes
|
|
78
|
-
if (typeof globalThis !== "undefined" && globalThis.routes) {
|
|
79
|
-
return globalThis.routes;
|
|
80
|
-
}
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Generate a URL for a named route with parameters.
|
|
85
|
-
*
|
|
86
|
-
* @param routeName - The name of the route
|
|
87
|
-
* @param args - Route parameters (object or array)
|
|
88
|
-
* @returns The generated URL or "#" if route not found
|
|
89
|
-
*
|
|
90
|
-
* @example
|
|
91
|
-
* ```ts
|
|
92
|
-
* import { route } from 'litestar-vite-plugin/helpers'
|
|
93
|
-
*
|
|
94
|
-
* // Named parameters
|
|
95
|
-
* route('user:detail', { user_id: 123 }) // "/users/123"
|
|
96
|
-
*
|
|
97
|
-
* // Positional parameters
|
|
98
|
-
* route('user:detail', [123]) // "/users/123"
|
|
99
|
-
* ```
|
|
100
|
-
*/
|
|
101
|
-
export function route(routeName, ...args) {
|
|
102
|
-
const routes = getRoutes();
|
|
103
|
-
if (!routes) {
|
|
104
|
-
console.error("Routes not available. Ensure route metadata is injected.");
|
|
105
|
-
return "#";
|
|
106
|
-
}
|
|
107
|
-
let url = routes[routeName];
|
|
108
|
-
if (!url) {
|
|
109
|
-
console.error(`Route '${routeName}' not found.`);
|
|
110
|
-
return "#";
|
|
111
|
-
}
|
|
112
|
-
const argTokens = url.match(/\{([^}]+)\}/g);
|
|
113
|
-
if (!argTokens && args.length > 0 && args[0] !== undefined) {
|
|
114
|
-
console.error(`Route '${routeName}' does not accept parameters.`);
|
|
115
|
-
return "#";
|
|
116
|
-
}
|
|
117
|
-
if (!argTokens) {
|
|
118
|
-
return new URL(url, window.location.origin).href;
|
|
119
|
-
}
|
|
120
|
-
try {
|
|
121
|
-
if (typeof args[0] === "object" && !Array.isArray(args[0])) {
|
|
122
|
-
// Named parameters
|
|
123
|
-
for (const token of argTokens) {
|
|
124
|
-
let argName = token.slice(1, -1);
|
|
125
|
-
// Handle {param:type} syntax
|
|
126
|
-
if (argName.includes(":")) {
|
|
127
|
-
argName = argName.split(":")[0];
|
|
128
|
-
}
|
|
129
|
-
const argValue = args[0][argName];
|
|
130
|
-
if (argValue === undefined) {
|
|
131
|
-
throw new Error(`Missing parameter '${argName}'.`);
|
|
132
|
-
}
|
|
133
|
-
url = url.replace(token, String(argValue));
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
// Positional parameters
|
|
138
|
-
const argsArray = Array.isArray(args[0]) ? args[0] : Array.from(args);
|
|
139
|
-
if (argTokens.length !== argsArray.length) {
|
|
140
|
-
throw new Error(`Expected ${argTokens.length} parameters, got ${argsArray.length}.`);
|
|
141
|
-
}
|
|
142
|
-
argTokens.forEach((token, i) => {
|
|
143
|
-
const argValue = argsArray[i];
|
|
144
|
-
if (argValue === undefined) {
|
|
145
|
-
throw new Error(`Missing parameter at position ${i}.`);
|
|
146
|
-
}
|
|
147
|
-
url = url.replace(token, String(argValue));
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
catch (error) {
|
|
152
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
153
|
-
return "#";
|
|
154
|
-
}
|
|
155
|
-
return new URL(url, window.location.origin).href;
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Get the relative path portion of a URL.
|
|
159
|
-
*
|
|
160
|
-
* @param url - Full URL or path
|
|
161
|
-
* @returns Relative path with query string and hash
|
|
162
|
-
*/
|
|
163
|
-
export function getRelativeUrlPath(url) {
|
|
164
|
-
try {
|
|
165
|
-
const urlObject = new URL(url);
|
|
166
|
-
return urlObject.pathname + urlObject.search + urlObject.hash;
|
|
167
|
-
}
|
|
168
|
-
catch {
|
|
169
|
-
return url;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Convert a URL to a route name.
|
|
174
|
-
*
|
|
175
|
-
* @param url - URL to match
|
|
176
|
-
* @returns Route name or null if no match
|
|
177
|
-
*
|
|
178
|
-
* @example
|
|
179
|
-
* ```ts
|
|
180
|
-
* toRoute('/users/123') // "user:detail"
|
|
181
|
-
* ```
|
|
182
|
-
*/
|
|
183
|
-
export function toRoute(url) {
|
|
184
|
-
const routes = getRoutes();
|
|
185
|
-
if (!routes) {
|
|
186
|
-
return null;
|
|
187
|
-
}
|
|
188
|
-
const processedUrl = getRelativeUrlPath(url);
|
|
189
|
-
const normalizedUrl = processedUrl === "/" ? processedUrl : processedUrl.replace(/\/$/, "");
|
|
190
|
-
for (const [routeName, routePattern] of Object.entries(routes)) {
|
|
191
|
-
const regex = compileRoutePattern(routePattern);
|
|
192
|
-
if (regex.test(normalizedUrl)) {
|
|
193
|
-
return routeName;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return null;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Get the current route name based on window.location.
|
|
200
|
-
*
|
|
201
|
-
* @returns Current route name or null if no match
|
|
202
|
-
*/
|
|
203
|
-
export function currentRoute() {
|
|
204
|
-
if (typeof window === "undefined") {
|
|
205
|
-
return null;
|
|
206
|
-
}
|
|
207
|
-
return toRoute(window.location.pathname);
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Check if a URL matches a route pattern.
|
|
211
|
-
*
|
|
212
|
-
* Supports wildcard patterns like "user:*" to match "user:list", "user:detail", etc.
|
|
213
|
-
*
|
|
214
|
-
* @param url - URL to check
|
|
215
|
-
* @param routeName - Route name or pattern (supports * wildcards)
|
|
216
|
-
* @returns True if the URL matches the route
|
|
217
|
-
*
|
|
218
|
-
* @example
|
|
219
|
-
* ```ts
|
|
220
|
-
* isRoute('/users/123', 'user:detail') // true
|
|
221
|
-
* isRoute('/users/123', 'user:*') // true
|
|
222
|
-
* ```
|
|
223
|
-
*/
|
|
224
|
-
export function isRoute(url, routeName) {
|
|
225
|
-
const routes = getRoutes();
|
|
226
|
-
if (!routes) {
|
|
227
|
-
return false;
|
|
228
|
-
}
|
|
229
|
-
const processedUrl = getRelativeUrlPath(url);
|
|
230
|
-
const normalizedUrl = processedUrl === "/" ? processedUrl : processedUrl.replace(/\/$/, "");
|
|
231
|
-
// Convert route name pattern to regex
|
|
232
|
-
const routeNameRegex = new RegExp(`^${routeName.replace(/\*/g, ".*")}$`);
|
|
233
|
-
// Find all matching route names based on the pattern
|
|
234
|
-
const matchingRouteNames = Object.keys(routes).filter((name) => routeNameRegex.test(name));
|
|
235
|
-
for (const name of matchingRouteNames) {
|
|
236
|
-
const routePattern = routes[name];
|
|
237
|
-
const regex = compileRoutePattern(routePattern);
|
|
238
|
-
if (regex.test(normalizedUrl)) {
|
|
239
|
-
return true;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return false;
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Check if the current URL matches a route pattern.
|
|
246
|
-
*
|
|
247
|
-
* @param routeName - Route name or pattern (supports * wildcards)
|
|
248
|
-
* @returns True if the current URL matches the route
|
|
249
|
-
*
|
|
250
|
-
* @example
|
|
251
|
-
* ```ts
|
|
252
|
-
* // On /users/123
|
|
253
|
-
* isCurrentRoute('user:detail') // true
|
|
254
|
-
* isCurrentRoute('user:*') // true
|
|
255
|
-
* ```
|
|
256
|
-
*/
|
|
257
|
-
export function isCurrentRoute(routeName) {
|
|
258
|
-
const current = currentRoute();
|
|
259
|
-
if (!current) {
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
262
|
-
const routeNameRegex = new RegExp(`^${routeName.replace(/\*/g, ".*")}$`);
|
|
263
|
-
return routeNameRegex.test(current);
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Litestar helpers namespace object.
|
|
267
|
-
* Access via window.__LITESTAR__ or import functions directly from this module.
|
|
268
|
-
*/
|
|
269
|
-
export const LITESTAR = {
|
|
270
|
-
route,
|
|
271
|
-
toRoute,
|
|
272
|
-
currentRoute,
|
|
273
|
-
isRoute,
|
|
274
|
-
isCurrentRoute,
|
|
275
|
-
getRelativeUrlPath,
|
|
276
|
-
routes: {},
|
|
277
|
-
};
|
|
278
|
-
// Set up namespaced global access
|
|
279
|
-
if (typeof globalThis !== "undefined") {
|
|
280
|
-
globalThis.__LITESTAR__ = LITESTAR;
|
|
281
|
-
// Also set up routes for internal use
|
|
282
|
-
globalThis.routes = globalThis.routes || LITESTAR.routes;
|
|
283
|
-
globalThis.serverRoutes = globalThis.serverRoutes || globalThis.routes;
|
|
284
|
-
}
|
|
285
|
-
// Keep routes fresh during Vite HMR when the plugin regenerates metadata/types
|
|
286
|
-
if (import.meta.hot) {
|
|
287
|
-
import.meta.hot.on("litestar:types-updated", () => {
|
|
288
|
-
if (typeof window === "undefined") {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
const updated = getRoutes();
|
|
292
|
-
if (updated) {
|
|
293
|
-
// Update all references
|
|
294
|
-
LITESTAR.routes = updated;
|
|
295
|
-
window.serverRoutes = updated;
|
|
296
|
-
window.routes = updated;
|
|
297
|
-
if (window.__LITESTAR__) {
|
|
298
|
-
window.__LITESTAR__.routes = updated;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
}
|