Skip to content

Commit

Permalink
feat: add support for regex instances
Browse files Browse the repository at this point in the history
  • Loading branch information
mateothegreat committed Feb 22, 2025
1 parent d92bc5d commit b6d2ab9
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 24 deletions.
67 changes: 45 additions & 22 deletions src/lib/instance.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<any> | Snippet | (() => Promise<Component<any> | Snippet>) | Function | any;
props?: Record<string, any>;
pre?: PreHooks;
Expand Down Expand Up @@ -138,37 +138,60 @@ 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.
*/
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) };
}
}

Expand Down
4 changes: 2 additions & 2 deletions test/app/src/app.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
const routes: Route[] = [
{
path: "^/$",
path: /^\/$/,
component: Default
},
{
Expand Down Expand Up @@ -170,7 +170,7 @@
<div class=" w-full flex-1 bg-zinc-900 p-6">
<div class="flex flex-col gap-4 rounded-lg bg-zinc-950 p-4 shadow-xl">
<p class="text-center text-xs text-zinc-500">app.svelte</p>
<Router basePath="/mybasepath" bind:instance {routes} pre={globalAuthGuardHook} post={globalLoggerPostHook} />
<Router bind:instance {routes} pre={globalAuthGuardHook} post={globalLoggerPostHook} />
</div>
</div>
</div>

0 comments on commit b6d2ab9

Please sign in to comment.