import type { ExtractParams } from "./types.js"; import type { SearchSchema, ResolveSearchSchema } from "./search-params.js"; /** * Sanitize prefix string by removing leading slash * "/shop" -> "shop", "blog" -> "blog", "" -> "" */ export type SanitizePrefix = T extends `/${infer P}` ? P : T; /** * Helper type to merge multiple route definitions into a single accumulated type. * Note: When using createRouter, types accumulate automatically through the * builder chain, so this type is typically not needed. * * @example * ```typescript * // Manual type merging (rarely needed): * type AppRoutes = MergeRoutes<[ * typeof homeRoutes, * PrefixRoutePatterns, * ]>; * * // Preferred: Let router accumulate types automatically * const router = createRouter() * .routes(homeRoutes).map(...) * .routes("/blog", blogRoutes).map(...); * type AppRoutes = typeof router.routeMap; * ``` */ export type MergeRoutes = T extends [ infer First, ...infer Rest ] ? First & MergeRoutes : {}; /** * Add key prefix to all entries in a route map * { "cart": "/cart" } with prefix "shop" -> { "shop.cart": "/shop/cart" } */ export type PrefixRouteKeys = Prefix extends "" ? T : { [K in keyof T as `${Prefix}.${K & string}`]: T[K]; }; /** * Add path prefix to all patterns in a route map * { "cart": "/cart" } with prefix "/shop" -> { "cart": "/shop/cart" } */ export type PrefixRoutePatterns = { [K in keyof T]: PathPrefix extends "" | "/" ? T[K] : T[K] extends "/" ? PathPrefix : T[K] extends string ? `${PathPrefix}${T[K]}` : T[K]; }; /** * Combined: prefix both keys and patterns * Used for module augmentation registration * * @example * ```typescript * // Given shopRoutes = { "index": "/", "cart": "/cart", "products.detail": "/product/:slug" } * // PrefixedRoutes produces: * // { "shop.index": "/shop", "shop.cart": "/shop/cart", "shop.products.detail": "/shop/product/:slug" } * ``` */ export type PrefixedRoutes = PrefixRouteKeys, KeyPrefix>; /** * Helper to safely extract route patterns from a routes object * Handles string values, { path, response } objects, and interface types (like RegisteredRoutes) */ type RoutePatternFor = TRoutes[TName] extends string ? TRoutes[TName] : TRoutes[TName] extends { readonly path: infer P extends string; } ? P : string; /** * Extract params type for a route */ export type ParamsFor = ExtractParams>; /** * Check if an object type has any keys */ type IsEmptyObject = keyof T extends never ? true : false; /** * Extract search schema from a route entry. * Returns {} if no search schema is defined. */ type ExtractSearchSchema = TRoutes[TName] extends { readonly search: infer S extends SearchSchema; } ? S : {}; /** * Type-safe reverse function signature (Django-style URL reversal) * * Validates route names and params at compile time. * Use route names instead of raw paths for full type safety. * * @example * ```typescript * reverse("cart") // ✓ Validates route exists * reverse("product.detail", { id: "123" }) // ✓ Validates route + params * ``` */ export type ReverseFunction = { /** * Route without params - validates route name exists */ (name: IsEmptyObject>> extends true ? TName : never): string; /** * Route with params - validates both route name and params */ (name: TName, params: ExtractParams>): string; /** * Route with params and search - validates route name, params, and search */ (name: TName, params: ExtractParams>, search: ResolveSearchSchema>): string; }; /** * Type-safe scoped reverse function that validates all route names and params. * * When used via HandlerContext or scopedReverse(), local routes are merged with * global RegisteredRoutes so all names are fully type-checked. * * @example * ```typescript * reverse("cart") // ✓ Validates local route * reverse("blog.post", { slug: "hello" }) // ✓ Validates global route + params * reverse("typo") // ✗ Compile error * ``` */ export type ScopedReverseFunction = { /** * Route without params - validates route name exists * @recommended Use this for type-safe URL generation */ (name: IsEmptyObject>> extends true ? TName : never): string; /** * Route with params - validates both route name and params * @recommended Use this for type-safe URL generation with parameters */ (name: TName, params: ExtractParams>): string; /** * Route with params and search - validates route name, params, and search */ (name: TName, params: ExtractParams>, search: ResolveSearchSchema>): string; }; /** * Extract local routes type from UrlPatterns * Used with scopedReverse() to get the routes type from patterns */ export type ExtractLocalRoutes = TPatterns extends { readonly _routes?: infer TRoutes; } ? TRoutes : TPatterns extends Record ? TPatterns : Record; /** * Extract the response data type for a named route from a UrlPatterns instance. * Re-exported from urls.ts for consumer convenience. */ export type { RouteResponse } from "./urls.js"; /** * Get a locally-typed reverse function from ctx.reverse for composable modules. * * This is a type-only cast - ctx.reverse already resolves local names at runtime * based on the current route prefix. This helper just provides type safety * for local route names within a url module. * * @param reverse - The ctx.reverse function from HandlerContext * @returns The same reverse function, but typed for local routes * * @example * ```typescript * // urls/blog.tsx * export const blogPatterns = urls(({ path }) => [ * path("/", (ctx) => { * // Get locally-typed reverse for this module's routes * const reverse = scopedReverse(ctx.reverse); * * reverse("index"); // ✓ Type-safe local route * reverse("post", { slug: "x" }); // ✓ Type-safe with params * reverse("shop.cart"); // ✓ Type-safe global route * * return ; * }, { name: "index" }), * * path("/:slug", BlogPost, { name: "post" }), * ]); * ``` */ export declare function scopedReverse(reverse: ((...args: any[]) => string)): ScopedReverseFunction>; /** * Create a type-safe reverse function for URL generation * * @param routeMap - Flattened route map with all registered routes * @returns Type-safe reverse function * * @example * ```typescript * // Given routes: { cart: "/shop/cart", detail: "/shop/product/:slug" } * const reverse = createReverse(routeMap); * reverse("cart"); // "/shop/cart" * reverse("detail", { slug: "my-product" }); // "/shop/product/my-product" * ``` */ type RouteMapEntry = string | { path: string; search?: Record; }; export declare function createReverse>(routeMap: TRoutes, getFallbackMap?: () => Record | undefined): ReverseFunction>; //# sourceMappingURL=reverse.d.ts.map