})
})
+ it('adds children', () => {
+ const matcher = createRouterMatcher([], {})
+ matcher.addRoute({ path: '/parent', component, name: 'home' })
+ const parent = matcher.getRecordMatcher('home')
+ matcher.addRoute({ path: 'foo', component, name: 'foo' }, parent)
+ expect(
+ matcher.resolve({ path: '/parent/foo' }, currentLocation)
+ ).toMatchObject({
+ name: 'foo',
+ matched: [
+ expect.objectContaining({ name: 'home' }),
+ expect.objectContaining({ name: 'foo' }),
+ ],
+ })
+ })
+
describe('addRoute returned function', () => {
it('remove records', () => {
const matcher = createRouterMatcher([], {})
})
it.todo('remove aliases')
- it.todo('remove children')
it.todo('remove aliases children')
+
+ it('remove children when removing the parent', () => {
+ const matcher = createRouterMatcher([], {})
+ const remove = matcher.addRoute({
+ path: '/',
+ component,
+ name: 'home',
+ children: [
+ // absolute path so it can work out
+ { path: '/about', name: 'child', component },
+ ],
+ })
+
+ remove()
+
+ expect(
+ matcher.resolve({ path: '/about' }, currentLocation)
+ ).toMatchObject({
+ name: undefined,
+ matched: [],
+ })
+
+ expect(matcher.getRecordMatcher('child')).toBe(undefined)
+ expect(() => {
+ matcher.resolve({ name: 'child' }, currentLocation)
+ }).toThrow()
+ })
})
it('can remove records by name', () => {
})
})
- it('removes children', () => {
+ it('removes children when removing the parent', () => {
const matcher = createRouterMatcher([], {})
matcher.addRoute({
path: '/',
name: 'home',
children: [
// absolute path so it can work out
- { path: '/about', component },
+ { path: '/about', name: 'child', component },
],
})
name: undefined,
matched: [],
})
+
+ expect(matcher.getRecordMatcher('child')).toBe(undefined)
+ expect(() => {
+ matcher.resolve({ name: 'child' }, currentLocation)
+ }).toThrow()
})
it.todo('removes alias by name')
- it.todo('removes children by name')
+ it('removes children by name', () => {
+ const matcher = createRouterMatcher([], {})
+ matcher.addRoute({
+ path: '/',
+ component,
+ name: 'home',
+ children: [
+ // absolute path so it can work out
+ { path: '/about', name: 'child', component },
+ ],
+ })
+
+ matcher.removeRoute('child')
+
+ expect(matcher.resolve({ path: '/about' }, currentLocation)).toMatchObject({
+ name: undefined,
+ matched: [],
+ })
+
+ expect(matcher.getRecordMatcher('child')).toBe(undefined)
+ expect(() => {
+ matcher.resolve({ name: 'child' }, currentLocation)
+ }).toThrow()
+
+ expect(matcher.resolve({ path: '/' }, currentLocation)).toMatchObject({
+ name: 'home',
+ })
+ })
+
+ it.todo('removes children by name from parent')
+
it.todo('removes children alias by name')
})
}
)
})
+
+ it('resolves children with root as the parent', () => {
+ const Nested = { path: 'nested', name: 'nested', components }
+ const Parent = {
+ path: '/',
+ name: 'parent',
+ components,
+ children: [Nested],
+ }
+ assertRecordMatch(
+ Parent,
+ { path: '/nested' },
+ {
+ name: 'nested',
+ path: '/nested',
+ params: {},
+ matched: [Parent, { ...Nested, path: `/nested` }].map(
+ normalizeRouteRecord
+ ),
+ }
+ )
+ })
+
+ it('resolves children with parent with trailing slash', () => {
+ const Nested = { path: 'nested', name: 'nested', components }
+ const Parent = {
+ path: '/parent/',
+ name: 'parent',
+ components,
+ children: [Nested],
+ }
+ assertRecordMatch(
+ Parent,
+ { path: '/parent/nested' },
+ {
+ name: 'nested',
+ path: '/parent/nested',
+ params: {},
+ matched: [Parent, { ...Nested, path: `/parent/nested` }].map(
+ normalizeRouteRecord
+ ),
+ }
+ )
+ })
})
})
})
(name: Required<RouteRecord>['name']): void
}
// TODO:
- // getRoutes: () => RouteRecordMatcher
- // hasRoute: (name: Required<RouteRecord>['name']) => boolean
+ // getRoutes: () => RouteRecordMatcher[]
+ getRecordMatcher: (
+ name: Required<RouteRecord>['name']
+ ) => RouteRecordMatcher | undefined
resolve: (
location: Readonly<MatcherLocation>,
currentLocation: Readonly<MatcherLocationNormalized>
const matchers: RouteRecordMatcher[] = []
const matcherMap = new Map<string | symbol, RouteRecordMatcher>()
+ function getRecordMatcher(name: string) {
+ return matcherMap.get(name)
+ }
+
function addRoute(
record: Readonly<RouteRecord>,
parent?: RouteRecordMatcher
for (const normalizedRecord of normalizedRecords) {
let { path } = normalizedRecord
- // build up the path for nested routes if the child isn't an absolute route
- // only add the / delimiter if the child path isn't empty
+ // Build up the path for nested routes if the child isn't an absolute
+ // route. Only add the / delimiter if the child path isn't empty and if the
+ // parent path doesn't have a trailing slash
if (parent && path[0] !== '/') {
- normalizedRecord.path = parent.record.path + (path && '/' + path)
+ let parentPath = parent.record.path
+ let connectingSlash =
+ parentPath[parentPath.length - 1] === '/' ? '' : '/'
+ normalizedRecord.path =
+ parent.record.path + (path && connectingSlash + path)
}
// create the object before hand so it can be passed to children
// add initial routes
routes.forEach(route => addRoute(route))
- return { addRoute, resolve, removeRoute }
+ return { addRoute, resolve, removeRoute, getRecordMatcher }
}
/**