Skip to content

Commit

Permalink
feat(matcher): link aliases to their original record
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Mar 13, 2020
1 parent 3ca0675 commit e9eb648
Show file tree
Hide file tree
Showing 5 changed files with 350 additions and 16 deletions.
314 changes: 313 additions & 1 deletion __tests__/matcher/resolve.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,324 @@ describe('Router Matcher', () => {
components,
aliasOf: expect.objectContaining({ path: '/parent' }),
},
{ path: '/p/one', name: 'nested', components },
{
path: '/p/one',
name: 'nested',
components,
aliasOf: expect.objectContaining({ path: '/parent/one' }),
},
],
}
)
})

describe('nested aliases', () => {
const children = [
{
path: 'one',
component,
name: 'nested',
alias: 'o',
children: [
{ path: 'two', alias: 't', name: 'nestednested', component },
],
},
{
path: 'other',
alias: 'otherAlias',
component,
name: 'other',
},
]
const record = {
path: '/parent',
name: 'parent',
alias: '/p',
component,
children,
}

it('resolves the parent as an alias', () => {
assertRecordMatch(
record,
{ path: '/p' },
expect.objectContaining({
path: '/p',
name: 'parent',
matched: [
expect.objectContaining({
path: '/p',
aliasOf: expect.objectContaining({ path: '/parent' }),
}),
],
})
)
})

describe('multiple children', () => {
// tests concerning the /parent/other path and its aliases

it('resolves the alias parent', () => {
assertRecordMatch(
record,
{ path: '/p/other' },
expect.objectContaining({
path: '/p/other',
name: 'other',
matched: [
expect.objectContaining({
path: '/p',
aliasOf: expect.objectContaining({ path: '/parent' }),
}),
expect.objectContaining({
path: '/p/other',
aliasOf: expect.objectContaining({ path: '/parent/other' }),
}),
],
})
)
})

it('resolves the alias child', () => {
assertRecordMatch(
record,
{ path: '/parent/otherAlias' },
expect.objectContaining({
path: '/parent/otherAlias',
name: 'other',
matched: [
expect.objectContaining({
path: '/parent',
aliasOf: undefined,
}),
expect.objectContaining({
path: '/parent/otherAlias',
aliasOf: expect.objectContaining({ path: '/parent/other' }),
}),
],
})
)
})

it('resolves the alias parent and child', () => {
assertRecordMatch(
record,
{ path: '/p/otherAlias' },
expect.objectContaining({
path: '/p/otherAlias',
name: 'other',
matched: [
expect.objectContaining({
path: '/p',
aliasOf: expect.objectContaining({ path: '/parent' }),
}),
expect.objectContaining({
path: '/p/otherAlias',
aliasOf: expect.objectContaining({ path: '/parent/other' }),
}),
],
})
)
})
})

it('resolves the original one with no aliases', () => {
assertRecordMatch(
record,
{ path: '/parent/one/two' },
expect.objectContaining({
path: '/parent/one/two',
name: 'nestednested',
matched: [
expect.objectContaining({
path: '/parent',
aliasOf: undefined,
}),
expect.objectContaining({
path: '/parent/one',
aliasOf: undefined,
}),
expect.objectContaining({
path: '/parent/one/two',
aliasOf: undefined,
}),
],
})
)
})

it('resolves when parent is an alias', () => {
assertRecordMatch(
record,
{ path: '/p/one/two' },
expect.objectContaining({
path: '/p/one/two',
name: 'nestednested',
matched: [
expect.objectContaining({
path: '/p',
aliasOf: expect.objectContaining({ path: '/parent' }),
}),
expect.objectContaining({
path: '/p/one',
aliasOf: expect.objectContaining({ path: '/parent/one' }),
}),
expect.objectContaining({
path: '/p/one/two',
aliasOf: expect.objectContaining({ path: '/parent/one/two' }),
}),
],
})
)
})

it('resolves a different child when parent is an alias', () => {
assertRecordMatch(
record,
{ path: '/p/other' },
expect.objectContaining({
path: '/p/other',
name: 'other',
matched: [
expect.objectContaining({
path: '/p',
aliasOf: expect.objectContaining({ path: '/parent' }),
}),
expect.objectContaining({
path: '/p/other',
aliasOf: expect.objectContaining({ path: '/parent/other' }),
}),
],
})
)
})

it('resolves when the first child is an alias', () => {
assertRecordMatch(
record,
{ path: '/parent/o/two' },
expect.objectContaining({
path: '/parent/o/two',
name: 'nestednested',
matched: [
expect.objectContaining({
path: '/parent',
aliasOf: undefined,
}),
expect.objectContaining({
path: '/parent/o',
aliasOf: expect.objectContaining({ path: '/parent/one' }),
}),
expect.objectContaining({
path: '/parent/o/two',
aliasOf: expect.objectContaining({ path: '/parent/one/two' }),
}),
],
})
)
})

it('resolves when the second child is an alias', () => {
assertRecordMatch(
record,
{ path: '/parent/one/t' },
expect.objectContaining({
path: '/parent/one/t',
name: 'nestednested',
matched: [
expect.objectContaining({
path: '/parent',
aliasOf: undefined,
}),
expect.objectContaining({
path: '/parent/one',
aliasOf: undefined,
}),
expect.objectContaining({
path: '/parent/one/t',
aliasOf: expect.objectContaining({ path: '/parent/one/two' }),
}),
],
})
)
})

it('resolves when the two last children are aliases', () => {
assertRecordMatch(
record,
{ path: '/parent/o/t' },
expect.objectContaining({
path: '/parent/o/t',
name: 'nestednested',
matched: [
expect.objectContaining({
path: '/parent',
aliasOf: undefined,
}),
expect.objectContaining({
path: '/parent/o',
aliasOf: expect.objectContaining({ path: '/parent/one' }),
}),
expect.objectContaining({
path: '/parent/o/t',
aliasOf: expect.objectContaining({ path: '/parent/one/two' }),
}),
],
})
)
})

it('resolves when all are aliases', () => {
assertRecordMatch(
record,
{ path: '/p/o/t' },
expect.objectContaining({
path: '/p/o/t',
name: 'nestednested',
matched: [
expect.objectContaining({
path: '/p',
aliasOf: expect.objectContaining({ path: '/parent' }),
}),
expect.objectContaining({
path: '/p/o',
aliasOf: expect.objectContaining({ path: '/parent/one' }),
}),
expect.objectContaining({
path: '/p/o/t',
aliasOf: expect.objectContaining({ path: '/parent/one/two' }),
}),
],
})
)
})

it('resolves when first and last are aliases', () => {
assertRecordMatch(
record,
{ path: '/p/one/t' },
expect.objectContaining({
path: '/p/one/t',
name: 'nestednested',
matched: [
expect.objectContaining({
path: '/p',
aliasOf: expect.objectContaining({ path: '/parent' }),
}),
expect.objectContaining({
path: '/p/one',
aliasOf: expect.objectContaining({ path: '/parent/one' }),
}),
expect.objectContaining({
path: '/p/one/t',
aliasOf: expect.objectContaining({ path: '/parent/one/two' }),
}),
],
})
)
})
})

it('resolves the original path of the named children of a route with an alias', () => {
const children = [{ path: 'one', component, name: 'nested' }]
assertRecordMatch(
Expand Down
30 changes: 22 additions & 8 deletions src/matcher/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ export function createRouterMatcher(
// TODO: add routes to children of parent
function addRoute(
record: Readonly<RouteRecord>,
parent?: RouteRecordMatcher
parent?: RouteRecordMatcher,
originalRecord?: RouteRecordMatcher
) {
const mainNormalizedRecord = normalizeRouteRecord(record)
let mainNormalizedRecord = normalizeRouteRecord(record)
// we might be the child of an alias
mainNormalizedRecord.aliasOf = originalRecord && originalRecord.record
const options: PathParserOptions = { ...globalOptions, ...record.options }
// generate an array of records to correctly handle aliases
const normalizedRecords: RouteRecordNormalized[] = [mainNormalizedRecord]
Expand All @@ -60,7 +63,10 @@ export function createRouterMatcher(
normalizedRecords.push({
...mainNormalizedRecord,
path: alias,
aliasOf: mainNormalizedRecord,
// we might be the child of an alias
aliasOf: originalRecord
? originalRecord.record
: mainNormalizedRecord,
})
}
}
Expand All @@ -83,11 +89,19 @@ export function createRouterMatcher(
// create the object before hand so it can be passed to children
matcher = createRouteRecordMatcher(normalizedRecord, parent, options)

if ('children' in record) {
for (const childRecord of record.children!)
addRoute(childRecord, matcher)
let children = mainNormalizedRecord.children
for (let i = 0; i < children.length; i++) {
addRoute(
children[i],
matcher,
originalRecord && originalRecord.children[i]
)
}

// if there was no original record, then the first one was not an alias and all
// other alias (if any) need to reference this record when adding children
originalRecord = originalRecord || matcher

insertMatcher(matcher)
}

Expand Down Expand Up @@ -235,8 +249,8 @@ export function normalizeRouteRecord(
return {
path: record.path,
components,
// fallback to empty array for monomorphic objects
children: (record as any).children,
// record is an object and if it has a children property, it's an array
children: (record as any).children || [],
name: record.name,
beforeEnter,
meta: record.meta || {},
Expand Down
Loading

0 comments on commit e9eb648

Please sign in to comment.