103 lines
3.1 KiB
TypeScript
103 lines
3.1 KiB
TypeScript
// Advanced sitemap generation utilities
|
|
|
|
import { MetadataRoute } from 'next';
|
|
import { getBaseUrl, getAllRoutes } from './sitemap-utils';
|
|
|
|
// Generate XML sitemap manually (alternative to Next.js built-in)
|
|
export function generateSitemapXML(): string {
|
|
const baseUrl = getBaseUrl();
|
|
const routes = getAllRoutes();
|
|
|
|
const urlEntries = routes
|
|
.map((route) => {
|
|
const url = `${baseUrl}${route.url}`;
|
|
const lastmod =
|
|
route.lastModified?.toISOString().split('T')[0] ||
|
|
new Date().toISOString().split('T')[0];
|
|
const changefreq = route.changeFrequency || 'monthly';
|
|
const priority = route.priority || 0.5;
|
|
|
|
return ` <url>
|
|
<loc>${url}</loc>
|
|
<lastmod>${lastmod}</lastmod>
|
|
<changefreq>${changefreq}</changefreq>
|
|
<priority>${priority}</priority>
|
|
</url>`;
|
|
})
|
|
.join('\n');
|
|
|
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
${urlEntries}
|
|
</urlset>`;
|
|
}
|
|
|
|
// Generate sitemap index for multiple sitemaps
|
|
export function generateSitemapIndex(): string {
|
|
const baseUrl = getBaseUrl();
|
|
const now = new Date().toISOString();
|
|
|
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
<sitemap>
|
|
<loc>${baseUrl}/sitemap.xml</loc>
|
|
<lastmod>${now}</lastmod>
|
|
</sitemap>
|
|
</sitemapindex>`;
|
|
}
|
|
|
|
// Validate sitemap URLs
|
|
export function validateSitemapUrls(): { valid: boolean; errors: string[] } {
|
|
const routes = getAllRoutes();
|
|
const errors: string[] = [];
|
|
|
|
routes.forEach((route, index) => {
|
|
// Check for valid URL format
|
|
if (!route.url.startsWith('/') && route.url !== '') {
|
|
errors.push(`Route ${index}: URL should start with '/' or be empty for root`);
|
|
}
|
|
|
|
// Check priority range
|
|
if (route.priority && (route.priority < 0 || route.priority > 1)) {
|
|
errors.push(`Route ${index}: Priority should be between 0 and 1`);
|
|
}
|
|
|
|
// Check for duplicate URLs
|
|
const duplicates = routes.filter((r) => r.url === route.url);
|
|
if (duplicates.length > 1) {
|
|
errors.push(`Route ${index}: Duplicate URL found: ${route.url}`);
|
|
}
|
|
});
|
|
|
|
return {
|
|
valid: errors.length === 0,
|
|
errors,
|
|
};
|
|
}
|
|
|
|
// Get sitemap statistics
|
|
export function getSitemapStats() {
|
|
const routes = getAllRoutes();
|
|
const baseUrl = getBaseUrl();
|
|
|
|
return {
|
|
totalUrls: routes.length,
|
|
baseUrl,
|
|
lastGenerated: new Date().toISOString(),
|
|
routesByPriority: {
|
|
high: routes.filter((r) => (r.priority || 0) >= 0.8).length,
|
|
medium: routes.filter((r) => (r.priority || 0) >= 0.5 && (r.priority || 0) < 0.8)
|
|
.length,
|
|
low: routes.filter((r) => (r.priority || 0) < 0.5).length,
|
|
},
|
|
routesByChangeFreq: routes.reduce(
|
|
(acc, route) => {
|
|
const freq = route.changeFrequency || 'monthly';
|
|
acc[freq] = (acc[freq] || 0) + 1;
|
|
return acc;
|
|
},
|
|
{} as Record<string, number>,
|
|
),
|
|
};
|
|
}
|