@nuxtjs/sitemap 7.2.10 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/client/200.html +9 -9
  2. package/dist/client/404.html +9 -9
  3. package/dist/client/_nuxt/Cp-IABpG.js +1 -0
  4. package/dist/client/_nuxt/{DDzCRRw4.js → DJVkgDQ2.js} +1 -1
  5. package/dist/client/_nuxt/SmY-NWqO.js +172 -0
  6. package/dist/client/_nuxt/builds/latest.json +1 -1
  7. package/dist/client/_nuxt/builds/meta/e48bfd5b-6605-4bbc-a466-32a664787616.json +1 -0
  8. package/dist/client/_nuxt/error-404.CtcyoHAN.css +1 -0
  9. package/dist/client/_nuxt/error-500.BIlfyoPk.css +1 -0
  10. package/dist/client/_nuxt/{DdvkoY3I.js → lL_X76lO.js} +1 -1
  11. package/dist/client/index.html +9 -9
  12. package/dist/module.cjs +57 -18
  13. package/dist/module.json +2 -2
  14. package/dist/module.mjs +58 -19
  15. package/dist/runtime/server/plugins/warm-up.js +20 -4
  16. package/dist/runtime/server/routes/__sitemap__/debug.js +2 -2
  17. package/dist/runtime/server/routes/sitemap/[sitemap].xml.js +37 -7
  18. package/dist/runtime/server/routes/sitemap_index.xml.js +11 -3
  19. package/dist/runtime/server/sitemap/builder/sitemap-index.d.ts +1 -1
  20. package/dist/runtime/server/sitemap/builder/sitemap-index.js +110 -16
  21. package/dist/runtime/server/sitemap/builder/sitemap.d.ts +1 -1
  22. package/dist/runtime/server/sitemap/builder/sitemap.js +62 -36
  23. package/dist/runtime/server/sitemap/builder/xml.d.ts +2 -3
  24. package/dist/runtime/server/sitemap/builder/xml.js +182 -80
  25. package/dist/runtime/server/sitemap/nitro.js +68 -20
  26. package/dist/runtime/server/sitemap/urlset/normalise.js +21 -19
  27. package/dist/runtime/server/sitemap/urlset/sort.d.ts +1 -1
  28. package/dist/runtime/server/sitemap/urlset/sort.js +9 -15
  29. package/dist/runtime/server/sitemap/utils/chunk.d.ts +10 -0
  30. package/dist/runtime/server/sitemap/utils/chunk.js +66 -0
  31. package/dist/runtime/types.d.ts +44 -0
  32. package/dist/runtime/utils-pure.js +13 -5
  33. package/package.json +23 -22
  34. package/dist/client/_nuxt/BLmTiKMJ.js +0 -1
  35. package/dist/client/_nuxt/BUP090M8.js +0 -172
  36. package/dist/client/_nuxt/builds/meta/3c351607-eab3-459a-b743-aba04e49a80e.json +0 -1
  37. package/dist/client/_nuxt/error-404.BMkETmdU.css +0 -1
  38. package/dist/client/_nuxt/error-500.C3_I-O7u.css +0 -1
  39. /package/dist/client/_nuxt/{entry.BrROiVtQ.css → entry.CgW0_noo.css} +0 -0
@@ -1,11 +1,33 @@
1
1
  import { defu } from "defu";
2
2
  import { joinURL } from "ufo";
3
+ import { defineCachedFunction } from "nitropack/runtime";
4
+ import { getHeader } from "h3";
3
5
  import { normaliseDate } from "../urlset/normalise.js";
4
- import { globalSitemapSources, resolveSitemapSources } from "../urlset/sources.js";
5
- import { sortSitemapUrls } from "../urlset/sort.js";
6
- import { escapeValueForXml, wrapSitemapXml } from "./xml.js";
6
+ import { globalSitemapSources, childSitemapSources, resolveSitemapSources } from "../urlset/sources.js";
7
+ import { sortInPlace } from "../urlset/sort.js";
8
+ import { escapeValueForXml } from "./xml.js";
7
9
  import { resolveSitemapEntries } from "./sitemap.js";
8
- export async function buildSitemapIndex(resolvers, runtimeConfig, nitro) {
10
+ const buildSitemapIndexCached = defineCachedFunction(
11
+ async (event, resolvers, runtimeConfig, nitro) => {
12
+ return buildSitemapIndexInternal(resolvers, runtimeConfig, nitro);
13
+ },
14
+ {
15
+ name: "sitemap:index",
16
+ group: "sitemap",
17
+ maxAge: 60 * 10,
18
+ // 10 minutes default
19
+ base: "sitemap",
20
+ // Use the sitemap storage
21
+ getKey: (event) => {
22
+ const host = getHeader(event, "host") || getHeader(event, "x-forwarded-host") || "";
23
+ const proto = getHeader(event, "x-forwarded-proto") || "https";
24
+ return `sitemap-index-${proto}-${host}`;
25
+ },
26
+ swr: true
27
+ // Enable stale-while-revalidate
28
+ }
29
+ );
30
+ async function buildSitemapIndexInternal(resolvers, runtimeConfig, nitro) {
9
31
  const {
10
32
  sitemaps,
11
33
  // enhancing
@@ -20,13 +42,32 @@ export async function buildSitemapIndex(resolvers, runtimeConfig, nitro) {
20
42
  if (!sitemaps)
21
43
  throw new Error("Attempting to build a sitemap index without required `sitemaps` configuration.");
22
44
  function maybeSort(urls) {
23
- return sortEntries ? sortSitemapUrls(urls) : urls;
45
+ return sortEntries ? sortInPlace(urls) : urls;
24
46
  }
25
- const isChunking = typeof sitemaps.chunks !== "undefined";
26
47
  const chunks = {};
27
- if (isChunking) {
48
+ for (const sitemapName in sitemaps) {
49
+ if (sitemapName === "index" || sitemapName === "chunks") continue;
50
+ const sitemapConfig = sitemaps[sitemapName];
51
+ if (sitemapConfig.chunks || sitemapConfig._isChunking) {
52
+ sitemapConfig._isChunking = true;
53
+ sitemapConfig._chunkSize = typeof sitemapConfig.chunks === "number" ? sitemapConfig.chunks : sitemapConfig.chunkSize || defaultSitemapsChunkSize || 1e3;
54
+ } else {
55
+ chunks[sitemapName] = chunks[sitemapName] || { urls: [] };
56
+ }
57
+ }
58
+ if (typeof sitemaps.chunks !== "undefined") {
28
59
  const sitemap = sitemaps.chunks;
29
- const sources = await resolveSitemapSources(await globalSitemapSources());
60
+ let sourcesInput = await globalSitemapSources();
61
+ if (nitro && resolvers.event) {
62
+ const ctx = {
63
+ event: resolvers.event,
64
+ sitemapName: sitemap.sitemapName,
65
+ sources: sourcesInput
66
+ };
67
+ await nitro.hooks.callHook("sitemap:sources", ctx);
68
+ sourcesInput = ctx.sources;
69
+ }
70
+ const sources = await resolveSitemapSources(sourcesInput, resolvers.event);
30
71
  const resolvedCtx = {
31
72
  urls: sources.flatMap((s) => s.urls),
32
73
  sitemapName: sitemap.sitemapName,
@@ -41,12 +82,6 @@ export async function buildSitemapIndex(resolvers, runtimeConfig, nitro) {
41
82
  chunks[chunkIndex] = chunks[chunkIndex] || { urls: [] };
42
83
  chunks[chunkIndex].urls.push(url);
43
84
  });
44
- } else {
45
- for (const sitemap in sitemaps) {
46
- if (sitemap !== "index") {
47
- chunks[sitemap] = chunks[sitemap] || { urls: [] };
48
- }
49
- }
50
85
  }
51
86
  const entries = [];
52
87
  for (const name in chunks) {
@@ -62,6 +97,48 @@ export async function buildSitemapIndex(resolvers, runtimeConfig, nitro) {
62
97
  entry.lastmod = normaliseDate(lastmod);
63
98
  entries.push(entry);
64
99
  }
100
+ for (const sitemapName in sitemaps) {
101
+ if (sitemapName !== "index" && sitemaps[sitemapName]._isChunking) {
102
+ const sitemapConfig = sitemaps[sitemapName];
103
+ const chunkSize = sitemapConfig._chunkSize || defaultSitemapsChunkSize || 1e3;
104
+ let sourcesInput = sitemapConfig.includeAppSources ? await globalSitemapSources() : [];
105
+ sourcesInput.push(...await childSitemapSources(sitemapConfig));
106
+ if (nitro && resolvers.event) {
107
+ const ctx = {
108
+ event: resolvers.event,
109
+ sitemapName: sitemapConfig.sitemapName,
110
+ sources: sourcesInput
111
+ };
112
+ await nitro.hooks.callHook("sitemap:sources", ctx);
113
+ sourcesInput = ctx.sources;
114
+ }
115
+ const sources = await resolveSitemapSources(sourcesInput, resolvers.event);
116
+ const resolvedCtx = {
117
+ urls: sources.flatMap((s) => s.urls),
118
+ sitemapName: sitemapConfig.sitemapName,
119
+ event: resolvers.event
120
+ };
121
+ await nitro?.hooks.callHook("sitemap:input", resolvedCtx);
122
+ const normalisedUrls = resolveSitemapEntries(sitemapConfig, resolvedCtx.urls, { autoI18n, isI18nMapped }, resolvers);
123
+ const totalUrls = normalisedUrls.length;
124
+ const chunkCount = Math.ceil(totalUrls / chunkSize);
125
+ sitemapConfig._chunkCount = chunkCount;
126
+ for (let i = 0; i < chunkCount; i++) {
127
+ const chunkName = `${sitemapName}-${i}`;
128
+ const entry = {
129
+ _sitemapName: chunkName,
130
+ sitemap: resolvers.canonicalUrlResolver(joinURL(sitemapsPathPrefix || "", `/${chunkName}.xml`))
131
+ };
132
+ const chunkUrls = normalisedUrls.slice(i * chunkSize, (i + 1) * chunkSize);
133
+ let lastmod = chunkUrls.filter((a) => !!a?.lastmod).map((a) => typeof a.lastmod === "string" ? new Date(a.lastmod) : a.lastmod).sort((a, b) => (b?.getTime() || 0) - (a?.getTime() || 0))?.[0];
134
+ if (!lastmod && autoLastmod)
135
+ lastmod = /* @__PURE__ */ new Date();
136
+ if (lastmod)
137
+ entry.lastmod = normaliseDate(lastmod);
138
+ entries.push(entry);
139
+ }
140
+ }
141
+ }
65
142
  if (sitemaps.index) {
66
143
  entries.push(...sitemaps.index.sitemaps.map((entry) => {
67
144
  return typeof entry === "string" ? { sitemap: entry } : entry;
@@ -77,9 +154,26 @@ export function urlsToIndexXml(sitemaps, resolvers, { version, xsl, credits, min
77
154
  e.lastmod ? ` <lastmod>${escapeValueForXml(e.lastmod)}</lastmod>` : false,
78
155
  " </sitemap>"
79
156
  ].filter(Boolean).join("\n")).join("\n");
80
- return wrapSitemapXml([
157
+ const xmlParts = [
158
+ '<?xml version="1.0" encoding="UTF-8"?>'
159
+ ];
160
+ if (xsl) {
161
+ const relativeBaseUrl = resolvers.relativeBaseUrlResolver?.(xsl) ?? xsl;
162
+ xmlParts.push(`<?xml-stylesheet type="text/xsl" href="${escapeValueForXml(relativeBaseUrl)}"?>`);
163
+ }
164
+ xmlParts.push(
81
165
  '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
82
166
  sitemapXml,
83
167
  "</sitemapindex>"
84
- ], resolvers, { version, xsl, credits, minify });
168
+ );
169
+ if (credits) {
170
+ xmlParts.push(`<!-- XML Sitemap Index generated by @nuxtjs/sitemap v${version} at ${(/* @__PURE__ */ new Date()).toISOString()} -->`);
171
+ }
172
+ return minify ? xmlParts.join("").replace(/(?<!<[^>]*)\s(?![^<]*>)/g, "") : xmlParts.join("\n");
173
+ }
174
+ export async function buildSitemapIndex(resolvers, runtimeConfig, nitro) {
175
+ if (!import.meta.dev && !!runtimeConfig.cacheMaxAgeSeconds && runtimeConfig.cacheMaxAgeSeconds > 0 && resolvers.event) {
176
+ return buildSitemapIndexCached(resolvers.event, resolvers, runtimeConfig, nitro);
177
+ }
178
+ return buildSitemapIndexInternal(resolvers, runtimeConfig, nitro);
85
179
  }
@@ -7,4 +7,4 @@ export interface NormalizedI18n extends ResolvedSitemapUrl {
7
7
  }
8
8
  export declare function resolveSitemapEntries(sitemap: SitemapDefinition, urls: SitemapUrlInput[], runtimeConfig: Pick<ModuleRuntimeConfig, 'autoI18n' | 'isI18nMapped'>, resolvers?: NitroUrlResolvers): ResolvedSitemapUrl[];
9
9
  export declare function buildSitemapUrls(sitemap: SitemapDefinition, resolvers: NitroUrlResolvers, runtimeConfig: ModuleRuntimeConfig, nitro?: NitroApp): Promise<ResolvedSitemapUrl[]>;
10
- export declare function urlsToXml(urls: ResolvedSitemapUrl[], resolvers: NitroUrlResolvers, { version, xsl, credits, minify }: Pick<ModuleRuntimeConfig, 'version' | 'xsl' | 'credits' | 'minify'>): string;
10
+ export { urlsToXml } from './xml.js';
@@ -2,9 +2,9 @@ import { resolveSitePath } from "nuxt-site-config/urls";
2
2
  import { joinURL, withHttps } from "ufo";
3
3
  import { preNormalizeEntry } from "../urlset/normalise.js";
4
4
  import { childSitemapSources, globalSitemapSources, resolveSitemapSources } from "../urlset/sources.js";
5
- import { sortSitemapUrls } from "../urlset/sort.js";
5
+ import { sortInPlace } from "../urlset/sort.js";
6
6
  import { createPathFilter, logger, splitForLocales } from "../../../utils-pure.js";
7
- import { handleEntry, wrapSitemapXml } from "./xml.js";
7
+ import { parseChunkInfo, sliceUrlsForChunk } from "../utils/chunk.js";
8
8
  export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
9
9
  const {
10
10
  autoI18n,
@@ -85,9 +85,23 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
85
85
  });
86
86
  } else {
87
87
  for (const l of autoI18n.locales) {
88
- let loc = joinURL(`/${l.code}`, e._pathWithoutPrefix);
89
- if (autoI18n.differentDomains || ["prefix_and_default", "prefix_except_default"].includes(autoI18n.strategy) && l.code === autoI18n.defaultLocale)
90
- loc = e._pathWithoutPrefix;
88
+ let loc = e._pathWithoutPrefix;
89
+ if (autoI18n.pages) {
90
+ const pageKey = e._pathWithoutPrefix.replace(/^\//, "").replace(/\/index$/, "") || "index";
91
+ const pageMappings = autoI18n.pages[pageKey];
92
+ if (pageMappings && pageMappings[l.code] !== void 0) {
93
+ const customPath = pageMappings[l.code];
94
+ if (customPath === false)
95
+ continue;
96
+ if (typeof customPath === "string")
97
+ loc = customPath.startsWith("/") ? customPath : `/${customPath}`;
98
+ } else if (!autoI18n.differentDomains && !(["prefix_and_default", "prefix_except_default"].includes(autoI18n.strategy) && l.code === autoI18n.defaultLocale)) {
99
+ loc = joinURL(`/${l.code}`, e._pathWithoutPrefix);
100
+ }
101
+ } else {
102
+ if (!autoI18n.differentDomains && !(["prefix_and_default", "prefix_except_default"].includes(autoI18n.strategy) && l.code === autoI18n.defaultLocale))
103
+ loc = joinURL(`/${l.code}`, e._pathWithoutPrefix);
104
+ }
91
105
  const _sitemap = isI18nMapped ? l._sitemap : void 0;
92
106
  const newEntry = preNormalizeEntry({
93
107
  _sitemap,
@@ -99,14 +113,30 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
99
113
  alternatives: [{ code: "x-default", _hreflang: "x-default" }, ...autoI18n.locales].map((locale) => {
100
114
  const code = locale.code === "x-default" ? autoI18n.defaultLocale : locale.code;
101
115
  const isDefault = locale.code === "x-default" || locale.code === autoI18n.defaultLocale;
102
- let href = "";
103
- if (autoI18n.strategy === "prefix") {
104
- href = joinURL("/", code, e._pathWithoutPrefix);
105
- } else if (["prefix_and_default", "prefix_except_default"].includes(autoI18n.strategy)) {
106
- if (isDefault) {
107
- href = e._pathWithoutPrefix;
108
- } else {
116
+ let href = e._pathWithoutPrefix;
117
+ if (autoI18n.pages) {
118
+ const pageKey = e._pathWithoutPrefix.replace(/^\//, "").replace(/\/index$/, "") || "index";
119
+ const pageMappings = autoI18n.pages[pageKey];
120
+ if (pageMappings && pageMappings[code] !== void 0) {
121
+ const customPath = pageMappings[code];
122
+ if (customPath === false)
123
+ return false;
124
+ if (typeof customPath === "string")
125
+ href = customPath.startsWith("/") ? customPath : `/${customPath}`;
126
+ } else if (autoI18n.strategy === "prefix") {
109
127
  href = joinURL("/", code, e._pathWithoutPrefix);
128
+ } else if (["prefix_and_default", "prefix_except_default"].includes(autoI18n.strategy)) {
129
+ if (!isDefault) {
130
+ href = joinURL("/", code, e._pathWithoutPrefix);
131
+ }
132
+ }
133
+ } else {
134
+ if (autoI18n.strategy === "prefix") {
135
+ href = joinURL("/", code, e._pathWithoutPrefix);
136
+ } else if (["prefix_and_default", "prefix_except_default"].includes(autoI18n.strategy)) {
137
+ if (!isDefault) {
138
+ href = joinURL("/", code, e._pathWithoutPrefix);
139
+ }
110
140
  }
111
141
  }
112
142
  if (!filterPath(href))
@@ -151,16 +181,12 @@ export async function buildSitemapUrls(sitemap, resolvers, runtimeConfig, nitro)
151
181
  // chunking
152
182
  defaultSitemapsChunkSize
153
183
  } = runtimeConfig;
154
- const isChunking = typeof sitemaps.chunks !== "undefined" && !Number.isNaN(Number(sitemap.sitemapName));
184
+ const chunkInfo = parseChunkInfo(sitemap.sitemapName, sitemaps, defaultSitemapsChunkSize);
155
185
  function maybeSort(urls) {
156
- return sortEntries ? sortSitemapUrls(urls) : urls;
186
+ return sortEntries ? sortInPlace(urls) : urls;
157
187
  }
158
188
  function maybeSlice(urls) {
159
- if (isChunking && defaultSitemapsChunkSize) {
160
- const chunk = Number(sitemap.sitemapName);
161
- return urls.slice(chunk * defaultSitemapsChunkSize, (chunk + 1) * defaultSitemapsChunkSize);
162
- }
163
- return urls;
189
+ return sliceUrlsForChunk(urls, sitemap.sitemapName, sitemaps, defaultSitemapsChunkSize);
164
190
  }
165
191
  if (autoI18n?.differentDomains) {
166
192
  const domain = autoI18n.locales.find((e) => [e.language, e.code].includes(sitemap.sitemapName))?.domain;
@@ -175,8 +201,22 @@ export async function buildSitemapUrls(sitemap, resolvers, runtimeConfig, nitro)
175
201
  });
176
202
  }
177
203
  }
178
- const sourcesInput = sitemap.includeAppSources ? await globalSitemapSources() : [];
179
- sourcesInput.push(...await childSitemapSources(sitemap));
204
+ let effectiveSitemap = sitemap;
205
+ const baseSitemapName = chunkInfo.baseSitemapName;
206
+ if (chunkInfo.isChunked && baseSitemapName !== sitemap.sitemapName && sitemaps[baseSitemapName]) {
207
+ effectiveSitemap = sitemaps[baseSitemapName];
208
+ }
209
+ let sourcesInput = effectiveSitemap.includeAppSources ? await globalSitemapSources() : [];
210
+ sourcesInput.push(...await childSitemapSources(effectiveSitemap));
211
+ if (nitro && resolvers.event) {
212
+ const ctx = {
213
+ event: resolvers.event,
214
+ sitemapName: baseSitemapName,
215
+ sources: sourcesInput
216
+ };
217
+ await nitro.hooks.callHook("sitemap:sources", ctx);
218
+ sourcesInput = ctx.sources;
219
+ }
180
220
  const sources = await resolveSitemapSources(sourcesInput, resolvers.event);
181
221
  const resolvedCtx = {
182
222
  urls: sources.flatMap((s) => s.urls),
@@ -193,18 +233,4 @@ export async function buildSitemapUrls(sitemap, resolvers, runtimeConfig, nitro)
193
233
  const sortedUrls = maybeSort(filteredUrls);
194
234
  return maybeSlice(sortedUrls);
195
235
  }
196
- export function urlsToXml(urls, resolvers, { version, xsl, credits, minify }) {
197
- const urlset = urls.map((e) => {
198
- const keys = Object.keys(e).filter((k) => !k.startsWith("_"));
199
- return [
200
- " <url>",
201
- keys.map((k) => handleEntry(k, e)).filter(Boolean).join("\n"),
202
- " </url>"
203
- ].join("\n");
204
- });
205
- return wrapSitemapXml([
206
- '<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd http://www.google.com/schemas/sitemap-image/1.1 http://www.google.com/schemas/sitemap-image/1.1/sitemap-image.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
207
- urlset.join("\n"),
208
- "</urlset>"
209
- ], resolvers, { version, xsl, credits, minify });
210
- }
236
+ export { urlsToXml } from "./xml.js";
@@ -1,4 +1,3 @@
1
- import type { ModuleRuntimeConfig, NitroUrlResolvers } from '../../../types.js';
2
- export declare function handleEntry(k: string, e: Record<string, any> | (string | Record<string, any>)[]): string | false;
3
- export declare function wrapSitemapXml(input: string[], resolvers: NitroUrlResolvers, options: Pick<ModuleRuntimeConfig, 'version' | 'xsl' | 'credits' | 'minify'>): string;
1
+ import type { ModuleRuntimeConfig, NitroUrlResolvers, ResolvedSitemapUrl } from '../../../types.js';
4
2
  export declare function escapeValueForXml(value: boolean | string | number): string;
3
+ export declare function urlsToXml(urls: ResolvedSitemapUrl[], resolvers: NitroUrlResolvers, { version, xsl, credits, minify }: Pick<ModuleRuntimeConfig, 'version' | 'xsl' | 'credits' | 'minify'>): string;
@@ -1,86 +1,188 @@
1
- function resolveKey(k) {
2
- switch (k) {
3
- case "images":
4
- return "image";
5
- case "videos":
6
- return "video";
7
- // news & others?
8
- case "news":
9
- return "news";
10
- default:
11
- return k;
12
- }
1
+ export function escapeValueForXml(value) {
2
+ if (value === true || value === false)
3
+ return value ? "yes" : "no";
4
+ return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
13
5
  }
14
- function handleObject(key, obj) {
15
- return [
16
- ` <${key}:${key}>`,
17
- ...Object.entries(obj).map(([sk, sv]) => {
18
- if (key === "video" && Array.isArray(sv)) {
19
- return sv.map((v) => {
20
- if (typeof v === "string") {
21
- return [
22
- ` `,
23
- `<${key}:${sk}>`,
24
- escapeValueForXml(v),
25
- `</${key}:${sk}>`
26
- ].join("");
6
+ const URLSET_OPENING_TAG = '<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd http://www.google.com/schemas/sitemap-image/1.1 http://www.google.com/schemas/sitemap-image/1.1/sitemap-image.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
7
+ function buildUrlXml(url) {
8
+ const capacity = 50;
9
+ const parts = Array.from({ length: capacity });
10
+ let partIndex = 0;
11
+ parts[partIndex++] = " <url>";
12
+ if (url.loc) {
13
+ parts[partIndex++] = ` <loc>${escapeValueForXml(url.loc)}</loc>`;
14
+ }
15
+ if (url.lastmod) {
16
+ parts[partIndex++] = ` <lastmod>${url.lastmod}</lastmod>`;
17
+ }
18
+ if (url.changefreq) {
19
+ parts[partIndex++] = ` <changefreq>${url.changefreq}</changefreq>`;
20
+ }
21
+ if (url.priority !== void 0) {
22
+ const priorityValue = Number.parseFloat(String(url.priority));
23
+ const formattedPriority = priorityValue % 1 === 0 ? String(priorityValue) : priorityValue.toFixed(1);
24
+ parts[partIndex++] = ` <priority>${formattedPriority}</priority>`;
25
+ }
26
+ const keys = Object.keys(url).filter((k) => !k.startsWith("_") && !["loc", "lastmod", "changefreq", "priority"].includes(k));
27
+ for (const key of keys) {
28
+ const value = url[key];
29
+ if (value === void 0 || value === null) continue;
30
+ switch (key) {
31
+ case "alternatives":
32
+ if (Array.isArray(value) && value.length > 0) {
33
+ for (const alt of value) {
34
+ const attrs = Object.entries(alt).map(([k, v]) => `${k}="${escapeValueForXml(v)}"`).join(" ");
35
+ parts[partIndex++] = ` <xhtml:link rel="alternate" ${attrs} />`;
27
36
  }
28
- const attributes = Object.entries(v).filter(([ssk]) => ssk !== sk).map(([ssk, ssv]) => `${ssk}="${escapeValueForXml(ssv)}"`).join(" ");
29
- return [
30
- ` <${key}:${sk} ${attributes}>`,
31
- // value is the same sk
32
- v[sk],
33
- `</${key}:${sk}>`
34
- ].join("");
35
- }).join("\n");
36
- }
37
- if (typeof sv === "object") {
38
- if (key === "video") {
39
- const attributes = Object.entries(sv).filter(([ssk]) => ssk !== sk).map(([ssk, ssv]) => `${ssk}="${escapeValueForXml(ssv)}"`).join(" ");
40
- return [
41
- ` <${key}:${sk} ${attributes}>`,
42
- // value is the same sk
43
- sv[sk],
44
- `</${key}:${sk}>`
45
- ].join("");
46
37
  }
47
- return [
48
- ` <${key}:${sk}>`,
49
- ...Object.entries(sv).map(([ssk, ssv]) => ` <${key}:${ssk}>${escapeValueForXml(ssv)}</${key}:${ssk}>`),
50
- ` </${key}:${sk}>`
51
- ].join("\n");
52
- }
53
- return ` <${key}:${sk}>${escapeValueForXml(sv)}</${key}:${sk}>`;
54
- }),
55
- ` </${key}:${key}>`
56
- ].join("\n");
57
- }
58
- function handleArray(key, arr) {
59
- if (arr.length === 0)
60
- return false;
61
- key = resolveKey(key);
62
- if (key === "alternatives") {
63
- return arr.map((obj) => [
64
- ` <xhtml:link rel="alternate" ${Object.entries(obj).map(([sk, sv]) => `${sk}="${escapeValueForXml(sv)}"`).join(" ")} />`
65
- ].join("\n")).join("\n");
38
+ break;
39
+ case "images":
40
+ if (Array.isArray(value) && value.length > 0) {
41
+ for (const img of value) {
42
+ parts[partIndex++] = " <image:image>";
43
+ parts[partIndex++] = ` <image:loc>${escapeValueForXml(img.loc)}</image:loc>`;
44
+ if (img.title) parts[partIndex++] = ` <image:title>${escapeValueForXml(img.title)}</image:title>`;
45
+ if (img.caption) parts[partIndex++] = ` <image:caption>${escapeValueForXml(img.caption)}</image:caption>`;
46
+ if (img.geo_location) parts[partIndex++] = ` <image:geo_location>${escapeValueForXml(img.geo_location)}</image:geo_location>`;
47
+ if (img.license) parts[partIndex++] = ` <image:license>${escapeValueForXml(img.license)}</image:license>`;
48
+ parts[partIndex++] = " </image:image>";
49
+ }
50
+ }
51
+ break;
52
+ case "videos":
53
+ if (Array.isArray(value) && value.length > 0) {
54
+ for (const video of value) {
55
+ parts[partIndex++] = " <video:video>";
56
+ parts[partIndex++] = ` <video:title>${escapeValueForXml(video.title)}</video:title>`;
57
+ if (video.thumbnail_loc) {
58
+ parts[partIndex++] = ` <video:thumbnail_loc>${escapeValueForXml(video.thumbnail_loc)}</video:thumbnail_loc>`;
59
+ }
60
+ parts[partIndex++] = ` <video:description>${escapeValueForXml(video.description)}</video:description>`;
61
+ if (video.content_loc) {
62
+ parts[partIndex++] = ` <video:content_loc>${escapeValueForXml(video.content_loc)}</video:content_loc>`;
63
+ }
64
+ if (video.player_loc) {
65
+ const attrs = video.player_loc.allow_embed ? ' allow_embed="yes"' : "";
66
+ const autoplay = video.player_loc.autoplay ? ' autoplay="yes"' : "";
67
+ parts[partIndex++] = ` <video:player_loc${attrs}${autoplay}>${escapeValueForXml(video.player_loc)}</video:player_loc>`;
68
+ }
69
+ if (video.duration !== void 0) {
70
+ parts[partIndex++] = ` <video:duration>${video.duration}</video:duration>`;
71
+ }
72
+ if (video.expiration_date) {
73
+ parts[partIndex++] = ` <video:expiration_date>${video.expiration_date}</video:expiration_date>`;
74
+ }
75
+ if (video.rating !== void 0) {
76
+ parts[partIndex++] = ` <video:rating>${video.rating}</video:rating>`;
77
+ }
78
+ if (video.view_count !== void 0) {
79
+ parts[partIndex++] = ` <video:view_count>${video.view_count}</video:view_count>`;
80
+ }
81
+ if (video.publication_date) {
82
+ parts[partIndex++] = ` <video:publication_date>${video.publication_date}</video:publication_date>`;
83
+ }
84
+ if (video.family_friendly !== void 0) {
85
+ parts[partIndex++] = ` <video:family_friendly>${video.family_friendly === "yes" || video.family_friendly === true ? "yes" : "no"}</video:family_friendly>`;
86
+ }
87
+ if (video.restriction) {
88
+ const relationship = video.restriction.relationship || "allow";
89
+ parts[partIndex++] = ` <video:restriction relationship="${relationship}">${escapeValueForXml(video.restriction.restriction)}</video:restriction>`;
90
+ }
91
+ if (video.platform) {
92
+ const relationship = video.platform.relationship || "allow";
93
+ parts[partIndex++] = ` <video:platform relationship="${relationship}">${escapeValueForXml(video.platform.platform)}</video:platform>`;
94
+ }
95
+ if (video.requires_subscription !== void 0) {
96
+ parts[partIndex++] = ` <video:requires_subscription>${video.requires_subscription === "yes" || video.requires_subscription === true ? "yes" : "no"}</video:requires_subscription>`;
97
+ }
98
+ if (video.price) {
99
+ const prices = Array.isArray(video.price) ? video.price : [video.price];
100
+ for (const price of prices) {
101
+ const attrs = [];
102
+ if (price.currency) attrs.push(`currency="${price.currency}"`);
103
+ if (price.type) attrs.push(`type="${price.type}"`);
104
+ const attrsStr = attrs.length > 0 ? " " + attrs.join(" ") : "";
105
+ parts[partIndex++] = ` <video:price${attrsStr}>${escapeValueForXml(price.price)}</video:price>`;
106
+ }
107
+ }
108
+ if (video.uploader) {
109
+ const info = video.uploader.info ? ` info="${escapeValueForXml(video.uploader.info)}"` : "";
110
+ parts[partIndex++] = ` <video:uploader${info}>${escapeValueForXml(video.uploader.uploader)}</video:uploader>`;
111
+ }
112
+ if (video.live !== void 0) {
113
+ parts[partIndex++] = ` <video:live>${video.live === "yes" || video.live === true ? "yes" : "no"}</video:live>`;
114
+ }
115
+ if (video.tag) {
116
+ const tags = Array.isArray(video.tag) ? video.tag : [video.tag];
117
+ for (const tag of tags) {
118
+ parts[partIndex++] = ` <video:tag>${escapeValueForXml(tag)}</video:tag>`;
119
+ }
120
+ }
121
+ if (video.category) {
122
+ parts[partIndex++] = ` <video:category>${escapeValueForXml(video.category)}</video:category>`;
123
+ }
124
+ if (video.gallery_loc) {
125
+ const title = video.gallery_loc.title ? ` title="${escapeValueForXml(video.gallery_loc.title)}"` : "";
126
+ parts[partIndex++] = ` <video:gallery_loc${title}>${escapeValueForXml(video.gallery_loc)}</video:gallery_loc>`;
127
+ }
128
+ parts[partIndex++] = " </video:video>";
129
+ }
130
+ }
131
+ break;
132
+ case "news":
133
+ if (value) {
134
+ parts[partIndex++] = " <news:news>";
135
+ parts[partIndex++] = " <news:publication>";
136
+ parts[partIndex++] = ` <news:name>${escapeValueForXml(value.publication.name)}</news:name>`;
137
+ parts[partIndex++] = ` <news:language>${escapeValueForXml(value.publication.language)}</news:language>`;
138
+ parts[partIndex++] = " </news:publication>";
139
+ if (value.title) {
140
+ parts[partIndex++] = ` <news:title>${escapeValueForXml(value.title)}</news:title>`;
141
+ }
142
+ if (value.publication_date) {
143
+ parts[partIndex++] = ` <news:publication_date>${value.publication_date}</news:publication_date>`;
144
+ }
145
+ if (value.access) {
146
+ parts[partIndex++] = ` <news:access>${value.access}</news:access>`;
147
+ }
148
+ if (value.genres) {
149
+ parts[partIndex++] = ` <news:genres>${escapeValueForXml(value.genres)}</news:genres>`;
150
+ }
151
+ if (value.keywords) {
152
+ parts[partIndex++] = ` <news:keywords>${escapeValueForXml(value.keywords)}</news:keywords>`;
153
+ }
154
+ if (value.stock_tickers) {
155
+ parts[partIndex++] = ` <news:stock_tickers>${escapeValueForXml(value.stock_tickers)}</news:stock_tickers>`;
156
+ }
157
+ parts[partIndex++] = " </news:news>";
158
+ }
159
+ break;
160
+ }
66
161
  }
67
- return arr.map((obj) => handleObject(key, obj)).join("\n");
68
- }
69
- export function handleEntry(k, e) {
70
- return Array.isArray(e[k]) ? handleArray(k, e[k]) : typeof e[k] === "object" ? handleObject(k, e[k]) : ` <${k}>${escapeValueForXml(e[k])}</${k}>`;
162
+ parts[partIndex++] = " </url>";
163
+ return parts.slice(0, partIndex).join("\n");
71
164
  }
72
- export function wrapSitemapXml(input, resolvers, options) {
73
- const xsl = options.xsl ? resolvers.relativeBaseUrlResolver(options.xsl) : false;
74
- const credits = options.credits;
75
- input.unshift(`<?xml version="1.0" encoding="UTF-8"?>${xsl ? `<?xml-stylesheet type="text/xsl" href="${xsl}"?>` : ""}`);
76
- if (credits)
77
- input.push(`<!-- XML Sitemap generated by @nuxtjs/sitemap v${options.version} at ${(/* @__PURE__ */ new Date()).toISOString()} -->`);
78
- if (options.minify)
79
- return input.join("").replace(/(?<!<[^>]*)\s(?![^<]*>)/g, "");
80
- return input.join("\n");
81
- }
82
- export function escapeValueForXml(value) {
83
- if (value === true || value === false)
84
- return value ? "yes" : "no";
85
- return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
165
+ export function urlsToXml(urls, resolvers, { version, xsl, credits, minify }) {
166
+ const estimatedSize = urls.length + 5;
167
+ const xmlParts = Array.from({ length: estimatedSize });
168
+ let partIndex = 0;
169
+ const xslHref = xsl ? resolvers.relativeBaseUrlResolver(xsl) : false;
170
+ if (xslHref) {
171
+ xmlParts[partIndex++] = `<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="${xslHref}"?>`;
172
+ } else {
173
+ xmlParts[partIndex++] = '<?xml version="1.0" encoding="UTF-8"?>';
174
+ }
175
+ xmlParts[partIndex++] = URLSET_OPENING_TAG;
176
+ for (const url of urls) {
177
+ xmlParts[partIndex++] = buildUrlXml(url);
178
+ }
179
+ xmlParts[partIndex++] = "</urlset>";
180
+ if (credits) {
181
+ xmlParts[partIndex++] = `<!-- XML Sitemap generated by @nuxtjs/sitemap v${version} at ${(/* @__PURE__ */ new Date()).toISOString()} -->`;
182
+ }
183
+ const xmlContent = xmlParts.slice(0, partIndex);
184
+ if (minify) {
185
+ return xmlContent.join("").replace(/(?<!<[^>]*)\s(?![^<]*>)/g, "");
186
+ }
187
+ return xmlContent.join("\n");
86
188
  }