import type * as interfaces from './interfaces/index.js'; import { XmlRenderer } from './smartsitemap.classes.xmlrenderer.js'; import { UrlsetBuilder } from './smartsitemap.classes.urlsetbuilder.js'; /** * Builder for sitemap index files (). * Used when you have multiple sitemaps that need to be referenced from a single index. * Every mutating method returns `this` for fluent chaining. */ export class SitemapIndexBuilder { private entries: interfaces.ISitemapIndexEntry[] = []; private options: interfaces.ISitemapOptions; constructor(options?: interfaces.ISitemapOptions) { this.options = options ?? {}; } /** Add a sitemap index entry */ add(entry: interfaces.ISitemapIndexEntry): this { this.entries.push(entry); return this; } /** Add a sitemap by URL, optionally with lastmod */ addSitemap(loc: string, lastmod?: Date | string | number): this { const entry: interfaces.ISitemapIndexEntry = { loc }; if (lastmod != null) { entry.lastmod = lastmod; } this.entries.push(entry); return this; } /** Add multiple sitemap entries */ addSitemaps(entries: interfaces.ISitemapIndexEntry[]): this { this.entries.push(...entries); return this; } /** * Build an index and individual sitemaps from a UrlsetBuilder that needs splitting. * The builder's URLs are divided into chunks of maxUrlsPerSitemap. */ static fromBuilder( builder: UrlsetBuilder, baseUrl: string, ): { index: SitemapIndexBuilder; sitemaps: UrlsetBuilder[] } { const urls = builder.getUrls(); const options = builder.getOptions(); const maxUrls = Math.min(options.maxUrlsPerSitemap ?? 50000, 50000); const index = new SitemapIndexBuilder(options); const sitemaps: UrlsetBuilder[] = []; for (let i = 0; i < urls.length; i += maxUrls) { const chunk = urls.slice(i, i + maxUrls); const chunkBuilder = new UrlsetBuilder(options); chunkBuilder.addUrls(chunk); sitemaps.push(chunkBuilder); const filename = `sitemap-${sitemaps.length}.xml`; index.addSitemap(`${baseUrl.replace(/\/$/, '')}/${filename}`); } return { index, sitemaps }; } /** Export as sitemap index XML string */ toXml(): string { return XmlRenderer.renderIndex(this.entries, this.options); } /** Get all entries */ getEntries(): interfaces.ISitemapIndexEntry[] { return [...this.entries]; } /** Get the number of sitemaps in this index */ get count(): number { return this.entries.length; } }