Skip to content

Commit

Permalink
fix: deep merge meta properties
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Jul 26, 2022
1 parent 918bfd0 commit 47bce4f
Show file tree
Hide file tree
Showing 8 changed files with 285 additions and 51 deletions.
97 changes: 82 additions & 15 deletions src/codegen/__snapshots__/generateRouteRecords.spec.ts.snap
Expand Up @@ -37,21 +37,6 @@ exports[`generateRouteRecord > adds children and name when folder and component
]"
`;

exports[`generateRouteRecord > adds meta data 1`] = `
"[
{
path: '/',
name: '/',
component: () => import('index.vue'),
/* no children */
meta: {
\\"auth\\": true,
\\"title\\": \\"Home\\"
}
}
]"
`;

exports[`generateRouteRecord > correctly names index.vue files 1`] = `
"[
{
Expand Down Expand Up @@ -409,6 +394,88 @@ exports[`generateRouteRecord > nested children 2`] = `
]"
`;

exports[`generateRouteRecord > route block > adds meta data 1`] = `
"[
{
path: '/',
name: '/',
component: () => import('index.vue'),
/* no children */
meta: {
\\"auth\\": true,
\\"title\\": \\"Home\\"
}
}
]"
`;

exports[`generateRouteRecord > route block > handles named views with empty route blocks 1`] = `
"[
{
path: '/',
name: '/',
components: {
'default': () => import('index.vue'),
'named': () => import('index@named.vue')
},
/* no children */
meta: {
\\"auth\\": true,
\\"title\\": \\"Home\\"
}
}
]"
`;

exports[`generateRouteRecord > route block > merges deep meta properties 1`] = `
"[
{
path: '/',
name: '/',
component: () => import('index.vue'),
/* no children */
meta: {
\\"a\\": {
\\"one\\": 1,
\\"two\\": 1
},
\\"b\\": {
\\"a\\": [
2,
3
]
}
}
}
]"
`;

exports[`generateRouteRecord > route block > merges multiple meta properties 1`] = `
"[
{
path: '/custom',
name: 'hello',
component: () => import('index.vue'),
/* no children */
meta: {
\\"one\\": true,
\\"two\\": true
}
}
]"
`;

exports[`generateRouteRecord > route block > merges regardless of order 1`] = `
"[
{
path: '/',
name: 'b',
component: () => import('index.vue'),
/* no children */
}
]"
`;

exports[`generateRouteRecord > works with some paths at root 1`] = `
"[
{
Expand Down
123 changes: 114 additions & 9 deletions src/codegen/generateRouteRecords.spec.ts
Expand Up @@ -116,16 +116,121 @@ describe('generateRouteRecord', () => {
})
})

it('adds meta data', () => {
const tree = createPrefixTree(DEFAULT_OPTIONS)
const node = tree.insert('index.vue')
node.setCustomRouteBlock({
meta: {
auth: true,
title: 'Home',
},
describe('route block', () => {
it('adds meta data', async () => {
const tree = createPrefixTree(DEFAULT_OPTIONS)
const node = tree.insert('index.vue')
node.setCustomRouteBlock('index.vue', {
meta: {
auth: true,
title: 'Home',
},
})

expect(generateRouteRecord(tree)).toMatchSnapshot()
})

expect(generateRouteRecord(tree)).toMatchSnapshot()
it('merges multiple meta properties', async () => {
const tree = createPrefixTree(DEFAULT_OPTIONS)
const node = tree.insert('index.vue')
node.setCustomRouteBlock('index.vue', {
path: '/custom',
meta: {
one: true,
},
})
node.setCustomRouteBlock('index@named.vue', {
name: 'hello',
meta: {
two: true,
},
})

expect(generateRouteRecord(tree)).toMatchSnapshot()
})

it('merges regardless of order', async () => {
const tree = createPrefixTree(DEFAULT_OPTIONS)
const node = tree.insert('index.vue')
node.setCustomRouteBlock('index.vue', {
name: 'a',
})
node.setCustomRouteBlock('index@named.vue', {
name: 'b',
})

const one = generateRouteRecord(tree)

node.setCustomRouteBlock('index@named.vue', {
name: 'b',
})
node.setCustomRouteBlock('index.vue', {
name: 'a',
})

expect(generateRouteRecord(tree)).toBe(one)

expect(one).toMatchSnapshot()
})

it('handles named views with empty route blocks', () => {
const tree = createPrefixTree(DEFAULT_OPTIONS)
const node = tree.insert('index.vue')
const n2 = tree.insert('index@named.vue')
expect(node).toBe(n2)
// coming from index.vue
node.setCustomRouteBlock('index.vue', {
meta: {
auth: true,
title: 'Home',
},
})
// coming from index@named.vue (no route block)
node.setCustomRouteBlock('index@named.vue', undefined)

expect(generateRouteRecord(tree)).toMatchSnapshot()
})

// FIXME: allow aliases
it('merges alias properties', async () => {
const tree = createPrefixTree(DEFAULT_OPTIONS)
const node = tree.insert('index.vue')
node.setCustomRouteBlock('index.vue', {
alias: '/one',
})
node.setCustomRouteBlock('index@named.vue', {
alias: ['/two', '/three'],
})

expect(generateRouteRecord(tree)).toMatchInlineSnapshot(`
"[
{
path: '/',
name: '/',
component: () => import('index.vue'),
/* no children */
}
]"
`)
})

it('merges deep meta properties', async () => {
const tree = createPrefixTree(DEFAULT_OPTIONS)
const node = tree.insert('index.vue')
node.setCustomRouteBlock('index.vue', {
meta: {
a: { one: 1 },
b: { a: [2] },
},
})
node.setCustomRouteBlock('index@named.vue', {
meta: {
a: { two: 1 },
b: { a: [3] },
},
})

expect(generateRouteRecord(tree)).toMatchSnapshot()
})
})
})
4 changes: 2 additions & 2 deletions src/core/context.ts
Expand Up @@ -103,7 +103,7 @@ export function createRoutesContext(options: ResolvedOptions) {
// './' + path
resolve(root, path)
)
node.setCustomRouteBlock(routeBlock)
node.setCustomRouteBlock(path, routeBlock)
node.value.includeLoaderGuard = await hasNamedExports(path)

routeMap.set(path, node)
Expand All @@ -116,7 +116,7 @@ export function createRoutesContext(options: ResolvedOptions) {
console.warn(`Cannot update "${path}": Not found.`)
return
}
node.setCustomRouteBlock(await getRouteBlock(path, options))
node.setCustomRouteBlock(path, await getRouteBlock(path, options))
node.value.includeLoaderGuard = await hasNamedExports(path)
}

Expand Down
16 changes: 8 additions & 8 deletions src/core/tree.spec.ts
Expand Up @@ -297,31 +297,31 @@ describe('Tree', () => {
it('allows a custom name', () => {
const tree = createPrefixTree(DEFAULT_OPTIONS)
let leaf = tree.insert('[a]-[b].vue')
leaf.value.overrides = {
leaf.value.setOverride('', {
name: 'custom',
}
})
expect(leaf.name).toBe('custom')

leaf = tree.insert('auth/login.vue')
leaf.value.overrides = {
leaf.value.setOverride('', {
name: 'custom-child',
}
})
expect(leaf.name).toBe('custom-child')
})

it('allows a custom path', () => {
const tree = createPrefixTree(DEFAULT_OPTIONS)
let leaf = tree.insert('[a]-[b].vue')
leaf.value.overrides = {
leaf.value.setOverride('', {
path: '/custom',
}
})
expect(leaf.path).toBe('/custom')
expect(leaf.fullPath).toBe('/custom')

leaf = tree.insert('auth/login.vue')
leaf.value.overrides = {
leaf.value.setOverride('', {
path: '/custom-child',
}
})
expect(leaf.path).toBe('/custom-child')
expect(leaf.fullPath).toBe('/custom-child')
})
Expand Down
5 changes: 3 additions & 2 deletions src/core/tree.ts
Expand Up @@ -9,6 +9,7 @@ export class TreeLeaf {
* value of the node
*/
value: TreeLeafValue

/**
* children of the node
*/
Expand Down Expand Up @@ -54,8 +55,8 @@ export class TreeLeaf {
return child
}

setCustomRouteBlock(routeBlock: CustomRouteBlock | undefined) {
this.value.overrides = routeBlock || {}
setCustomRouteBlock(path: string, routeBlock: CustomRouteBlock | undefined) {
this.value.setOverride(path, routeBlock)
}

getSortedChildren() {
Expand Down
39 changes: 26 additions & 13 deletions src/core/treeLeafValue.ts
@@ -1,11 +1,17 @@
import { RouteMeta } from 'vue-router'
import { joinPath } from './utils'
import { RouteRecordRaw } from 'vue-router'
import { CustomRouteBlock } from './customBlock'
import { joinPath, mergeRouteRecordOverride } from './utils'

export const enum TreeLeafType {
static,
param,
}

export interface RouteRecordOverride
extends Partial<Pick<RouteRecordRaw, 'meta' | 'props' | 'alias' | 'path'>> {
name?: string
}

export type SubSegment = string | TreeRouteParam

class _TreeLeafValueBase {
Expand All @@ -32,17 +38,10 @@ class _TreeLeafValueBase {
*/
path: string

overrides: {
path?: string
/**
* Overridden name for this route.
*/
name?: string
/**
* Meta of the route
*/
meta?: RouteMeta
} = {}
/**
* Overrides defined by each file. The map is necessary to handle named views.
*/
private _overrides = new Map<string, RouteRecordOverride>()

includeLoaderGuard: boolean = false

Expand Down Expand Up @@ -81,6 +80,20 @@ class _TreeLeafValueBase {
isStatic(): this is TreeLeafValueStatic {
return this._type === TreeLeafType.static
}

get overrides() {
return [...this._overrides.entries()]
.sort(([nameA], [nameB]) =>
nameA === nameB ? 0 : nameA < nameB ? -1 : 1
)
.reduce((acc, [_path, routeBlock]) => {
return mergeRouteRecordOverride(acc, routeBlock)
}, {} as RouteRecordOverride)
}

setOverride(path: string, routeBlock: CustomRouteBlock | undefined) {
this._overrides.set(path, routeBlock || {})
}
}

export class TreeLeafValueStatic extends _TreeLeafValueBase {
Expand Down

0 comments on commit 47bce4f

Please sign in to comment.