{"version":3,"file":"handle-route-update.cjs","names":[],"sources":["../../../../src/core/hmr/handle-route-update.ts"],"sourcesContent":["import type {\n  AnyRoute,\n  AnyRouteMatch,\n  AnyRouter,\n  RouterWritableStore,\n} from '@tanstack/router-core'\n\ntype AnyRouteWithPrivateProps = AnyRoute & {\n  options: Record<string, unknown>\n  _componentsPromise?: Promise<void>\n  _lazyPromise?: Promise<void>\n  update: (options: Record<string, unknown>) => unknown\n  _path: string\n  _id: string\n  _fullPath: string\n  _to: string\n}\n\ntype AnyRouterWithPrivateMaps = AnyRouter & {\n  routesById: Record<string, AnyRoute>\n  routesByPath: Record<string, AnyRoute>\n  stores: AnyRouter['stores'] & {\n    cachedMatchStores: Map<\n      string,\n      Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>\n    >\n    pendingMatchStores: Map<\n      string,\n      Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>\n    >\n    matchStores: Map<\n      string,\n      Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>\n    >\n  }\n}\n\ntype AnyRouteMatchWithPrivateProps = AnyRouteMatch & {\n  __beforeLoadContext?: unknown\n  __routeContext?: Record<string, unknown>\n  context?: Record<string, unknown>\n}\n\nfunction handleRouteUpdate(\n  routeId: string,\n  newRoute: AnyRouteWithPrivateProps,\n) {\n  const router = window.__TSR_ROUTER__ as AnyRouterWithPrivateMaps\n  const oldRoute = router.routesById[routeId] as\n    | AnyRouteWithPrivateProps\n    | undefined\n\n  if (!oldRoute) {\n    return\n  }\n\n  // Keys whose identity must remain stable to prevent React from\n  // unmounting/remounting the component tree.  React Fast Refresh already\n  // handles hot-updating the function bodies of these components — our job\n  // is only to update non-component route options (loader, head, etc.).\n  // For code-split (splittable) routes, the lazyRouteComponent wrapper is\n  // already cached in the bundler hot data so its identity is stable.\n  // For unsplittable routes (e.g. root routes), the component is a plain\n  // function reference that gets recreated on every module re-execution,\n  // so we must explicitly preserve the old reference.\n  const removedKeys = new Set<string>()\n  Object.keys(oldRoute.options).forEach((key) => {\n    if (!(key in newRoute.options)) {\n      removedKeys.add(key)\n      delete oldRoute.options[key]\n    }\n  })\n\n  const oldHasShellComponent = 'shellComponent' in oldRoute.options\n  const newHasShellComponent = 'shellComponent' in newRoute.options\n  const preserveComponentIdentity =\n    oldHasShellComponent === newHasShellComponent\n\n  // Preserve component identity so React doesn't remount.\n  // React Fast Refresh patches the function bodies in-place.\n  const componentKeys = '__TSR_COMPONENT_TYPES__' as unknown as Array<string>\n  if (preserveComponentIdentity) {\n    componentKeys.forEach((key) => {\n      if (key in oldRoute.options && key in newRoute.options) {\n        newRoute.options[key] = oldRoute.options[key]\n      }\n    })\n  }\n\n  oldRoute.options = newRoute.options\n  oldRoute.update(newRoute.options)\n  oldRoute._componentsPromise = undefined\n  oldRoute._lazyPromise = undefined\n\n  router.routesById[oldRoute.id] = oldRoute\n  router.routesByPath[oldRoute.fullPath] = oldRoute\n\n  router.processedTree.matchCache.clear()\n  router.processedTree.flatCache?.clear()\n  router.processedTree.singleCache.clear()\n  router.resolvePathCache.clear()\n  walkReplaceSegmentTree(oldRoute, router.processedTree.segmentTree)\n\n  const filter = (m: AnyRouteMatch) => m.routeId === oldRoute.id\n  const activeMatch = router.stores.matches.get().find(filter)\n  const pendingMatch = router.stores.pendingMatches.get().find(filter)\n  const cachedMatches = router.stores.cachedMatches.get().filter(filter)\n\n  if (activeMatch || pendingMatch || cachedMatches.length > 0) {\n    // Clear stale match data for removed route options BEFORE invalidating.\n    // Without this, router.invalidate() -> matchRoutes() reuses the existing\n    // match from the store (via ...existingMatch spread) and the stale\n    // loaderData / __beforeLoadContext survives the reload cycle.\n    //\n    // We must update the store directly (not via router.updateMatch) because\n    // updateMatch wraps in startTransition which may defer the state update,\n    // and we need the clear to be visible before invalidate reads the store.\n    if (removedKeys.has('loader') || removedKeys.has('beforeLoad')) {\n      const matchIds = [\n        activeMatch?.id,\n        pendingMatch?.id,\n        ...cachedMatches.map((match) => match.id),\n      ].filter(Boolean) as Array<string>\n      router.batch(() => {\n        for (const matchId of matchIds) {\n          const store =\n            router.stores.pendingMatchStores.get(matchId) ||\n            router.stores.matchStores.get(matchId) ||\n            router.stores.cachedMatchStores.get(matchId)\n          if (store) {\n            store.set((prev) => {\n              const next: AnyRouteMatchWithPrivateProps = { ...prev }\n\n              if (removedKeys.has('loader')) {\n                next.loaderData = undefined\n              }\n              if (removedKeys.has('beforeLoad')) {\n                next.__beforeLoadContext = undefined\n                next.context = rebuildMatchContextWithoutBeforeLoad(next)\n              }\n\n              return next\n            })\n          }\n        }\n      })\n    }\n\n    router.invalidate({ filter, sync: true })\n  }\n\n  function walkReplaceSegmentTree(\n    route: AnyRouteWithPrivateProps,\n    node: AnyRouter['processedTree']['segmentTree'],\n  ) {\n    if (node.route?.id === route.id) node.route = route\n    if (node.index) walkReplaceSegmentTree(route, node.index)\n    node.static?.forEach((child) => walkReplaceSegmentTree(route, child))\n    node.staticInsensitive?.forEach((child) =>\n      walkReplaceSegmentTree(route, child),\n    )\n    node.dynamic?.forEach((child) => walkReplaceSegmentTree(route, child))\n    node.optional?.forEach((child) => walkReplaceSegmentTree(route, child))\n    node.wildcard?.forEach((child) => walkReplaceSegmentTree(route, child))\n  }\n\n  function getStoreMatch(matchId: string) {\n    return (\n      router.stores.pendingMatchStores.get(matchId)?.get() ||\n      router.stores.matchStores.get(matchId)?.get() ||\n      router.stores.cachedMatchStores.get(matchId)?.get()\n    )\n  }\n\n  function getMatchList(matchId: string) {\n    const pendingMatches = router.stores.pendingMatches.get()\n    if (pendingMatches.some((match) => match.id === matchId)) {\n      return pendingMatches\n    }\n\n    const activeMatches = router.stores.matches.get()\n    if (activeMatches.some((match) => match.id === matchId)) {\n      return activeMatches\n    }\n\n    const cachedMatches = router.stores.cachedMatches.get()\n    if (cachedMatches.some((match) => match.id === matchId)) {\n      return cachedMatches\n    }\n\n    return []\n  }\n\n  function getParentMatch(match: AnyRouteMatch) {\n    const matchList = getMatchList(match.id)\n    const matchIndex = matchList.findIndex((item) => item.id === match.id)\n\n    if (matchIndex <= 0) {\n      return undefined\n    }\n\n    const parentMatch = matchList[matchIndex - 1]!\n    return getStoreMatch(parentMatch.id) || parentMatch\n  }\n\n  function rebuildMatchContextWithoutBeforeLoad(\n    match: AnyRouteMatchWithPrivateProps,\n  ) {\n    const parentMatch = getParentMatch(match)\n    const getParentContext = (\n      router as unknown as {\n        getParentContext?: (\n          parentMatch?: AnyRouteMatch,\n        ) => Record<string, unknown> | undefined\n      }\n    ).getParentContext\n    const parentContext = getParentContext\n      ? getParentContext.call(router, parentMatch)\n      : (parentMatch?.context ?? router.options.context)\n\n    return {\n      ...(parentContext ?? {}),\n      ...(match.__routeContext ?? {}),\n    }\n  }\n}\n\nconst handleRouteUpdateStr = handleRouteUpdate.toString()\n\nexport function getHandleRouteUpdateCode(stableRouteOptionKeys: Array<string>) {\n  return handleRouteUpdateStr.replace(\n    /['\"]__TSR_COMPONENT_TYPES__['\"]/,\n    JSON.stringify(stableRouteOptionKeys),\n  )\n}\n"],"mappings":"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"}