summaryrefslogtreecommitdiff
path: root/packages/web-util/src/utils/route.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/web-util/src/utils/route.ts')
-rw-r--r--packages/web-util/src/utils/route.ts126
1 files changed, 126 insertions, 0 deletions
diff --git a/packages/web-util/src/utils/route.ts b/packages/web-util/src/utils/route.ts
new file mode 100644
index 000000000..494a61efa
--- /dev/null
+++ b/packages/web-util/src/utils/route.ts
@@ -0,0 +1,126 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022-2024 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+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 | undefined> = EmptyObject,
+>(pattern: RegExp, reverse: (p: T) => string): RouteDefinition<T> {
+ const url = reverse as (p: T) => AppLocation;
+ return {
+ pattern: new RegExp(pattern),
+ url,
+ };
+}
+
+/**
+ * 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) => AppLocation;
+};
+
+const nullRountDef = {
+ pattern: new RegExp(/.*/),
+ url: () => "" as AppLocation,
+};
+export function buildNullRoutDefinition<
+ T extends ObjectOf<string>,
+>(): RouteDefinition<T> {
+ return nullRountDef;
+}
+
+/**
+ * Search path in the pageList
+ * get the values from the path found
+ * add params from searchParams
+ *
+ * @param path
+ * @param params
+ */
+export function findMatch<T extends ObjectOf<RouteDefinition>>(
+ pagesMap: T,
+ pageList: Array<keyof T>,
+ path: string,
+ params: Record<string, string[]>,
+): 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 = {} as Record<string, unknown>;
+
+ 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, params };
+ }
+ }
+ return undefined;
+}
+
+/**
+ * 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>;
+ params: Record<string, string[]>;
+ }
+ : never;
+};
+
+/**
+ * create a enumeration of value of a mapped type
+ */
+type EnumerationOf<T> = T[keyof T];
+
+export type Location<T> = EnumerationOf<MapKeyValue<T>>;