UNPKG

@furystack/shades

Version:

A lightweight UI framework for FuryStack with JSX support

73 lines 2.84 kB
import { LocationService } from '../services/location-service.js'; /** * Walks a route tree and returns the route value declared at the given path, * matching each URL pattern segment-by-segment. The root `/` pattern is * transparent: its children are searched with the full path. * * Exported for unit testing only — consumers should go through * {@link createNestedHooks}. * * @internal */ export const walkRoute = (routes, path) => { for (const [pattern, route] of Object.entries(routes)) { if (pattern === path) return route; if (pattern === '/' && route.children) { const nested = walkRoute(route.children, path); if (nested) return nested; } else if (route.children && path.startsWith(pattern)) { const rest = path.slice(pattern.length); if (rest.startsWith('/') || rest === '') { const nested = walkRoute(route.children, rest || '/'); if (nested) return nested; } } } return undefined; }; /** * Creates a pair of type-safe synchronous read helpers (`getTypedQuery`, * `getTypedHash`) bound to a specific route tree. The returned functions * validate the current URL's query and hash against the route declared at * the given path, returning typed values or `null`/`undefined` on mismatch. * * The concrete route tree is captured at factory time, so call sites only * pass `(injector, path)`; the type-level narrowing is derived from the * inferred tree generic. * * @typeParam TRoutes - The route tree type (inferred from the `routes` argument) * * @example * ```typescript * const { getTypedQuery, getTypedHash } = createNestedHooks(appRoutes) * * const query = getTypedQuery(injector, '/users') // typed * const hash = getTypedHash(injector, '/users') // typed * ``` */ export const createNestedHooks = (routes) => { return { getTypedQuery: (injector, path) => { const route = walkRoute(routes, path); if (!route?.query) return null; const locationService = injector.get(LocationService); const deserialized = locationService.onDeserializedLocationSearchChanged.getValue(); return route.query(deserialized); }, getTypedHash: (injector, path) => { const route = walkRoute(routes, path); const declaredHash = route?.hash; if (!declaredHash) return undefined; const locationService = injector.get(LocationService); const currentHash = locationService.onLocationHashChanged.getValue(); return declaredHash.includes(currentHash) ? currentHash : undefined; }, }; }; //# sourceMappingURL=nested-hooks.js.map