export type RouteParams = { [p: string]: string | number | undefined } | string[] | string | number; export type QueryParamsRecord = Record; export type QueryParams = string[][] | QueryParamsRecord | string | URLSearchParams; export let routes: Record = {}; export function setRoutes(newRoutes: Record): void { routes = newRoutes; } export function registerRoute(routeName: string, routePath: string): boolean { if (!routes[routeName]) { routes[routeName] = routePath; return true; } return false; } export let publicUrl: string; export function setPublicUrl(newPublicUrl: string): void { publicUrl = newPublicUrl; } export function route( route: string, params: RouteParams = [], query: QueryParams = '', absolute: boolean = false, ): string { let path = routes[route]; if (path === undefined) throw new Error(`Unknown route for name ${route}.`); const regExp = getRouteParamRegExp('[a-zA-Z0-9_-]+', 'g'); if (typeof params === 'string' || typeof params === 'number') { path = path.replace(regExp, '' + params); } else if (Array.isArray(params)) { let i = 0; for (const match of path.matchAll(regExp)) { if (match.length > 0) { path = path.replace(match[0], typeof params[i] !== 'undefined' ? params[i] : ''); } i++; } path = path.replace(/\/+/g, '/'); } else { for (const key of Object.keys(params)) { const paramValue = params[key]; if (paramValue) { path = path.replace(getRouteParamRegExp(key), paramValue.toString()); } } } let filteredQuery: string[][] | Record | string | URLSearchParams; if (typeof query !== "string" && !(query instanceof URLSearchParams) && !Array.isArray(query)) { for (const key of Object.keys(query)) { if (query[key] === undefined || query[key] === null) delete query[key]; else if (typeof query[key] === "number") query[key] = (query[key] as number).toString(); else if (typeof query[key] === "boolean") query[key] = query[key] ? '1' : '0'; } filteredQuery = query as Record; } else { filteredQuery = query; } const queryStr = new URLSearchParams(filteredQuery).toString(); return `${absolute ? publicUrl : ''}${path}` + (queryStr.length > 0 ? '?' + queryStr : ''); } export function getRouteParamRegExp(key: string, flags?: string): RegExp { return new RegExp(`:${key}(\\(.+?\\))?\\??`, flags); } export function hasRoute(...routesToMatch: string[]): boolean { for (const route of routesToMatch) { if (!routes[route]) return false; } return true; } export function hasAnyRoute(...routesToMatch: string[]): boolean { for (const route of routesToMatch) { if (routes[route]) return true; } return false; }