{"version":3,"sources":["../../../../src/build/static-paths/app/extract-pathname-route-param-segments-from-loader-tree.ts"],"sourcesContent":["import type { LoaderTree } from '../../../server/lib/app-dir-module'\nimport type { Params } from '../../../server/request/params'\nimport type { DynamicParamTypes } from '../../../shared/lib/app-router-types'\nimport {\n  parseAppRouteSegment,\n  type NormalizedAppRoute,\n  type NormalizedAppRouteSegment,\n} from '../../../shared/lib/router/routes/app'\nimport { parseLoaderTree } from '../../../shared/lib/router/utils/parse-loader-tree'\nimport { resolveParamValue } from '../../../shared/lib/router/utils/resolve-param-value'\n\n/**\n * Validates that the static segments in currentPath match the corresponding\n * segments in targetSegments. This ensures we only extract dynamic parameters\n * that are part of the target pathname structure.\n *\n * Segments are compared literally - interception markers like \"(.)photo\" are\n * part of the pathname and must match exactly.\n *\n * @example\n * // Matching paths\n * currentPath: ['blog', '(.)photo']\n * targetSegments: ['blog', '(.)photo', '[id]']\n * → Returns true (both static segments match exactly)\n *\n * @example\n * // Non-matching paths\n * currentPath: ['blog', '(.)photo']\n * targetSegments: ['blog', 'photo', '[id]']\n * → Returns false (segments don't match - marker is part of pathname)\n *\n * @param currentPath - The accumulated path segments from the loader tree\n * @param targetSegments - The target pathname split into segments\n * @returns true if all static segments match, false otherwise\n */\nfunction validatePrefixMatch(\n  currentPath: NormalizedAppRouteSegment[],\n  route: NormalizedAppRoute\n): boolean {\n  for (let i = 0; i < currentPath.length; i++) {\n    const pathSegment = currentPath[i]\n    const targetPathSegment = route.segments[i]\n\n    // Type mismatch - one is static, one is dynamic\n    if (pathSegment.type !== targetPathSegment.type) {\n      return false\n    }\n\n    // One has an interception marker, the other doesn't.\n    if (\n      pathSegment.interceptionMarker !== targetPathSegment.interceptionMarker\n    ) {\n      return false\n    }\n\n    // Both are static but names don't match\n    if (\n      pathSegment.type === 'static' &&\n      targetPathSegment.type === 'static' &&\n      pathSegment.name !== targetPathSegment.name\n    ) {\n      return false\n    }\n    // Both are dynamic but param names don't match\n    else if (\n      pathSegment.type === 'dynamic' &&\n      targetPathSegment.type === 'dynamic' &&\n      pathSegment.param.paramType !== targetPathSegment.param.paramType &&\n      pathSegment.param.paramName !== targetPathSegment.param.paramName\n    ) {\n      return false\n    }\n  }\n\n  return true\n}\n\n/**\n * Extracts pathname route param segments from a loader tree and resolves\n * parameter values from static segments in the route.\n *\n * @param loaderTree - The loader tree structure containing route hierarchy\n * @param route - The target route to match against\n * @returns Object containing pathname route param segments and resolved params\n */\nexport function extractPathnameRouteParamSegmentsFromLoaderTree(\n  loaderTree: LoaderTree,\n  route: NormalizedAppRoute\n): {\n  pathnameRouteParamSegments: Array<{\n    readonly name: string\n    readonly paramName: string\n    readonly paramType: DynamicParamTypes\n  }>\n  params: Params\n} {\n  const pathnameRouteParamSegments: Array<{\n    readonly name: string\n    readonly paramName: string\n    readonly paramType: DynamicParamTypes\n  }> = []\n  const params: Params = {}\n\n  // BFS traversal with depth and path tracking\n  const queue: Array<{\n    tree: LoaderTree\n    depth: number\n    currentPath: NormalizedAppRouteSegment[]\n  }> = [{ tree: loaderTree, depth: 0, currentPath: [] }]\n\n  while (queue.length > 0) {\n    const { tree, depth, currentPath } = queue.shift()!\n    const { segment, parallelRoutes } = parseLoaderTree(tree)\n\n    // Build the path for the current node\n    let updatedPath = currentPath\n    let nextDepth = depth\n\n    const appSegment = parseAppRouteSegment(segment)\n\n    // Only add to path if it's a real segment that appears in the URL\n    // Route groups and parallel markers don't contribute to URL pathname\n    if (\n      appSegment &&\n      appSegment.type !== 'route-group' &&\n      appSegment.type !== 'parallel-route'\n    ) {\n      updatedPath = [...currentPath, appSegment]\n      nextDepth = depth + 1\n    }\n\n    // Check if this segment has a param and matches the target pathname at this depth\n    if (appSegment?.type === 'dynamic') {\n      const { paramName, paramType } = appSegment.param\n\n      // Check if this segment is at the correct depth in the target pathname\n      // A segment matches if:\n      // 1. There's a dynamic segment at this depth in the pathname\n      // 2. The parameter names match (e.g., [id] matches [id], not [category])\n      // 3. The static segments leading up to this point match (prefix check)\n      if (depth < route.segments.length) {\n        const targetSegment = route.segments[depth]\n\n        // Match if the target pathname has a dynamic segment at this depth\n        if (targetSegment.type === 'dynamic') {\n          // Check that parameter names match exactly\n          // This prevents [category] from matching against /[id]\n          if (paramName !== targetSegment.param.paramName) {\n            continue // Different param names, skip this segment\n          }\n\n          // Validate that the path leading up to this dynamic segment matches\n          // the target pathname. This prevents false matches like extracting\n          // [slug] from \"/news/[slug]\" when the tree has \"/blog/[slug]\"\n          if (validatePrefixMatch(currentPath, route)) {\n            pathnameRouteParamSegments.push({\n              name: segment,\n              paramName,\n              paramType,\n            })\n          }\n        }\n      }\n\n      // Resolve parameter value if it's not already known.\n      if (!params.hasOwnProperty(paramName)) {\n        const paramValue = resolveParamValue(\n          paramName,\n          paramType,\n          depth,\n          route,\n          params\n        )\n\n        if (paramValue !== undefined) {\n          params[paramName] = paramValue\n        }\n      }\n    }\n\n    // Continue traversing all parallel routes to find matching segments\n    for (const parallelRoute of Object.values(parallelRoutes)) {\n      queue.push({\n        tree: parallelRoute,\n        depth: nextDepth,\n        currentPath: updatedPath,\n      })\n    }\n  }\n\n  return { pathnameRouteParamSegments, params }\n}\n"],"names":["extractPathnameRouteParamSegmentsFromLoaderTree","validatePrefixMatch","currentPath","route","i","length","pathSegment","targetPathSegment","segments","type","interceptionMarker","name","param","paramType","paramName","loaderTree","pathnameRouteParamSegments","params","queue","tree","depth","shift","segment","parallelRoutes","parseLoaderTree","updatedPath","nextDepth","appSegment","parseAppRouteSegment","targetSegment","push","hasOwnProperty","paramValue","resolveParamValue","undefined","parallelRoute","Object","values"],"mappings":"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","ignoreList":[0]}