From 59bb8c4f77d83ddd6280e11879651598de787ee2 Mon Sep 17 00:00:00 2001 From: olliethedev <3martynov@gmail.com> Date: Tue, 24 Feb 2026 13:05:16 -0500 Subject: [PATCH 1/2] feat: add routeKey to getRoute return type --- package.json | 2 +- src/__tests__/router.test.ts | 47 ++++++++++++++++++++++++++++++++++++ src/router.ts | 13 ++++++++-- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 9fe384b..0844a52 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@btst/yar", - "version": "1.1.1", + "version": "1.2.0", "packageManager": "pnpm@10.14.0", "description": "Pluggable router for modern react frameworks", "type": "module", diff --git a/src/__tests__/router.test.ts b/src/__tests__/router.test.ts index 0b19f4f..70a9818 100644 --- a/src/__tests__/router.test.ts +++ b/src/__tests__/router.test.ts @@ -994,3 +994,50 @@ describe("Edge cases", () => { } }); }); + +describe("routeKey", () => { + it("should expose the route key on a matched route", () => { + const routes = { + home: createRoute("/", () => ({ PageComponent: MockComponent })), + about: createRoute("/about", () => ({ PageComponent: AnotherComponent })), + }; + + const router = createRouter(routes); + + expect(router.getRoute("/")?.routeKey).toBe("home"); + expect(router.getRoute("/about")?.routeKey).toBe("about"); + }); + + it("should return null for unmatched paths (no routeKey)", () => { + const routes = { + home: createRoute("/", () => ({ PageComponent: MockComponent })), + }; + + const router = createRouter(routes); + expect(router.getRoute("/missing")).toBeNull(); + }); + + it("should set the correct routeKey for parameterised routes", () => { + const routes = { + post: createRoute("/posts/:slug", () => ({ PageComponent: MockComponent })), + user: createRoute("/users/:id", () => ({ PageComponent: AnotherComponent })), + }; + + const router = createRouter(routes); + + expect(router.getRoute("/posts/hello-world")?.routeKey).toBe("post"); + expect(router.getRoute("/users/42")?.routeKey).toBe("user"); + }); + + it("should set the correct routeKey when exact and parameterised routes overlap", () => { + const routes = { + me: createRoute("/users/me", () => ({ PageComponent: MockComponent })), + user: createRoute("/users/:id", () => ({ PageComponent: AnotherComponent })), + }; + + const router = createRouter(routes); + + expect(router.getRoute("/users/me")?.routeKey).toBe("me"); + expect(router.getRoute("/users/123")?.routeKey).toBe("user"); + }); +}); diff --git a/src/router.ts b/src/router.ts index 3ff2eae..264921c 100644 --- a/src/router.ts +++ b/src/router.ts @@ -104,11 +104,13 @@ type ExtractRouteReturn = R extends (...args: any[]) => infer Return ? Return : never; -// The return type for getRoute, combining each handler return with params -// We distribute the intersection over the union to preserve all properties +// The return type for getRoute, combining each handler return with params and routeKey. +// Distributing the mapped type over the union preserves the discriminated union so +// TypeScript can narrow params and other properties based on routeKey. type GetRouteReturn> = { [K in keyof Routes]: ExtractRouteReturn & { params: Record; + routeKey: K; }; }[keyof Routes]; @@ -192,6 +194,12 @@ export const createRouter = < extra, } = responseObj; + // Resolve the route key by finding the entry whose handler is the same + // reference as the one the internal router matched. + const routeKey = Object.entries(routes).find( + ([, v]) => v === handler, + )?.[0] as keyof E | undefined; + return { PageComponent, LoadingComponent, @@ -200,6 +208,7 @@ export const createRouter = < loader, meta, extra, + routeKey, } as GetRouteReturn; }, }; From 4abaddeeaced5022630ce1eee879aed144d38a9a Mon Sep 17 00:00:00 2001 From: olliethedev <3martynov@gmail.com> Date: Tue, 24 Feb 2026 13:06:57 -0500 Subject: [PATCH 2/2] lint: fix lint issue --- src/__tests__/router.test.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/__tests__/router.test.ts b/src/__tests__/router.test.ts index 70a9818..83539e1 100644 --- a/src/__tests__/router.test.ts +++ b/src/__tests__/router.test.ts @@ -1019,8 +1019,12 @@ describe("routeKey", () => { it("should set the correct routeKey for parameterised routes", () => { const routes = { - post: createRoute("/posts/:slug", () => ({ PageComponent: MockComponent })), - user: createRoute("/users/:id", () => ({ PageComponent: AnotherComponent })), + post: createRoute("/posts/:slug", () => ({ + PageComponent: MockComponent, + })), + user: createRoute("/users/:id", () => ({ + PageComponent: AnotherComponent, + })), }; const router = createRouter(routes); @@ -1032,7 +1036,9 @@ describe("routeKey", () => { it("should set the correct routeKey when exact and parameterised routes overlap", () => { const routes = { me: createRoute("/users/me", () => ({ PageComponent: MockComponent })), - user: createRoute("/users/:id", () => ({ PageComponent: AnotherComponent })), + user: createRoute("/users/:id", () => ({ + PageComponent: AnotherComponent, + })), }; const router = createRouter(routes);