@stratal/inertia 0.0.19 → 0.0.21

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/react.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference path="../global.d.ts" />
2
2
  import { MessageKeys, MessageParams } from "stratal/i18n";
3
- import { RouteName, RouteParams } from "stratal/router";
3
+ import { CurrentRoute, RouteMatcher, RouteName, RouteParams } from "stratal/router";
4
4
 
5
5
  //#region src/react/use-i18n.d.ts
6
6
  /**
@@ -42,33 +42,35 @@ declare function useI18n(): {
42
42
  /**
43
43
  * Hook that provides Ziggy-like route URL generation in React components.
44
44
  *
45
- * Consumes `routes` from Inertia shared props and returns a `route()` function
46
- * that builds URLs client-side using the serialized route map.
45
+ * Consumes `routes` and the current-request snapshot (`route`) from Inertia
46
+ * shared props. Route names and params are strictly typed from
47
+ * `StratalRouteMap` (generated by `quarry route:types`).
47
48
  *
48
- * Route names and params are strictly typed from `StratalRouteMap` (generated
49
- * by `quarry route:types`).
49
+ * Requires the `routes` option to be set on `InertiaModule.forRoot()`.
50
50
  *
51
- * Requires the `routes` option to be set on `InertiaModule.forRoot()` to inject
52
- * the shared props.
51
+ * Sticky params anything in `defaults` (set server-side via `Uri.defaults()`)
52
+ * and anything in the current route's extracted `params` (filtered to the
53
+ * target route's declared params) — are merged into every `route()` call.
54
+ * Explicit params always win.
53
55
  *
54
- * @returns An object with:
55
- * - `route` — URL generation function accepting a route name and optional params
56
- * - `current` Function to check the current route name or match against a name
56
+ * @returns
57
+ * - `route(name, params?)` — URL builder
58
+ * - `current()` / `current(name)` matched route name (or wildcard match)
59
+ * - `params` — extracted params for the current request URL
57
60
  *
58
61
  * @example
59
62
  * ```tsx
60
63
  * import { useRoute } from '@stratal/inertia/react'
61
64
  *
62
65
  * export default function UserProfile({ user }) {
63
- * const { route, current } = useRoute()
66
+ * const { route, current, currentRoute } = useRoute()
64
67
  *
65
68
  * return (
66
69
  * <nav>
67
70
  * <a href={route('users.index')}>All Users</a>
68
- * <a href={route('users.show', { id: user.id })}>
69
- * {user.name}
70
- * </a>
71
- * {current('users.show') && <span>Currently viewing</span>}
71
+ * <a href={route('users.show', { id: user.id })}>{user.name}</a>
72
+ * {current('users.*') && <span>On a users page</span>}
73
+ * {currentRoute.name === 'users.show' && <span>#{currentRoute.params.id}</span>}
72
74
  * </nav>
73
75
  * )
74
76
  * }
@@ -76,7 +78,12 @@ declare function useI18n(): {
76
78
  */
77
79
  declare function useRoute(): {
78
80
  route: <N extends RouteName>(name: N, params?: RouteParams<N>) => string;
79
- current: (name?: RouteName) => boolean | string | undefined;
81
+ current: {
82
+ (): RouteName | null;
83
+ (name: RouteMatcher): boolean;
84
+ };
85
+ currentRoute: CurrentRoute;
86
+ params: Record<string, string>;
80
87
  };
81
88
  //#endregion
82
89
  export { useI18n, useRoute };
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.mts","names":[],"sources":["../src/react/use-i18n.ts","../src/react/use-route.ts"],"mappings":";;;;;;;;;;;;;AC+HA;;;;;;;;;;;;;;;;;;;;;iBDtEgB,OAAA,CAAA;WAcA,WAAA,EAAW,MAAA,GAAW,aAAA;;;;;;;;;;;;;;ACwDtC;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,QAAA,CAAA;oBAKK,SAAA,EAAS,IAAA,EAAQ,CAAA,EAAC,MAAA,GAAW,WAAA,CAAY,CAAA;mBAW5C,SAAA;AAAA"}
1
+ {"version":3,"file":"react.d.mts","names":[],"sources":["../src/react/use-i18n.ts","../src/react/use-route.ts"],"mappings":";;;;;;;;;;;;;ACkOA;;;;;;;;;;;;;;;;;;;;;iBDzKgB,OAAA,CAAA;WAcA,WAAA,EAAW,MAAA,GAAW,aAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBC2JtB,QAAA,CAAA;oBAKK,SAAA,EAAS,IAAA,EAAQ,CAAA,EAAC,MAAA,GAAW,WAAA,CAAY,CAAA;;QAOvC,SAAA;IAAA,OACG,YAAA;EAAA"}
package/dist/react.mjs CHANGED
@@ -52,6 +52,40 @@ function useI18n() {
52
52
  //#endregion
53
53
  //#region src/react/use-route.ts
54
54
  /**
55
+ * Apply a trailing-slash mode to a URL or path.
56
+ *
57
+ * Pure reimplementation of `applyTrailingSlash()` from `stratal/router` —
58
+ * mirrored here to keep the React bundle decoupled from server-only deps.
59
+ *
60
+ * - `'ignore'` — return as-is.
61
+ * - `'always'` — append `/` unless path is root or last segment is file-like (`.json`, etc.).
62
+ * - `'never'` — strip a single trailing `/` from the pathname (skip root).
63
+ *
64
+ * Preserves query string and hash. Handles relative paths and absolute URLs.
65
+ */
66
+ function applyTrailingSlash(url, mode) {
67
+ if (mode === "ignore") return url;
68
+ const isAbsolute = /^https?:\/\//i.test(url);
69
+ const parsed = isAbsolute ? new URL(url) : new URL(url, "http://placeholder.local");
70
+ const path = parsed.pathname;
71
+ if (path === "/") return url;
72
+ const hasTrailing = path.endsWith("/");
73
+ if (mode === "always" && !hasTrailing) {
74
+ if (path.slice(path.lastIndexOf("/") + 1).includes(".")) return url;
75
+ parsed.pathname = `${path}/`;
76
+ } else if (mode === "never" && hasTrailing) parsed.pathname = path.slice(0, -1);
77
+ else return url;
78
+ return isAbsolute ? parsed.toString() : `${parsed.pathname}${parsed.search}${parsed.hash}`;
79
+ }
80
+ /**
81
+ * Encode a path-param value while preserving forward slashes so catch-all
82
+ * params (`:slug{.+}`) round-trip cleanly. Mirrors the server-side
83
+ * `encodePathParam()` in `stratal/router`.
84
+ */
85
+ function encodePathParam(value) {
86
+ return value.split("/").map(encodeURIComponent).join("/");
87
+ }
88
+ /**
55
89
  * Build a URL from a serialized route definition.
56
90
  *
57
91
  * Mirrors `buildRouteUrl()` from `stratal/router` (pure reimplementation to
@@ -68,7 +102,7 @@ function buildUrl(route, name, params) {
68
102
  for (const paramName of route.paramNames) {
69
103
  const value = allParams[paramName];
70
104
  if (value === void 0) throw new Error(`Missing required parameter "${paramName}" for route "${name}" (path: ${route.path})`);
71
- url = url.replace(new RegExp(`:${paramName}(\\{[^}]*\\})?`), encodeURIComponent(value));
105
+ url = url.replace(new RegExp(`:${paramName}(\\{[^}]*\\})?`), encodePathParam(value));
72
106
  consumedKeys.add(paramName);
73
107
  }
74
108
  let domain;
@@ -90,66 +124,96 @@ function buildUrl(route, name, params) {
90
124
  return url;
91
125
  }
92
126
  /**
93
- * Check if a route path pattern matches a given pathname.
94
- * Converts `:param{constraint}` and `:param` segments to regex wildcards.
127
+ * Filter a param bag down to the keys the target route actually declares —
128
+ * so a `companyId` carried over from the current URL never leaks into the
129
+ * query string of an unrelated route.
95
130
  */
96
- function matchPath(routePath, pathname) {
97
- const regexStr = routePath.replace(/:[\w]+\{[^}]*\}/g, "[^/]+").replace(/:[\w]+/g, "[^/]+");
98
- return new RegExp(`^${regexStr}$`).test(pathname);
131
+ function filterCarryover(carryover, route) {
132
+ const allowed = new Set([...route.paramNames, ...route.domainParamNames]);
133
+ if (route.localePaths?.length) allowed.add("locale");
134
+ if (allowed.size === 0) return {};
135
+ const filtered = {};
136
+ for (const [key, value] of Object.entries(carryover)) if (allowed.has(key)) filtered[key] = value;
137
+ return filtered;
138
+ }
139
+ /**
140
+ * Pure URL resolver. Mirrors what {@link useRoute}'s `route()` does, but
141
+ * without React — exposed for testing and for non-hook callers.
142
+ *
143
+ * Merges params in order (last wins): sticky `defaults`, current-route
144
+ * carryover (filtered to the target's declared params), explicit params.
145
+ */
146
+ function resolveUrl(name, explicitParams, routes, currentRoute, trailingSlash = "ignore") {
147
+ const target = routes[name];
148
+ if (!target) throw new Error(`Route "${name}" not found.`);
149
+ return applyTrailingSlash(buildUrl(target, name, {
150
+ ...currentRoute.defaults,
151
+ ...filterCarryover(currentRoute.params, target),
152
+ ...explicitParams
153
+ }), trailingSlash);
154
+ }
155
+ function matchCurrent(currentRoute, name) {
156
+ if (name === void 0) return currentRoute.name;
157
+ if (currentRoute.name === null) return false;
158
+ if (typeof name === "string" && name.endsWith(".*")) {
159
+ const prefix = name.slice(0, -1);
160
+ return currentRoute.name.startsWith(prefix);
161
+ }
162
+ return currentRoute.name === name;
99
163
  }
100
164
  /**
101
165
  * Hook that provides Ziggy-like route URL generation in React components.
102
166
  *
103
- * Consumes `routes` from Inertia shared props and returns a `route()` function
104
- * that builds URLs client-side using the serialized route map.
167
+ * Consumes `routes` and the current-request snapshot (`route`) from Inertia
168
+ * shared props. Route names and params are strictly typed from
169
+ * `StratalRouteMap` (generated by `quarry route:types`).
105
170
  *
106
- * Route names and params are strictly typed from `StratalRouteMap` (generated
107
- * by `quarry route:types`).
171
+ * Requires the `routes` option to be set on `InertiaModule.forRoot()`.
108
172
  *
109
- * Requires the `routes` option to be set on `InertiaModule.forRoot()` to inject
110
- * the shared props.
173
+ * Sticky params anything in `defaults` (set server-side via `Uri.defaults()`)
174
+ * and anything in the current route's extracted `params` (filtered to the
175
+ * target route's declared params) — are merged into every `route()` call.
176
+ * Explicit params always win.
111
177
  *
112
- * @returns An object with:
113
- * - `route` — URL generation function accepting a route name and optional params
114
- * - `current` Function to check the current route name or match against a name
178
+ * @returns
179
+ * - `route(name, params?)` — URL builder
180
+ * - `current()` / `current(name)` matched route name (or wildcard match)
181
+ * - `params` — extracted params for the current request URL
115
182
  *
116
183
  * @example
117
184
  * ```tsx
118
185
  * import { useRoute } from '@stratal/inertia/react'
119
186
  *
120
187
  * export default function UserProfile({ user }) {
121
- * const { route, current } = useRoute()
188
+ * const { route, current, currentRoute } = useRoute()
122
189
  *
123
190
  * return (
124
191
  * <nav>
125
192
  * <a href={route('users.index')}>All Users</a>
126
- * <a href={route('users.show', { id: user.id })}>
127
- * {user.name}
128
- * </a>
129
- * {current('users.show') && <span>Currently viewing</span>}
193
+ * <a href={route('users.show', { id: user.id })}>{user.name}</a>
194
+ * {current('users.*') && <span>On a users page</span>}
195
+ * {currentRoute.name === 'users.show' && <span>#{currentRoute.params.id}</span>}
130
196
  * </nav>
131
197
  * )
132
198
  * }
133
199
  * ```
134
200
  */
135
201
  function useRoute() {
136
- const page = usePage();
137
- const { routes } = page.props;
202
+ const { routes, trailingSlash = "ignore", route: currentRoute } = usePage().props;
138
203
  return {
139
- route: useMemo(() => (name, params) => {
140
- const serializedRoute = routes[name];
141
- if (!serializedRoute) throw new Error(`Route "${name}" not found.`);
142
- return buildUrl(serializedRoute, name, params);
143
- }, [routes]),
144
- current: useMemo(() => (name) => {
145
- const pathname = page.url.split("?")[0];
146
- if (name !== void 0) {
147
- const serializedRoute = routes[name];
148
- if (!serializedRoute) return false;
149
- return matchPath(serializedRoute.path, pathname);
204
+ route: useMemo(() => (name, params) => resolveUrl(name, params, routes, currentRoute, trailingSlash), [
205
+ routes,
206
+ trailingSlash,
207
+ currentRoute
208
+ ]),
209
+ current: useMemo(() => {
210
+ function impl(name) {
211
+ return name === void 0 ? matchCurrent(currentRoute) : matchCurrent(currentRoute, name);
150
212
  }
151
- for (const [routeName, routeDef] of Object.entries(routes)) if (matchPath(routeDef.path, pathname)) return routeName;
152
- }, [routes, page.url])
213
+ return impl;
214
+ }, [currentRoute]),
215
+ currentRoute,
216
+ params: currentRoute.params
153
217
  };
154
218
  }
155
219
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"react.mjs","names":[],"sources":["../src/react/use-i18n.ts","../src/react/use-route.ts"],"sourcesContent":["/**\n * React hook for using Stratal's i18n translations on the frontend.\n *\n * Reads `locale` and `translations` from Inertia shared props (injected by\n * the `i18n` option on {@link InertiaModuleOptions}) and provides a type-safe\n * `t()` function powered by `@intlify/core-base`.\n *\n * @module\n */\n\nimport type { PageProps } from '@inertiajs/core'\nimport { usePage } from '@inertiajs/react'\nimport { compile, createCoreContext, registerMessageCompiler, translate } from '@intlify/core-base'\nimport { useMemo } from 'react'\nimport type { MessageKeys, MessageParams } from 'stratal/i18n'\n\n// Register JIT message compiler from the SAME @intlify/core-base instance that provides\n// createCoreContext/translate. Importing setupI18nCompiler from stratal/i18n/utils can\n// resolve a different @intlify/core-base copy (duplicate modules in node_modules),\n// causing the compiler registration to be invisible to this module's createCoreContext.\nregisterMessageCompiler(compile)\n\ninterface I18nPageProps extends PageProps {\n locale: string\n translations: Record<string, string>\n}\n\n/**\n * Hook that provides i18n translation capabilities in React components.\n *\n * Consumes `locale` and `translations` from Inertia shared props and returns\n * a `t()` function that translates message keys with optional interpolation.\n *\n * Requires the `i18n` option to be set on `InertiaModule.forRoot()` to inject\n * the shared props.\n *\n * @returns An object with:\n * - `t` — Translation function accepting a message key and optional params\n * - `locale` — The current locale string\n *\n * @example\n * ```tsx\n * import { useI18n } from '@stratal/inertia/react'\n *\n * export default function Header() {\n * const { t, locale } = useI18n()\n *\n * return (\n * <header>\n * <h1>{t('common.title')}</h1>\n * <p>{t('common.greeting', { name: 'World' })}</p>\n * <span>Locale: {locale}</span>\n * </header>\n * )\n * }\n * ```\n */\nexport function useI18n() {\n const { locale, translations } = usePage<I18nPageProps>().props\n\n const context = useMemo(\n () => createCoreContext({\n locale,\n messages: { [locale]: translations },\n missingWarn: !import.meta.env.PROD,\n fallbackWarn: !import.meta.env.PROD,\n }),\n [locale, translations],\n )\n\n const t = useMemo(\n () => (key: MessageKeys, params?: MessageParams): string => {\n const result = params !== undefined\n ? translate(context, key, params)\n : translate(context, key)\n return typeof result === 'string' ? result : key\n },\n [context],\n )\n\n return { t, locale }\n}\n","/**\n * React hook for Ziggy-like client-side URL generation.\n *\n * Reads serialized routes from Inertia shared props (injected by the `routes`\n * option on {@link InertiaModuleOptions}) and provides a type-safe `route()`\n * function that mirrors the server-side `buildRouteUrl()`.\n *\n * @module\n */\n\nimport type { PageProps } from '@inertiajs/core'\nimport { usePage } from '@inertiajs/react'\nimport { useMemo } from 'react'\nimport type { RouteName, RouteParams, SerializedRoute, SerializedRoutes } from 'stratal/router'\n\ninterface RoutesPageProps extends PageProps {\n routes: SerializedRoutes\n}\n\n/**\n * Build a URL from a serialized route definition.\n *\n * Mirrors `buildRouteUrl()` from `stratal/router` (pure reimplementation to\n * avoid pulling server-side dependencies into the browser bundle).\n */\nfunction buildUrl(route: SerializedRoute, name: string, params?: Record<string, string>): string {\n const allParams = { ...params }\n const consumedKeys = new Set<string>()\n let url = route.path\n\n // When locale is provided and route has locale variants, prepend locale segment\n if (allParams.locale && route.localePaths?.length) {\n url = `/${allParams.locale}${url === '/' ? '' : url}`\n consumedKeys.add('locale')\n }\n\n // Fill path :param placeholders (handles optional regex constraints like :locale{en|de|fr})\n for (const paramName of route.paramNames) {\n const value = allParams[paramName]\n if (value === undefined) {\n throw new Error(`Missing required parameter \"${paramName}\" for route \"${name}\" (path: ${route.path})`)\n }\n url = url.replace(\n new RegExp(`:${paramName}(\\\\{[^}]*\\\\})?`),\n encodeURIComponent(value),\n )\n consumedKeys.add(paramName)\n }\n\n // Build domain if present\n let domain: string | undefined\n if (route.domain) {\n domain = route.domain\n for (const domainParam of route.domainParamNames) {\n const value = allParams[domainParam]\n if (value === undefined) {\n throw new Error(`Missing required parameter \"${domainParam}\" for route \"${name}\" (domain: ${route.domain})`)\n }\n domain = domain.replace(`{${domainParam}}`, encodeURIComponent(value))\n consumedKeys.add(domainParam)\n }\n }\n\n // Remaining params become query string\n const queryEntries = Object.entries(allParams).filter(([key]) => !consumedKeys.has(key))\n if (queryEntries.length > 0) {\n const queryString = queryEntries\n .filter(([, v]) => Boolean(v))\n .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)\n .join('&')\n url = `${url}${queryString.length ? `?${queryString}` : ''}`\n }\n\n // Prepend domain if present\n if (domain) {\n url = `https://${domain}${url}`\n }\n\n return url\n}\n\n/**\n * Check if a route path pattern matches a given pathname.\n * Converts `:param{constraint}` and `:param` segments to regex wildcards.\n */\nfunction matchPath(routePath: string, pathname: string): boolean {\n const regexStr = routePath\n .replace(/:[\\w]+\\{[^}]*\\}/g, '[^/]+')\n .replace(/:[\\w]+/g, '[^/]+')\n return new RegExp(`^${regexStr}$`).test(pathname)\n}\n\n/**\n * Hook that provides Ziggy-like route URL generation in React components.\n *\n * Consumes `routes` from Inertia shared props and returns a `route()` function\n * that builds URLs client-side using the serialized route map.\n *\n * Route names and params are strictly typed from `StratalRouteMap` (generated\n * by `quarry route:types`).\n *\n * Requires the `routes` option to be set on `InertiaModule.forRoot()` to inject\n * the shared props.\n *\n * @returns An object with:\n * - `route` — URL generation function accepting a route name and optional params\n * - `current` — Function to check the current route name or match against a name\n *\n * @example\n * ```tsx\n * import { useRoute } from '@stratal/inertia/react'\n *\n * export default function UserProfile({ user }) {\n * const { route, current } = useRoute()\n *\n * return (\n * <nav>\n * <a href={route('users.index')}>All Users</a>\n * <a href={route('users.show', { id: user.id })}>\n * {user.name}\n * </a>\n * {current('users.show') && <span>Currently viewing</span>}\n * </nav>\n * )\n * }\n * ```\n */\nexport function useRoute() {\n const page = usePage<RoutesPageProps>()\n const { routes } = page.props\n\n const route = useMemo(\n () => <N extends RouteName>(name: N, params?: RouteParams<N>): string => {\n const serializedRoute = routes[name]\n if (!serializedRoute) {\n throw new Error(`Route \"${name}\" not found.`)\n }\n return buildUrl(serializedRoute, name, params)\n },\n [routes],\n )\n\n const current = useMemo(\n () => (name?: RouteName): boolean | string | undefined => {\n const pathname = page.url.split('?')[0]\n\n if (name !== undefined) {\n const serializedRoute = routes[name]\n if (!serializedRoute) return false\n return matchPath(serializedRoute.path, pathname)\n }\n\n for (const [routeName, routeDef] of Object.entries(routes)) {\n if (matchPath(routeDef.path, pathname)) {\n return routeName\n }\n }\n return undefined\n },\n [routes, page.url],\n )\n\n return { route, current }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"react.mjs","names":[],"sources":["../src/react/use-i18n.ts","../src/react/use-route.ts"],"sourcesContent":["/**\n * React hook for using Stratal's i18n translations on the frontend.\n *\n * Reads `locale` and `translations` from Inertia shared props (injected by\n * the `i18n` option on {@link InertiaModuleOptions}) and provides a type-safe\n * `t()` function powered by `@intlify/core-base`.\n *\n * @module\n */\n\nimport type { PageProps } from '@inertiajs/core'\nimport { usePage } from '@inertiajs/react'\nimport { compile, createCoreContext, registerMessageCompiler, translate } from '@intlify/core-base'\nimport { useMemo } from 'react'\nimport type { MessageKeys, MessageParams } from 'stratal/i18n'\n\n// Register JIT message compiler from the SAME @intlify/core-base instance that provides\n// createCoreContext/translate. Importing setupI18nCompiler from stratal/i18n/utils can\n// resolve a different @intlify/core-base copy (duplicate modules in node_modules),\n// causing the compiler registration to be invisible to this module's createCoreContext.\nregisterMessageCompiler(compile)\n\ninterface I18nPageProps extends PageProps {\n locale: string\n translations: Record<string, string>\n}\n\n/**\n * Hook that provides i18n translation capabilities in React components.\n *\n * Consumes `locale` and `translations` from Inertia shared props and returns\n * a `t()` function that translates message keys with optional interpolation.\n *\n * Requires the `i18n` option to be set on `InertiaModule.forRoot()` to inject\n * the shared props.\n *\n * @returns An object with:\n * - `t` — Translation function accepting a message key and optional params\n * - `locale` — The current locale string\n *\n * @example\n * ```tsx\n * import { useI18n } from '@stratal/inertia/react'\n *\n * export default function Header() {\n * const { t, locale } = useI18n()\n *\n * return (\n * <header>\n * <h1>{t('common.title')}</h1>\n * <p>{t('common.greeting', { name: 'World' })}</p>\n * <span>Locale: {locale}</span>\n * </header>\n * )\n * }\n * ```\n */\nexport function useI18n() {\n const { locale, translations } = usePage<I18nPageProps>().props\n\n const context = useMemo(\n () => createCoreContext({\n locale,\n messages: { [locale]: translations },\n missingWarn: !import.meta.env.PROD,\n fallbackWarn: !import.meta.env.PROD,\n }),\n [locale, translations],\n )\n\n const t = useMemo(\n () => (key: MessageKeys, params?: MessageParams): string => {\n const result = params !== undefined\n ? translate(context, key, params)\n : translate(context, key)\n return typeof result === 'string' ? result : key\n },\n [context],\n )\n\n return { t, locale }\n}\n","/**\n * React hook for Ziggy-like client-side URL generation.\n *\n * Reads serialized routes and the current request's matched-route snapshot\n * (injected by the `routes` option on {@link InertiaModuleOptions}) and\n * provides a type-safe `route()` function that mirrors the server-side\n * `buildRouteUrl()`, plus `current()` and `params` for current-route\n * introspection.\n *\n * @module\n */\n\nimport type { PageProps } from '@inertiajs/core'\nimport { usePage } from '@inertiajs/react'\nimport { useMemo } from 'react'\nimport type { CurrentRoute, RouteMatcher, RouteName, RouteParams, SerializedRoute, SerializedRoutes, TrailingSlashMode } from 'stratal/router'\n\ninterface RoutesPageProps extends PageProps {\n routes: SerializedRoutes\n trailingSlash?: TrailingSlashMode\n route: CurrentRoute\n}\n\n/**\n * Apply a trailing-slash mode to a URL or path.\n *\n * Pure reimplementation of `applyTrailingSlash()` from `stratal/router` —\n * mirrored here to keep the React bundle decoupled from server-only deps.\n *\n * - `'ignore'` — return as-is.\n * - `'always'` — append `/` unless path is root or last segment is file-like (`.json`, etc.).\n * - `'never'` — strip a single trailing `/` from the pathname (skip root).\n *\n * Preserves query string and hash. Handles relative paths and absolute URLs.\n */\nexport function applyTrailingSlash(url: string, mode: TrailingSlashMode): string {\n if (mode === 'ignore') return url\n\n const isAbsolute = /^https?:\\/\\//i.test(url)\n const parsed = isAbsolute ? new URL(url) : new URL(url, 'http://placeholder.local')\n const path = parsed.pathname\n if (path === '/') return url\n const hasTrailing = path.endsWith('/')\n\n if (mode === 'always' && !hasTrailing) {\n const lastSegment = path.slice(path.lastIndexOf('/') + 1)\n if (lastSegment.includes('.')) return url\n parsed.pathname = `${path}/`\n } else if (mode === 'never' && hasTrailing) {\n parsed.pathname = path.slice(0, -1)\n } else {\n return url\n }\n\n return isAbsolute\n ? parsed.toString()\n : `${parsed.pathname}${parsed.search}${parsed.hash}`\n}\n\n/**\n * Encode a path-param value while preserving forward slashes so catch-all\n * params (`:slug{.+}`) round-trip cleanly. Mirrors the server-side\n * `encodePathParam()` in `stratal/router`.\n */\nfunction encodePathParam(value: string): string {\n return value.split('/').map(encodeURIComponent).join('/')\n}\n\n/**\n * Build a URL from a serialized route definition.\n *\n * Mirrors `buildRouteUrl()` from `stratal/router` (pure reimplementation to\n * avoid pulling server-side dependencies into the browser bundle).\n */\nfunction buildUrl(route: SerializedRoute, name: string, params?: Record<string, string>): string {\n const allParams = { ...params }\n const consumedKeys = new Set<string>()\n let url = route.path\n\n if (allParams.locale && route.localePaths?.length) {\n url = `/${allParams.locale}${url === '/' ? '' : url}`\n consumedKeys.add('locale')\n }\n\n for (const paramName of route.paramNames) {\n const value = allParams[paramName]\n if (value === undefined) {\n throw new Error(`Missing required parameter \"${paramName}\" for route \"${name}\" (path: ${route.path})`)\n }\n url = url.replace(\n new RegExp(`:${paramName}(\\\\{[^}]*\\\\})?`),\n encodePathParam(value),\n )\n consumedKeys.add(paramName)\n }\n\n let domain: string | undefined\n if (route.domain) {\n domain = route.domain\n for (const domainParam of route.domainParamNames) {\n const value = allParams[domainParam]\n if (value === undefined) {\n throw new Error(`Missing required parameter \"${domainParam}\" for route \"${name}\" (domain: ${route.domain})`)\n }\n domain = domain.replace(`{${domainParam}}`, encodeURIComponent(value))\n consumedKeys.add(domainParam)\n }\n }\n\n const queryEntries = Object.entries(allParams).filter(([key]) => !consumedKeys.has(key))\n if (queryEntries.length > 0) {\n const queryString = queryEntries\n .filter(([, v]) => Boolean(v))\n .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)\n .join('&')\n url = `${url}${queryString.length ? `?${queryString}` : ''}`\n }\n\n if (domain) {\n url = `https://${domain}${url}`\n }\n\n return url\n}\n\n/**\n * Filter a param bag down to the keys the target route actually declares —\n * so a `companyId` carried over from the current URL never leaks into the\n * query string of an unrelated route.\n */\nfunction filterCarryover(carryover: Record<string, string>, route: SerializedRoute): Record<string, string> {\n const allowed = new Set<string>([...route.paramNames, ...route.domainParamNames])\n if (route.localePaths?.length) allowed.add('locale')\n if (allowed.size === 0) return {}\n\n const filtered: Record<string, string> = {}\n for (const [key, value] of Object.entries(carryover)) {\n if (allowed.has(key)) filtered[key] = value\n }\n return filtered\n}\n\n/**\n * Pure URL resolver. Mirrors what {@link useRoute}'s `route()` does, but\n * without React — exposed for testing and for non-hook callers.\n *\n * Merges params in order (last wins): sticky `defaults`, current-route\n * carryover (filtered to the target's declared params), explicit params.\n */\nexport function resolveUrl<N extends RouteName>(\n name: N,\n explicitParams: RouteParams<N> | undefined,\n routes: SerializedRoutes,\n currentRoute: CurrentRoute,\n trailingSlash: TrailingSlashMode = 'ignore',\n): string {\n const target = routes[name]\n if (!target) {\n throw new Error(`Route \"${name}\" not found.`)\n }\n\n const merged = {\n ...currentRoute.defaults,\n ...filterCarryover(currentRoute.params, target),\n ...explicitParams,\n } as Record<string, string>\n\n return applyTrailingSlash(buildUrl(target, name, merged), trailingSlash)\n}\n\n/**\n * Pure overload signatures for {@link matchCurrent} / `useRoute().current()`.\n *\n * - No arg → matched route name (or `null`).\n * - With a name → `true`/`false`. Strict-typed: only real route names and\n * dotted wildcard prefixes (`'users.*'`) are accepted.\n */\nexport function matchCurrent(currentRoute: CurrentRoute): RouteName | null\nexport function matchCurrent(currentRoute: CurrentRoute, name: RouteMatcher): boolean\nexport function matchCurrent(currentRoute: CurrentRoute, name?: RouteMatcher): RouteName | null | boolean {\n if (name === undefined) return currentRoute.name\n if (currentRoute.name === null) return false\n if (typeof name === 'string' && name.endsWith('.*')) {\n const prefix = name.slice(0, -1)\n return currentRoute.name.startsWith(prefix)\n }\n return currentRoute.name === name\n}\n\n/**\n * Hook that provides Ziggy-like route URL generation in React components.\n *\n * Consumes `routes` and the current-request snapshot (`route`) from Inertia\n * shared props. Route names and params are strictly typed from\n * `StratalRouteMap` (generated by `quarry route:types`).\n *\n * Requires the `routes` option to be set on `InertiaModule.forRoot()`.\n *\n * Sticky params — anything in `defaults` (set server-side via `Uri.defaults()`)\n * and anything in the current route's extracted `params` (filtered to the\n * target route's declared params) — are merged into every `route()` call.\n * Explicit params always win.\n *\n * @returns\n * - `route(name, params?)` — URL builder\n * - `current()` / `current(name)` — matched route name (or wildcard match)\n * - `params` — extracted params for the current request URL\n *\n * @example\n * ```tsx\n * import { useRoute } from '@stratal/inertia/react'\n *\n * export default function UserProfile({ user }) {\n * const { route, current, currentRoute } = useRoute()\n *\n * return (\n * <nav>\n * <a href={route('users.index')}>All Users</a>\n * <a href={route('users.show', { id: user.id })}>{user.name}</a>\n * {current('users.*') && <span>On a users page</span>}\n * {currentRoute.name === 'users.show' && <span>#{currentRoute.params.id}</span>}\n * </nav>\n * )\n * }\n * ```\n */\nexport function useRoute() {\n const page = usePage<RoutesPageProps>()\n const { routes, trailingSlash = 'ignore', route: currentRoute } = page.props\n\n const route = useMemo(\n () => <N extends RouteName>(name: N, params?: RouteParams<N>): string =>\n resolveUrl(name, params, routes, currentRoute, trailingSlash),\n [routes, trailingSlash, currentRoute],\n )\n\n const current = useMemo(\n () => {\n function impl(): RouteName | null\n function impl(name: RouteMatcher): boolean\n function impl(name?: RouteMatcher): RouteName | null | boolean {\n return name === undefined ? matchCurrent(currentRoute) : matchCurrent(currentRoute, name)\n }\n return impl\n },\n [currentRoute],\n )\n\n return { route, current, currentRoute, params: currentRoute.params }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"testing.mjs","names":[],"sources":["../src/augment/test-response.ts","../src/testing.ts"],"sourcesContent":["import type { Page } from '@inertiajs/core'\nimport { getValueAtPath, hasValueAtPath, TestResponse } from '@stratal/testing'\nimport { expect } from 'vitest'\n\ndeclare module '@stratal/testing' {\n interface TestResponse {\n /** Assert the response is an Inertia response. Optionally run a callback with the page object for custom assertions. */\n assertInertia(callback?: (page: Page) => void): Promise<this>\n /** Assert the Inertia page component matches the expected name. */\n assertInertiaComponent(component: string): Promise<this>\n /** Assert the Inertia page prop at the given dot-path equals the expected value. */\n assertInertiaProp(path: string, expected: unknown): Promise<this>\n /** Assert the Inertia page prop at the given dot-path exists. */\n assertInertiaPropExists(path: string): Promise<this>\n /** Assert the Inertia page prop at the given dot-path does not exist. */\n assertInertiaPropMissing(path: string): Promise<this>\n /** Assert the Inertia page URL matches the expected value. */\n assertInertiaUrl(url: string): Promise<this>\n /** Assert the Inertia page version matches the expected value. */\n assertInertiaVersion(version: string | null): Promise<this>\n /** Assert the Inertia page flash data contains the given key with the expected value. */\n assertInertiaFlash(key: string, value: unknown): Promise<this>\n /** Assert a prop is listed as deferred in the given group. */\n assertInertiaDeferredProp(prop: string, group: string): Promise<this>\n /** Assert a prop is listed as a merge prop. */\n assertInertiaMergeProp(prop: string): Promise<this>\n /** Assert a prop is listed as a shared prop. */\n assertInertiaSharedProp(prop: string): Promise<this>\n /** Assert the response is a successful precognition response (204 with precognition headers). */\n assertSuccessfulPrecognition(): this\n /** Assert the response is a precognition validation error (422 with precognition headers). Optionally assert specific errors. */\n assertPrecognitionValidationErrors(errors?: Record<string, string>): Promise<this>\n }\n}\n\nexport function augmentTestResponse(): void {\n TestResponse.macro('assertInertia', async function (this: TestResponse, callback?: (page: Page) => void) {\n this.assertHeader('x-inertia', 'true')\n this.assertOk()\n\n if (callback) {\n const page = await this.json<Page>()\n callback(page)\n }\n\n return this\n })\n\n TestResponse.macro('assertInertiaComponent', async function (this: TestResponse, component: string) {\n const page = await this.json<Page>()\n\n expect(\n page.component,\n `Expected Inertia component \"${component}\", got \"${page.component}\"`,\n ).toBe(component)\n\n return this\n })\n\n TestResponse.macro('assertInertiaProp', async function (this: TestResponse, path: string, expected: unknown) {\n const page = await this.json<Page>()\n const actual = getValueAtPath(page.props, path)\n\n expect(\n actual,\n `Expected Inertia prop \"${path}\" to be ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`,\n ).toStrictEqual(expected)\n\n return this\n })\n\n TestResponse.macro('assertInertiaPropExists', async function (this: TestResponse, path: string) {\n const page = await this.json<Page>()\n const exists = hasValueAtPath(page.props, path)\n\n expect(\n exists,\n `Expected Inertia prop \"${path}\" to exist`,\n ).toBe(true)\n\n return this\n })\n\n TestResponse.macro('assertInertiaPropMissing', async function (this: TestResponse, path: string) {\n const page = await this.json<Page>()\n const exists = hasValueAtPath(page.props, path)\n\n expect(\n exists,\n `Expected Inertia prop \"${path}\" to not exist`,\n ).toBe(false)\n\n return this\n })\n\n TestResponse.macro('assertInertiaUrl', async function (this: TestResponse, url: string) {\n const page = await this.json<Page>()\n\n expect(\n page.url,\n `Expected Inertia URL \"${url}\", got \"${page.url}\"`,\n ).toBe(url)\n\n return this\n })\n\n TestResponse.macro('assertInertiaVersion', async function (this: TestResponse, version: string | null) {\n const page = await this.json<Page>()\n\n expect(\n page.version,\n `Expected Inertia version \"${version}\", got \"${page.version}\"`,\n ).toBe(version)\n\n return this\n })\n\n TestResponse.macro('assertInertiaFlash', async function (this: TestResponse, key: string, value: unknown) {\n const page = await this.json<Page>()\n const actual = page.flash?.[key]\n\n expect(\n actual,\n `Expected Inertia flash \"${key}\" to be ${JSON.stringify(value)}, got ${JSON.stringify(actual)}`,\n ).toStrictEqual(value)\n\n return this\n })\n\n TestResponse.macro('assertInertiaDeferredProp', async function (this: TestResponse, prop: string, group: string) {\n const page = await this.json<Page>()\n\n expect(\n page.deferredProps?.[group],\n `Expected Inertia deferred group \"${group}\" to contain \"${prop}\"`,\n ).toContain(prop)\n\n return this\n })\n\n TestResponse.macro('assertInertiaMergeProp', async function (this: TestResponse, prop: string) {\n const page = await this.json<Page>()\n\n expect(\n page.mergeProps,\n `Expected Inertia mergeProps to contain \"${prop}\"`,\n ).toContain(prop)\n\n return this\n })\n\n TestResponse.macro('assertInertiaSharedProp', async function (this: TestResponse, prop: string) {\n const page = await this.json<Page>()\n\n expect(\n page.sharedProps,\n `Expected Inertia sharedProps to contain \"${prop}\"`,\n ).toContain(prop)\n\n return this\n })\n\n TestResponse.macro('assertSuccessfulPrecognition', function (this: TestResponse) {\n this.assertNoContent()\n this.assertHeader('Precognition', 'true')\n this.assertHeader('Precognition-Success', 'true')\n\n return this\n })\n\n TestResponse.macro('assertPrecognitionValidationErrors', async function (this: TestResponse, errors?: Record<string, string>) {\n this.assertUnprocessable()\n this.assertHeader('Precognition', 'true')\n\n if (errors) {\n const body = await this.json<{ errors: Record<string, string> }>()\n\n expect(\n body.errors,\n `Expected precognition errors to match ${JSON.stringify(errors)}, got ${JSON.stringify(body.errors)}`,\n ).toStrictEqual(errors)\n }\n\n return this\n })\n}\n","import { augmentTestResponse } from './augment/test-response'\n\n// Augmentation (side-effect import: augments TestResponse types)\nimport './augment/test-response'\n\n// Patch TestResponse.prototype with Inertia assertion methods\naugmentTestResponse()\n\n// Re-export useful types for test authors\nexport type { Page as InertiaPage } from '@inertiajs/core'\n"],"mappings":"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"}
1
+ {"version":3,"file":"testing.mjs","names":[],"sources":["../src/augment/test-response.ts","../src/testing.ts"],"sourcesContent":["import type { Page } from '@inertiajs/core'\nimport { getValueAtPath, hasValueAtPath, TestResponse } from '@stratal/testing'\nimport { expect } from 'vitest'\n\ndeclare module '@stratal/testing' {\n interface TestResponse {\n /** Assert the response is an Inertia response. Optionally run a callback with the page object for custom assertions. */\n assertInertia(callback?: (page: Page) => void): Promise<this>\n /** Assert the Inertia page component matches the expected name. */\n assertInertiaComponent(component: string): Promise<this>\n /** Assert the Inertia page prop at the given dot-path equals the expected value. */\n assertInertiaProp(path: string, expected: unknown): Promise<this>\n /** Assert the Inertia page prop at the given dot-path exists. */\n assertInertiaPropExists(path: string): Promise<this>\n /** Assert the Inertia page prop at the given dot-path does not exist. */\n assertInertiaPropMissing(path: string): Promise<this>\n /** Assert the Inertia page URL matches the expected value. */\n assertInertiaUrl(url: string): Promise<this>\n /** Assert the Inertia page version matches the expected value. */\n assertInertiaVersion(version: string | null): Promise<this>\n /** Assert the Inertia page flash data contains the given key with the expected value. */\n assertInertiaFlash(key: string, value: unknown): Promise<this>\n /** Assert a prop is listed as deferred in the given group. */\n assertInertiaDeferredProp(prop: string, group: string): Promise<this>\n /** Assert a prop is listed as a merge prop. */\n assertInertiaMergeProp(prop: string): Promise<this>\n /** Assert a prop is listed as a shared prop. */\n assertInertiaSharedProp(prop: string): Promise<this>\n /** Assert the response is a successful precognition response (204 with precognition headers). */\n assertSuccessfulPrecognition(): this\n /** Assert the response is a precognition validation error (422 with precognition headers). Optionally assert specific errors. */\n assertPrecognitionValidationErrors(errors?: Record<string, string>): Promise<this>\n }\n}\n\nexport function augmentTestResponse(): void {\n TestResponse.macro('assertInertia', async function (this: TestResponse, callback?: (page: Page) => void) {\n this.assertHeader('x-inertia', 'true')\n this.assertOk()\n\n if (callback) {\n const page = await this.json<Page>()\n callback(page)\n }\n\n return this\n })\n\n TestResponse.macro('assertInertiaComponent', async function (this: TestResponse, component: string) {\n const page = await this.json<Page>()\n\n expect(\n page.component,\n `Expected Inertia component \"${component}\", got \"${page.component}\"`,\n ).toBe(component)\n\n return this\n })\n\n TestResponse.macro('assertInertiaProp', async function (this: TestResponse, path: string, expected: unknown) {\n const page = await this.json<Page>()\n const actual = getValueAtPath(page.props, path)\n\n expect(\n actual,\n `Expected Inertia prop \"${path}\" to be ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`,\n ).toStrictEqual(expected)\n\n return this\n })\n\n TestResponse.macro('assertInertiaPropExists', async function (this: TestResponse, path: string) {\n const page = await this.json<Page>()\n const exists = hasValueAtPath(page.props, path)\n\n expect(\n exists,\n `Expected Inertia prop \"${path}\" to exist`,\n ).toBe(true)\n\n return this\n })\n\n TestResponse.macro('assertInertiaPropMissing', async function (this: TestResponse, path: string) {\n const page = await this.json<Page>()\n const exists = hasValueAtPath(page.props, path)\n\n expect(\n exists,\n `Expected Inertia prop \"${path}\" to not exist`,\n ).toBe(false)\n\n return this\n })\n\n TestResponse.macro('assertInertiaUrl', async function (this: TestResponse, url: string) {\n const page = await this.json<Page>()\n\n expect(\n page.url,\n `Expected Inertia URL \"${url}\", got \"${page.url}\"`,\n ).toBe(url)\n\n return this\n })\n\n TestResponse.macro('assertInertiaVersion', async function (this: TestResponse, version: string | null) {\n const page = await this.json<Page>()\n\n expect(\n page.version,\n `Expected Inertia version \"${version}\", got \"${page.version}\"`,\n ).toBe(version)\n\n return this\n })\n\n TestResponse.macro('assertInertiaFlash', async function (this: TestResponse, key: string, value: unknown) {\n const page = await this.json<Page>()\n const actual = page.flash?.[key]\n\n expect(\n actual,\n `Expected Inertia flash \"${key}\" to be ${JSON.stringify(value)}, got ${JSON.stringify(actual)}`,\n ).toStrictEqual(value)\n\n return this\n })\n\n TestResponse.macro('assertInertiaDeferredProp', async function (this: TestResponse, prop: string, group: string) {\n const page = await this.json<Page>()\n\n expect(\n page.deferredProps?.[group],\n `Expected Inertia deferred group \"${group}\" to contain \"${prop}\"`,\n ).toContain(prop)\n\n return this\n })\n\n TestResponse.macro('assertInertiaMergeProp', async function (this: TestResponse, prop: string) {\n const page = await this.json<Page>()\n\n expect(\n page.mergeProps,\n `Expected Inertia mergeProps to contain \"${prop}\"`,\n ).toContain(prop)\n\n return this\n })\n\n TestResponse.macro('assertInertiaSharedProp', async function (this: TestResponse, prop: string) {\n const page = await this.json<Page>()\n\n expect(\n page.sharedProps,\n `Expected Inertia sharedProps to contain \"${prop}\"`,\n ).toContain(prop)\n\n return this\n })\n\n TestResponse.macro('assertSuccessfulPrecognition', function (this: TestResponse) {\n this.assertNoContent()\n this.assertHeader('Precognition', 'true')\n this.assertHeader('Precognition-Success', 'true')\n\n return this\n })\n\n TestResponse.macro('assertPrecognitionValidationErrors', async function (this: TestResponse, errors?: Record<string, string>) {\n this.assertUnprocessable()\n this.assertHeader('Precognition', 'true')\n\n if (errors) {\n const body = await this.json<{ errors: Record<string, string> }>()\n\n expect(\n body.errors,\n `Expected precognition errors to match ${JSON.stringify(errors)}, got ${JSON.stringify(body.errors)}`,\n ).toStrictEqual(errors)\n }\n\n return this\n })\n}\n","import { augmentTestResponse } from './augment/test-response'\n\n// Augmentation (side-effect import: augments TestResponse types)\nimport './augment/test-response'\n\n// Patch TestResponse.prototype with Inertia assertion methods\naugmentTestResponse()\n\n// Re-export useful types for test authors\nexport type { Page as InertiaPage } from '@inertiajs/core'\n"],"mappings":";;;AAmCA,SAAgB,sBAA4B;CAC1C,aAAa,MAAM,iBAAiB,eAAoC,UAAiC;EACvG,KAAK,aAAa,aAAa,OAAO;EACtC,KAAK,UAAU;EAEf,IAAI,UAEF,SAAS,MADU,KAAK,MAAY,CACtB;EAGhB,OAAO;GACP;CAEF,aAAa,MAAM,0BAA0B,eAAoC,WAAmB;EAClG,MAAM,OAAO,MAAM,KAAK,MAAY;EAEpC,OACE,KAAK,WACL,+BAA+B,UAAU,UAAU,KAAK,UAAU,GACnE,CAAC,KAAK,UAAU;EAEjB,OAAO;GACP;CAEF,aAAa,MAAM,qBAAqB,eAAoC,MAAc,UAAmB;EAE3G,MAAM,SAAS,gBAAe,MADX,KAAK,MAAY,EACD,OAAO,KAAK;EAE/C,OACE,QACA,0BAA0B,KAAK,UAAU,KAAK,UAAU,SAAS,CAAC,QAAQ,KAAK,UAAU,OAAO,GACjG,CAAC,cAAc,SAAS;EAEzB,OAAO;GACP;CAEF,aAAa,MAAM,2BAA2B,eAAoC,MAAc;EAI9F,OAFe,gBAAe,MADX,KAAK,MAAY,EACD,OAAO,KAGlC,EACN,0BAA0B,KAAK,YAChC,CAAC,KAAK,KAAK;EAEZ,OAAO;GACP;CAEF,aAAa,MAAM,4BAA4B,eAAoC,MAAc;EAI/F,OAFe,gBAAe,MADX,KAAK,MAAY,EACD,OAAO,KAGlC,EACN,0BAA0B,KAAK,gBAChC,CAAC,KAAK,MAAM;EAEb,OAAO;GACP;CAEF,aAAa,MAAM,oBAAoB,eAAoC,KAAa;EACtF,MAAM,OAAO,MAAM,KAAK,MAAY;EAEpC,OACE,KAAK,KACL,yBAAyB,IAAI,UAAU,KAAK,IAAI,GACjD,CAAC,KAAK,IAAI;EAEX,OAAO;GACP;CAEF,aAAa,MAAM,wBAAwB,eAAoC,SAAwB;EACrG,MAAM,OAAO,MAAM,KAAK,MAAY;EAEpC,OACE,KAAK,SACL,6BAA6B,QAAQ,UAAU,KAAK,QAAQ,GAC7D,CAAC,KAAK,QAAQ;EAEf,OAAO;GACP;CAEF,aAAa,MAAM,sBAAsB,eAAoC,KAAa,OAAgB;EAExG,MAAM,UAAS,MADI,KAAK,MAAY,EAChB,QAAQ;EAE5B,OACE,QACA,2BAA2B,IAAI,UAAU,KAAK,UAAU,MAAM,CAAC,QAAQ,KAAK,UAAU,OAAO,GAC9F,CAAC,cAAc,MAAM;EAEtB,OAAO;GACP;CAEF,aAAa,MAAM,6BAA6B,eAAoC,MAAc,OAAe;EAG/G,QACE,MAHiB,KAAK,MAAY,EAG7B,gBAAgB,QACrB,oCAAoC,MAAM,gBAAgB,KAAK,GAChE,CAAC,UAAU,KAAK;EAEjB,OAAO;GACP;CAEF,aAAa,MAAM,0BAA0B,eAAoC,MAAc;EAG7F,QACE,MAHiB,KAAK,MAAY,EAG7B,YACL,2CAA2C,KAAK,GACjD,CAAC,UAAU,KAAK;EAEjB,OAAO;GACP;CAEF,aAAa,MAAM,2BAA2B,eAAoC,MAAc;EAG9F,QACE,MAHiB,KAAK,MAAY,EAG7B,aACL,4CAA4C,KAAK,GAClD,CAAC,UAAU,KAAK;EAEjB,OAAO;GACP;CAEF,aAAa,MAAM,gCAAgC,WAA8B;EAC/E,KAAK,iBAAiB;EACtB,KAAK,aAAa,gBAAgB,OAAO;EACzC,KAAK,aAAa,wBAAwB,OAAO;EAEjD,OAAO;GACP;CAEF,aAAa,MAAM,sCAAsC,eAAoC,QAAiC;EAC5H,KAAK,qBAAqB;EAC1B,KAAK,aAAa,gBAAgB,OAAO;EAEzC,IAAI,QAAQ;GACV,MAAM,OAAO,MAAM,KAAK,MAA0C;GAElE,OACE,KAAK,QACL,yCAAyC,KAAK,UAAU,OAAO,CAAC,QAAQ,KAAK,UAAU,KAAK,OAAO,GACpG,CAAC,cAAc,OAAO;;EAGzB,OAAO;GACP;;;;AClLJ,qBAAqB"}
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  //#region src/generator/type-generator.ts
4
4
  async function loadTsMorph() {
@@ -221,7 +221,10 @@ function extractSharedDataType(project, SK, tsObj, moduleFilePath) {
221
221
  return null;
222
222
  }
223
223
  function componentNameToPropsTypeName(componentName, segmentCount = 2) {
224
- return componentName.split("/").slice(-segmentCount).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("") + "PageProps";
224
+ return componentName.split("/").slice(-segmentCount).map(toPascalCase).join("") + "PageProps";
225
+ }
226
+ function toPascalCase(segment) {
227
+ return segment.split(/[-_\s]+/).filter((part) => part.length > 0).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
225
228
  }
226
229
  function resolvePagePropsTypeNames(pages) {
227
230
  const result = /* @__PURE__ */ new Map();
@@ -348,8 +351,14 @@ function expandTypeToInline(type, tsObj, fallbackLocation, visiting = /* @__PURE
348
351
  }
349
352
  }
350
353
  function writeInertiaTypes(outputPath, content) {
354
+ if (existsSync(outputPath)) try {
355
+ if (readFileSync(outputPath, "utf-8") === content) return false;
356
+ } catch {}
351
357
  mkdirSync(dirname(outputPath), { recursive: true });
352
- writeFileSync(outputPath, content, "utf-8");
358
+ const tmpPath = `${outputPath}.tmp-${process.pid}-${Date.now()}`;
359
+ writeFileSync(tmpPath, content, "utf-8");
360
+ renameSync(tmpPath, outputPath);
361
+ return true;
353
362
  }
354
363
  function findAppModulePath(cwd) {
355
364
  return [join(cwd, "src", "app.module.ts"), join(cwd, "src", "app.module.tsx")].find(existsSync);
@@ -388,4 +397,4 @@ async function runTypeGeneration(cwd) {
388
397
  //#endregion
389
398
  export { runTypeGeneration as n, findPagesDir as t };
390
399
 
391
- //# sourceMappingURL=type-generator-C5JljyzK.mjs.map
400
+ //# sourceMappingURL=type-generator-o_PxETTs.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-generator-o_PxETTs.mjs","names":[],"sources":["../src/generator/type-generator.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\n\nexport interface PageTypeInfo {\n componentName: string\n propsType: string\n}\n\nexport interface SharedDataTypeInfo {\n members: SharedDataMember[]\n}\n\nexport interface SharedDataMember {\n name: string\n type: string\n optional: boolean\n}\n\nexport interface FlashTypeInfo {\n members: { name: string; type: string }[]\n}\n\nasync function loadTsMorph() {\n return import('ts-morph')\n}\n\ntype TsMorphModule = Awaited<ReturnType<typeof loadTsMorph>>\ntype TsObj = TsMorphModule['ts']\ntype Project = InstanceType<TsMorphModule['Project']>\ntype SourceFile = InstanceType<TsMorphModule['Project']> extends { getSourceFiles(): (infer S)[] } ? S : never\ntype Node = ReturnType<SourceFile['getDescendants']>[number]\ntype Type = ReturnType<Node['getType']>\n\n// --- Shared ts-morph project creation ---\n\nasync function createProject(tsConfigPath?: string): Promise<{ project: Project; SyntaxKind: TsMorphModule['SyntaxKind']; ts: TsObj }> {\n const { Project, SyntaxKind, ts } = await loadTsMorph()\n\n const project = new Project({\n tsConfigFilePath: tsConfigPath,\n skipAddingFilesFromTsConfig: true,\n compilerOptions: tsConfigPath ? undefined : {\n jsx: ts.JsxEmit.ReactJSX,\n esModuleInterop: true,\n moduleResolution: ts.ModuleResolutionKind.Bundler,\n module: ts.ModuleKind.ESNext,\n target: ts.ScriptTarget.ESNext,\n },\n })\n\n return { project, SyntaxKind, ts }\n}\n\n// --- Controller ctx.inertia() extraction ---\n\nconst WRAPPER_TYPE_NAMES = [\n 'InertiaDeferredProp',\n 'InertiaMergeProp',\n 'InertiaOptionalProp',\n 'InertiaOnceProp',\n 'InertiaAlwaysProp',\n]\n\nexport function extractControllerPageTypes(\n project: Project,\n SK: TsMorphModule['SyntaxKind'],\n tsObj: TsObj,\n srcDir: string,\n pagesDir: string,\n): PageTypeInfo[] {\n project.addSourceFilesAtPaths(join(srcDir, '**/*.ts'))\n\n // Map from component name to all collected prop type strings (one per call site)\n const pages = new Map<string, string[]>()\n\n for (const sourceFile of project.getSourceFiles()) {\n const filePath = sourceFile.getFilePath()\n if (filePath.includes(pagesDir.replace(/\\\\/g, '/'))) continue\n // Skip test files\n if (filePath.includes('__tests__') || filePath.includes('.spec.') || filePath.includes('.test.')) continue\n\n const callExpressions = sourceFile.getDescendantsOfKind(SK.CallExpression)\n\n for (const call of callExpressions) {\n const expr = call.getExpression()\n if (!expr.isKind(SK.PropertyAccessExpression)) continue\n if (expr.getName() !== 'inertia') continue\n\n const args = call.getArguments()\n if (args.length === 0) continue\n\n // First arg must be a string literal (component name)\n const firstArg = args[0]\n if (!firstArg.isKind(SK.StringLiteral)) continue\n const componentName = firstArg.getLiteralValue()\n\n if (!pages.has(componentName)) {\n pages.set(componentName, [])\n }\n\n // Second arg is the props object\n if (args.length < 2) {\n pages.get(componentName)!.push('Record<string, never>')\n continue\n }\n\n const propsArg = args[1]\n const propsType = propsArg.getType()\n\n // Unwrap prop wrappers from each property\n if (propsType.isObject() && !propsType.isArray()) {\n const properties = propsType.getProperties()\n if (properties.length === 0) {\n pages.get(componentName)!.push('Record<string, never>')\n continue\n }\n\n const members = properties.map((prop) => {\n const decl = prop.getDeclarations()[0] ?? prop.getValueDeclaration()\n const location = decl ?? propsArg\n const isOptional = prop.isOptional()\n const propType = prop.getTypeAtLocation(location)\n const unwrapped = unwrapWrapperType(propType, tsObj, propsArg)\n return `${prop.getName()}${isOptional ? '?' : ''}: ${unwrapped}`\n })\n\n pages.get(componentName)!.push(`{ ${members.join('; ')} }`)\n } else {\n pages.get(componentName)!.push(typeToString(propsType, tsObj, propsArg))\n }\n }\n }\n\n return Array.from(pages.entries())\n .map(([componentName, typeVariants]) => {\n // Deduplicate identical variants then join with union\n const unique = [...new Set(typeVariants)]\n const propsType = unique.length === 1 ? unique[0] : unique.join(' | ')\n return { componentName, propsType }\n })\n .sort((a, b) => a.componentName.localeCompare(b.componentName))\n}\n\nfunction unwrapWrapperType(type: Type, tsObj: TsObj, fallbackLocation?: Node): string {\n if (type.isUnion()) {\n const unionTypes = type.getUnionTypes()\n const unwrapped = unionTypes\n .filter((t) => {\n const text = t.getText(undefined, tsObj.TypeFormatFlags.NoTruncation)\n return !WRAPPER_TYPE_NAMES.some((name) => text.includes(name))\n })\n .map((t) => typeToString(t, tsObj, fallbackLocation))\n\n if (unwrapped.length > 0) {\n return unwrapped.join(' | ')\n }\n }\n\n // Check if the type itself is a wrapper type — extract callback return type\n const text = type.getText(undefined, tsObj.TypeFormatFlags.NoTruncation)\n for (const wrapperName of WRAPPER_TYPE_NAMES) {\n if (text.includes(wrapperName)) {\n const callbackProp = type.getProperty('callback')\n if (callbackProp) {\n const decl = callbackProp.getDeclarations()[0] ?? callbackProp.getValueDeclaration()\n const location = decl ?? fallbackLocation\n if (!location) return 'unknown'\n const callbackType = callbackProp.getTypeAtLocation(location)\n const callSignatures = callbackType.getCallSignatures()\n if (callSignatures.length > 0) {\n return unwrapPromise(callSignatures[0].getReturnType(), tsObj, fallbackLocation)\n }\n }\n return 'unknown'\n }\n }\n\n return widenLiteralType(type, tsObj, fallbackLocation)\n}\n\nfunction unwrapPromise(type: Type, tsObj: TsObj, fallbackLocation?: Node): string {\n const text = type.getText(undefined, tsObj.TypeFormatFlags.NoTruncation)\n if (text.startsWith('Promise<')) {\n const typeArgs = type.getTypeArguments()\n if (typeArgs.length > 0) {\n return stripReadonly(typeArgs[0], tsObj, fallbackLocation)\n }\n }\n return stripReadonly(type, tsObj, fallbackLocation)\n}\n\nfunction stripReadonly(type: Type, tsObj: TsObj, fallbackLocation?: Node): string {\n if (type.isTuple()) {\n const elements = type.getTupleElements()\n const parts = elements.map((e) => typeToString(e, tsObj, fallbackLocation))\n return `[${parts.join(', ')}]`\n }\n\n const text = type.getText(undefined, tsObj.TypeFormatFlags.NoTruncation)\n if (text.startsWith('readonly ') && type.isArray()) {\n const elementType = type.getArrayElementType()\n if (elementType) {\n return `Array<${typeToString(elementType, tsObj, fallbackLocation)}>`\n }\n }\n\n return typeToString(type, tsObj, fallbackLocation)\n}\n\n// --- Extract this.inertia.share() call types ---\n\nexport function extractShareCallTypes(\n project: Project,\n SK: TsMorphModule['SyntaxKind'],\n tsObj: TsObj,\n srcDir: string,\n): Map<string, string> {\n const shareTypes = new Map<string, string>()\n\n for (const sourceFile of project.getSourceFiles()) {\n const filePath = sourceFile.getFilePath()\n if (!filePath.startsWith(srcDir.replace(/\\\\/g, '/'))) continue\n if (filePath.includes('__tests__') || filePath.includes('.spec.') || filePath.includes('.test.')) continue\n\n const callExpressions = sourceFile.getDescendantsOfKind(SK.CallExpression)\n\n for (const call of callExpressions) {\n const expr = call.getExpression()\n if (!expr.isKind(SK.PropertyAccessExpression)) continue\n if (expr.getName() !== 'share') continue\n\n // Check that the object is inertia-related (this.inertia.share, inertia.share)\n const objExpr = expr.getExpression()\n const objText = objExpr.getText()\n if (!objText.includes('inertia')) continue\n\n const args = call.getArguments()\n if (args.length < 2) continue\n\n const keyArg = args[0]\n if (!keyArg.isKind(SK.StringLiteral)) continue\n const key = keyArg.getLiteralValue()\n\n if (shareTypes.has(key)) continue\n\n const valueType = widenLiteralType(args[1].getType(), tsObj)\n shareTypes.set(key, valueType)\n }\n }\n\n return shareTypes\n}\n\n// --- Detect i18n config in InertiaModule.forRoot() ---\n\nexport function detectI18nConfig(\n project: Project,\n SK: TsMorphModule['SyntaxKind'],\n moduleFilePath: string,\n): boolean {\n const sourceFile = project.getSourceFile(moduleFilePath)\n if (!sourceFile) return false\n\n const callExpressions = sourceFile.getDescendantsOfKind(SK.CallExpression)\n\n for (const call of callExpressions) {\n const expr = call.getExpression()\n if (!expr.isKind(SK.PropertyAccessExpression)) continue\n\n const propName = expr.getName()\n if (propName !== 'forRoot' && propName !== 'forRootAsync') continue\n\n const objExpr = expr.getExpression()\n if (!objExpr.isKind(SK.Identifier) || objExpr.getText() !== 'InertiaModule') continue\n\n const args = call.getArguments()\n if (args.length === 0) continue\n\n const optionsArg = args[0]\n if (!optionsArg.isKind(SK.ObjectLiteralExpression)) continue\n\n return !!optionsArg.getProperty('i18n')\n }\n\n return false\n}\n\n// --- Extract ctx.flash() call types ---\n\nexport function extractFlashTypes(\n project: Project,\n SK: TsMorphModule['SyntaxKind'],\n tsObj: TsObj,\n srcDir: string,\n): FlashTypeInfo | null {\n const flashMembers = new Map<string, string>()\n\n for (const sourceFile of project.getSourceFiles()) {\n const filePath = sourceFile.getFilePath()\n if (!filePath.startsWith(srcDir.replace(/\\\\/g, '/'))) continue\n if (filePath.includes('__tests__') || filePath.includes('.spec.') || filePath.includes('.test.')) continue\n\n const callExpressions = sourceFile.getDescendantsOfKind(SK.CallExpression)\n\n for (const call of callExpressions) {\n const expr = call.getExpression()\n if (!expr.isKind(SK.PropertyAccessExpression)) continue\n if (expr.getName() !== 'flash') continue\n\n const args = call.getArguments()\n if (args.length < 2) continue\n\n const keyArg = args[0]\n if (!keyArg.isKind(SK.StringLiteral)) continue\n const key = keyArg.getLiteralValue()\n\n if (flashMembers.has(key)) continue\n\n const valueType = widenLiteralType(args[1].getType(), tsObj)\n flashMembers.set(key, valueType)\n }\n }\n\n if (flashMembers.size === 0) return null\n\n return {\n members: Array.from(flashMembers.entries()).map(([name, type]) => ({ name, type })),\n }\n}\n\n// --- Extract shared data from module config (existing, refactored) ---\n\nexport function extractSharedDataType(\n project: Project,\n SK: TsMorphModule['SyntaxKind'],\n tsObj: TsObj,\n moduleFilePath: string,\n): SharedDataTypeInfo | null {\n const sourceFile = project.getSourceFile(moduleFilePath)\n ?? project.addSourceFileAtPath(moduleFilePath)\n\n const callExpressions = sourceFile.getDescendantsOfKind(SK.CallExpression)\n\n for (const call of callExpressions) {\n const expr = call.getExpression()\n if (!expr.isKind(SK.PropertyAccessExpression)) continue\n\n const propName = expr.getName()\n if (propName !== 'forRoot' && propName !== 'forRootAsync') continue\n\n const objExpr = expr.getExpression()\n if (!objExpr.isKind(SK.Identifier) || objExpr.getText() !== 'InertiaModule') continue\n\n const args = call.getArguments()\n if (args.length === 0) continue\n\n const optionsArg = args[0]\n if (!optionsArg.isKind(SK.ObjectLiteralExpression)) continue\n\n const sharedDataProp = optionsArg.getProperty('sharedData')\n if (!sharedDataProp) continue\n\n if (!sharedDataProp.isKind(SK.PropertyAssignment)) continue\n\n const initializer = sharedDataProp.getInitializer()\n if (!initializer?.isKind(SK.ObjectLiteralExpression)) continue\n\n const members: SharedDataMember[] = []\n for (const prop of initializer.getProperties()) {\n if (!prop.isKind(SK.PropertyAssignment)) continue\n\n const name = prop.getName()\n const value = prop.getInitializer()\n if (!value) continue\n\n let valueType: string\n\n if (value.isKind(SK.ArrowFunction) || value.isKind(SK.FunctionExpression)) {\n const returnType = value.getReturnType()\n valueType = typeToString(returnType, tsObj)\n } else {\n valueType = typeToString(value.getType(), tsObj)\n }\n\n members.push({ name, type: valueType, optional: false })\n }\n\n if (members.length > 0) {\n return { members }\n }\n }\n\n return null\n}\n\n// --- Generate output ---\n\nexport interface GenerateTypesInput {\n pages: PageTypeInfo[]\n sharedData: SharedDataTypeInfo | null\n shareCallTypes: Map<string, string>\n hasI18n: boolean\n flashTypes: FlashTypeInfo | null\n}\n\nfunction componentNameToPropsTypeName(componentName: string, segmentCount = 2): string {\n const segments = componentName.split('/')\n const used = segments.slice(-segmentCount)\n return used.map(toPascalCase).join('') + 'PageProps'\n}\n\nfunction toPascalCase(segment: string): string {\n return segment\n .split(/[-_\\s]+/)\n .filter((part) => part.length > 0)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('')\n}\n\nfunction resolvePagePropsTypeNames(pages: PageTypeInfo[]): Map<string, string> {\n const result = new Map<string, string>()\n\n // First pass: use last 2 segments\n const nameToComponents = new Map<string, string[]>()\n for (const page of pages) {\n const typeName = componentNameToPropsTypeName(page.componentName)\n const existing = nameToComponents.get(typeName) ?? []\n existing.push(page.componentName)\n nameToComponents.set(typeName, existing)\n }\n\n // Second pass: resolve collisions by using all segments\n for (const [typeName, components] of nameToComponents) {\n if (components.length === 1) {\n result.set(components[0], typeName)\n } else {\n for (const componentName of components) {\n const fullSegments = componentName.split('/').length\n result.set(componentName, componentNameToPropsTypeName(componentName, fullSegments))\n }\n }\n }\n\n return result\n}\n\nexport function generateInertiaTypes(input: GenerateTypesInput): string {\n const { pages, sharedData, shareCallTypes, hasI18n, flashTypes } = input\n\n // Compute type names with collision resolution\n const typeNames = resolvePagePropsTypeNames(pages)\n\n const lines: string[] = [\n '// Auto-generated by @stratal/inertia. Do not edit.',\n ]\n\n // Global page props types\n if (pages.length > 0) {\n lines.push('declare global {')\n for (const page of pages) {\n const typeName = typeNames.get(page.componentName)!\n lines.push(` type ${typeName} = ${page.propsType}`)\n }\n lines.push('}')\n lines.push('')\n }\n\n // InertiaPageRegistry augmentation referencing global types\n lines.push(\"declare module '@stratal/inertia' {\")\n lines.push(' interface InertiaPageRegistry {')\n for (const page of pages) {\n const typeName = typeNames.get(page.componentName)!\n lines.push(` '${page.componentName}': ${typeName}`)\n }\n lines.push(' }')\n lines.push('}')\n\n // Build InertiaConfig augmentation\n const configMembers: string[] = []\n\n // Flash data type\n if (flashTypes && flashTypes.members.length > 0) {\n const flashProps = flashTypes.members\n .map((m) => `${m.name}?: ${m.type}`)\n .join('; ')\n configMembers.push(` flashDataType: { ${flashProps} }`)\n }\n\n // Shared page props\n const sharedMembers: string[] = []\n\n // From module config (non-optional)\n if (sharedData) {\n for (const member of sharedData.members) {\n sharedMembers.push(` ${member.name}${member.optional ? '?' : ''}: ${member.type}`)\n }\n }\n\n // From i18n detection (non-optional)\n if (hasI18n) {\n sharedMembers.push(' locale: string')\n sharedMembers.push(' translations: Record<string, string>')\n }\n\n // From .share() calls (optional — per-request)\n for (const [key, type] of shareCallTypes) {\n // Skip if already declared by module config\n if (sharedData?.members.some((m) => m.name === key)) continue\n sharedMembers.push(` ${key}?: ${type}`)\n }\n\n if (sharedMembers.length > 0) {\n configMembers.push(` sharedPageProps: {\\n${sharedMembers.join('\\n')}\\n }`)\n }\n\n if (configMembers.length > 0) {\n lines.push('')\n lines.push(\"declare module '@inertiajs/core' {\")\n lines.push(' export interface InertiaConfig {')\n for (const member of configMembers) {\n lines.push(member)\n }\n lines.push(' }')\n lines.push('}')\n }\n\n lines.push('', 'export {}', '')\n\n return lines.join('\\n')\n}\n\n// --- Type string helpers ---\n\nfunction widenLiteralType(type: Type, tsObj: TsObj, fallbackLocation?: Node): string {\n if (type.isStringLiteral()) return 'string'\n if (type.isNumberLiteral()) return 'number'\n if (type.isBooleanLiteral()) return 'boolean'\n return typeToString(type, tsObj, fallbackLocation)\n}\n\nfunction typeToString(type: Type, tsObj: TsObj, fallbackLocation?: Node): string {\n // Always expand objects/unions/intersections so getText() can't leak inline\n // index signatures (e.g. StratalRouteMap params' `[key: string]: ...`).\n if (type.isObject() || type.isUnion() || type.isIntersection()) {\n return expandTypeToInline(type, tsObj, fallbackLocation)\n }\n\n const text = type.getText(undefined, tsObj.TypeFormatFlags.NoTruncation | tsObj.TypeFormatFlags.UseFullyQualifiedType)\n\n if (text.includes('import(')) {\n return expandTypeToInline(type, tsObj, fallbackLocation)\n }\n\n return text\n}\n\nfunction expandPropertyType(\n type: Type,\n tsObj: TsObj,\n fallbackLocation: Node | undefined,\n visiting: Set<Type>,\n isOptional: boolean,\n): string {\n // The `?` marker already implies `undefined`, so strip it from the union\n // to avoid `id?: undefined | string`.\n if (isOptional && type.isUnion()) {\n const parts = type.getUnionTypes().filter((t) => !t.isUndefined())\n if (parts.length === 0) return 'undefined'\n if (parts.length === 1) return expandTypeToInline(parts[0], tsObj, fallbackLocation, visiting)\n return parts.map((t) => expandTypeToInline(t, tsObj, fallbackLocation, visiting)).join(' | ')\n }\n return expandTypeToInline(type, tsObj, fallbackLocation, visiting)\n}\n\nfunction expandTypeToInline(\n type: Type,\n tsObj: TsObj,\n fallbackLocation?: Node,\n visiting = new Set<Type>(),\n): string {\n if (visiting.has(type)) return 'unknown'\n // `boolean` is internally `true | false` — short-circuit before the union branch.\n if (type.isBoolean()) return 'boolean'\n visiting.add(type)\n try {\n if (type.isObject() && !type.isArray() && !type.isReadonlyArray()) {\n // Named global types (Date, RegExp, Map, Set, ...) — emit text as-is.\n // Expanding them iterates every method and produces garbage like\n // `{ toString: ...; getTime: ...; }` for Date.\n const symbolName = type.getSymbol()?.getName()\n const text = type.getText(undefined, tsObj.TypeFormatFlags.NoTruncation | tsObj.TypeFormatFlags.UseFullyQualifiedType)\n if (\n symbolName\n && !symbolName.startsWith('__')\n && symbolName !== 'Object'\n && !text.includes('import(')\n ) {\n return text\n }\n\n const properties = type.getProperties()\n if (properties.length === 0) {\n const stringIndexType = type.getStringIndexType()\n if (stringIndexType) {\n return `Record<string, ${expandTypeToInline(stringIndexType, tsObj, fallbackLocation, visiting)}>`\n }\n // Use `{}` not `Record<string, never>` — `never` collapses intersections.\n return '{}'\n }\n\n const members = properties.map((prop) => {\n const decl = prop.getDeclarations()[0] ?? prop.getValueDeclaration()\n const location = decl ?? fallbackLocation\n const isOptional = prop.isOptional()\n if (!location) return `${prop.getName()}${isOptional ? '?' : ''}: unknown`\n const propType = prop.getTypeAtLocation(location)\n const propTypeStr = expandPropertyType(propType, tsObj, fallbackLocation, visiting, isOptional)\n return `${prop.getName()}${isOptional ? '?' : ''}: ${propTypeStr}`\n })\n\n return `{ ${members.join('; ')} }`\n }\n\n if (type.isArray() || type.isReadonlyArray()) {\n const elementType = type.getArrayElementType()\n if (elementType) {\n const inner = expandTypeToInline(elementType, tsObj, fallbackLocation, visiting)\n return type.isReadonlyArray() ? `ReadonlyArray<${inner}>` : `Array<${inner}>`\n }\n }\n\n if (type.isUnion()) {\n return type.getUnionTypes().map((t) => expandTypeToInline(t, tsObj, fallbackLocation, visiting)).join(' | ')\n }\n\n if (type.isIntersection()) {\n return type.getIntersectionTypes().map((t) => expandTypeToInline(t, tsObj, fallbackLocation, visiting)).join(' & ')\n }\n\n const text = type.getText(undefined, tsObj.TypeFormatFlags.NoTruncation)\n if (text.includes('import(')) {\n return 'unknown'\n }\n return text\n } finally {\n visiting.delete(type)\n }\n}\n\n// --- File path helpers ---\n\nexport function writeInertiaTypes(outputPath: string, content: string): boolean {\n if (existsSync(outputPath)) {\n try {\n if (readFileSync(outputPath, 'utf-8') === content) return false\n } catch {\n // fall through and write\n }\n }\n mkdirSync(dirname(outputPath), { recursive: true })\n const tmpPath = `${outputPath}.tmp-${process.pid}-${Date.now()}`\n writeFileSync(tmpPath, content, 'utf-8')\n renameSync(tmpPath, outputPath)\n return true\n}\n\nexport function findAppModulePath(cwd: string): string | undefined {\n const candidates = [\n join(cwd, 'src', 'app.module.ts'),\n join(cwd, 'src', 'app.module.tsx'),\n ]\n\n return candidates.find(existsSync)\n}\n\nexport function findPagesDir(cwd: string): string {\n return join(cwd, 'src', 'inertia', 'pages')\n}\n\nexport function findOutputPath(cwd: string): string {\n return join(cwd, 'src', 'inertia', 'inertia.d.ts')\n}\n\nexport function findTsConfigPath(cwd: string): string | undefined {\n const candidate = join(cwd, 'tsconfig.json')\n return existsSync(candidate) ? candidate : undefined\n}\n\n// --- Main pipeline ---\n\nexport async function runTypeGeneration(cwd: string): Promise<{ outputPath: string; pageCount: number }> {\n const pagesDir = findPagesDir(cwd)\n const srcDir = join(cwd, 'src')\n const outputPath = findOutputPath(cwd)\n const moduleFilePath = findAppModulePath(cwd)\n const tsConfigPath = findTsConfigPath(cwd)\n\n // Single shared project for all extractors\n const { project, SyntaxKind, ts } = await createProject(tsConfigPath)\n\n // 1. Controller ctx.inertia() calls — sole source of truth for InertiaPageRegistry\n const pages = extractControllerPageTypes(project, SyntaxKind, ts, srcDir, pagesDir)\n\n // 2. Module shared data config\n const sharedData = moduleFilePath\n ? extractSharedDataType(project, SyntaxKind, ts, moduleFilePath)\n : null\n\n // 3. i18n detection\n const hasI18n = moduleFilePath\n ? detectI18nConfig(project, SyntaxKind, moduleFilePath)\n : false\n\n // 4. Per-request .share() calls\n const shareCallTypes = extractShareCallTypes(project, SyntaxKind, ts, srcDir)\n\n // 5. Flash ctx.flash() calls\n const flashTypes = extractFlashTypes(project, SyntaxKind, ts, srcDir)\n\n // 6. Generate\n const content = generateInertiaTypes({\n pages,\n sharedData,\n shareCallTypes,\n hasI18n,\n flashTypes,\n })\n writeInertiaTypes(outputPath, content)\n\n return { outputPath, pageCount: pages.length }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"vite.d.mts","names":[],"sources":["../src/vite/inertia-dev-css-plugin.ts","../src/vite/inertia-types-plugin.ts","../src/vite.ts"],"mappings":";;;UAMiB,oBAAA;EACf,OAAA;AAAA;AAAA,iBAqEc,oBAAA,CAAqB,OAAA,EAAS,oBAAA,GAAuB,MAAA;;;iBCrErD,mBAAA,CAAA,GAAuB,MAAA;;;UCDtB,2BAAA;;EAEf,OAAA;AAAA;AAAA,iBAGc,cAAA,CAAe,OAAA,GAAU,2BAAA,GAA8B,MAAA"}
1
+ {"version":3,"file":"vite.d.mts","names":[],"sources":["../src/vite/inertia-dev-css-plugin.ts","../src/vite/inertia-types-plugin.ts","../src/vite.ts"],"mappings":";;;UAMiB,oBAAA;EACf,OAAA;AAAA;AAAA,iBAqEc,oBAAA,CAAqB,OAAA,EAAS,oBAAA,GAAuB,MAAA;;;iBCpErD,mBAAA,CAAA,GAAuB,MAAA;;;UCFtB,2BAAA;;EAEf,OAAA;AAAA;AAAA,iBAGc,cAAA,CAAe,OAAA,GAAU,2BAAA,GAA8B,MAAA"}