From b6d2ab9ff3cf5088c9c2b0d81a6ad2182570602d Mon Sep 17 00:00:00 2001 From: Matthew Davis Date: Sat, 22 Feb 2025 16:38:36 -0600 Subject: [PATCH] feat: add support for regex instances --- src/lib/instance.svelte.ts | 67 +++++++++++++++++++++++++------------- test/app/src/app.svelte | 4 +-- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/lib/instance.svelte.ts b/src/lib/instance.svelte.ts index 682a4d6..dd04b94 100644 --- a/src/lib/instance.svelte.ts +++ b/src/lib/instance.svelte.ts @@ -14,7 +14,7 @@ export type PostHooks = ((route: Route) => void)[] | ((route: Route) => Promise< * A route that can be navigated to. */ export interface Route { - path: RegExp | string; + path: RegExp | string | number; component?: Component | Snippet | (() => Promise | Snippet>) | Function | any; props?: Record; pre?: PreHooks; @@ -138,6 +138,36 @@ export class Instance { } } + /** + * Find a matching route for a given path by checking if the path is a string or a RegExp. + * @param {string} path The path to find a matching route for. + * @returns {Route} The matching route. + */ + match(path: string): Route | undefined { + for (const r of this.routes) { + if (typeof r.path === "string") { + // Check if the path contains regex syntax characters + const hasRegexSyntax = /[[\]{}()*+?.,\\^$|#\s]/.test(r.path); + if (!hasRegexSyntax) { + // If no regex syntax, treat as plain string match + if (path === r.path) { + return { ...r, params: {} }; + } + continue; + } + const match = new RegExp(r.path).exec(path); + if (match) { + return { ...r, params: match.groups || match.slice(1) }; + } + } else if (typeof r.path === "object") { + const match = r.path.exec(path); + if (match) { + return { ...r, params: match.groups || match.slice(1) }; + } + } + } + } + /** * Get the route for a given path. * @returns { Route } The route for the given path. @@ -145,30 +175,23 @@ export class Instance { get(path: string): Route | undefined { let route: Route | undefined; - let pathToMatch = path; - // If the base path is set, remove it from the path: - if (this.basePath && this.basePath !== "/") { - pathToMatch = path.replace(this.basePath, ""); - } + // Handle base path + const normalizedPath = this.basePath && this.basePath !== "/" + ? path.replace(this.basePath, "") + : path; - // If the path is the root path, return the root route: - if (pathToMatch === "/") { - route = this.routes.find((route) => route.path === "/"); + // Check for root path first + if (normalizedPath === "/") { + // return this.routes.find((route) => route.path === "/"); + return this.match(path); } - // Split the path into the first segment and the rest: - const [first, ...rest] = pathToMatch.replace(/^\//, "").split("/"); - route = this.routes.find((route) => route.path === first); - - // If the route is not found, try to find a route that matches at least part of the path: - if (!route) { - for (const r of this.routes) { - const regexp = new RegExp(r.path); - const match = regexp.exec(path); - if (match) { - route = { ...r, params: match.groups || match.slice(1) }; - break; - } + // Try to find a matching route using RegExp + for (const r of this.routes) { + const regexp = new RegExp(r.path); + const match = regexp.exec(normalizedPath); + if (match) { + return { ...r, params: match.groups || match.slice(1) }; } } diff --git a/test/app/src/app.svelte b/test/app/src/app.svelte index f0c44d0..912a280 100644 --- a/test/app/src/app.svelte +++ b/test/app/src/app.svelte @@ -14,7 +14,7 @@ const routes: Route[] = [ { - path: "^/$", + path: /^\/$/, component: Default }, { @@ -170,7 +170,7 @@

app.svelte

- +