import { SitemapStream, streamToPromise } from "sitemap"; import { absoluteUrl, normalizeSiteUrl } from "./url.js"; import type { SitemapEntry, SiteSeoConfig } from "./types.js"; /** * 生成 sitemap.xml 字符串(走官方 `sitemap` 包流式序列化)。 * 异步:stream 需 `streamToPromise` 冲刷。 */ export async function buildSitemapXml( site: Pick, entries: SitemapEntry[], ): Promise { const stream = new SitemapStream({ hostname: normalizeSiteUrl(site.siteUrl), }); const done = streamToPromise(stream); for (const e of entries) { stream.write({ url: absoluteUrl(site.siteUrl, e.url), ...(e.lastmod ? { lastmod: e.lastmod } : {}), ...(e.changefreq ? { changefreq: e.changefreq } : {}), ...(e.priority !== undefined ? { priority: Math.min(1, Math.max(0, e.priority)) } : {}), ...(e.alternates?.length ? { links: e.alternates.map((alt) => ({ url: absoluteUrl(site.siteUrl, alt.href), lang: alt.hreflang, })), } : {}), }); } stream.end(); const xml = await done; return String(xml); } /** 常用:从路径列表生成 entry(默认 priority/changefreq 可覆盖)。 */ export function pathsToEntries(paths: string[], defaults?: Partial): SitemapEntry[] { return paths.map((p) => { const { url: _u, ...rest } = defaults ?? {}; return { ...rest, url: p }; }); }