From 35af202fbc3de5c06bb4f55fafaed70f4a980df0 Mon Sep 17 00:00:00 2001 From: Sven Rogge Date: Wed, 1 Apr 2026 01:21:53 +0200 Subject: [PATCH 1/2] fix: restrict route guard property to function type only The `"?"` key in `Routes` now only accepts `Resolve` (a guard function), not a sub-routes object. Adds a type test to verify the constraint, and bumps versions to 0.12.2. Closes #10 --- packages/esroute-lit/package.json | 4 ++-- packages/esroute/package.json | 2 +- packages/esroute/src/route-resolver.spec.ts | 11 +++++++++++ packages/esroute/src/route-resolver.ts | 5 +++-- packages/esroute/src/routes.ts | 3 ++- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/esroute-lit/package.json b/packages/esroute-lit/package.json index 8088d4a..382cbac 100644 --- a/packages/esroute-lit/package.json +++ b/packages/esroute-lit/package.json @@ -1,6 +1,6 @@ { "name": "@esroute/lit", - "version": "0.12.1", + "version": "0.12.2", "description": "A small efficient client-side routing library for lit, written in TypeScript.", "main": "dist/index.js", "sideEffects": false, @@ -22,7 +22,7 @@ "typescript": "^5.4.5" }, "dependencies": { - "esroute": "^0.12.1", + "esroute": "^0.12.2", "lit": "^3.1.1" } } diff --git a/packages/esroute/package.json b/packages/esroute/package.json index 42f450e..f678caa 100644 --- a/packages/esroute/package.json +++ b/packages/esroute/package.json @@ -1,6 +1,6 @@ { "name": "esroute", - "version": "0.12.1", + "version": "0.12.2", "description": "A small efficient framework-agnostic client-side routing library, written in TypeScript.", "types": "dist/index.d.ts", "main": "dist/index.js", diff --git a/packages/esroute/src/route-resolver.spec.ts b/packages/esroute/src/route-resolver.spec.ts index 57ce57c..3e2aab8 100644 --- a/packages/esroute/src/route-resolver.spec.ts +++ b/packages/esroute/src/route-resolver.spec.ts @@ -273,6 +273,17 @@ describe("Resolver", () => { }); }); + describe("types", () => { + it("should not allow a route object as guard", () => { + // @ts-expect-error "?" must be a function, not a sub-routes object + const _routes: Routes = { "?": { foo: () => "foo" } }; + }); + + it("should allow a function as guard", () => { + const _routes: Routes = { "?": () => undefined }; + }); + }); + describe("redirects", () => { it("should resolve a redirect via calling 'go()'", async () => { const navOpts = new NavOpts("/foo"); diff --git a/packages/esroute/src/route-resolver.ts b/packages/esroute/src/route-resolver.ts index b69ec2f..9a63fb6 100644 --- a/packages/esroute/src/route-resolver.ts +++ b/packages/esroute/src/route-resolver.ts @@ -49,13 +49,13 @@ const getResolves = async ( ): Promise => { const { path, params } = opts; const resolves: Resolve[] = []; - let routes: Routes | Resolve | null = root; + let routes: Routes | Resolve | null | undefined = root; for (let i = 0; i < path.length; i++) { const part = path[i]; if (!routes || typeof routes === "function") return null; const redirect = await checkGuard(routes, opts); if (redirect) return [() => redirect]; - const virtual: Routes | Resolve | void = routes[""]; + const virtual: Routes | Resolve | undefined = routes[""]; if (typeof virtual === "function") resolves.unshift(virtual); if (part in routes) routes = routes[part]; else if ("*" in routes) { @@ -73,6 +73,7 @@ const getResolves = async ( resolves.unshift(routes); return resolves; } + if (!routes) return null; const redirect = await checkGuard(routes, opts); if (redirect) return [() => redirect]; } while ((routes = routes[""])); diff --git a/packages/esroute/src/routes.ts b/packages/esroute/src/routes.ts index ca9563f..ad2cdc3 100644 --- a/packages/esroute/src/routes.ts +++ b/packages/esroute/src/routes.ts @@ -10,7 +10,8 @@ export type Resolve = ( ) => T | NavOpts | Promise>; export interface Routes { - [k: string]: Routes | Resolve; + "?"?: Resolve; + [k: string]: Routes | Resolve | undefined; } // Depth counter using a string to track recursion depth (max 10 levels) From 2a5f7d67a244fdb35fbdf1fe12fd85eda82cced3 Mon Sep 17 00:00:00 2001 From: Sven Rogge Date: Wed, 1 Apr 2026 01:38:39 +0200 Subject: [PATCH 2/2] docs: add changelog entry for 0.12.2 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7a3b2c..52220f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.12.2] - 2026-04-01 + +### Fixed +- Route guard property `"?"` is now restricted to function type only, preventing accidental assignment of sub-routes objects (closes #10) + ## [0.12.1] - 2026-04-01 ### Fixed