Sync local packages into the registry repo and update index.json and README.md to include all 9 packages.
102 lines
3.7 KiB
Plaintext
102 lines
3.7 KiB
Plaintext
// rss - RSS 2.0 feed generator for Lux
|
|
//
|
|
// Generates valid RSS 2.0 XML feeds from structured data.
|
|
|
|
import xml
|
|
|
|
// An RSS feed item
|
|
type Item =
|
|
| Item(String, String, String, String, String)
|
|
// Item(title, link, description, pubDate, guid)
|
|
|
|
// An RSS channel/feed
|
|
type Feed =
|
|
| Feed(String, String, String, String, List<Item>)
|
|
// Feed(title, link, description, language, items)
|
|
|
|
// Create a feed item
|
|
pub fn item(title: String, link: String, description: String, pubDate: String): Item =
|
|
Item(title, link, description, pubDate, link)
|
|
|
|
// Create a feed item with custom GUID
|
|
pub fn itemWithGuid(title: String, link: String, description: String, pubDate: String, guid: String): Item =
|
|
Item(title, link, description, pubDate, guid)
|
|
|
|
// Create an RSS feed
|
|
pub fn feed(title: String, link: String, description: String, items: List<Item>): Feed =
|
|
Feed(title, link, description, "en", items)
|
|
|
|
// Create an RSS feed with language
|
|
pub fn feedWithLang(title: String, link: String, description: String, language: String, items: List<Item>): Feed =
|
|
Feed(title, link, description, language, items)
|
|
|
|
// Access item fields
|
|
pub fn itemTitle(i: Item): String = match i { Item(t, _, _, _, _) => t, }
|
|
pub fn itemLink(i: Item): String = match i { Item(_, l, _, _, _) => l, }
|
|
pub fn itemDescription(i: Item): String = match i { Item(_, _, d, _, _) => d, }
|
|
pub fn itemPubDate(i: Item): String = match i { Item(_, _, _, p, _) => p, }
|
|
pub fn itemGuid(i: Item): String = match i { Item(_, _, _, _, g) => g, }
|
|
|
|
// Convert ISO date (2025-01-29) to RFC 822 format (29 Jan 2025 00:00:00 GMT)
|
|
pub fn isoToRfc822(isoDate: String): String =
|
|
if String.length(isoDate) < 10 then isoDate
|
|
else {
|
|
let year = String.substring(isoDate, 0, 4)
|
|
let month = String.substring(isoDate, 5, 7)
|
|
let day = String.substring(isoDate, 8, 10)
|
|
let monthName = if month == "01" then "Jan"
|
|
else if month == "02" then "Feb"
|
|
else if month == "03" then "Mar"
|
|
else if month == "04" then "Apr"
|
|
else if month == "05" then "May"
|
|
else if month == "06" then "Jun"
|
|
else if month == "07" then "Jul"
|
|
else if month == "08" then "Aug"
|
|
else if month == "09" then "Sep"
|
|
else if month == "10" then "Oct"
|
|
else if month == "11" then "Nov"
|
|
else "Dec"
|
|
day + " " + monthName + " " + year + " 00:00:00 GMT"
|
|
}
|
|
|
|
// Render a single item to XML string
|
|
fn renderItemXml(i: Item): String =
|
|
match i {
|
|
Item(title, link, desc, pubDate, guid) =>
|
|
xml.render(xml.el("item", [
|
|
xml.textEl("title", title),
|
|
xml.textEl("link", link),
|
|
xml.textEl("description", desc),
|
|
xml.textEl("pubDate", isoToRfc822(pubDate)),
|
|
xml.textElAttr("guid", [xml.attr("isPermaLink", "true")], guid)
|
|
])),
|
|
}
|
|
|
|
// Render items to concatenated XML string
|
|
fn renderItemsXml(items: List<Item>): String =
|
|
match List.head(items) {
|
|
None => "",
|
|
Some(i) => renderItemXml(i) + match List.tail(items) {
|
|
Some(rest) => renderItemsXml(rest),
|
|
None => "",
|
|
},
|
|
}
|
|
|
|
// Render an RSS feed to XML string
|
|
pub fn render(f: Feed): String =
|
|
match f {
|
|
Feed(title, link, desc, lang, items) => {
|
|
let itemsXml = renderItemsXml(items)
|
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
|
"<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\">" +
|
|
"<channel>" +
|
|
"<title>" + xml.escape(title) + "</title>" +
|
|
"<link>" + xml.escape(link) + "</link>" +
|
|
"<description>" + xml.escape(desc) + "</description>" +
|
|
"<language>" + lang + "</language>" +
|
|
"<generator>Lux RSS Package</generator>" +
|
|
itemsXml +
|
|
"</channel></rss>"
|
|
},
|
|
}
|