{"version":3,"file":"scanner.mjs","sources":["../../../src/lib/routing/scanner.ts"],"sourcesContent":["/**\n * @file Route File System Scanner\n * @description Discovers routes from file system with convention-based parsing and caching\n */\n\nimport type { Dirent } from 'fs';\nimport type { DiscoveredRoute, ParsedRouteSegment, DiscoveryConfig } from './types';\n\n// =============================================================================\n// Re-export core segment parsing utilities\n// =============================================================================\nimport {\n  parseRouteSegment as coreParseRouteSegment,\n  parseDirectoryPath as coreParseDirectoryPath,\n  segmentsToUrlPath as coreSegmentsToUrlPath,\n  generateRouteId as coreGenerateRouteId,\n  generateDisplayName as coreGenerateDisplayName,\n  extractParamNames as coreExtractParamNames,\n  hasDynamicSegments as coreHasDynamicSegments,\n  getStaticPrefix as coreGetStaticPrefix,\n} from './core';\n\n/**\n * Parse a filename or directory name into a route segment\n * @see core/segment-parser.ts for implementation details\n */\nexport function parseRouteSegment(filename: string): ParsedRouteSegment {\n  return coreParseRouteSegment(filename);\n}\n\n/**\n * Convert parsed segments to URL path\n * @see core/segment-parser.ts for implementation details\n */\nexport function segmentsToUrlPath(segments: readonly ParsedRouteSegment[]): string {\n  return coreSegmentsToUrlPath(segments as ParsedRouteSegment[]);\n}\n\n/**\n * Parse a full directory path into route segments\n * @see core/segment-parser.ts for implementation details\n */\nexport function parseDirectoryPath(\n  dirPath: string,\n  filename: string\n): readonly ParsedRouteSegment[] {\n  return coreParseDirectoryPath(dirPath, filename);\n}\n\n// =============================================================================\n// File System Scanning\n// =============================================================================\n\n/**\n * Check if a file should be ignored based on ignore patterns\n */\nfunction shouldIgnore(filePath: string, ignorePatterns: readonly string[]): boolean {\n  for (const pattern of ignorePatterns) {\n    // Convert glob pattern to regex\n    const regexPattern = pattern\n      .replace(/\\*\\*/g, '{{GLOBSTAR}}')\n      .replace(/\\*/g, '[^/]*')\n      .replace(/\\?/g, '.')\n      .replace(/\\{\\{GLOBSTAR\\}\\}/g, '.*')\n      .replace(/\\{([^}]+)\\}/g, (_: string, group: string) => `(${group.split(',').join('|')})`);\n\n    const regex = new RegExp(regexPattern);\n    if (regex.test(filePath)) {\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * Check if a file has a valid route extension\n */\nfunction hasValidExtension(filename: string, extensions: readonly string[]): boolean {\n  return extensions.some((ext) => filename.endsWith(ext));\n}\n\n/**\n * Build layout map from discovered routes\n */\nfunction buildLayoutMap(routes: DiscoveredRoute[], _scanPath: string): Map<string, string> {\n  const layoutMap = new Map<string, string>();\n\n  for (const route of routes) {\n    if (route.isLayout) {\n      // Get the directory containing the layout\n      const layoutDir = route.relativePath.replace(/[/\\\\][^/\\\\]+$/, '');\n      layoutMap.set(layoutDir || '.', route.filePath);\n    }\n  }\n\n  return layoutMap;\n}\n\n/**\n * Find parent layout for a route\n */\nfunction findParentLayout(\n  routeRelativePath: string,\n  layoutMap: Map<string, string>\n): string | undefined {\n  // Get the directory of the route\n  let searchPath = routeRelativePath.replace(/[/\\\\][^/\\\\]+$/, '');\n\n  // Walk up the directory tree looking for a layout\n  while (searchPath) {\n    if (layoutMap.has(searchPath)) {\n      return layoutMap.get(searchPath);\n    }\n    // Move up one directory\n    const parentPath = searchPath.replace(/[/\\\\][^/\\\\]+$/, '');\n    if (parentPath === searchPath) break;\n    searchPath = parentPath;\n  }\n\n  // Check root level\n  if (layoutMap.has('.')) {\n    return layoutMap.get('.');\n  }\n\n  return undefined;\n}\n\n/**\n * Scan a directory for route files (Node.js environment only - for build time)\n *\n * Note: This function uses dynamic imports for Node.js modules\n * and should only be called in build context (Vite plugin)\n */\nexport async function scanRouteFiles(\n  rootDir: string,\n  config: DiscoveryConfig\n): Promise<DiscoveredRoute[]> {\n  // Dynamic imports for Node.js modules (only available in build context)\n  const { promises: fs } = await import('fs');\n  const path = await import('path');\n\n  const routes: DiscoveredRoute[] = [];\n\n  for (const scanPath of config.scanPaths) {\n    const fullScanPath = path.resolve(rootDir, scanPath);\n\n    // Check if scan path exists\n    try {\n      await fs.access(fullScanPath);\n    } catch {\n      // Skip non-existent paths\n      continue;\n    }\n\n    // Recursively scan directory\n    const discoveredFiles = await scanDirectory(fullScanPath, fullScanPath, config, path, fs);\n\n    routes.push(...discoveredFiles);\n  }\n\n  // Build layout map and assign parent layouts\n  const layoutMap = buildLayoutMap(routes, rootDir);\n\n  // Second pass: assign parent layouts\n  for (const route of routes) {\n    if (!route.isLayout) {\n      const parentLayout = findParentLayout(route.relativePath, layoutMap);\n      if (parentLayout !== undefined && parentLayout !== null) {\n        // TypeScript doesn't allow direct mutation, so we create a new object\n        Object.assign(route, { parentLayout });\n      }\n    }\n  }\n\n  // Sort routes for consistent ordering\n  return routes.sort((a, b) => {\n    // Layouts first\n    if (a.isLayout && !b.isLayout) return -1;\n    if (!a.isLayout && b.isLayout) return 1;\n\n    // Then by depth\n    if (a.depth !== b.depth) return a.depth - b.depth;\n\n    // Then alphabetically by path\n    return a.urlPath.localeCompare(b.urlPath);\n  });\n}\n\n/**\n * Recursively scan a directory for route files\n */\nasync function scanDirectory(\n  dirPath: string,\n  basePath: string,\n  config: DiscoveryConfig,\n  path: typeof import('path'),\n  fs: typeof import('fs').promises\n): Promise<DiscoveredRoute[]> {\n  const routes: DiscoveredRoute[] = [];\n\n  let entries: Dirent[];\n  try {\n    entries = await fs.readdir(dirPath, { withFileTypes: true });\n  } catch {\n    return routes;\n  }\n\n  for (const entry of entries) {\n    const entryName = entry.name;\n    const entryPath = path.join(dirPath, entryName);\n    const relativePath = path.relative(basePath, entryPath);\n\n    if (entry.isDirectory()) {\n      // Skip ignored directories\n      if (shouldIgnore(`${relativePath}/`, config.ignorePatterns)) {\n        continue;\n      }\n\n      // Recurse into subdirectory\n      const subRoutes = await scanDirectory(entryPath, basePath, config, path, fs);\n      routes.push(...subRoutes);\n    } else if (entry.isFile()) {\n      // Check if file has valid extension\n      if (!hasValidExtension(entryName, config.extensions)) {\n        continue;\n      }\n\n      // Skip ignored files\n      if (shouldIgnore(relativePath, config.ignorePatterns)) {\n        continue;\n      }\n\n      // Parse route from file\n      const dirRelative = path.relative(basePath, dirPath);\n      const parsedSegments = parseDirectoryPath(dirRelative, entryName);\n      const segments: readonly ParsedRouteSegment[] = parsedSegments;\n\n      const isLayout = Array.from(segments).some((s) => s.type === 'layout');\n\n      const lastSegment = Array.from(segments)[segments.length - 1];\n\n      const isIndex = lastSegment?.type === 'index';\n\n      const route: DiscoveredRoute = {\n        filePath: entryPath,\n        relativePath,\n        urlPath: segmentsToUrlPath(parsedSegments),\n\n        segments,\n        isLayout,\n        isIndex,\n\n        depth: Array.from(segments).filter((s) => s.type !== 'group').length,\n      };\n\n      routes.push(route);\n    }\n  }\n\n  return routes;\n}\n\n// =============================================================================\n// Route Cache\n// =============================================================================\n\ninterface CacheEntry {\n  routes: DiscoveredRoute[];\n  timestamp: number;\n}\n\nconst routeCache = new Map<string, CacheEntry>();\n\n/**\n * Get cache key for a configuration\n */\nfunction getCacheKey(rootDir: string, config: DiscoveryConfig): string {\n  return `${rootDir}:${JSON.stringify(config.scanPaths)}:${JSON.stringify(config.extensions)}`;\n}\n\n/**\n * Scan routes with caching support\n */\nexport async function scanRouteFilesCached(\n  rootDir: string,\n  config: DiscoveryConfig,\n  maxAge: number = 5000\n): Promise<DiscoveredRoute[]> {\n  if (!config.cacheResults) {\n    return scanRouteFiles(rootDir, config);\n  }\n\n  const cacheKey = getCacheKey(rootDir, config);\n  const cached = routeCache.get(cacheKey);\n\n  if (cached && Date.now() - cached.timestamp < maxAge) {\n    return cached.routes;\n  }\n\n  const routes = await scanRouteFiles(rootDir, config);\n  routeCache.set(cacheKey, { routes, timestamp: Date.now() });\n\n  return routes;\n}\n\n/**\n * Clear the route cache\n */\nexport function clearRouteCache(): void {\n  routeCache.clear();\n}\n\n/**\n * Invalidate cache for a specific root directory\n */\nexport function invalidateCache(rootDir: string): void {\n  for (const key of routeCache.keys()) {\n    if (key.startsWith(rootDir)) {\n      routeCache.delete(key);\n    }\n  }\n}\n\n// =============================================================================\n// Utility Functions (delegating to core)\n// =============================================================================\n\n/**\n * Extract parameter names from a URL path pattern\n * @see core/path-utils.ts for implementation details\n */\nexport function extractParamNames(path: string): string[] {\n  return coreExtractParamNames(path);\n}\n\n/**\n * Check if a path has dynamic segments\n * @see core/path-utils.ts for implementation details\n */\nexport function hasDynamicSegments(path: string): boolean {\n  return coreHasDynamicSegments(path);\n}\n\n/**\n * Get the static prefix of a path (before first dynamic segment)\n * @see core/path-utils.ts for implementation details\n */\nexport function getStaticPrefix(path: string): string {\n  return coreGetStaticPrefix(path);\n}\n\n/**\n * Generate a route ID from a discovered route\n * @see core/segment-parser.ts for implementation details\n */\nexport function generateRouteId(route: DiscoveredRoute): string {\n  return coreGenerateRouteId(route.segments, route.urlPath);\n}\n\n/**\n * Generate a display name from a discovered route\n * @see core/segment-parser.ts for implementation details\n */\nexport function generateDisplayName(route: DiscoveredRoute): string {\n  return coreGenerateDisplayName(route.segments);\n}\n\n// =============================================================================\n// Parallel Scanning (for large codebases)\n// =============================================================================\n\n/**\n * Options for parallel scanning\n */\nexport interface ParallelScanOptions {\n  /** Maximum concurrent directory scans */\n  maxConcurrency?: number;\n  /** Timeout per directory scan (ms) */\n  scanTimeout?: number;\n  /** Enable progress reporting */\n  onProgress?: (progress: ScanProgress) => void;\n}\n\n/**\n * Scan progress information\n */\nexport interface ScanProgress {\n  /** Total directories found */\n  totalDirs: number;\n  /** Directories scanned */\n  scannedDirs: number;\n  /** Routes discovered so far */\n  routesFound: number;\n  /** Current directory being scanned */\n  currentDir: string;\n  /** Elapsed time (ms) */\n  elapsedMs: number;\n}\n\n/**\n * Scan route files with parallel processing for large codebases\n */\nexport async function scanRouteFilesParallel(\n  rootDir: string,\n  config: DiscoveryConfig,\n  options: ParallelScanOptions = {}\n): Promise<DiscoveredRoute[]> {\n  const { maxConcurrency = 4, scanTimeout = 30000, onProgress } = options;\n\n  const startTime = Date.now();\n\n  // Dynamic imports for Node.js modules\n  const { promises: fs } = await import('fs');\n  const path = await import('path');\n\n  const routes: DiscoveredRoute[] = [];\n  const dirQueue: Array<{ dirPath: string; basePath: string }> = [];\n  const inProgress = new Set<string>();\n  let scannedDirs = 0;\n  let totalDirs = 0;\n\n  // Initialize queue with scan paths\n  for (const scanPath of config.scanPaths) {\n    const fullScanPath = path.resolve(rootDir, scanPath);\n    try {\n      await fs.access(fullScanPath);\n      dirQueue.push({ dirPath: fullScanPath, basePath: fullScanPath });\n      totalDirs++;\n    } catch {\n      // Skip non-existent paths\n    }\n  }\n\n  // Process directory and add subdirectories to queue\n  async function processDirectory(dirPath: string, basePath: string): Promise<void> {\n    let entries: Dirent[];\n    try {\n      entries = await fs.readdir(dirPath, { withFileTypes: true });\n    } catch {\n      return;\n    }\n\n    for (const entry of entries) {\n      const entryName = entry.name;\n      const entryPath = path.join(dirPath, entryName);\n      const relativePath = path.relative(basePath, entryPath);\n\n      if (entry.isDirectory()) {\n        // Skip ignored directories\n        if (shouldIgnore(`${relativePath}/`, config.ignorePatterns)) {\n          continue;\n        }\n\n        // Add to queue for parallel processing\n        dirQueue.push({ dirPath: entryPath, basePath });\n        totalDirs++;\n      } else if (entry.isFile()) {\n        // Check if file has valid extension\n        if (!hasValidExtension(entryName, config.extensions)) {\n          continue;\n        }\n\n        // Skip ignored files\n        if (shouldIgnore(relativePath, config.ignorePatterns)) {\n          continue;\n        }\n\n        // Parse route from file\n        const dirRelative = path.relative(basePath, dirPath);\n        const parsedSegments = parseDirectoryPath(dirRelative, entryName);\n        const segments: readonly ParsedRouteSegment[] = parsedSegments;\n\n        const isLayout = Array.from(segments).some((s) => s.type === 'layout');\n\n        const lastSegment = Array.from(segments)[segments.length - 1];\n\n        const isIndex = lastSegment?.type === 'index';\n\n        const route: DiscoveredRoute = {\n          filePath: entryPath,\n          relativePath,\n          urlPath: segmentsToUrlPath(parsedSegments),\n\n          segments,\n          isLayout,\n          isIndex,\n\n          depth: Array.from(segments).filter((s) => s.type !== 'group').length,\n        };\n\n        routes.push(route);\n      }\n    }\n  }\n\n  // Process queue with concurrency control\n  async function processQueue(): Promise<void> {\n    while (dirQueue.length > 0 || inProgress.size > 0) {\n      // Fill up to max concurrency\n      while (dirQueue.length > 0 && inProgress.size < maxConcurrency) {\n        const item = dirQueue.shift();\n        if (item) {\n          inProgress.add(item.dirPath);\n          processDirectory(item.dirPath, item.basePath)\n            .then(() => {\n              inProgress.delete(item.dirPath);\n              scannedDirs++;\n            })\n            .catch(() => {\n              inProgress.delete(item.dirPath);\n              scannedDirs++;\n            });\n        }\n      }\n\n      // Wait a tick for progress\n      await new Promise((resolve) => setTimeout(resolve, 1));\n\n      // Report progress\n      if (onProgress) {\n        onProgress({\n          totalDirs,\n          scannedDirs,\n          routesFound: routes.length,\n          currentDir: Array.from(inProgress)[0] ?? '',\n          elapsedMs: Date.now() - startTime,\n        });\n      }\n\n      // Check timeout\n      if (Date.now() - startTime > scanTimeout) {\n        throw new Error(`Route scanning timed out after ${scanTimeout}ms`);\n      }\n    }\n  }\n\n  await processQueue();\n\n  // Build layout map and assign parent layouts\n  const layoutMap = buildLayoutMap(routes, rootDir);\n\n  // Second pass: assign parent layouts\n  for (const route of routes) {\n    if (!route.isLayout) {\n      const parentLayout = findParentLayout(route.relativePath, layoutMap);\n      if (parentLayout !== undefined && parentLayout !== null) {\n        Object.assign(route, { parentLayout });\n      }\n    }\n  }\n\n  // Sort routes for consistent ordering\n  return routes.sort((a, b) => {\n    if (a.isLayout && !b.isLayout) return -1;\n    if (!a.isLayout && b.isLayout) return 1;\n    if (a.depth !== b.depth) return a.depth - b.depth;\n    return a.urlPath.localeCompare(b.urlPath);\n  });\n}\n\n// =============================================================================\n// Incremental Scanning\n// =============================================================================\n\n/**\n * File change event for incremental scanning\n */\nexport interface FileChangeEvent {\n  type: 'add' | 'unlink' | 'change';\n  filePath: string;\n}\n\n/**\n * Result of incremental scan\n */\nexport interface IncrementalScanResult {\n  /** Routes added */\n  added: DiscoveredRoute[];\n  /** Routes removed */\n  removed: DiscoveredRoute[];\n  /** Routes modified */\n  modified: DiscoveredRoute[];\n  /** Whether a full rescan is needed */\n  requiresFullRescan: boolean;\n}\n\n/**\n * Apply incremental file changes to cached routes\n */\nexport function applyIncrementalChanges(\n  cachedRoutes: DiscoveredRoute[],\n  changes: FileChangeEvent[],\n  config: DiscoveryConfig\n): IncrementalScanResult {\n  const result: IncrementalScanResult = {\n    added: [],\n    removed: [],\n    modified: [],\n    requiresFullRescan: false,\n  };\n\n  const routesByPath = new Map(cachedRoutes.map((r) => [r.filePath, r]));\n\n  for (const change of changes) {\n    // Check if file is in a scanned path\n    const isInScanPath = config.scanPaths.some((sp) => change.filePath.includes(sp));\n\n    if (!isInScanPath) continue;\n\n    // Check extension\n    if (!hasValidExtension(change.filePath, config.extensions)) {\n      continue;\n    }\n\n    switch (change.type) {\n      case 'add': {\n        // Parse the new route\n        const basePath = config.scanPaths.find((sp) => change.filePath.includes(sp));\n        if (basePath === undefined || basePath === null) break;\n\n        const relativePath = change.filePath.split(basePath)[1]?.replace(/^[/\\\\]/, '') ?? '';\n        const filename = change.filePath.split(/[/\\\\]/).pop() ?? '';\n        const dirRelative = relativePath.replace(/[/\\\\][^/\\\\]+$/, '');\n\n        const parsedSegments = parseDirectoryPath(dirRelative, filename);\n        const segments: readonly ParsedRouteSegment[] = parsedSegments;\n\n        const isLayout = Array.from(segments).some((s) => s.type === 'layout');\n\n        const lastSegment = Array.from(segments)[segments.length - 1];\n\n        const isIndex = lastSegment?.type === 'index';\n\n        const route: DiscoveredRoute = {\n          filePath: change.filePath,\n          relativePath,\n          urlPath: segmentsToUrlPath(parsedSegments),\n\n          segments,\n          isLayout,\n          isIndex,\n\n          depth: Array.from(segments).filter((s) => s.type !== 'group').length,\n        };\n\n        result.added.push(route);\n\n        // Layout changes require full rescan for parent assignment\n        if (isLayout) {\n          result.requiresFullRescan = true;\n        }\n        break;\n      }\n\n      case 'unlink': {\n        const existingRoute = routesByPath.get(change.filePath);\n        if (existingRoute) {\n          result.removed.push(existingRoute);\n\n          // Layout removal requires full rescan\n          if (existingRoute.isLayout) {\n            result.requiresFullRescan = true;\n          }\n        }\n        break;\n      }\n\n      case 'change': {\n        const existingRoute = routesByPath.get(change.filePath);\n        if (existingRoute) {\n          result.modified.push(existingRoute);\n        }\n        break;\n      }\n    }\n  }\n\n  return result;\n}\n\n// =============================================================================\n// Route Discovery Statistics\n// =============================================================================\n\n/**\n * Calculate discovery statistics for routes\n */\nexport function calculateDiscoveryStats(\n  routes: DiscoveredRoute[],\n  scanDurationMs: number,\n  filesScanned: number,\n  filesIgnored: number\n): import('./types').RouteDiscoveryStats {\n  const layouts = routes.filter((r) => r.isLayout);\n  const dynamicRoutes = routes.filter((r) =>\n    r.segments.some((s) => s.type === 'dynamic' || s.type === 'catchAll')\n  );\n\n  let maxDepth = 0;\n  for (const route of routes) {\n    if (route.depth > maxDepth) {\n      maxDepth = route.depth;\n    }\n  }\n\n  return {\n    totalRoutes: routes.length,\n    layoutCount: layouts.length,\n    dynamicRouteCount: dynamicRoutes.length,\n    maxDepth,\n    scanDurationMs,\n    filesScanned,\n    filesIgnored,\n  };\n}\n\n// =============================================================================\n// Layout Tree Building\n// =============================================================================\n\n/**\n * Build a layout tree from discovered routes\n */\nexport function buildLayoutTree(routes: DiscoveredRoute[]): import('./types').RouteLayoutTree {\n  const layouts = routes.filter((r) => r.isLayout);\n  const nonLayouts = routes.filter((r) => !r.isLayout);\n\n  if (layouts.length === 0) {\n    return {\n      root: null,\n      orphanedLayouts: [],\n    };\n  }\n\n  // Sort layouts by depth (shallowest first)\n  const sortedLayouts = [...layouts].sort((a, b) => a.depth - b.depth);\n\n  // Build tree structure\n  const layoutNodes = new Map<string, import('./types').RouteLayoutNode>();\n  const orphanedLayouts: string[] = [];\n\n  for (const layout of sortedLayouts) {\n    const node: import('./types').RouteLayoutNode = {\n      layoutPath: layout.filePath,\n      children: [],\n      routes: nonLayouts.filter((r) => r.parentLayout === layout.filePath),\n    };\n    layoutNodes.set(layout.filePath, node);\n  }\n\n  // Connect children to parents\n  for (const layout of sortedLayouts) {\n    if (layout.parentLayout !== undefined && layout.parentLayout !== null) {\n      const parentNode = layoutNodes.get(layout.parentLayout);\n      const currentNode = layoutNodes.get(layout.filePath);\n\n      if (parentNode && currentNode) {\n        (parentNode.children as import('./types').RouteLayoutNode[]).push(currentNode);\n      } else if (currentNode) {\n        orphanedLayouts.push(layout.filePath);\n      }\n    }\n  }\n\n  // Find root layouts (no parent)\n  const rootLayouts = sortedLayouts.filter(\n    (l) => l.parentLayout === undefined || l.parentLayout === null\n  );\n\n  if (rootLayouts.length === 0) {\n    return {\n      root: null,\n      orphanedLayouts: layouts.map((l) => l.filePath),\n    };\n  }\n\n  // If multiple root layouts, create a virtual root\n  const [firstRootLayout] = rootLayouts;\n  const rootNode = firstRootLayout ? (layoutNodes.get(firstRootLayout.filePath) ?? null) : null;\n\n  return {\n    root: rootNode,\n    orphanedLayouts,\n  };\n}\n"],"names":["segmentsToUrlPath","segments","coreSegmentsToUrlPath","parseDirectoryPath","dirPath","filename","coreParseDirectoryPath","shouldIgnore","filePath","ignorePatterns","pattern","regexPattern","_","group","hasValidExtension","extensions","ext","buildLayoutMap","routes","_scanPath","layoutMap","route","layoutDir","findParentLayout","routeRelativePath","searchPath","parentPath","scanRouteFiles","rootDir","config","fs","path","scanPath","fullScanPath","discoveredFiles","scanDirectory","parentLayout","a","b","basePath","entries","entry","entryName","entryPath","relativePath","subRoutes","dirRelative","parsedSegments","isLayout","s","isIndex","routeCache","getCacheKey","scanRouteFilesCached","maxAge","cacheKey","cached","clearRouteCache","invalidateCache","key","extractParamNames","coreExtractParamNames","generateRouteId","coreGenerateRouteId","generateDisplayName","coreGenerateDisplayName","scanRouteFilesParallel","options","maxConcurrency","scanTimeout","onProgress","startTime","dirQueue","inProgress","scannedDirs","totalDirs","processDirectory","processQueue","item","resolve","applyIncrementalChanges","cachedRoutes","changes","result","routesByPath","r","change","sp","existingRoute","calculateDiscoveryStats","scanDurationMs","filesScanned","filesIgnored","layouts","dynamicRoutes","maxDepth","buildLayoutTree","nonLayouts","sortedLayouts","layoutNodes","orphanedLayouts","layout","node","parentNode","currentNode","rootLayouts","l","firstRootLayout"],"mappings":"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"}