-
-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create route methods implementation #31
Changes from all commits
5f372db
172fad4
c339a90
cbbf863
4869821
5abf5c6
6458a53
c409c70
cf7a457
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { describe, expect, test } from 'vitest' | ||
import { Routes } from '@/types' | ||
import { createRouteMethods, resolveRoutes } from '@/utilities' | ||
import { component } from '@/utilities/testHelpers' | ||
|
||
describe('createRouteMethods', () => { | ||
test.each([ | ||
[undefined], | ||
[true], | ||
Comment on lines
+7
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't look like you're using these values in your test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
])('given route is named and is public, makes parent callable', (isPublic) => { | ||
const routes = [ | ||
{ | ||
name: 'parent', | ||
path: '/parent', | ||
public: isPublic, | ||
component, | ||
}, | ||
] as const satisfies Routes | ||
const resolved = resolveRoutes(routes) | ||
|
||
const response = createRouteMethods(resolved) | ||
|
||
expect(response.parent).toBeTypeOf('function') | ||
}) | ||
|
||
test('given route is NOT public, returns empty object', () => { | ||
const routes = [ | ||
{ | ||
name: 'parent', | ||
path: '/parent', | ||
public: false, | ||
component, | ||
}, | ||
] as const satisfies Routes | ||
const resolved = resolveRoutes(routes) | ||
|
||
const response = createRouteMethods(resolved) | ||
|
||
expect(response).toMatchObject({}) | ||
}) | ||
|
||
test.each([ | ||
[undefined], | ||
[true], | ||
[false], | ||
])('given parent route with named children, has property for child name', (isPublic) => { | ||
const routes = [ | ||
{ | ||
name: 'parent', | ||
path: '/parent', | ||
children: [ | ||
{ | ||
name: 'child', | ||
path: '/child', | ||
public: isPublic, | ||
component, | ||
}, | ||
], | ||
}, | ||
] as const satisfies Routes | ||
const resolved = resolveRoutes(routes) | ||
|
||
const response = createRouteMethods(resolved) | ||
|
||
expect(response.parent.child).toBeDefined() | ||
|
||
if (isPublic !== false) { | ||
expect(response.parent.child).toBeTypeOf('function') | ||
} | ||
}) | ||
|
||
test('given parent route with named children and grandchildren, has path to grandchild all callable', () => { | ||
const routes = [ | ||
{ | ||
name: 'parent', | ||
path: '/parent', | ||
children: [ | ||
{ | ||
name: 'child', | ||
path: '/child', | ||
children: [ | ||
{ | ||
name: 'grandchild', | ||
path: '/grandchild', | ||
component, | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
] as const satisfies Routes | ||
const resolved = resolveRoutes(routes) | ||
|
||
const response = createRouteMethods(resolved) | ||
|
||
expect(response.parent).toBeTypeOf('function') | ||
expect(response.parent.child).toBeTypeOf('function') | ||
expect(response.parent.child.grandchild).toBeTypeOf('function') | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { Resolved, Route, RouteMethodRoute, isPublicRoute } from '@/types' | ||
import { assembleUrl } from '@/utilities/urlAssembly' | ||
|
||
type NonCallableNode = Record<string, any> | ||
type CallableNode = NonCallableNode & { | ||
(values: Record<string, unknown[]>): RouteMethodRoute, | ||
} | ||
type Node = CallableNode | NonCallableNode | ||
Comment on lines
+4
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm assuming these types will get replaced with some of the types in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep, this these types are super wide and intended to just prove that the logic is working. I'm hoping we can replace these with something much better this afternoon |
||
|
||
export function createRouteMethods(routes: Resolved<Route>[]): Record<string, Node> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll probably want to use generics here somehow. Because we already have a type for But I assume you're accepting |
||
const methods: Record<string, any> = {} | ||
|
||
routes.forEach(route => { | ||
const currentLevel = traverseParents(route, methods) | ||
const routeNode = createNodeForRoute(route) | ||
|
||
Object.assign(routeNode, currentLevel[route.name]) | ||
|
||
currentLevel[route.name] = routeNode | ||
}) | ||
|
||
return methods | ||
} | ||
|
||
function traverseParents(route: Resolved<Route>, currentLevel: Record<string, any>): Record<string, any> { | ||
route.parentNames.forEach(parentName => { | ||
if (!currentLevel[parentName]) { | ||
currentLevel[parentName] = {} | ||
} | ||
|
||
currentLevel = currentLevel[parentName] | ||
}) | ||
|
||
return currentLevel | ||
} | ||
|
||
function createNodeForRoute(route: Resolved<Route>): Node { | ||
if (isPublicRoute(route.matched)) { | ||
return createCallableNode(route) | ||
} | ||
|
||
return {} | ||
} | ||
|
||
function createCallableNode(route: Resolved<Route>): CallableNode { | ||
const node: CallableNode = (values) => { | ||
return { | ||
push: () => null, | ||
replace: () => null, | ||
url: assembleUrl(route, values), | ||
} | ||
} | ||
|
||
return node | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
export * from './createRouteMethods' | ||
export * from './createRouter' | ||
export * from './mergeParams' | ||
export * from './paramValidation' | ||
export * from './params' | ||
export * from './paramsFinder' | ||
export * from './paramValidation' | ||
export * from './path' | ||
export * from './random' | ||
export * from './routeResolver' | ||
export * from './string' | ||
export * from './urlAssembly' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol curious what you ran into here. Guessing
T['name'][]
resolves to(string | undefined)[]
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exactly. Originally I thought I needed to retain values from
T
but not sure it was actually providing any value