Utilities
Comprehensive guide to validation, conversion, and feed manipulation utilities.
Validation Utilities
Validate feeds against format specifications to ensure compliance.
validateRSS2
Validate RSS 2.0 feeds:
import { validateRSS2 } from 'rss.today';
const result = validateRSS2(parsedFeed);
console.log(`Valid: ${result.valid}`);
console.log('Errors:', result.errors);
console.log('Warnings:', result.warnings);Validation checks:
- Feed title is required
- Feed description is required
- Feed link is required and valid
- Items have title or description
- Item links are valid URLs
- Enclosure URLs are valid
- Enclosure type and length are present
Result Interface:
interface ValidationResult {
valid: boolean; // true if no errors
errors: string[]; // Critical issues
warnings: string[]; // Minor issues
}validateAtom
Validate Atom 1.0 feeds:
import { validateAtom } from 'rss.today';
const result = validateAtom(parsedFeed);
if (!result.valid) {
console.error('Validation failed:', result.errors);
}
if (result.warnings.length > 0) {
console.warn('Warnings:', result.warnings);
}Validation checks:
- Feed title is required
- Feed has link or feedUrl
- Items have title
- Item links are valid URLs
- Items have ID
- Items have published date
validateJSONFeed
Validate JSON Feed 1.0:
import { validateJSONFeed } from 'rss.today';
const result = validateJSONFeed(jsonFeed);
if (result.valid) {
console.log('Valid JSON Feed');
}Validation checks:
- Version includes jsonfeed.org/version/
- Title is present
- Items have ID
- Items have URL or content
Conversion Utilities
Convert feeds between different formats.
convertToRSS2
Convert any parsed feed to RSS 2.0:
import { Parser, convertToRSS2 } from 'rss.today';
const parser = new Parser();
// Convert Atom to RSS 2.0
const atomFeed = await parser.parseURL('https://example.com/atom.xml');
const rss2Xml = convertToRSS2(atomFeed);
console.log(rss2Xml);
// Convert JSON Feed to RSS 2.0
const jsonFeed = await parser.parseJSON(jsonString);
const rss2Xml = convertToRSS2(jsonFeed);convertToAtom
Convert any parsed feed to Atom 1.0:
import { Parser, convertToAtom } from 'rss.today';
const parser = new Parser();
// Convert RSS 2.0 to Atom
const rssFeed = await parser.parseURL('https://example.com/rss.xml');
const atomXml = convertToAtom(rssFeed);
console.log(atomXml);convertToJSON
Convert any parsed feed to JSON Feed 1.0:
import { Parser, convertToJSON } from 'rss.today';
const parser = new Parser();
// Convert RSS 2.0 to JSON Feed
const rssFeed = await parser.parseURL('https://example.com/rss.xml');
const jsonFeed = convertToJSON(rssFeed);
console.log(jsonFeed);
// Parse as JSON
const feedData = JSON.parse(jsonFeed);
console.log(feedData.title);Feed Utilities
mergeFeeds
Combine multiple feeds into one, automatically removing duplicates:
import { Parser, mergeFeeds } from 'rss.today';
const parser = new Parser();
const feeds = await Promise.all([
parser.parseURL('https://example.com/feed1.xml'),
parser.parseURL('https://example.com/feed2.xml'),
parser.parseURL('https://example.com/feed3.xml')
]);
const merged = mergeFeeds(feeds);
console.log(`Merged ${merged.items.length} items`);
console.log(`Title: ${merged.title}`);Duplicate detection:
- Uses GUID if present
- Falls back to item link
- Keeps first occurrence
diffFeeds
Compare two feeds to find differences:
import { Parser, diffFeeds } from 'rss.today';
const parser = new Parser();
const oldFeed = await parser.parseFile('./old-feed.xml');
const newFeed = await parser.parseFile('./new-feed.xml');
const diff = diffFeeds(oldFeed, newFeed);
console.log(`Added: ${diff.added.length} items`);
console.log(`Removed: ${diff.removed.length} items`);
console.log(`Modified: ${diff.modified.length} items`);
console.log(`Unchanged: ${diff.unchanged.length} items`);
// Show new items
diff.added.forEach(item => {
console.log(`New: ${item.title} - ${item.link}`);
});FeedDiffResult Interface:
interface FeedDiffResult {
added: ParsedItem[]; // Items in new feed only
removed: ParsedItem[]; // Items in old feed only
modified: ParsedItem[]; // Items that changed
unchanged: ParsedItem[]; // Items that stayed the same
}filterFeed
Filter feed items using a custom predicate:
import { filterFeed } from 'rss.today';
const filtered = filterFeed(feed, (item, index) => {
// Only include items with specific keywords in title
return item.title?.toLowerCase().includes('typescript');
});
// Or with more complex logic
const filtered = filterFeed(feed, (item, index) => {
const hasContent = item.content && item.content.length > 100;
const isRecent = item.pubDate && new Date(item.pubDate) > new Date('2024-01-01');
return hasContent && isRecent;
});filterByCategory
Filter items by category:
import { filterByCategory } from 'rss.today';
const techFeed = filterByCategory(feed, 'technology');
const jsFeed = filterByCategory(feed, 'javascript');Category matching:
- Matches category name exactly
- Works with both string and object categories
- Case-sensitive matching
filterByAuthor
Filter items by author:
import { filterByAuthor } from 'rss.today';
const authorFeed = filterByAuthor(feed, 'John Doe');
console.log(`Found ${authorFeed.items.length} items by John Doe`);filterByDateRange
Filter items by date range:
import { filterByDateRange } from 'rss.today';
const startDate = new Date('2024-01-01');
const endDate = new Date('2024-01-31');
const januaryFeed = filterByDateRange(feed, startDate, endDate);
// Only start date
const recentFeed = filterByDateRange(feed, startDate);sortFeed
Sort feed items using a custom comparator:
import { sortFeed } from 'rss.today';
const sorted = sortFeed(feed, (a, b) => {
// Sort by custom criteria
const lengthA = a.title?.length || 0;
const lengthB = b.title?.length || 0;
return lengthA - lengthB;
});sortByDate
Sort feed items by date:
import { sortByDate } from 'rss.today';
// Newest first (default)
const newestFirst = sortByDate(feed, 'desc');
// Oldest first
const oldestFirst = sortByDate(feed, 'asc');sortByTitle
Sort feed items by title:
import { sortByTitle } from 'rss.today';
// Alphabetical (default)
const alphabetical = sortByTitle(feed, 'asc');
// Reverse alphabetical
const reverseAlphabetical = sortByTitle(feed, 'desc');limitFeed
Limit feed to a specific number of items:
import { limitFeed } from 'rss.today';
const latest5 = limitFeed(feed, 5);
const latest10 = limitFeed(feed, 10);Best practice: Sort before limiting:
import { sortByDate, limitFeed } from 'rss.today';
const latest10 = limitFeed(sortByDate(feed, 'desc'), 10);deduplicateFeed
Remove duplicate items from a feed:
import { deduplicateFeed } from 'rss.today';
const unique = deduplicateFeed(feed);
console.log(`Removed duplicates: ${feed.items.length - unique.items.length}`);Duplicate detection:
- Uses GUID if present
- Falls back to item link
- Keeps first occurrence
Complete Examples
Feed Validation Workflow
import { Parser, validateRSS2 } from 'rss.today';
async function validateAndParse(url: string) {
const parser = new Parser();
try {
const feed = await parser.parseURL(url);
// Validate RSS 2.0
const validation = validateRSS2(feed);
if (!validation.valid) {
console.error('Validation failed:');
validation.errors.forEach(error => console.error(` - ${error}`));
}
if (validation.warnings.length > 0) {
console.warn('Warnings:');
validation.warnings.forEach(warning => console.warn(` - ${warning}`));
}
if (validation.valid) {
console.log('Feed is valid RSS 2.0');
console.log(`Title: ${feed.title}`);
console.log(`Items: ${feed.items.length}`);
}
return feed;
} catch (error) {
console.error('Error:', error.message);
throw error;
}
}Feed Aggregation
import { Parser, mergeFeeds, sortByDate, limitFeed } from 'rss.today';
async function aggregateFeeds(feedUrls: string[], limit: number = 20) {
const parser = new Parser();
// Fetch all feeds
const feeds = await Promise.all(
feedUrls.map(url => parser.parseURL(url))
);
// Merge feeds
const merged = mergeFeeds(feeds);
// Sort by date (newest first)
const sorted = sortByDate(merged, 'desc');
// Limit results
const final = limitFeed(sorted, limit);
console.log(`Aggregated ${limit} items from ${feedUrls.length} feeds`);
return final;
}
aggregateFeeds([
'https://example.com/feed1.xml',
'https://example.com/feed2.xml',
'https://example.com/feed3.xml'
], 10);Feed Monitoring
import { Parser, diffFeeds } from 'rss.today';
import * as fs from 'fs/promises';
async function monitorFeed(url: string) {
const parser = new Parser();
// Load previous state
let oldFeed = null;
try {
const saved = await fs.readFile('./feed-state.json', 'utf-8');
oldFeed = JSON.parse(saved);
} catch {
console.log('No previous state found');
}
// Fetch current feed
const newFeed = await parser.parseURL(url);
if (oldFeed) {
// Compare feeds
const diff = diffFeeds(oldFeed, newFeed);
if (diff.added.length > 0) {
console.log(`New items: ${diff.added.length}`);
diff.added.forEach(item => {
console.log(` + ${item.title}`);
});
}
if (diff.removed.length > 0) {
console.log(`Removed items: ${diff.removed.length}`);
}
}
// Save current state
await fs.writeFile('./feed-state.json', JSON.stringify(newFeed, null, 2));
}
monitorFeed('https://example.com/feed.xml');Format Conversion
import { Parser, convertToRSS2, convertToAtom, convertToJSON } from 'rss.today';
import * as fs from 'fs/promises';
async function convertFeedFormats(sourceUrl: string) {
const parser = new Parser();
const feed = await parser.parseURL(sourceUrl);
// Convert to all formats
const rss2 = convertToRSS2(feed);
const atom = convertToAtom(feed);
const json = convertToJSON(feed);
// Save all formats
await fs.writeFile('./output/feed.rss.xml', rss2);
await fs.writeFile('./output/feed.atom.xml', atom);
await fs.writeFile('./output/feed.json', json);
console.log('Converted to all formats');
console.log(' - RSS 2.0: feed.rss.xml');
console.log(' - Atom 1.0: feed.atom.xml');
console.log(' - JSON Feed: feed.json');
}
convertFeedFormats('https://example.com/feed.xml');Advanced Filtering
import {
Parser,
filterByCategory,
filterByDateRange,
sortByDate,
limitFeed
} from 'rss.today';
async function getRecentTechPosts(url: string, days: number = 7) {
const parser = new Parser();
const feed = await parser.parseURL(url);
// Filter by category
const techFeed = filterByCategory(feed, 'technology');
// Filter by date range (last N days)
const startDate = new Date();
startDate.setDate(startDate.getDate() - days);
const recentFeed = filterByDateRange(techFeed, startDate);
// Sort by date
const sorted = sortByDate(recentFeed, 'desc');
// Limit results
const results = limitFeed(sorted, 10);
console.log(`Found ${results.items.length} tech posts from last ${days} days`);
return results;
}
getRecentTechPosts('https://example.com/feed.xml', 7);