diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 976d1a3..554e309 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@stack-spot/citron-navigator", - "version": "1.5.0", + "version": "1.6.0", "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/runtime/src/CitronNavigator.ts b/packages/runtime/src/CitronNavigator.ts index 833a9cc..6bc70f9 100644 --- a/packages/runtime/src/CitronNavigator.ts +++ b/packages/runtime/src/CitronNavigator.ts @@ -143,14 +143,20 @@ export class CitronNavigator { }, []) } - private findRouteByPath(route: Route, path: string): Route | undefined { + private findRouteByPath(route: Route, path: string, lastMatch?: Route): Route | undefined { switch (route.$match(path)) { - case 'exact': return route + case 'exact': + return route.$path.endsWith('*') + ? this.childrenOf(route).reduce( + (result, child) => result ?? this.findRouteByPath(child, path, route), + undefined, + ) ?? route + : route case 'subroute': return this.childrenOf(route).reduce( - (result, child) => result ?? this.findRouteByPath(child, path), + (result, child) => result ?? this.findRouteByPath(child, path, lastMatch), undefined, - ) ?? (route.$path.endsWith('*') ? route : undefined) + ) ?? (route.$path.endsWith('*') ? route : lastMatch) } } diff --git a/packages/runtime/test/CitronNavigator.spec.ts b/packages/runtime/test/CitronNavigator.spec.ts index e96fc4d..1f1d78c 100644 --- a/packages/runtime/test/CitronNavigator.spec.ts +++ b/packages/runtime/test/CitronNavigator.spec.ts @@ -130,6 +130,24 @@ describe('Citron Navigator', () => { expect(navigator.currentParams).toEqual({ studioId: 'studio1', stackId: 'stack1', starterId: 'starter1', str: 'test' }) })) + describe('should use deep wildcard instead of shallow', testHash({ + routeFactory: () => new AlternativeRootRoute(), + testFn: ({ p, navigator, route: root }) => { + mockLocation(`https://www.stackspot.com${p('/workspaces/a/stacks')}`) + navigator.updateRoute() + expect(navigator.currentRoute).toBe(root.workspaces.workspace.stacks) + expect(navigator.currentParams).toEqual({ workspaceId: 'a' }) + mockLocation(`https://www.stackspot.com${p('/workspaces/a')}`) + navigator.updateRoute() + expect(navigator.currentRoute).toBe(root.workspaces.workspace) + expect(navigator.currentParams).toEqual({ workspaceId: 'a' }) + mockLocation(`https://www.stackspot.com${p('/workspaces')}`) + navigator.updateRoute() + expect(navigator.currentRoute).toBe(root.workspaces) + expect(navigator.currentParams).toEqual({}) + }, + })) + describe('should deserialize route parameters', testHash({ locationFactory: (p) => { const urlParams = [ diff --git a/packages/runtime/test/routes.ts b/packages/runtime/test/routes.ts index 1d06f3a..733961b 100644 --- a/packages/runtime/test/routes.ts +++ b/packages/runtime/test/routes.ts @@ -93,6 +93,22 @@ export class WorkspacesRoute extends Route { constructor(parent: AlternativeRootRoute) { super('root.workspaces', '/workspaces/*', parent, {}) } + + workspace = new WorkspaceRoute(this) +} + +export class WorkspaceRoute extends Route { + constructor(parent: WorkspacesRoute) { + super('root.workspaces.workspace', '/workspaces/{workspaceId}/*', parent, { workspaceId: 'string' }) + } + + stacks = new WorkspaceStacksRoute(this) +} + +export class WorkspaceStacksRoute extends Route { + constructor(parent: WorkspaceRoute) { + super('root.workspaces.workspace.stacks', '/workspaces/{workspaceId}/stacks/*', parent, { workspaceId: 'string' }) + } } export class AccountRoute extends Route {