@nuxtjs/sitemap 7.4.8 → 7.4.10

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 (33) hide show
  1. package/dist/client/200.html +1 -1
  2. package/dist/client/404.html +1 -1
  3. package/dist/client/_nuxt/{BD3NqoLn.js → CjT5ejtq.js} +1 -1
  4. package/dist/client/_nuxt/{CGPPaMu7.js → DBmpb9dG.js} +1 -1
  5. package/dist/client/_nuxt/{HdjdXzAy.js → FE81ed4p.js} +14 -16
  6. package/dist/client/_nuxt/builds/latest.json +1 -1
  7. package/dist/client/_nuxt/builds/meta/698c1660-7b4c-4db3-a9a5-6c0e6240b3a7.json +1 -0
  8. package/dist/client/_nuxt/error-404.DC9fsYfS.css +1 -0
  9. package/dist/client/_nuxt/error-500.DPVweS-0.css +1 -0
  10. package/dist/client/index.html +1 -1
  11. package/dist/client/sitemap.xml +1 -1
  12. package/dist/content.d.mts +36 -37
  13. package/dist/content.d.ts +36 -37
  14. package/dist/content.mjs +1 -1
  15. package/dist/module.json +1 -1
  16. package/dist/module.mjs +38 -28
  17. package/dist/runtime/server/plugins/nuxt-content-v2.js +6 -7
  18. package/dist/runtime/server/routes/__sitemap__/debug.js +3 -2
  19. package/dist/runtime/server/routes/__sitemap__/nuxt-content-urls-v2.d.ts +1 -1
  20. package/dist/runtime/server/routes/__sitemap__/nuxt-content-urls-v3.d.ts +3 -1
  21. package/dist/runtime/server/routes/__sitemap__/nuxt-content-urls-v3.js +7 -6
  22. package/dist/runtime/server/routes/sitemap/[sitemap].xml.js +1 -1
  23. package/dist/runtime/server/sitemap/builder/sitemap.js +67 -74
  24. package/dist/runtime/server/sitemap/builder/xml.js +81 -169
  25. package/dist/runtime/server/sitemap/nitro.js +4 -3
  26. package/dist/runtime/server/sitemap/urlset/normalise.js +29 -26
  27. package/dist/runtime/types.d.ts +8 -2
  28. package/dist/runtime/utils-pure.js +1 -1
  29. package/dist/utils.mjs +1 -2
  30. package/package.json +21 -13
  31. package/dist/client/_nuxt/builds/meta/61bb4b51-7d01-424f-91fb-0e4ca01f7b22.json +0 -1
  32. package/dist/client/_nuxt/error-404.i2ufnNET.css +0 -1
  33. package/dist/client/_nuxt/error-500.CIrNTbBE.css +0 -1
@@ -3,8 +3,12 @@ import { joinURL, withHttps } from "ufo";
3
3
  import { preNormalizeEntry } from "../urlset/normalise.js";
4
4
  import { childSitemapSources, globalSitemapSources, resolveSitemapSources } from "../urlset/sources.js";
5
5
  import { sortInPlace } from "../urlset/sort.js";
6
- import { createPathFilter, logger, splitForLocales } from "../../../utils-pure.js";
6
+ import { createPathFilter, splitForLocales } from "../../../utils-pure.js";
7
7
  import { parseChunkInfo, sliceUrlsForChunk } from "../utils/chunk.js";
8
+ function getPageKey(pathWithoutPrefix) {
9
+ const stripped = pathWithoutPrefix[0] === "/" ? pathWithoutPrefix.slice(1) : pathWithoutPrefix;
10
+ return stripped.endsWith("/index") ? stripped.slice(0, -6) || "index" : stripped || "index";
11
+ }
8
12
  export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
9
13
  const {
10
14
  autoI18n,
@@ -21,10 +25,16 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
21
25
  return e;
22
26
  }).filter(Boolean);
23
27
  let validI18nUrlsForTransform = [];
24
- let warnIncorrectI18nTransformUsage = false;
25
28
  const withoutPrefixPaths = {};
26
29
  if (autoI18n && autoI18n.strategy !== "no_prefix") {
27
30
  const localeCodes = autoI18n.locales.map((l) => l.code);
31
+ const localeByCode = new Map(autoI18n.locales.map((l) => [l.code, l]));
32
+ const isPrefixStrategy = autoI18n.strategy === "prefix";
33
+ const isPrefixExceptOrAndDefault = autoI18n.strategy === "prefix_and_default" || autoI18n.strategy === "prefix_except_default";
34
+ const xDefaultAndLocales = [{ code: "x-default", _hreflang: "x-default" }, ...autoI18n.locales];
35
+ const defaultLocale = autoI18n.defaultLocale;
36
+ const hasPages = !!autoI18n.pages;
37
+ const hasDifferentDomains = !!autoI18n.differentDomains;
28
38
  validI18nUrlsForTransform = _urls.map((_e, i) => {
29
39
  if (_e._abs)
30
40
  return false;
@@ -32,15 +42,15 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
32
42
  let localeCode = split[0];
33
43
  const pathWithoutPrefix = split[1];
34
44
  if (!localeCode)
35
- localeCode = autoI18n.defaultLocale;
45
+ localeCode = defaultLocale;
36
46
  const e = _e;
37
47
  e._pathWithoutPrefix = pathWithoutPrefix;
38
- const locale = autoI18n.locales.find((l) => l.code === localeCode);
48
+ const locale = localeByCode.get(localeCode);
39
49
  if (!locale)
40
50
  return false;
41
51
  e._locale = locale;
42
52
  e._index = i;
43
- e._key = `${e._sitemap || ""}${e._path?.pathname || "/"}${e._path.search}`;
53
+ e._key = `${e._sitemap || ""}${e._path?.pathname || "/"}${e._path?.search || ""}`;
44
54
  withoutPrefixPaths[pathWithoutPrefix] = withoutPrefixPaths[pathWithoutPrefix] || [];
45
55
  if (!withoutPrefixPaths[pathWithoutPrefix].some((e2) => e2._locale.code === locale.code))
46
56
  withoutPrefixPaths[pathWithoutPrefix].push(e);
@@ -48,9 +58,9 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
48
58
  }).filter(Boolean);
49
59
  for (const e of validI18nUrlsForTransform) {
50
60
  if (!e._i18nTransform && !e.alternatives?.length) {
51
- const alternatives = withoutPrefixPaths[e._pathWithoutPrefix].map((u) => {
61
+ const alternatives = (withoutPrefixPaths[e._pathWithoutPrefix] || []).map((u) => {
52
62
  const entries = [];
53
- if (u._locale.code === autoI18n.defaultLocale) {
63
+ if (u._locale.code === defaultLocale) {
54
64
  entries.push({
55
65
  href: u.loc,
56
66
  hreflang: "x-default"
@@ -58,7 +68,7 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
58
68
  }
59
69
  entries.push({
60
70
  href: u.loc,
61
- hreflang: u._locale._hreflang || autoI18n.defaultLocale
71
+ hreflang: u._locale._hreflang || defaultLocale
62
72
  });
63
73
  return entries;
64
74
  }).flat().filter(Boolean);
@@ -66,14 +76,11 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
66
76
  e.alternatives = alternatives;
67
77
  } else if (e._i18nTransform) {
68
78
  delete e._i18nTransform;
69
- if (autoI18n.strategy === "no_prefix") {
70
- warnIncorrectI18nTransformUsage = true;
71
- }
72
- if (autoI18n.differentDomains) {
79
+ if (hasDifferentDomains) {
80
+ const defLocale = localeByCode.get(defaultLocale);
73
81
  e.alternatives = [
74
82
  {
75
- // apply default locale domain
76
- ...autoI18n.locales.find((l) => [l.code, l.language].includes(autoI18n.defaultLocale)),
83
+ ...defLocale,
77
84
  code: "x-default"
78
85
  },
79
86
  ...autoI18n.locales.filter((l) => !!l.domain)
@@ -84,68 +91,53 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
84
91
  };
85
92
  });
86
93
  } else {
94
+ const pageKey = hasPages ? getPageKey(e._pathWithoutPrefix) : "";
95
+ const pageMappings = hasPages ? autoI18n.pages[pageKey] : void 0;
96
+ const pathSearch = e._path?.search || "";
97
+ const pathWithoutPrefix = e._pathWithoutPrefix;
87
98
  for (const l of autoI18n.locales) {
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];
99
+ let loc = pathWithoutPrefix;
100
+ if (hasPages && pageMappings && pageMappings[l.code] !== void 0) {
101
+ const customPath = pageMappings[l.code];
102
+ if (customPath === false)
103
+ continue;
104
+ if (typeof customPath === "string")
105
+ loc = customPath[0] === "/" ? customPath : `/${customPath}`;
106
+ } else if (!hasDifferentDomains && !(isPrefixExceptOrAndDefault && l.code === defaultLocale)) {
107
+ loc = joinURL(`/${l.code}`, pathWithoutPrefix);
108
+ }
109
+ const _sitemap = isI18nMapped ? l._sitemap : void 0;
110
+ const alternatives = [];
111
+ for (const locale of xDefaultAndLocales) {
112
+ const code = locale.code === "x-default" ? defaultLocale : locale.code;
113
+ const isDefault = locale.code === "x-default" || locale.code === defaultLocale;
114
+ let href = pathWithoutPrefix;
115
+ if (hasPages && pageMappings && pageMappings[code] !== void 0) {
116
+ const customPath = pageMappings[code];
94
117
  if (customPath === false)
95
118
  continue;
96
119
  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);
120
+ href = customPath[0] === "/" ? customPath : `/${customPath}`;
121
+ } else if (isPrefixStrategy) {
122
+ href = joinURL("/", code, pathWithoutPrefix);
123
+ } else if (isPrefixExceptOrAndDefault && !isDefault) {
124
+ href = joinURL("/", code, pathWithoutPrefix);
100
125
  }
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);
126
+ if (!filterPath(href))
127
+ continue;
128
+ alternatives.push({
129
+ hreflang: locale._hreflang,
130
+ href
131
+ });
104
132
  }
105
- const _sitemap = isI18nMapped ? l._sitemap : void 0;
133
+ const { _index: _, ...rest } = e;
106
134
  const newEntry = preNormalizeEntry({
107
135
  _sitemap,
108
- ...e,
109
- _index: void 0,
110
- _key: `${_sitemap || ""}${loc || "/"}${e._path.search}`,
136
+ ...rest,
137
+ _key: `${_sitemap || ""}${loc || "/"}${pathSearch}`,
111
138
  _locale: l,
112
139
  loc,
113
- alternatives: [{ code: "x-default", _hreflang: "x-default" }, ...autoI18n.locales].map((locale) => {
114
- const code = locale.code === "x-default" ? autoI18n.defaultLocale : locale.code;
115
- const isDefault = locale.code === "x-default" || locale.code === autoI18n.defaultLocale;
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") {
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
- }
140
- }
141
- }
142
- if (!filterPath(href))
143
- return false;
144
- return {
145
- hreflang: locale._hreflang,
146
- href
147
- };
148
- }).filter(Boolean)
140
+ alternatives
149
141
  }, resolvers);
150
142
  if (e._locale.code === newEntry._locale.code) {
151
143
  _urls[e._index] = newEntry;
@@ -158,15 +150,12 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
158
150
  }
159
151
  if (isI18nMapped) {
160
152
  e._sitemap = e._sitemap || e._locale._sitemap;
161
- e._key = `${e._sitemap || ""}${e.loc || "/"}${e._path.search}`;
153
+ e._key = `${e._sitemap || ""}${e.loc || "/"}${e._path?.search || ""}`;
162
154
  }
163
155
  if (e._index)
164
156
  _urls[e._index] = e;
165
157
  }
166
158
  }
167
- if (import.meta.dev && warnIncorrectI18nTransformUsage) {
168
- logger.warn("You're using _i18nTransform with the `no_prefix` strategy. This will cause issues with the sitemap. Please remove the _i18nTransform flag or change i18n strategy.");
169
- }
170
159
  return _urls;
171
160
  }
172
161
  export async function buildSitemapUrls(sitemap, resolvers, runtimeConfig, nitro) {
@@ -181,15 +170,16 @@ export async function buildSitemapUrls(sitemap, resolvers, runtimeConfig, nitro)
181
170
  // chunking
182
171
  defaultSitemapsChunkSize
183
172
  } = runtimeConfig;
184
- const chunkInfo = parseChunkInfo(sitemap.sitemapName, sitemaps, defaultSitemapsChunkSize);
173
+ const chunkSize = defaultSitemapsChunkSize || void 0;
174
+ const chunkInfo = parseChunkInfo(sitemap.sitemapName, sitemaps, chunkSize);
185
175
  function maybeSort(urls2) {
186
176
  return sortEntries ? sortInPlace(urls2) : urls2;
187
177
  }
188
178
  function maybeSlice(urls2) {
189
- return sliceUrlsForChunk(urls2, sitemap.sitemapName, sitemaps, defaultSitemapsChunkSize);
179
+ return sliceUrlsForChunk(urls2, sitemap.sitemapName, sitemaps, chunkSize);
190
180
  }
191
181
  if (autoI18n?.differentDomains) {
192
- const domain = autoI18n.locales.find((e) => [e.language, e.code].includes(sitemap.sitemapName))?.domain;
182
+ const domain = autoI18n.locales.find((e) => e.language === sitemap.sitemapName || e.code === sitemap.sitemapName)?.domain;
193
183
  if (domain) {
194
184
  const _tester = resolvers.canonicalUrlResolver;
195
185
  resolvers.canonicalUrlResolver = (path) => resolveSitePath(path, {
@@ -232,8 +222,11 @@ export async function buildSitemapUrls(sitemap, resolvers, runtimeConfig, nitro)
232
222
  const filteredUrls = enhancedUrls.filter((e) => {
233
223
  if (e._sitemap === false)
234
224
  return false;
235
- if (isMultiSitemap && e._sitemap && sitemap.sitemapName)
225
+ if (isMultiSitemap && e._sitemap && sitemap.sitemapName) {
226
+ if (sitemap._isChunking)
227
+ return sitemap.sitemapName.startsWith(e._sitemap + "-");
236
228
  return e._sitemap === sitemap.sitemapName;
229
+ }
237
230
  return true;
238
231
  });
239
232
  const sortedUrls = maybeSort(filteredUrls);
@@ -5,193 +5,105 @@ export function escapeValueForXml(value) {
5
5
  return value ? "yes" : "no";
6
6
  return xmlEscape(String(value));
7
7
  }
8
+ const yesNo = (v) => v === "yes" || v === true ? "yes" : "no";
8
9
  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">';
9
- function buildUrlXml(url) {
10
- const capacity = 50;
11
- const parts = Array.from({ length: capacity });
12
- let partIndex = 0;
13
- parts[partIndex++] = " <url>";
14
- if (url.loc) {
15
- parts[partIndex++] = ` <loc>${escapeValueForXml(url.loc)}</loc>`;
16
- }
17
- if (url.lastmod) {
18
- parts[partIndex++] = ` <lastmod>${url.lastmod}</lastmod>`;
10
+ function buildUrlXml(url, NL, I1, I2, I3, I4) {
11
+ let xml = `${I1}<url>${NL}`;
12
+ if (url.loc) xml += `${I2}<loc>${xmlEscape(url.loc)}</loc>${NL}`;
13
+ if (url.lastmod) xml += `${I2}<lastmod>${url.lastmod}</lastmod>${NL}`;
14
+ if (url.changefreq) xml += `${I2}<changefreq>${url.changefreq}</changefreq>${NL}`;
15
+ if (url.priority !== void 0) {
16
+ const p = typeof url.priority === "number" ? url.priority : Number.parseFloat(url.priority);
17
+ xml += `${I2}<priority>${p % 1 === 0 ? p : p.toFixed(1)}</priority>${NL}`;
19
18
  }
20
- if (url.changefreq) {
21
- parts[partIndex++] = ` <changefreq>${url.changefreq}</changefreq>`;
19
+ if (url.alternatives) {
20
+ for (const alt of url.alternatives) {
21
+ let attrs = "";
22
+ for (const [k, v] of Object.entries(alt)) attrs += ` ${k}="${xmlEscape(String(v))}"`;
23
+ xml += `${I2}<xhtml:link rel="alternate"${attrs} />${NL}`;
24
+ }
22
25
  }
23
- if (url.priority !== void 0) {
24
- const priorityValue = Number.parseFloat(String(url.priority));
25
- const formattedPriority = priorityValue % 1 === 0 ? String(priorityValue) : priorityValue.toFixed(1);
26
- parts[partIndex++] = ` <priority>${formattedPriority}</priority>`;
26
+ if (url.images) {
27
+ for (const img of url.images) {
28
+ xml += `${I2}<image:image>${NL}${I3}<image:loc>${xmlEscape(img.loc)}</image:loc>${NL}`;
29
+ if (img.title) xml += `${I3}<image:title>${xmlEscape(img.title)}</image:title>${NL}`;
30
+ if (img.caption) xml += `${I3}<image:caption>${xmlEscape(img.caption)}</image:caption>${NL}`;
31
+ if (img.geo_location) xml += `${I3}<image:geo_location>${xmlEscape(img.geo_location)}</image:geo_location>${NL}`;
32
+ if (img.license) xml += `${I3}<image:license>${xmlEscape(img.license)}</image:license>${NL}`;
33
+ xml += `${I2}</image:image>${NL}`;
34
+ }
27
35
  }
28
- const keys = Object.keys(url).filter((k) => !k.startsWith("_") && !["loc", "lastmod", "changefreq", "priority"].includes(k));
29
- for (const key of keys) {
30
- const value = url[key];
31
- if (value === void 0 || value === null) continue;
32
- switch (key) {
33
- case "alternatives":
34
- if (Array.isArray(value) && value.length > 0) {
35
- for (const alt of value) {
36
- const attrs = Object.entries(alt).map(([k, v]) => `${k}="${escapeValueForXml(v)}"`).join(" ");
37
- parts[partIndex++] = ` <xhtml:link rel="alternate" ${attrs} />`;
38
- }
39
- }
40
- break;
41
- case "images":
42
- if (Array.isArray(value) && value.length > 0) {
43
- for (const img of value) {
44
- parts[partIndex++] = " <image:image>";
45
- parts[partIndex++] = ` <image:loc>${escapeValueForXml(img.loc)}</image:loc>`;
46
- if (img.title) parts[partIndex++] = ` <image:title>${escapeValueForXml(img.title)}</image:title>`;
47
- if (img.caption) parts[partIndex++] = ` <image:caption>${escapeValueForXml(img.caption)}</image:caption>`;
48
- if (img.geo_location) parts[partIndex++] = ` <image:geo_location>${escapeValueForXml(img.geo_location)}</image:geo_location>`;
49
- if (img.license) parts[partIndex++] = ` <image:license>${escapeValueForXml(img.license)}</image:license>`;
50
- parts[partIndex++] = " </image:image>";
51
- }
36
+ if (url.videos) {
37
+ for (const video of url.videos) {
38
+ xml += `${I2}<video:video>${NL}${I3}<video:title>${xmlEscape(video.title)}</video:title>${NL}`;
39
+ if (video.thumbnail_loc) xml += `${I3}<video:thumbnail_loc>${xmlEscape(video.thumbnail_loc)}</video:thumbnail_loc>${NL}`;
40
+ xml += `${I3}<video:description>${xmlEscape(video.description)}</video:description>${NL}`;
41
+ if (video.content_loc) xml += `${I3}<video:content_loc>${xmlEscape(video.content_loc)}</video:content_loc>${NL}`;
42
+ if (video.player_loc) xml += `${I3}<video:player_loc>${xmlEscape(video.player_loc)}</video:player_loc>${NL}`;
43
+ if (video.duration !== void 0) xml += `${I3}<video:duration>${video.duration}</video:duration>${NL}`;
44
+ if (video.expiration_date) xml += `${I3}<video:expiration_date>${video.expiration_date}</video:expiration_date>${NL}`;
45
+ if (video.rating !== void 0) xml += `${I3}<video:rating>${video.rating}</video:rating>${NL}`;
46
+ if (video.view_count !== void 0) xml += `${I3}<video:view_count>${video.view_count}</video:view_count>${NL}`;
47
+ if (video.publication_date) xml += `${I3}<video:publication_date>${video.publication_date}</video:publication_date>${NL}`;
48
+ if (video.family_friendly !== void 0) xml += `${I3}<video:family_friendly>${yesNo(video.family_friendly)}</video:family_friendly>${NL}`;
49
+ if (video.restriction) xml += `${I3}<video:restriction relationship="${video.restriction.relationship || "allow"}">${xmlEscape(video.restriction.restriction)}</video:restriction>${NL}`;
50
+ if (video.platform) xml += `${I3}<video:platform relationship="${video.platform.relationship || "allow"}">${xmlEscape(video.platform.platform)}</video:platform>${NL}`;
51
+ if (video.requires_subscription !== void 0) xml += `${I3}<video:requires_subscription>${yesNo(video.requires_subscription)}</video:requires_subscription>${NL}`;
52
+ if (video.price) {
53
+ for (const price of video.price) {
54
+ const c = price.currency ? ` currency="${price.currency}"` : "";
55
+ const t = price.type ? ` type="${price.type}"` : "";
56
+ xml += `${I3}<video:price${c}${t}>${xmlEscape(String(price.price ?? ""))}</video:price>${NL}`;
52
57
  }
53
- break;
54
- case "videos":
55
- if (Array.isArray(value) && value.length > 0) {
56
- for (const video of value) {
57
- parts[partIndex++] = " <video:video>";
58
- parts[partIndex++] = ` <video:title>${escapeValueForXml(video.title)}</video:title>`;
59
- if (video.thumbnail_loc) {
60
- parts[partIndex++] = ` <video:thumbnail_loc>${escapeValueForXml(video.thumbnail_loc)}</video:thumbnail_loc>`;
61
- }
62
- parts[partIndex++] = ` <video:description>${escapeValueForXml(video.description)}</video:description>`;
63
- if (video.content_loc) {
64
- parts[partIndex++] = ` <video:content_loc>${escapeValueForXml(video.content_loc)}</video:content_loc>`;
65
- }
66
- if (video.player_loc) {
67
- const attrs = video.player_loc.allow_embed ? ' allow_embed="yes"' : "";
68
- const autoplay = video.player_loc.autoplay ? ' autoplay="yes"' : "";
69
- parts[partIndex++] = ` <video:player_loc${attrs}${autoplay}>${escapeValueForXml(video.player_loc)}</video:player_loc>`;
70
- }
71
- if (video.duration !== void 0) {
72
- parts[partIndex++] = ` <video:duration>${video.duration}</video:duration>`;
73
- }
74
- if (video.expiration_date) {
75
- parts[partIndex++] = ` <video:expiration_date>${video.expiration_date}</video:expiration_date>`;
76
- }
77
- if (video.rating !== void 0) {
78
- parts[partIndex++] = ` <video:rating>${video.rating}</video:rating>`;
79
- }
80
- if (video.view_count !== void 0) {
81
- parts[partIndex++] = ` <video:view_count>${video.view_count}</video:view_count>`;
82
- }
83
- if (video.publication_date) {
84
- parts[partIndex++] = ` <video:publication_date>${video.publication_date}</video:publication_date>`;
85
- }
86
- if (video.family_friendly !== void 0) {
87
- parts[partIndex++] = ` <video:family_friendly>${video.family_friendly === "yes" || video.family_friendly === true ? "yes" : "no"}</video:family_friendly>`;
88
- }
89
- if (video.restriction) {
90
- const relationship = video.restriction.relationship || "allow";
91
- parts[partIndex++] = ` <video:restriction relationship="${relationship}">${escapeValueForXml(video.restriction.restriction)}</video:restriction>`;
92
- }
93
- if (video.platform) {
94
- const relationship = video.platform.relationship || "allow";
95
- parts[partIndex++] = ` <video:platform relationship="${relationship}">${escapeValueForXml(video.platform.platform)}</video:platform>`;
96
- }
97
- if (video.requires_subscription !== void 0) {
98
- parts[partIndex++] = ` <video:requires_subscription>${video.requires_subscription === "yes" || video.requires_subscription === true ? "yes" : "no"}</video:requires_subscription>`;
99
- }
100
- if (video.price) {
101
- const prices = Array.isArray(video.price) ? video.price : [video.price];
102
- for (const price of prices) {
103
- const attrs = [];
104
- if (price.currency) attrs.push(`currency="${price.currency}"`);
105
- if (price.type) attrs.push(`type="${price.type}"`);
106
- const attrsStr = attrs.length > 0 ? " " + attrs.join(" ") : "";
107
- parts[partIndex++] = ` <video:price${attrsStr}>${escapeValueForXml(price.price)}</video:price>`;
108
- }
109
- }
110
- if (video.uploader) {
111
- const info = video.uploader.info ? ` info="${escapeValueForXml(video.uploader.info)}"` : "";
112
- parts[partIndex++] = ` <video:uploader${info}>${escapeValueForXml(video.uploader.uploader)}</video:uploader>`;
113
- }
114
- if (video.live !== void 0) {
115
- parts[partIndex++] = ` <video:live>${video.live === "yes" || video.live === true ? "yes" : "no"}</video:live>`;
116
- }
117
- if (video.tag) {
118
- const tags = Array.isArray(video.tag) ? video.tag : [video.tag];
119
- for (const tag of tags) {
120
- parts[partIndex++] = ` <video:tag>${escapeValueForXml(tag)}</video:tag>`;
121
- }
122
- }
123
- if (video.category) {
124
- parts[partIndex++] = ` <video:category>${escapeValueForXml(video.category)}</video:category>`;
125
- }
126
- if (video.gallery_loc) {
127
- const title = video.gallery_loc.title ? ` title="${escapeValueForXml(video.gallery_loc.title)}"` : "";
128
- parts[partIndex++] = ` <video:gallery_loc${title}>${escapeValueForXml(video.gallery_loc)}</video:gallery_loc>`;
129
- }
130
- parts[partIndex++] = " </video:video>";
131
- }
132
- }
133
- break;
134
- case "news":
135
- if (value) {
136
- parts[partIndex++] = " <news:news>";
137
- parts[partIndex++] = " <news:publication>";
138
- parts[partIndex++] = ` <news:name>${escapeValueForXml(value.publication.name)}</news:name>`;
139
- parts[partIndex++] = ` <news:language>${escapeValueForXml(value.publication.language)}</news:language>`;
140
- parts[partIndex++] = " </news:publication>";
141
- if (value.title) {
142
- parts[partIndex++] = ` <news:title>${escapeValueForXml(value.title)}</news:title>`;
143
- }
144
- if (value.publication_date) {
145
- parts[partIndex++] = ` <news:publication_date>${value.publication_date}</news:publication_date>`;
146
- }
147
- if (value.access) {
148
- parts[partIndex++] = ` <news:access>${value.access}</news:access>`;
149
- }
150
- if (value.genres) {
151
- parts[partIndex++] = ` <news:genres>${escapeValueForXml(value.genres)}</news:genres>`;
152
- }
153
- if (value.keywords) {
154
- parts[partIndex++] = ` <news:keywords>${escapeValueForXml(value.keywords)}</news:keywords>`;
155
- }
156
- if (value.stock_tickers) {
157
- parts[partIndex++] = ` <news:stock_tickers>${escapeValueForXml(value.stock_tickers)}</news:stock_tickers>`;
158
- }
159
- parts[partIndex++] = " </news:news>";
160
- }
161
- break;
58
+ }
59
+ if (video.uploader) {
60
+ const info = video.uploader.info ? ` info="${xmlEscape(video.uploader.info)}"` : "";
61
+ xml += `${I3}<video:uploader${info}>${xmlEscape(video.uploader.uploader)}</video:uploader>${NL}`;
62
+ }
63
+ if (video.live !== void 0) xml += `${I3}<video:live>${yesNo(video.live)}</video:live>${NL}`;
64
+ if (video.tag) {
65
+ const tags = Array.isArray(video.tag) ? video.tag : [video.tag];
66
+ for (const t of tags) xml += `${I3}<video:tag>${xmlEscape(t)}</video:tag>${NL}`;
67
+ }
68
+ if (video.category) xml += `${I3}<video:category>${xmlEscape(video.category)}</video:category>${NL}`;
69
+ if (video.gallery_loc) xml += `${I3}<video:gallery_loc>${xmlEscape(video.gallery_loc)}</video:gallery_loc>${NL}`;
70
+ xml += `${I2}</video:video>${NL}`;
162
71
  }
163
72
  }
164
- parts[partIndex++] = " </url>";
165
- return parts.slice(0, partIndex).join("\n");
73
+ if (url.news) {
74
+ xml += `${I2}<news:news>${NL}${I3}<news:publication>${NL}`;
75
+ xml += `${I4}<news:name>${xmlEscape(url.news.publication.name)}</news:name>${NL}`;
76
+ xml += `${I4}<news:language>${xmlEscape(url.news.publication.language)}</news:language>${NL}`;
77
+ xml += `${I3}</news:publication>${NL}`;
78
+ if (url.news.title) xml += `${I3}<news:title>${xmlEscape(url.news.title)}</news:title>${NL}`;
79
+ if (url.news.publication_date) xml += `${I3}<news:publication_date>${url.news.publication_date}</news:publication_date>${NL}`;
80
+ xml += `${I2}</news:news>${NL}`;
81
+ }
82
+ xml += `${I1}</url>`;
83
+ return xml;
166
84
  }
167
85
  export function urlsToXml(urls, resolvers, { version, xsl, credits, minify }, errorInfo) {
168
- const estimatedSize = urls.length + 5;
169
- const xmlParts = Array.from({ length: estimatedSize });
170
- let partIndex = 0;
171
86
  let xslHref = xsl ? resolvers.relativeBaseUrlResolver(xsl) : false;
172
- if (xslHref && errorInfo && errorInfo.messages.length > 0) {
87
+ if (xslHref && errorInfo?.messages.length) {
173
88
  xslHref = withQuery(xslHref, {
174
89
  errors: "true",
175
90
  error_messages: errorInfo.messages,
176
91
  error_urls: errorInfo.urls
177
92
  });
178
93
  }
179
- if (xslHref) {
180
- xmlParts[partIndex++] = `<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="${escapeValueForXml(xslHref)}"?>`;
181
- } else {
182
- xmlParts[partIndex++] = '<?xml version="1.0" encoding="UTF-8"?>';
183
- }
184
- xmlParts[partIndex++] = URLSET_OPENING_TAG;
94
+ const NL = minify ? "" : "\n";
95
+ const I1 = minify ? "" : " ";
96
+ const I2 = minify ? "" : " ";
97
+ const I3 = minify ? "" : " ";
98
+ const I4 = minify ? "" : " ";
99
+ let xml = xslHref ? `<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="${escapeValueForXml(xslHref)}"?>${NL}` : `<?xml version="1.0" encoding="UTF-8"?>${NL}`;
100
+ xml += URLSET_OPENING_TAG + NL;
185
101
  for (const url of urls) {
186
- xmlParts[partIndex++] = buildUrlXml(url);
102
+ xml += buildUrlXml(url, NL, I1, I2, I3, I4) + NL;
187
103
  }
188
- xmlParts[partIndex++] = "</urlset>";
104
+ xml += "</urlset>";
189
105
  if (credits) {
190
- xmlParts[partIndex++] = `<!-- XML Sitemap generated by @nuxtjs/sitemap v${version} at ${(/* @__PURE__ */ new Date()).toISOString()} -->`;
191
- }
192
- const xmlContent = xmlParts.slice(0, partIndex);
193
- if (minify) {
194
- return xmlContent.join("").replace(/(?<!<[^>]*)\s(?![^<]*>)/g, "");
106
+ xml += `${NL}<!-- XML Sitemap generated by @nuxtjs/sitemap v${version} at ${(/* @__PURE__ */ new Date()).toISOString()} -->`;
195
107
  }
196
- return xmlContent.join("\n");
108
+ return xml;
197
109
  }
@@ -35,7 +35,7 @@ async function buildSitemapXml(event, definition, resolvers, runtimeConfig) {
35
35
  nitro._sitemapWarned = true;
36
36
  logger.error("Sitemap Site URL missing!");
37
37
  logger.info("To fix this please add `{ site: { url: 'site.com' } }` to your Nuxt config or a `NUXT_PUBLIC_SITE_URL=site.com` to your .env. Learn more at https://nuxtseo.com/site-config/getting-started/how-it-works");
38
- throw new createError({
38
+ throw createError({
39
39
  statusMessage: "You must provide a site URL to prerender a sitemap.",
40
40
  statusCode: 500
41
41
  });
@@ -78,8 +78,9 @@ async function buildSitemapXml(event, definition, resolvers, runtimeConfig) {
78
78
  resolvedCtx.urls = resolvedCtx.urls.map((e) => preNormalizeEntry(e, resolvers));
79
79
  }
80
80
  const maybeSort = (urls2) => runtimeConfig.sortEntries ? sortInPlace(urls2) : urls2;
81
- const normalizedPreDedupe = resolvedCtx.urls.map((e) => normaliseEntry(e, definition.defaults, resolvers));
82
- const urls = maybeSort(mergeOnKey(normalizedPreDedupe, "_key").map((e) => normaliseEntry(e, definition.defaults, resolvers)));
81
+ const defaults = definition.defaults || {};
82
+ const normalizedPreDedupe = resolvedCtx.urls.map((e) => normaliseEntry(e, defaults, resolvers));
83
+ const urls = maybeSort(mergeOnKey(normalizedPreDedupe, "_key").map((e) => normaliseEntry(e, defaults, resolvers)));
83
84
  if (definition._isChunking && definition.sitemapName.includes("-")) {
84
85
  const parts = definition.sitemapName.split("-");
85
86
  const lastPart = parts.pop();