{"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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"}