### Setup commands for benchmark environment Source: https://feedsmith.dev/benchmarks Installs system packages, language-specific dependencies, builds the Go binary, and runs the benchmarks. Note that Composer's vendor/ directory forces Go module mode via GOFLAGS, and Python uses a local virtualenv due to Homebrew's PEP 668 restrictions. ```bash # 1. Install system packages brew install hyperfine bun ruby python go php composer # 2. Install language-specific packages bundle install composer install # Composer's vendor/ directory makes Go assume vendored modules, so force module mode. export GOFLAGS=-mod=mod go mod tidy # Python is installed in a local virtualenv (Homebrew Python blocks global pip installs # per PEP 668). parsing.sh runs the benchmark with .venv/bin/python3. python3 -m venv .venv .venv/bin/pip install -r requirements.txt # 3. Build Go binary go build -o parsing-gofeed parsing-gofeed.go # 4. Run benchmarks sh parsing.sh ``` -------------------------------- ### parseFeed() example Source: https://feedsmith.dev/reference Shows how to import and use `parseFeed` from 'feedsmith'. The example demonstrates basic parsing, limiting items with `maxItems: 5`, and skipping items entirely with `maxItems: 0` to get only feed metadata. Note that the universal parser uses detection functions; for maximum reliability when the format is known, use format-specific parsers. ```typescript import { parseFeed } from 'feedsmith' const { format, feed } = parseFeed(feedContent) // Limit number of items parsed const { format, feed } = parseFeed(feedContent, { maxItems: 5 }) // Parse only feed metadata (skip all items) const { format, feed } = parseFeed(feedContent, { maxItems: 0 }) ``` -------------------------------- ### Install dependencies with bun Source: https://feedsmith.dev/benchmarks Installs project dependencies using the bun package manager. Run this before executing benchmarks. ```bash bun install ``` -------------------------------- ### Run benchmarks with bash parsing.sh Source: https://feedsmith.dev/benchmarks Executes the benchmark script. Requires hyperfine to be installed via Homebrew (brew install hyperfine). ```bash bash parsing.sh ``` -------------------------------- ### XHTML content XML example with wrapper div Source: https://feedsmith.dev/migration/v2-to-v3 Example of an Atom `` element with `type="xhtml"` containing a `
` wrapper with XHTML namespace, illustrating the new parsing behavior. ```xml a < b ``` -------------------------------- ### Automatic namespace normalization example Source: https://feedsmith.dev/migration/v1-to-v2 Shows that custom namespace prefixes are automatically normalized to standard ones. The example demonstrates how a custom prefix 'custom' is converted to the standard 'dc' prefix. ```typescript // Input: John Doe // Automatically becomes: feed.dc.creator ``` -------------------------------- ### Atom content XML example Source: https://feedsmith.dev/migration/v2-to-v3 Example of an Atom `` element with `type="xhtml"`, `xml:base`, and `xml:lang` attributes, illustrating the new object representation. ```xml Text ``` -------------------------------- ### Format Type Namespaces Renamed: Before and After Source: https://feedsmith.dev/migration/v2-to-v3 Shows the rename of format-level type namespaces from Rss to RssFeed and Atom to AtomFeed. The before example uses the old names, and the after example uses the new names. ```typescript // Before (2.x) import type { Rss, Atom } from 'feedsmith/types' const feed: Rss.Feed = parseRssFeed(xml) const entry: Atom.Entry = entries[0] // After (3.x) import type { RssFeed, AtomFeed } from 'feedsmith' const feed: RssFeed.Feed = parseRssFeed(xml) const entry: AtomFeed.Entry = entries[0] ``` -------------------------------- ### RSS Person Fields as Strings Source: https://feedsmith.dev/migration/v2-to-v3 Example RSS XML showing the person fields as strings before migration. ```xml editor@example.com (Editor Name) john@example.com (John Doe) ``` -------------------------------- ### Custom prefix normalization example Source: https://feedsmith.dev/parsing/namespaces Shows a feed using custom prefixes (dublincore, podcast) for known namespaces, and the corresponding normalized access in the parsed object. The comments show the expected normalized property names. ```xml John Doe John Doe ``` ```typescript // Normalized in parsed object feed.itunes?.author // "John Doe" - podcast: prefix normalized to itunes: feed.dc?.creator // "John Doe" - creator: prefix normalized to dc: ``` -------------------------------- ### RSS GUID structure change: before (1.x) Source: https://feedsmith.dev/migration/v1-to-v2 In version 1.x, `item.guid` is a plain string. ```typescript const rssFeed = parseRssFeed(content) const guid = rssFeed.items?.[0]?.guid // string ``` -------------------------------- ### Install feedsmith with npm, yarn, pnpm, or bun Source: https://feedsmith.dev/quick-start Install the feedsmith package using npm, yarn, pnpm, or bun. The package supports Node.js 14.0.0+ and modern browsers, with CommonJS and ES modules. ```bash npm install feedsmith ``` ```bash yarn add feedsmith ``` ```bash pnpm add feedsmith ``` ```bash bun add feedsmith ``` -------------------------------- ### Install feedsmith v2 Source: https://feedsmith.dev/migration/v1-to-v2 Updates the feedsmith package to the latest 2.x version using npm. ```bash npm install feedsmith@latest ``` -------------------------------- ### Parse OPML files with parseOpml Source: https://feedsmith.dev/quick-start Parse OPML files using the parseOpml function. The example shows accessing the head title and outline properties. ```typescript import { parseOpml } from 'feedsmith' const opml = parseOpml('opml content') opml.head?.title opml.body?.outlines?.[0].text opml.body?.outlines?.[1].xmlUrl ``` -------------------------------- ### Generate Podcast RSS Feed with Feedsmith Source: https://feedsmith.dev/reference/typescript Complete example showing how to generate a podcast RSS feed using Feedsmith's typed sub-elements. It defines an array of items with enclosures and iTunes metadata, constructs a feed object, and calls generateRssFeed to produce the XML. Use this when generating feeds with Date objects. ```typescript import { type RssFeed, generateRssFeed } from 'feedsmith' const items: Array> = [{ title: 'Episode 1: Introduction', description: 'Getting started with TypeScript', pubDate: new Date('2024-01-15T10:00:00Z'), enclosures: [{ url: 'https://mypodcast.com/ep1.mp3', length: 45678901, type: 'audio/mpeg' }], itunes: { duration: '01:15:30', episode: 1, explicit: false } }] const feed: RssFeed.Feed = { title: 'My TypeScript Podcast', link: 'https://mypodcast.com', description: 'A podcast about TypeScript', language: 'en-us', pubDate: new Date(), itunes: { author: 'John Doe', owner: { name: 'John Doe', email: 'john@mypodcast.com' }, image: 'https://mypodcast.com/artwork.jpg', category: [{ name: 'Technology' }], explicit: false }, items } const xml = generateRssFeed(feed) ``` -------------------------------- ### Generate RSS, Atom, JSON, and OPML feeds Source: https://feedsmith.dev/migration/v1-to-v2 Version 2.x introduces functions to generate RSS, Atom, JSON, and OPML feeds. The example shows generating RSS and Atom feeds. ```typescript import { generateRssFeed, generateAtomFeed, generateJsonFeed, generateOpml } from 'feedsmith' // Generate RSS feed const rss = generateRssFeed({ title: 'My Blog', link: 'https://example.com', description: 'A blog about development', items: [/* items */] }) // Generate Atom feed const atom = generateAtomFeed({ id: 'https://example.com/feed', title: 'My Blog', updated: new Date(), entries: [/* entries */] }) ``` -------------------------------- ### Namespace Type Exports: Importing ItunesNs and PodcastNs Source: https://feedsmith.dev/migration/v2-to-v3 Shows how to import namespace types directly from the main package in Feedsmith 3.x. The example demonstrates using ItunesNs.Category and PodcastNs.Transcript. ```typescript import type { ItunesNs, DcNs, MediaNs, PodcastNs } from 'feedsmith' const category: ItunesNs.Category = { text: 'Technology' } const transcript: PodcastNs.Transcript = { url: 'https://example.com/transcript.srt', type: 'application/srt' } ``` -------------------------------- ### Example Atom XML with type attribute Source: https://feedsmith.dev/migration/v2-to-v3 Illustrates the XML structure for Atom text fields, showing an HTML-typed title. This is the input format that the new `AtomFeed.Text` object preserves. ```xml My <em>Blog</em> ``` -------------------------------- ### Namespace URI tolerance examples Source: https://feedsmith.dev/parsing/namespaces Shows four XML namespace declarations with URI variations (HTTPS, different capitalization, trailing slash, whitespace) that Feedsmith automatically recognizes and normalizes. ```xml ``` -------------------------------- ### RssFeed namespace - Access type definitions Source: https://feedsmith.dev/reference/feeds/rss All RSS types are available under the RssFeed namespace. This example shows how to import and use the types, with type parameters for dates and strict mode. ```typescript import type { RssFeed } from 'feedsmith' // Access any type from the definitions below type Feed = RssFeed.Feed type Item = RssFeed.Item type Category = RssFeed.Category type Enclosure = RssFeed.Enclosure // … see type definitions below for all available types ``` -------------------------------- ### Using namespace types for Dublin Core and Media Source: https://feedsmith.dev/reference/typescript Shows how to reference namespace-specific types like DcNs.Feed, MediaNs.Item, and MediaNs.Content for typing variables or parameters. ```typescript // Dublin Core namespace types type DcFeed = DcNs.Feed type DcItem = DcNs.Item // Media namespace types type MediaFeed = MediaNs.Feed type MediaItem = MediaNs.Item type MediaContent = MediaNs.Content type MediaGroup = MediaNs.Group ``` -------------------------------- ### Using namespace types with generateRssFeed Source: https://feedsmith.dev/reference/typescript Demonstrates using ItunesNs.Category and PodcastNs.Transcript types to construct objects passed to generateRssFeed for a podcast feed. ```typescript import type { ItunesNs, PodcastNs } from 'feedsmith' import { generateRssFeed } from 'feedsmith' const itunesCategory: ItunesNs.Category = { text: 'Technology', categories: [{ text: 'Software How-To' }] } const transcript: PodcastNs.Transcript = { url: 'https://example.com/transcript.srt', type: 'application/srt' } const xml = generateRssFeed({ title: 'My Podcast', itunes: { categories: [itunesCategory] }, items: [{ title: 'Episode 1', podcast: { transcripts: [transcript] } }] }) ``` -------------------------------- ### Run JavaScript benchmarks with bash parsing.sh Source: https://feedsmith.dev/benchmarks Run the benchmark script to print one comparison per category, sorted fastest first (mean ± σ over at least ten runs). Absolute timings depend on the machine. ```bash $ bash parsing.sh ``` -------------------------------- ### RSS GUID structure change: after (2.x) Source: https://feedsmith.dev/migration/v1-to-v2 In version 2.x, `item.guid` is an object with `value` and `isPermaLink` properties. ```typescript const rssFeed = parseRssFeed(content) const guid = rssFeed.items?.[0]?.guid?.value // string const isPermaLink = rssFeed.items?.[0]?.guid?.isPermaLink // boolean | undefined ``` -------------------------------- ### After (3.x): Importing types from main feedsmith entry point Source: https://feedsmith.dev/migration/v2-to-v3 Shows the new import style using the main `feedsmith` entry point and the format type namespace `RssFeed`. Replace `feedsmith/types` imports with `feedsmith` and update generic aliases like `RssFeed` to `RssFeed.Feed`. ```typescript import { type RssFeed, parseRssFeed } from 'feedsmith' ``` -------------------------------- ### RSS Type Definitions for SkipDays, Guid, Source, Item, and Feed Source: https://feedsmith.dev/reference/feeds/rss Defines TypeScript types for RSS 2.0 structures. Includes SkipDays, Guid, Source, Item, and Feed types. The Item type requires either title or description when strict mode is enabled. The Feed type requires title, link, and description. Supports many optional namespaces like atom, dc, itunes, podcast, media, and more. ```typescript export type SkipDays = Array export type Guid = Strict< { value: Requirable // Required in spec isPermaLink?: boolean }, TStrict > export type Source = Strict< { title: Requirable // Required in spec url: Requirable // Required in spec }, TStrict > export type Item = Strict< { title?: string // At least one of title or description is required in spec link?: string description?: string // At least one of title or description is required in spec authors?: Array categories?: Array> comments?: string enclosures?: Array> guid?: Guid pubDate?: TDate expirationDate?: TDate source?: Source atom?: AtomNs.Entry dc?: DcNs.ItemOrFeed dcterms?: DcTermsNs.ItemOrFeed content?: ContentNs.Item slash?: SlashNs.Item itunes?: ItunesNs.Item podcast?: PodcastNs.Item psc?: PscNs.Item media?: MediaNs.ItemOrFeed googleplay?: GooglePlayNs.Item spotify?: SpotifyNs.Item acast?: AcastNs.Item rawvoice?: RawVoiceNs.Item feedburner?: FeedBurnerNs.Item arxiv?: ArxivNs.Entry prism?: PrismNs.ItemOrFeed cc?: CcNs.ItemOrFeed creativeCommons?: CreativeCommonsNs.ItemOrFeed thr?: ThrNs.Item wfw?: WfwNs.Item pingback?: PingbackNs.Item trackback?: TrackbackNs.Item sourceNs?: SourceNs.Item geo?: GeoNs.ItemOrFeed georss?: GeoRssNs.ItemOrFeed xml?: XmlNs.ItemOrFeed }, TStrict > & (TStrict extends true ? { title: string } | { description: string } : unknown) export type Feed = Strict< { title: Requirable // Required in spec link: Requirable // Required in spec (but may be missing when atom:link rel="self" is present) description: Requirable // Required in spec language?: string copyright?: string managingEditor?: Person webMaster?: Person pubDate?: TDate lastBuildDate?: TDate categories?: Array> generator?: string docs?: string cloud?: Cloud ttl?: number image?: Image rating?: string textInput?: TextInput skipHours?: Array skipDays?: Array items?: Array> atom?: AtomNs.Feed dc?: DcNs.ItemOrFeed dcterms?: DcTermsNs.ItemOrFeed sy?: SyNs.Feed itunes?: ItunesNs.Feed podcast?: PodcastNs.Feed media?: MediaNs.ItemOrFeed googleplay?: GooglePlayNs.Feed spotify?: SpotifyNs.Feed acast?: AcastNs.Feed rawvoice?: RawVoiceNs.Feed feedburner?: FeedBurnerNs.Feed feedpress?: FeedPressNs.Feed opensearch?: OpenSearchNs.Feed prism?: PrismNs.ItemOrFeed cc?: CcNs.ItemOrFeed creativeCommons?: CreativeCommonsNs.ItemOrFeed admin?: AdminNs.Feed pingback?: PingbackNs.Feed sourceNs?: SourceNs.Feed blogChannel?: BlogChannelNs.Feed geo?: GeoNs.ItemOrFeed georss?: GeoRssNs.ItemOrFeed xml?: XmlNs.ItemOrFeed }, TStrict > ``` -------------------------------- ### Run benchmark script with sh parsing.sh Source: https://feedsmith.dev/benchmarks Executes the benchmark script that runs hyperfine comparisons across feed formats. The output shows performance tables for RSS, Atom, and RDF parsing with mean times and relative slowdowns. ```bash sh parsing.sh ``` -------------------------------- ### Before (2.x): Importing types from feedsmith/types Source: https://feedsmith.dev/migration/v2-to-v3 Shows the old import style using the `feedsmith/types` entry point and the `Rss` type alias. This entry point has been removed in 3.x. ```typescript import type { Rss } from 'feedsmith/types' import { parseRssFeed } from 'feedsmith' ``` -------------------------------- ### Accessing AtomFeed types Source: https://feedsmith.dev/reference/feeds/atom Shows how to access Atom types under the `AtomFeed` namespace. The example uses `Date` as the generic parameter for feed, entry, and link types. ```typescript import type { AtomFeed } from 'feedsmith' // Access any type from the definitions below type Feed = AtomFeed.Feed type Entry = AtomFeed.Entry type Link = AtomFeed.Link type Person = AtomFeed.Person // … see type definitions below for all available types ``` -------------------------------- ### Catch error types from parseFeed Source: https://feedsmith.dev/parsing/errors Shows that the universal parseFeed function throws the same error types as parseRssFeed. The example catches DetectError, MalformedError, and ParseError in order. ```typescript import { parseFeed, DetectError, MalformedError, ParseError } from 'feedsmith' try { parseFeed('') } catch (error) { if (error instanceof DetectError) { // Unrecognized feed format. } else if (error instanceof MalformedError) { // Malformed XML. } else if (error instanceof ParseError) { // Valid XML but invalid feed structure. } } ``` -------------------------------- ### Parsing JSON object example Source: https://feedsmith.dev/parsing/examples The default output from parsing an OPML document with feedsmith's parseOpml. Shows that outlines are nested under body.outlines and inherit the RSS metadata. ```json { "head": { "title": "Tech Sites", "dateCreated": "Mon, 15 Jan 2024 09:45:30 GMT", "ownerName": "Jack Smith" }, "body": { "outlines": [ { "text": "The Verge", "type": "rss", "xmlUrl": "https://www.theverge.com/rss/index.xml", "htmlUrl": "https://www.theverge.com/", "title": "The Verge", "version": "rss" }, { "text": "TechCrunch", "type": "rss", "xmlUrl": "https://techcrunch.com/feed/", "htmlUrl": "https://techcrunch.com/", "title": "TechCrunch", "version": "rss" } ] } } ``` -------------------------------- ### Generate RSS, Atom, JSON Feed, and OPML with feedsmith Source: https://feedsmith.dev/generating Imports the generation functions from 'feedsmith' and demonstrates generating each feed format by calling the respective function with placeholder data. The functions return properly formatted feeds as XML or JSON. ```typescript import { generateRssFeed, generateAtomFeed, generateJsonFeed, generateOpml } from 'feedsmith' // Generate different formats const rss = generateRssFeed({ /* feed data */ }) const atom = generateAtomFeed({ /* feed data */ }) const json = generateJsonFeed({ /* feed data */ }) const opml = generateOpml({ /* opml data */ }) ``` -------------------------------- ### Benchmark output for RSS and Atom feed parsing Source: https://feedsmith.dev/benchmarks Output from running `sh parsing.sh` showing hyperfine results for RSS (10 files × 5MB–50MB) and Atom (100 files × 100KB–5MB) feed parsing. Tables list each package with mean, min, and max times in milliseconds, plus relative performance versus the baseline. ```text $ sh parsing.sh ⏳ Running: RSS feed parsing (10 files × 5MB–50MB) ┌───┬─────────────────────┬───────────────┬─────────────────┬─────────┬─────────┐ │ │ Package │ Performance │ Mean (ms) │ Min │ Max │ ├───┼─────────────────────┼───────────────┼─────────────────┼─────────┼─────────┤ │ 0 │ feedsmith * │ baseline │ 454.0 ± 5.3 │ 446.7 │ 463.7 │ │ 1 │ simplepie (php) │ 1.39x slower │ 630.1 ± 3.6 │ 623.5 │ 635.1 │ │ 2 │ gofeed (go) │ 2.01x slower │ 914.2 ± 9.9 │ 898.2 │ 931.1 │ │ 3 │ feedjira (ruby) │ 2.84x slower │ 1288.1 ± 16.4 │ 1273.1 │ 1330.2 │ │ 4 │ feedparser (python) │ 27.55x slower │ 12506.6 ± 113.0 │ 12351.3 │ 12656.1 │ └───┴─────────────────────┴───────────────┴─────────────────┴─────────┴─────────┘ ⏳ Running: Atom feed parsing (100 files × 100KB–5MB) ┌───┬─────────────────────┬───────────────┬───────────────┬────────┬─────────┐ │ │ Package │ Performance │ Mean (ms) │ Min │ Max │ ├───┼─────────────────────┼───────────────┼───────────────┼────────┼─────────┤ │ 0 │ feedsmith * │ baseline │ 448.1 ± 4.0 │ 441.0 │ 454.1 │ │ 1 │ simplepie (php) │ 1.28x slower │ 575.7 ± 9.9 │ 558.2 │ 591.0 │ │ 2 │ gofeed (go) │ 2.36x slower │ 1059.5 ± 16.9 │ 1044.2 │ 1096.2 │ │ 3 │ feedjira (ruby) │ 2.87x slower │ 1284.2 ± 7.7 │ 1267.5 │ 1292.7 │ │ 4 │ feedparser (python) │ 22.32x slower │ 9999.7 ± 80.5 │ 9895.0 │ 10155.5 │ └───┴─────────────────────┴───────────────┴───────────────┴────────┴─────────┘ ``` -------------------------------- ### Use feedsmith via CDN with ES module Source: https://feedsmith.dev/quick-start Load feedsmith from a CDN using an ES module script tag. The example imports parseFeed from esm.sh and logs the feed title. ```html ``` -------------------------------- ### Type definitions for all feed formats Source: https://feedsmith.dev/reference/typescript Shows the complete type system for each format: RSS, Atom, JSON Feed, RDF, and OPML. Use these types to annotate variables with full type safety. ```typescript // RSS types type Feed = RssFeed.Feed type Item = RssFeed.Item type Category = RssFeed.Category type Enclosure = RssFeed.Enclosure // Atom types type Entry = AtomFeed.Entry type Link = AtomFeed.Link // JSON Feed types type JsonItem = JsonFeed.Item type Author = JsonFeed.Author // RDF types type RdfItem = RdfFeed.Item // OPML types type Document = Opml.Document type Outline = Opml.Outline ``` -------------------------------- ### Enhanced type system: before (1.x) Source: https://feedsmith.dev/migration/v1-to-v2 In version 1.x, types are simple and non-optional. ```typescript // Simple type definitions interface RssFeed { title: string items: RssItem[] } ``` -------------------------------- ### OPML 2.0 Feed List with Custom Attributes Source: https://feedsmith.dev/generating/examples Example OPML 2.0 feed list generated by the TypeScript API. Shows custom attributes such as customIcon, updateInterval, isPrivate, tags, customColor, and isPinned. ```xml My Custom Feed List Mon, 15 Jan 2024 12:00:00 GMT ``` -------------------------------- ### Generate RSS feed with Date objects Source: https://feedsmith.dev/reference/typescript Generates an RSS feed using Date objects for dates. Use for the generic parameter. The example creates a feed object and passes it to generateRssFeed to produce XML. ```typescript import { type RssFeed, generateRssFeed } from 'feedsmith' const feed: RssFeed.Feed = { title: 'My Podcast', link: 'https://example.com', description: 'A great podcast', pubDate: new Date(), items: [{ title: 'Episode 1', description: 'First episode', enclosures: [{ url: 'https://example.com/ep1.mp3', length: 12345678, type: 'audio/mpeg' }] }] } const xml = generateRssFeed(feed) ``` -------------------------------- ### Multiple Stylesheets with generateAtomFeed Source: https://feedsmith.dev/generating/styling Generates an Atom feed with two stylesheets: an XSL transformation and a CSS stylesheet. The `media` field targets the `screen` media type, and `alternate: false` marks the CSS as the primary stylesheet. ```typescript import { generateAtomFeed } from 'feedsmith' const atomFeed = generateAtomFeed(feedData, { stylesheets: [ { type: 'text/xsl', href: '/styles/feed.xsl', title: 'Pretty Feed', media: 'screen' }, { type: 'text/css', href: '/styles/feed.css', media: 'screen', alternate: false } ] }) ``` -------------------------------- ### Accessing namespace data with parseRssFeed Source: https://feedsmith.dev/parsing/namespaces Shows how to parse an RSS feed with namespace extensions (dc, itunes) and access the parsed namespace data on the feed and items. The example uses optional chaining to safely access properties. ```typescript import { parseRssFeed } from 'feedsmith' const feed = parseRssFeed(` My Podcast John Doe John Doe Episode 1 30:15 2024-01-15 `) // Access namespace data feed.itunes?.author feed.dc?.creator feed.items?.[0]?.itunes?.duration feed.items?.[0]?.dc?.date ```