swaf/src/common/Routing.ts

88 lines
3.0 KiB
TypeScript
Raw Normal View History

export type RouteParams = { [p: string]: string | number | undefined } | string[] | string | number;
export type QueryParamsRecord = Record<string, string | number | boolean | null | undefined>;
export type QueryParams = string[][] | QueryParamsRecord | string | URLSearchParams;
export let routes: Record<string, string | undefined> = {};
export function setRoutes(newRoutes: Record<string, string | undefined>): 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, string> | 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<string, string>;
} 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;
}