BREAKING CHANGE(api): redesign smartsitemap around builder-based sitemap creation, parsing, validation, and import utilities
This commit is contained in:
@@ -1,42 +1,277 @@
|
||||
export interface ISitemapYaml {
|
||||
daily: string[];
|
||||
// ============================================================
|
||||
// CORE TYPES
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Change frequency values per the sitemap protocol specification.
|
||||
* Note: Google ignores changefreq, but other search engines may use it.
|
||||
*/
|
||||
export type TChangeFreq =
|
||||
| 'always'
|
||||
| 'hourly'
|
||||
| 'daily'
|
||||
| 'weekly'
|
||||
| 'monthly'
|
||||
| 'yearly'
|
||||
| 'never';
|
||||
|
||||
/** Supported output formats */
|
||||
export type TOutputFormat = 'xml' | 'txt' | 'json';
|
||||
|
||||
// ============================================================
|
||||
// URL ENTRY — the core unit of a sitemap
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* A single URL entry in a sitemap, supporting all standard extensions.
|
||||
*/
|
||||
export interface ISitemapUrl {
|
||||
/** Absolute URL of the page (required, max 2048 chars) */
|
||||
loc: string;
|
||||
/** Last modification date — accepts Date, ISO string, or Unix timestamp (ms) */
|
||||
lastmod?: Date | string | number;
|
||||
/** How frequently the page changes */
|
||||
changefreq?: TChangeFreq;
|
||||
/** Priority relative to other URLs on your site, 0.0 to 1.0 */
|
||||
priority?: number;
|
||||
/** Image sitemap extension entries */
|
||||
images?: ISitemapImage[];
|
||||
/** Video sitemap extension entries */
|
||||
videos?: ISitemapVideo[];
|
||||
/** News sitemap extension */
|
||||
news?: ISitemapNews;
|
||||
/** Alternate language versions (hreflang) */
|
||||
alternates?: ISitemapAlternate[];
|
||||
}
|
||||
|
||||
export interface IRssItem {
|
||||
[key: string]: any;
|
||||
link?: string;
|
||||
guid?: string;
|
||||
// ============================================================
|
||||
// SITEMAP EXTENSIONS
|
||||
// ============================================================
|
||||
|
||||
export interface ISitemapImage {
|
||||
/** URL of the image (required) */
|
||||
loc: string;
|
||||
/** Caption for the image */
|
||||
caption?: string;
|
||||
/** Title of the image */
|
||||
title?: string;
|
||||
pubDate?: string;
|
||||
creator?: string;
|
||||
content?: string;
|
||||
isoDate?: string;
|
||||
categories?: string[];
|
||||
contentSnippet?: string;
|
||||
enclosure?: any;
|
||||
/** Geographic location (e.g. "New York, USA") */
|
||||
geoLocation?: string;
|
||||
/** URL to the image license */
|
||||
licenseUrl?: string;
|
||||
}
|
||||
|
||||
export interface IParsedSiteMap {
|
||||
urlset: {
|
||||
url:
|
||||
| {
|
||||
loc: string;
|
||||
lastmod: string;
|
||||
changefreq: string;
|
||||
}
|
||||
| {
|
||||
loc: string;
|
||||
lastmod: string;
|
||||
changefreq: string;
|
||||
}[]
|
||||
| {
|
||||
loc: string;
|
||||
'news:news': {
|
||||
'news:publication': [];
|
||||
'news:keywords': string;
|
||||
'news:publication_date': string;
|
||||
'news:title': string;
|
||||
};
|
||||
}[];
|
||||
};
|
||||
export interface ISitemapVideo {
|
||||
/** URL to the video thumbnail (required) */
|
||||
thumbnailLoc: string;
|
||||
/** Title of the video (required) */
|
||||
title: string;
|
||||
/** Description of the video, max 2048 chars (required) */
|
||||
description: string;
|
||||
/** URL of the actual video media file */
|
||||
contentLoc?: string;
|
||||
/** URL of the embeddable player — at least one of contentLoc or playerLoc required */
|
||||
playerLoc?: string;
|
||||
/** Duration in seconds (1–28800) */
|
||||
duration?: number;
|
||||
/** Rating 0.0 to 5.0 */
|
||||
rating?: number;
|
||||
/** Number of views */
|
||||
viewCount?: number;
|
||||
/** Publication date */
|
||||
publicationDate?: Date | string;
|
||||
/** Whether the video is family friendly (default true) */
|
||||
familyFriendly?: boolean;
|
||||
/** Tags for the video (max 32) */
|
||||
tags?: string[];
|
||||
/** Whether this is a live stream */
|
||||
live?: boolean;
|
||||
/** Whether a subscription is required to view */
|
||||
requiresSubscription?: boolean;
|
||||
}
|
||||
|
||||
export interface ISitemapNews {
|
||||
/** Publication information */
|
||||
publication: {
|
||||
/** Publication name (e.g. "The New York Times") */
|
||||
name: string;
|
||||
/** Language code (ISO 639, e.g. "en", "de", "zh-cn") */
|
||||
language: string;
|
||||
};
|
||||
/** Publication date of the article */
|
||||
publicationDate: Date | string | number;
|
||||
/** Article title */
|
||||
title: string;
|
||||
/** Keywords (array or comma-separated string) */
|
||||
keywords?: string[] | string;
|
||||
}
|
||||
|
||||
export interface ISitemapAlternate {
|
||||
/** Language code (ISO 639) or 'x-default' for the default version */
|
||||
hreflang: string;
|
||||
/** URL for this language version */
|
||||
href: string;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// SITEMAP INDEX
|
||||
// ============================================================
|
||||
|
||||
export interface ISitemapIndexEntry {
|
||||
/** URL to the sitemap file */
|
||||
loc: string;
|
||||
/** Last modification date of the referenced sitemap */
|
||||
lastmod?: Date | string | number;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// CONFIGURATION
|
||||
// ============================================================
|
||||
|
||||
export interface ISitemapOptions {
|
||||
/** Base URL for the website (used to resolve relative URLs and for auto-split filenames) */
|
||||
baseUrl?: string;
|
||||
/** XSL stylesheet URL for browser-viewable sitemaps */
|
||||
xslUrl?: string;
|
||||
/** Default changefreq for URLs that don't specify one */
|
||||
defaultChangeFreq?: TChangeFreq;
|
||||
/** Default priority for URLs that don't specify one (0.0–1.0) */
|
||||
defaultPriority?: number;
|
||||
/** Whether to pretty-print XML output (default: true) */
|
||||
prettyPrint?: boolean;
|
||||
/** Maximum URLs per sitemap file before auto-splitting (default: 50000, max: 50000) */
|
||||
maxUrlsPerSitemap?: number;
|
||||
/** Enable gzip compression for toGzipBuffer() */
|
||||
gzip?: boolean;
|
||||
/** Whether to validate URLs and fields (default: true) */
|
||||
validate?: boolean;
|
||||
}
|
||||
|
||||
export interface INewsSitemapOptions extends ISitemapOptions {
|
||||
/** Publication name — required for news sitemaps */
|
||||
publicationName: string;
|
||||
/** Publication language (default: 'en') */
|
||||
publicationLanguage?: string;
|
||||
}
|
||||
|
||||
export interface IFeedImportOptions {
|
||||
/** Publication name for news sitemap mapping */
|
||||
publicationName?: string;
|
||||
/** Publication language for news sitemap mapping */
|
||||
publicationLanguage?: string;
|
||||
/** Only include items newer than this date */
|
||||
newerThan?: Date | number;
|
||||
/** Maximum number of items to import */
|
||||
limit?: number;
|
||||
/** Custom mapping function from feed item to sitemap URL (return null to skip) */
|
||||
mapItem?: (item: IFeedItem) => ISitemapUrl | null;
|
||||
}
|
||||
|
||||
/** Shape of a parsed RSS/Atom feed item */
|
||||
export interface IFeedItem {
|
||||
title?: string;
|
||||
link?: string;
|
||||
pubDate?: string;
|
||||
author?: string;
|
||||
content?: string;
|
||||
contentSnippet?: string;
|
||||
isoDate?: string;
|
||||
id?: string;
|
||||
categories?: string[];
|
||||
enclosure?: {
|
||||
url?: string;
|
||||
type?: string;
|
||||
length?: string;
|
||||
};
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// YAML CONFIG
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Enhanced YAML configuration format for defining sitemaps declaratively.
|
||||
* Supports per-frequency URL groups, default settings, and feed imports.
|
||||
*/
|
||||
export interface ISitemapYamlConfig {
|
||||
/** Base URL to prepend to relative paths */
|
||||
baseUrl?: string;
|
||||
/** Default values for all URLs */
|
||||
defaults?: {
|
||||
changefreq?: TChangeFreq;
|
||||
priority?: number;
|
||||
};
|
||||
/** URL groups organized by change frequency */
|
||||
urls?: { [K in TChangeFreq]?: string[] };
|
||||
/** RSS/Atom feeds to import */
|
||||
feeds?: Array<{
|
||||
url: string;
|
||||
type: 'news' | 'standard';
|
||||
publicationName?: string;
|
||||
publicationLanguage?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// PARSED SITEMAP (bidirectional)
|
||||
// ============================================================
|
||||
|
||||
export interface IParsedSitemap {
|
||||
/** Whether this is a urlset or a sitemap index */
|
||||
type: 'urlset' | 'sitemapindex';
|
||||
/** Parsed URL entries (populated when type is 'urlset') */
|
||||
urls: ISitemapUrl[];
|
||||
/** Parsed index entries (populated when type is 'sitemapindex') */
|
||||
sitemaps: ISitemapIndexEntry[];
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// VALIDATION
|
||||
// ============================================================
|
||||
|
||||
export interface IValidationError {
|
||||
field: string;
|
||||
message: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export interface IValidationWarning {
|
||||
field: string;
|
||||
message: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export interface IValidationResult {
|
||||
valid: boolean;
|
||||
errors: IValidationError[];
|
||||
warnings: IValidationWarning[];
|
||||
stats: ISitemapStats;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// STATISTICS
|
||||
// ============================================================
|
||||
|
||||
export interface ISitemapStats {
|
||||
urlCount: number;
|
||||
imageCount: number;
|
||||
videoCount: number;
|
||||
newsCount: number;
|
||||
alternateCount: number;
|
||||
estimatedSizeBytes: number;
|
||||
needsIndex: boolean;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// AUTO-SPLIT OUTPUT
|
||||
// ============================================================
|
||||
|
||||
export interface ISitemapSet {
|
||||
/** Whether the URL count exceeded maxUrlsPerSitemap */
|
||||
needsIndex: boolean;
|
||||
/** The sitemap index XML (null if all URLs fit in one sitemap) */
|
||||
indexXml: string | null;
|
||||
/** Individual sitemap chunks */
|
||||
sitemaps: Array<{ filename: string; xml: string }>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user