diff --git a/packages/cli/src/Codegen.ts b/packages/cli/src/Codegen.ts index f4258fc..297639b 100644 --- a/packages/cli/src/Codegen.ts +++ b/packages/cli/src/Codegen.ts @@ -62,7 +62,7 @@ export class Codegen { const name = this.keyToClassName.get(route.localKey) const parentName = route.parent ? this.keyToClassName.get(route.parent.localKey) : 'undefined' const params = route.parent ? `parent: ${parentName}` : '' - const path = route.path.map(p => typeof p === 'string' ? p : `{${p.name}}`).join('/') + const path = route.path.map(p => typeof p === 'string' ? p : `{${p.name}}`).join('/').replace(/\/\*\//g, '/') return ` class ${name} extends Route<${parentName}, RouteParams['${route.localKey}']> { constructor(${params}) { diff --git a/packages/cli/test/__snapshots__/generate.spec.ts.snap b/packages/cli/test/__snapshots__/generate.spec.ts.snap index 84e0aee..5670da9 100644 --- a/packages/cli/test/__snapshots__/generate.spec.ts.snap +++ b/packages/cli/test/__snapshots__/generate.spec.ts.snap @@ -210,6 +210,8 @@ interface RouteParams { 'root': void, 'root.account': void, 'root.studios': { search?: string }, + 'root.studios.studio': { studioId: string }, + 'root.studios.studio.stacks': { studioId: string }, 'root.download': { platform?: 'mac' | 'debian' | 'windows' } } @@ -254,6 +256,34 @@ class StudiosRoute extends Route { ) } + studio = new StudioRoute(this) +} + + + +class StudioRoute extends Route { + constructor(parent: StudiosRoute) { + super( + 'root.studios.studio', + '/studios/{studioId}/*', parent, + { studioId: 'string' }, + ) + } + + stacks = new StacksRoute(this) +} + + + +class StacksRoute extends Route { + constructor(parent: StudioRoute) { + super( + 'root.studios.studio.stacks', + '/studios/{studioId}/stacks/*', parent, + { studioId: 'string' }, + ) + } + } @@ -280,6 +310,8 @@ const routeByKey: RouteByKey = { 'root': root, 'root.account': root.account, 'root.studios': root.studios, + 'root.studios.studio': root.studios.studio, + 'root.studios.studio.stacks': root.studios.studio.stacks, 'root.download': root.download } @@ -289,6 +321,8 @@ interface RouteByKey { 'root': RootRoute, 'root.account': AccountRoute, 'root.studios': StudiosRoute, + 'root.studios.studio': StudioRoute, + 'root.studios.studio.stacks': StacksRoute, 'root.download': DownloadRoute } diff --git a/packages/cli/test/navigation.parent.yaml b/packages/cli/test/navigation.parent.yaml index 0fd31c5..9789c92 100644 --- a/packages/cli/test/navigation.parent.yaml +++ b/packages/cli/test/navigation.parent.yaml @@ -2,5 +2,7 @@ + account (/account/*): + studios (/studios/*): search: string + + studio (/{studioId}/*): + + stacks (/stacks/*): + download (/download): platform: string ('mac' | 'debian' | 'windows') diff --git a/packages/runtime/src/CitronNavigator.ts b/packages/runtime/src/CitronNavigator.ts index ddb7db5..833a9cc 100644 --- a/packages/runtime/src/CitronNavigator.ts +++ b/packages/runtime/src/CitronNavigator.ts @@ -43,6 +43,28 @@ export class CitronNavigator { return CitronNavigator.instance } + /** + * Copies every child route of `source` to `target` if the child route of `source` doesn't exist in `target`. + * + * If a child of `source` exists in `target`, but it's path includes a wildcard (/*), we recursively copy its children to the same route + * in `target`. + * @param source the route to have its children copied. + * @param target the route to copy the children to. + */ + private copy(source: AnyRoute, target: AnyRoute) { + Object.keys(source).forEach((key) => { + const k = key as keyof AnyRoute + if (!k.startsWith('$') && source[k] instanceof Route) { + if (!(k in target)) { + source[k].$parent = target + target[k] = source[k] + } else if (source[k].$path.endsWith('/*')) { + this.copy(source[k], target[k]) + } + } + }) + } + /** * Updates the navigation tree by merging a node with another. * @@ -86,13 +108,8 @@ export class CitronNavigator { ) } }) - // copy all the child routes that existed in the old route, but don't exist in the new one (merge): - Object.keys(oldRoute).forEach((key) => { - if (!key.startsWith('$') && !(key in route) && oldRoute[key] instanceof Route) { - oldRoute[key].$parent = route - route[key as keyof typeof route] = oldRoute[key] - } - }) + + this.copy(oldRoute, route) this.updateRoute() }