diff options
Diffstat (limited to 'packages/demobank-ui/src/route.ts')
-rw-r--r-- | packages/demobank-ui/src/route.ts | 100 |
1 files changed, 67 insertions, 33 deletions
diff --git a/packages/demobank-ui/src/route.ts b/packages/demobank-ui/src/route.ts index 4b021d762..72c7802fb 100644 --- a/packages/demobank-ui/src/route.ts +++ b/packages/demobank-ui/src/route.ts @@ -15,43 +15,49 @@ */ import { useNavigationContext } from "./context/navigation.js"; +declare const __location: unique symbol; +/** + * special string that defined a location in the application + * + * this help to prevent wrong path + */ +export type AppLocation = string & { + [__location]: true; +}; +export type EmptyObject = Record<string, never>; + export function urlPattern< - T extends Record<string, string> = Record<string, never>, + T extends Record<string, string | undefined> = EmptyObject, >(pattern: RegExp, reverse: (p: T) => string): RouteDefinition<T> { + const url = reverse as ((p: T) => AppLocation) return { pattern: new RegExp(pattern), - url: reverse, + url, }; } -export type RouteDefinition<T> = { +/** + * defines a location in the app + * + * pattern: how a string will trigger this location + * url(): how a state serialize to a location + */ + +export type ObjectOf<T> = Record<string, T> | EmptyObject; + +export type RouteDefinition<T extends ObjectOf<string | undefined> = EmptyObject> = { pattern: RegExp; - url: (p: T) => string; + url: (p: T) => AppLocation; }; const nullRountDef = { pattern: new RegExp(/.*/), - url: () => "", + url: () => "" as AppLocation, }; -export function buildNullRoutDefinition<T>(): RouteDefinition<T> { +export function buildNullRoutDefinition<T extends ObjectOf<string>>(): RouteDefinition<T> { return nullRountDef; } -export type RouteMap<T> = { - [n in keyof T]: RouteDefinition<T[n]>; -}; - -export type RouteParamsType< - P, - T extends keyof P, -> = P[T] extends RouteDefinition<infer ASD> ? ASD : never; - -type Location<E, T extends RouteMap<E>, NAME extends keyof T> = { - parent: T; - name: NAME; - values: RouteParamsType<T, NAME>; -}; - /** * Search path in the pageList * get the values from the path found @@ -60,23 +66,28 @@ type Location<E, T extends RouteMap<E>, NAME extends keyof T> = { * @param path * @param params */ -function findMatch<DEF, RM extends RouteMap<DEF>, ROUTES extends keyof RM>( - pagesMap: RM, - pageList: Array<ROUTES>, +function findMatch<T extends ObjectOf<RouteDefinition>>( + pagesMap: T, + pageList: Array<keyof T>, path: string, params: Record<string, string>, -): Location<DEF, RM, ROUTES> | undefined { +): Location<T> | undefined { for (let idx = 0; idx < pageList.length; idx++) { const name = pageList[idx]; const found = pagesMap[name].pattern.exec(path); if (found !== null) { - const values = - found.groups === undefined ? {} : structuredClone(found.groups); + const values = {} as Record<string, any> Object.entries(params).forEach(([key, value]) => { values[key] = value; }); + if (found.groups !== undefined) { + Object.entries(found.groups).forEach(([key, value]) => { + values[key] = value; + }); + } + // @ts-expect-error values is a map string which is equivalent to the RouteParamsType return { name, parent: pagesMap, values }; } @@ -84,12 +95,35 @@ function findMatch<DEF, RM extends RouteMap<DEF>, ROUTES extends keyof RM>( return undefined; } -export function useCurrentLocation< - DEF, - RM extends RouteMap<DEF>, - ROUTES extends keyof RM, ->(pagesMap: RM) { - const pageList = Object.keys(pagesMap) as Array<ROUTES>; +/** + * get the type of the params of a location + * + */ +type RouteParamsType< + RouteType, + Key extends keyof RouteType, +> = RouteType[Key] extends RouteDefinition<infer ParamType> ? ParamType : never; + +/** + * Helps to create a map of a type with the key + */ +type MapKeyValue<Type> = { + [Key in keyof Type]: Key extends string ? { + parent: Type, + name: Key, + values: RouteParamsType<Type, Key>; + } : never; +} + +/** + * create a enumaration of value of a mapped type + */ +type EnumerationOf<T> = T[keyof T] + +type Location<T> = EnumerationOf<MapKeyValue<T>> + +export function useCurrentLocation<T extends ObjectOf<RouteDefinition<any>>>(pagesMap: T): Location<T> | undefined { + const pageList = Object.keys(pagesMap as object) as Array<keyof T>; const { path, params } = useNavigationContext(); return findMatch(pagesMap, pageList, path, params); |