{"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  buildRouteTree: () => Parameters<AnyRouter['setRoutes']>[0]\n  setRoutes: AnyRouter['setRoutes']\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  // Generated route-tree options are not present on the freshly imported route\n  // module, but they must stay on the live route before rebuilding indexes.\n  const generatedRouteOptionKeys = new Set(['id', 'path', 'getParentRoute'])\n  const generatedRouteOptions: Record<string, unknown> = {}\n  generatedRouteOptionKeys.forEach((key) => {\n    if (key in oldRoute.options) {\n      generatedRouteOptions[key] = oldRoute.options[key]\n    }\n  })\n\n  const removedKeys = new Set<string>()\n  Object.keys(oldRoute.options).forEach((key) => {\n    if (!generatedRouteOptionKeys.has(key) && !(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  // 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  // 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  const nextOptions = {\n    ...newRoute.options,\n    ...generatedRouteOptions,\n  }\n\n  oldRoute.options = nextOptions\n  oldRoute.update(nextOptions)\n  oldRoute._componentsPromise = undefined\n  oldRoute._lazyPromise = undefined\n\n  router.setRoutes(router.buildRouteTree())\n  router.resolvePathCache.clear()\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 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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"}