Created
December 29, 2021 16:11
-
-
Save tannerlinsley/b4285e52727aca94b8fd1a44b71fa4b4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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