{"version":3,"file":"headContentUtils.cjs","names":["Solid","escapeHtml","getAssetCrossOrigin","isInlinableStylesheet","resolveManifestAssetLink","useRouter","AssetCrossOriginConfig","RouterManagedTag","useTags","assetCrossOrigin","router","nonce","options","ssr","activeMatches","createMemo","stores","matches","get","routeMeta","map","match","meta","filter","Boolean","Accessor","Array","resultMeta","metaByAttribute","Record","title","routeMetasArray","i","length","metas","j","m","tag","children","json","JSON","stringify","push","attrs","type","attribute","name","property","content","reverse","links","constructed","flat","link","manifest","assets","routes","routeId","flatMap","asset","crossOrigin","inlineCss","const","preloadLinks","looseRoutesById","forEach","route","id","preloads","preload","preloadLink","rel","href","styles","style","headScripts","script","prev","next","uniqBy","d","undefined","replaceEqualTags","prevByKey","Map","set","isEqual","result","index","existing","arr","T","fn","item","seen","Set","key","has","add"],"sources":["../../src/headContentUtils.tsx"],"sourcesContent":["import * as Solid from 'solid-js'\nimport {\n  escapeHtml,\n  getAssetCrossOrigin,\n  isInlinableStylesheet,\n  resolveManifestAssetLink,\n} from '@tanstack/router-core'\nimport { useRouter } from './useRouter'\nimport type {\n  AssetCrossOriginConfig,\n  RouterManagedTag,\n} from '@tanstack/router-core'\n\n/**\n * Build the list of head/link/meta/script tags to render for active matches.\n * Used internally by `HeadContent`.\n */\nexport const useTags = (assetCrossOrigin?: AssetCrossOriginConfig) => {\n  const router = useRouter()\n  const nonce = router.options.ssr?.nonce\n  const activeMatches = Solid.createMemo(() => router.stores.matches.get())\n  const routeMeta = Solid.createMemo(() =>\n    activeMatches()\n      .map((match) => match.meta!)\n      .filter(Boolean),\n  )\n\n  const meta: Solid.Accessor<Array<RouterManagedTag>> = Solid.createMemo(() => {\n    const resultMeta: Array<RouterManagedTag> = []\n    const metaByAttribute: Record<string, true> = {}\n    let title: RouterManagedTag | undefined\n    const routeMetasArray = routeMeta()\n    for (let i = routeMetasArray.length - 1; i >= 0; i--) {\n      const metas = routeMetasArray[i]!\n      for (let j = metas.length - 1; j >= 0; j--) {\n        const m = metas[j]\n        if (!m) continue\n\n        if (m.title) {\n          if (!title) {\n            title = {\n              tag: 'title',\n              children: m.title,\n            }\n          }\n        } else if ('script:ld+json' in m) {\n          // Handle JSON-LD structured data\n          // Content is HTML-escaped to prevent XSS when injected via innerHTML\n          try {\n            const json = JSON.stringify(m['script:ld+json'])\n            resultMeta.push({\n              tag: 'script',\n              attrs: {\n                type: 'application/ld+json',\n              },\n              children: escapeHtml(json),\n            })\n          } catch {\n            // Skip invalid JSON-LD objects\n          }\n        } else {\n          const attribute = m.name ?? m.property\n          if (attribute) {\n            if (metaByAttribute[attribute]) {\n              continue\n            } else {\n              metaByAttribute[attribute] = true\n            }\n          }\n\n          resultMeta.push({\n            tag: 'meta',\n            attrs: {\n              ...m,\n              nonce,\n            },\n          })\n        }\n      }\n    }\n\n    if (title) {\n      resultMeta.push(title)\n    }\n\n    if (router.options.ssr?.nonce) {\n      resultMeta.push({\n        tag: 'meta',\n        attrs: {\n          property: 'csp-nonce',\n          content: router.options.ssr.nonce,\n        },\n      })\n    }\n    resultMeta.reverse()\n\n    return resultMeta\n  })\n\n  const links = Solid.createMemo(() => {\n    const matches = activeMatches()\n    const constructed = matches\n      .map((match) => match.links!)\n      .filter(Boolean)\n      .flat(1)\n      .map((link) => ({\n        tag: 'link',\n        attrs: {\n          ...link,\n          nonce,\n        },\n      })) satisfies Array<RouterManagedTag>\n\n    const manifest = router.ssr?.manifest\n\n    const assets = matches\n      .map((match) => manifest?.routes[match.routeId]?.assets ?? [])\n      .filter(Boolean)\n      .flat(1)\n      .flatMap((asset): Array<RouterManagedTag> => {\n        if (asset.tag === 'link') {\n          if (isInlinableStylesheet(manifest, asset)) {\n            return []\n          }\n\n          return [\n            {\n              tag: 'link',\n              attrs: {\n                ...asset.attrs,\n                crossOrigin:\n                  getAssetCrossOrigin(assetCrossOrigin, 'stylesheet') ??\n                  asset.attrs?.crossOrigin,\n                nonce,\n              },\n            },\n          ]\n        }\n\n        if (asset.tag === 'style') {\n          return [\n            {\n              tag: 'style',\n              attrs: {\n                ...asset.attrs,\n                nonce,\n              },\n              children: asset.children,\n              ...(asset.inlineCss ? { inlineCss: true as const } : {}),\n            },\n          ]\n        }\n\n        return []\n      })\n\n    return [...constructed, ...assets]\n  })\n\n  const preloadLinks = Solid.createMemo(() => {\n    const matches = activeMatches()\n    const preloadLinks: Array<RouterManagedTag> = []\n\n    matches\n      .map((match) => router.looseRoutesById[match.routeId]!)\n      .forEach((route) =>\n        router.ssr?.manifest?.routes[route.id]?.preloads\n          ?.filter(Boolean)\n          .forEach((preload) => {\n            const preloadLink = resolveManifestAssetLink(preload)\n            preloadLinks.push({\n              tag: 'link',\n              attrs: {\n                rel: 'modulepreload',\n                href: preloadLink.href,\n                crossOrigin:\n                  getAssetCrossOrigin(assetCrossOrigin, 'modulepreload') ??\n                  preloadLink.crossOrigin,\n                nonce,\n              },\n            })\n          }),\n      )\n\n    return preloadLinks\n  })\n\n  const styles = Solid.createMemo(() =>\n    (\n      activeMatches()\n        .map((match) => match.styles!)\n        .flat(1)\n        .filter(Boolean) as Array<RouterManagedTag>\n    ).map(({ children, ...style }) => ({\n      tag: 'style',\n      attrs: {\n        ...style,\n        nonce,\n      },\n      children,\n    })),\n  )\n\n  const headScripts = Solid.createMemo(() =>\n    (\n      activeMatches()\n        .map((match) => match.headScripts!)\n        .flat(1)\n        .filter(Boolean) as Array<RouterManagedTag>\n    ).map(({ children, ...script }) => ({\n      tag: 'script',\n      attrs: {\n        ...script,\n        nonce,\n      },\n      children,\n    })),\n  )\n\n  return Solid.createMemo((prev: Array<RouterManagedTag> | undefined) => {\n    const next = uniqBy(\n      [\n        ...meta(),\n        ...preloadLinks(),\n        ...links(),\n        ...styles(),\n        ...headScripts(),\n      ] as Array<RouterManagedTag>,\n      (d) => {\n        return JSON.stringify(d)\n      },\n    )\n    if (prev === undefined) {\n      return next\n    }\n    return replaceEqualTags(prev, next)\n  })\n}\n\nfunction replaceEqualTags(\n  prev: Array<RouterManagedTag>,\n  next: Array<RouterManagedTag>,\n) {\n  const prevByKey = new Map<string, RouterManagedTag>()\n  for (const tag of prev) {\n    prevByKey.set(JSON.stringify(tag), tag)\n  }\n\n  let isEqual = prev.length === next.length\n  const result = next.map((tag, index) => {\n    const existing = prevByKey.get(JSON.stringify(tag))\n    if (existing) {\n      if (existing !== prev[index]) {\n        isEqual = false\n      }\n      return existing\n    }\n\n    isEqual = false\n    return tag\n  })\n\n  return isEqual ? prev : result\n}\n\nexport function uniqBy<T>(arr: Array<T>, fn: (item: T) => string) {\n  const seen = new Set<string>()\n  return arr.filter((item) => {\n    const key = fn(item)\n    if (seen.has(key)) {\n      return false\n    }\n    seen.add(key)\n    return true\n  })\n}\n"],"mappings":"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"}