Skip to content

Instantly share code, notes, and snippets.

@tannerlinsley
Created December 29, 2021 16:11
Show Gist options
  • Save tannerlinsley/b4285e52727aca94b8fd1a44b71fa4b4 to your computer and use it in GitHub Desktop.
Save tannerlinsley/b4285e52727aca94b8fd1a44b71fa4b4 to your computer and use it in GitHub Desktop.
import { multiSortBy } from 'src/shared/utils'
export type PathNode<T> = {
id: string
path: string
parentId: string
meta: T
children?: PathNode<T>[]
}
export function treeFromPathMap<TMeta>(
rootMeta: TMeta,
flatRouteDefs: Record<string, TMeta>
): [PathNode<TMeta>, PathNode<TMeta>[], Record<string, PathNode<TMeta>>] {
// We need to go from a flat pathMap to a tree-like structure:
// {
// index: index.js
// a: a.js
// b: b.js
// c: c.js
// c/index: c/index.js
// c/d: c/d.js
// }
// Becomes
// {
// path: '/',
// meta: 'index.js',
// children: [{
// path: 'a',
// meta: 'a.js'
// }, {
// path: 'b',
// meta: 'b.js'
// }, {
// path: 'c',
// meta: 'c.js',
// children: [{
// path: '/',
// meta: 'c/index.js'
// }, {
// path: 'd',
// meta: 'c/d.js'
// }]
// }]
// }
// Make sure the paths are in order from root to leaf
let sortedRouteDefs = multiSortBy(Object.keys(flatRouteDefs), [
(d) => d.split('/').length,
(d) => (d.endsWith('index') ? -1 : 1),
(d) => d,
]).map((id) => {
return {
id,
file: flatRouteDefs[id],
}
})
// The root node
let root: PathNode<TMeta> = {
id: 'root',
path: '/',
parentId: '',
meta: rootMeta,
children: [],
}
// A flat list of the final node objects
let flatRoutes: PathNode<TMeta>[] = [root]
sortedRouteDefs.forEach(({ id, file }) => {
// Reduce each node's full path to build the sub-tre
const parts = id === '/' ? ['/'] : id.split('/')
parts.reduce((parent, pathPart) => {
const found = parent.children?.find((d) => d.path === pathPart)
if (found) {
return found
}
parent.children = parent.children ?? []
const resolvedPath = pathPart === 'index' ? '/' : pathPart
const pathNode: PathNode<TMeta> = {
path: resolvedPath,
id: [parent.id, pathPart].join('/'),
parentId: parent.id,
meta: file,
}
flatRoutes.push(pathNode)
parent.children.push(pathNode)
return pathNode
}, root)
})
//
const nodesByPath = flatRoutes.filter(Boolean).reduce((obj, node) => {
obj[node.path] = node
return obj
}, {} as Record<string, PathNode<TMeta>>)
return [root, flatRoutes, nodesByPath]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment