{"version":3,"file":"route-hmr-statement.cjs","names":[],"sources":["../../../src/core/route-hmr-statement.ts"],"sourcesContent":["import * as template from '@babel/template'\nimport type { AnyRoute, AnyRouteMatch, AnyRouter } 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    cachedMatchStoresById: Map<\n      string,\n      {\n        setState: (updater: (prev: AnyRouteMatch) => AnyRouteMatch) => void\n      }\n    >\n    pendingMatchStoresById: Map<\n      string,\n      {\n        setState: (updater: (prev: AnyRouteMatch) => AnyRouteMatch) => void\n      }\n    >\n    activeMatchStoresById: Map<\n      string,\n      {\n        setState: (updater: (prev: AnyRouteMatch) => AnyRouteMatch) => void\n      }\n    >\n  }\n}\n\ntype AnyRouteMatchWithPrivateProps = AnyRouteMatch & {\n  __beforeLoadContext?: 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 import.meta.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  // 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  componentKeys.forEach((key) => {\n    if (key in oldRoute.options && key in newRoute.options) {\n      newRoute.options[key] = oldRoute.options[key]\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.activeMatchesSnapshot.state.find(filter)\n  const pendingMatch = router.stores.pendingMatchesSnapshot.state.find(filter)\n  const cachedMatches = router.stores.cachedMatchesSnapshot.state.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.pendingMatchStoresById.get(matchId) ||\n            router.stores.activeMatchStoresById.get(matchId) ||\n            router.stores.cachedMatchStoresById.get(matchId)\n          if (store) {\n            store.setState((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              }\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\nconst handleRouteUpdateStr = handleRouteUpdate.toString()\n\nexport function createRouteHmrStatement(stableRouteOptionKeys: Array<string>) {\n  return template.statement(\n    `\nif (import.meta.hot) {\n  import.meta.hot.accept((newModule) => {\n    if (Route && newModule && newModule.Route) {\n      const routeId = import.meta.hot.data['tsr-route-id'] ?? Route.id\n      if (routeId) {\n        import.meta.hot.data['tsr-route-id'] = routeId\n      }\n      (${handleRouteUpdateStr.replace(\n        /['\"]__TSR_COMPONENT_TYPES__['\"]/,\n        JSON.stringify(stableRouteOptionKeys),\n      )})(routeId, newModule.Route)\n    }\n    })\n}\n`,\n    { placeholderPattern: false },\n  )()\n}\n"],"mappings":";;;;AA2CA,SAAS,kBACP,SACA,UACA;CACA,MAAM,SAAS,OAAO;CACtB,MAAM,WAAW,OAAO,WAAW;AAInC,KAAI,CAAC,SACH;CAYF,MAAM,8BAAc,IAAI,KAAa;AACrC,QAAO,KAAK,SAAS,QAAQ,CAAC,SAAS,QAAQ;AAC7C,MAAI,EAAE,OAAO,SAAS,UAAU;AAC9B,eAAY,IAAI,IAAI;AACpB,UAAO,SAAS,QAAQ;;GAE1B;AAIoB,2BACR,SAAS,QAAQ;AAC7B,MAAI,OAAO,SAAS,WAAW,OAAO,SAAS,QAC7C,UAAS,QAAQ,OAAO,SAAS,QAAQ;GAE3C;AAEF,UAAS,UAAU,SAAS;AAC5B,UAAS,OAAO,SAAS,QAAQ;AACjC,UAAS,qBAAqB,KAAA;AAC9B,UAAS,eAAe,KAAA;AAExB,QAAO,WAAW,SAAS,MAAM;AACjC,QAAO,aAAa,SAAS,YAAY;AAEzC,QAAO,cAAc,WAAW,OAAO;AACvC,QAAO,cAAc,WAAW,OAAO;AACvC,QAAO,cAAc,YAAY,OAAO;AACxC,QAAO,iBAAiB,OAAO;AAC/B,wBAAuB,UAAU,OAAO,cAAc,YAAY;CAElE,MAAM,UAAU,MAAqB,EAAE,YAAY,SAAS;CAC5D,MAAM,cAAc,OAAO,OAAO,sBAAsB,MAAM,KAAK,OAAO;CAC1E,MAAM,eAAe,OAAO,OAAO,uBAAuB,MAAM,KAAK,OAAO;CAC5E,MAAM,gBAAgB,OAAO,OAAO,sBAAsB,MAAM,OAAO,OAAO;AAE9E,KAAI,eAAe,gBAAgB,cAAc,SAAS,GAAG;AAS3D,MAAI,YAAY,IAAI,SAAS,IAAI,YAAY,IAAI,aAAa,EAAE;GAC9D,MAAM,WAAW;IACf,aAAa;IACb,cAAc;IACd,GAAG,cAAc,KAAK,UAAU,MAAM,GAAG;IAC1C,CAAC,OAAO,QAAQ;AACjB,UAAO,YAAY;AACjB,SAAK,MAAM,WAAW,UAAU;KAC9B,MAAM,QACJ,OAAO,OAAO,uBAAuB,IAAI,QAAQ,IACjD,OAAO,OAAO,sBAAsB,IAAI,QAAQ,IAChD,OAAO,OAAO,sBAAsB,IAAI,QAAQ;AAClD,SAAI,MACF,OAAM,UAAU,SAAS;MACvB,MAAM,OAAsC,EAAE,GAAG,MAAM;AAEvD,UAAI,YAAY,IAAI,SAAS,CAC3B,MAAK,aAAa,KAAA;AAEpB,UAAI,YAAY,IAAI,aAAa,CAC/B,MAAK,sBAAsB,KAAA;AAG7B,aAAO;OACP;;KAGN;;AAGJ,SAAO,WAAW;GAAE;GAAQ,MAAM;GAAM,CAAC;;CAG3C,SAAS,uBACP,OACA,MACA;AACA,MAAI,KAAK,OAAO,OAAO,MAAM,GAAI,MAAK,QAAQ;AAC9C,MAAI,KAAK,MAAO,wBAAuB,OAAO,KAAK,MAAM;AACzD,OAAK,QAAQ,SAAS,UAAU,uBAAuB,OAAO,MAAM,CAAC;AACrE,OAAK,mBAAmB,SAAS,UAC/B,uBAAuB,OAAO,MAAM,CACrC;AACD,OAAK,SAAS,SAAS,UAAU,uBAAuB,OAAO,MAAM,CAAC;AACtE,OAAK,UAAU,SAAS,UAAU,uBAAuB,OAAO,MAAM,CAAC;AACvE,OAAK,UAAU,SAAS,UAAU,uBAAuB,OAAO,MAAM,CAAC;;;AAI3E,IAAM,uBAAuB,kBAAkB,UAAU;AAEzD,SAAgB,wBAAwB,uBAAsC;AAC5E,QAAO,gBAAS,UACd;;;;;;;;SAQK,qBAAqB,QACtB,mCACA,KAAK,UAAU,sBAAsB,CACtC,CAAC;;;;GAKJ,EAAE,oBAAoB,OAAO,CAC9B,EAAE"}