UNPKG

@tanstack/router-generator

Version:

Modern and scalable routing for React applications

1 lines 12.4 kB
{"version":3,"file":"getRouteNodes.cjs","sources":["../../../../src/filesystem/virtual/getRouteNodes.ts"],"sourcesContent":["import path, { join, resolve } from 'node:path'\nimport {\n removeExt,\n removeLeadingSlash,\n removeTrailingSlash,\n replaceBackslash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesPhysical } from '../physical/getRouteNodes'\nimport { rootPathId } from '../physical/rootPathId'\nimport { virtualRootRouteSchema } from './config'\nimport { loadConfigFile } from './loadConfigFile'\nimport type {\n VirtualRootRoute,\n VirtualRouteNode,\n} from '@tanstack/virtual-file-routes'\nimport type { GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\n\nfunction ensureLeadingUnderScore(id: string) {\n if (id.startsWith('_')) {\n return id\n }\n return `_${id}`\n}\n\nfunction flattenTree(node: RouteNode): Array<RouteNode> {\n const result = [node]\n\n if (node.children) {\n for (const child of node.children) {\n result.push(...flattenTree(child))\n }\n }\n delete node.children\n\n return result\n}\n\nexport async function getRouteNodes(\n tsrConfig: Pick<\n Config,\n | 'routesDirectory'\n | 'virtualRouteConfig'\n | 'routeFileIgnorePrefix'\n | 'disableLogging'\n | 'indexToken'\n | 'routeToken'\n >,\n root: string,\n): Promise<GetRouteNodesResult> {\n const fullDir = resolve(tsrConfig.routesDirectory)\n if (tsrConfig.virtualRouteConfig === undefined) {\n throw new Error(`virtualRouteConfig is undefined`)\n }\n let virtualRouteConfig: VirtualRootRoute\n if (typeof tsrConfig.virtualRouteConfig === 'string') {\n virtualRouteConfig = await getVirtualRouteConfigFromFileExport(\n tsrConfig,\n root,\n )\n } else {\n virtualRouteConfig = tsrConfig.virtualRouteConfig\n }\n const { children, physicalDirectories } = await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n virtualRouteConfig.children,\n )\n const allNodes = flattenTree({\n children,\n filePath: virtualRouteConfig.file,\n fullPath: replaceBackslash(join(fullDir, virtualRouteConfig.file)),\n variableName: 'root',\n routePath: `/${rootPathId}`,\n _fsRouteType: '__root',\n })\n\n const rootRouteNode = allNodes[0]\n const routeNodes = allNodes.slice(1)\n\n return { rootRouteNode, routeNodes, physicalDirectories }\n}\n\n/**\n * Get the virtual route config from a file export\n *\n * @example\n * ```ts\n * // routes.ts\n * import { rootRoute } from '@tanstack/virtual-file-routes'\n *\n * export const routes = rootRoute({ ... })\n * // or\n * export default rootRoute({ ... })\n * ```\n *\n */\nasync function getVirtualRouteConfigFromFileExport(\n tsrConfig: Pick<Config, 'virtualRouteConfig'>,\n root: string,\n): Promise<VirtualRootRoute> {\n if (\n tsrConfig.virtualRouteConfig === undefined ||\n typeof tsrConfig.virtualRouteConfig !== 'string' ||\n tsrConfig.virtualRouteConfig === ''\n ) {\n throw new Error(`virtualRouteConfig is undefined or empty`)\n }\n const exports = await loadConfigFile(join(root, tsrConfig.virtualRouteConfig))\n\n if (!('routes' in exports) && !('default' in exports)) {\n throw new Error(\n `routes not found in ${tsrConfig.virtualRouteConfig}. The routes export must be named like 'export const routes = ...' or done using 'export default ...'`,\n )\n }\n\n const virtualRouteConfig =\n 'routes' in exports ? exports.routes : exports.default\n\n return virtualRootRouteSchema.parse(virtualRouteConfig)\n}\n\nexport async function getRouteNodesRecursive(\n tsrConfig: Pick<\n Config,\n | 'routesDirectory'\n | 'routeFileIgnorePrefix'\n | 'disableLogging'\n | 'indexToken'\n | 'routeToken'\n >,\n root: string,\n fullDir: string,\n nodes?: Array<VirtualRouteNode>,\n parent?: RouteNode,\n): Promise<{ children: Array<RouteNode>; physicalDirectories: Array<string> }> {\n if (nodes === undefined) {\n return { children: [], physicalDirectories: [] }\n }\n const allPhysicalDirectories: Array<string> = []\n const children = await Promise.all(\n nodes.map(async (node) => {\n if (node.type === 'physical') {\n const { routeNodes, physicalDirectories } = await getRouteNodesPhysical(\n {\n ...tsrConfig,\n routesDirectory: resolve(fullDir, node.directory),\n },\n root,\n )\n allPhysicalDirectories.push(node.directory)\n routeNodes.forEach((subtreeNode) => {\n subtreeNode.variableName = routePathToVariable(\n `${node.pathPrefix}/${removeExt(subtreeNode.filePath)}`,\n )\n subtreeNode.routePath = `${parent?.routePath ?? ''}${node.pathPrefix}${subtreeNode.routePath}`\n subtreeNode.filePath = `${node.directory}/${subtreeNode.filePath}`\n })\n return routeNodes\n }\n\n function getFile(file: string) {\n const filePath = file\n const variableName = routePathToVariable(removeExt(filePath))\n const fullPath = replaceBackslash(join(fullDir, filePath))\n return { filePath, variableName, fullPath }\n }\n const parentRoutePath = removeTrailingSlash(parent?.routePath ?? '/')\n\n switch (node.type) {\n case 'index': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n const routePath = `${parentRoutePath}/`\n return {\n filePath,\n fullPath,\n variableName,\n routePath,\n _fsRouteType: 'static',\n } satisfies RouteNode\n }\n\n case 'route': {\n const lastSegment = node.path\n let routeNode: RouteNode\n\n const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`\n if (node.file) {\n const { filePath, variableName, fullPath } = getFile(node.file)\n routeNode = {\n filePath,\n fullPath,\n variableName,\n routePath,\n _fsRouteType: 'static',\n }\n } else {\n routeNode = {\n filePath: '',\n fullPath: '',\n variableName: routePathToVariable(routePath),\n routePath,\n isVirtual: true,\n _fsRouteType: 'static',\n }\n }\n\n if (node.children !== undefined) {\n const { children, physicalDirectories } =\n await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n node.children,\n routeNode,\n )\n routeNode.children = children\n allPhysicalDirectories.push(...physicalDirectories)\n\n // If the route has children, it should be a layout\n routeNode._fsRouteType = 'layout'\n }\n return routeNode\n }\n case 'layout': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n\n if (node.id !== undefined) {\n node.id = ensureLeadingUnderScore(node.id)\n } else {\n const baseName = path.basename(filePath)\n const fileNameWithoutExt = path.parse(baseName).name\n node.id = ensureLeadingUnderScore(fileNameWithoutExt)\n }\n const lastSegment = node.id\n const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`\n\n const routeNode: RouteNode = {\n fullPath,\n filePath,\n variableName,\n routePath,\n _fsRouteType: 'pathless_layout',\n }\n\n if (node.children !== undefined) {\n const { children, physicalDirectories } =\n await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n node.children,\n routeNode,\n )\n routeNode.children = children\n allPhysicalDirectories.push(...physicalDirectories)\n }\n return routeNode\n }\n }\n }),\n )\n return {\n children: children.flat(),\n physicalDirectories: allPhysicalDirectories,\n }\n}\n"],"names":["resolve","replaceBackslash","join","rootPathId","exports","loadConfigFile","virtualRootRouteSchema","getRouteNodesPhysical","routePathToVariable","removeExt","removeTrailingSlash","removeLeadingSlash","children"],"mappings":"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"}