UNPKG

@bliztek/feed-generator

Version:

A simple and lightweight Node.js library for generating RSS 2.0, Atom, and JSON Feed formats.

162 lines (161 loc) 6.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.renderAtom = void 0; const xml_js_1 = require("../xml.js"); const inferImageType = (url) => { var _a; const ext = (_a = url.split(".").pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase(); const types = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", webp: "image/webp", svg: "image/svg+xml", avif: "image/avif", }; return ext ? types[ext] : undefined; }; const toIso = (date) => new Date(date).toISOString(); /** Ensure a URL used as an Atom ID is in canonical form (trailing slash on origin-only URLs). */ const canonicalizeId = (url) => { try { const u = new URL(url); if (u.pathname === "" || u.pathname === "/") { u.pathname = "/"; return u.toString(); } return url; } catch (_a) { return url; } }; const renderAuthors = (authors) => (authors !== null && authors !== void 0 ? authors : []).map((a) => ({ tag: "author", children: (0, xml_js_1.nodes)((0, xml_js_1.el)("name", a.name), a.email ? (0, xml_js_1.el)("email", a.email) : null, a.url ? (0, xml_js_1.el)("uri", a.url) : null), })); const renderAtom = (feed, options = { compact: false }) => { var _a, _b, _c, _d, _e, _f, _g; const { compact, stylesheet } = options; // feed.updated is already derived by prepareFeed in index.ts const feedUpdated = feed.updated ? toIso(feed.updated) : new Date().toISOString(); const feedId = canonicalizeId((_a = feed.id) !== null && _a !== void 0 ? _a : feed.link); const feedLinks = []; if ((_b = feed.feedLinks) === null || _b === void 0 ? void 0 : _b.atom) { feedLinks.push({ tag: "link", selfClosing: true, attributes: { href: feed.feedLinks.atom, rel: "self", type: "application/atom+xml", }, }); } feedLinks.push({ tag: "link", selfClosing: true, attributes: { href: feed.link, rel: "alternate", type: "text/html" }, }); if (feed.nextUrl) { feedLinks.push({ tag: "link", selfClosing: true, attributes: { href: feed.nextUrl, rel: "next" }, }); } if ((_c = feed.feedLinks) === null || _c === void 0 ? void 0 : _c.hub) { feedLinks.push({ tag: "link", selfClosing: true, attributes: { href: feed.feedLinks.hub, rel: "hub" }, }); } const categoryNodes = ((_d = feed.categories) !== null && _d !== void 0 ? _d : []).map((cat) => ({ tag: "category", selfClosing: true, attributes: { term: cat.name, scheme: cat.domain, label: cat.label, }, })); const entryNodes = feed.items.map((item) => { var _a, _b, _c, _d; const entryUpdated = item.updated ? toIso(item.updated) : item.date ? toIso(item.date) : feedUpdated; const entryLinks = []; if (item.link) { entryLinks.push({ tag: "link", selfClosing: true, attributes: { href: item.link, rel: "alternate", type: "text/html" }, }); } ((_a = item.enclosures) !== null && _a !== void 0 ? _a : []).forEach((enc) => { entryLinks.push({ tag: "link", selfClosing: true, attributes: { href: enc.url, rel: "enclosure", type: enc.type, length: enc.length, }, }); }); if (item.image) { entryLinks.push({ tag: "link", selfClosing: true, attributes: { href: item.image, rel: "enclosure", type: inferImageType(item.image), }, }); } const entryCategories = ((_b = item.categories) !== null && _b !== void 0 ? _b : []).map((cat) => ({ tag: "category", selfClosing: true, attributes: { term: cat.name, scheme: cat.domain, label: cat.label, }, })); return { tag: "entry", children: (0, xml_js_1.nodes)((0, xml_js_1.el)("title", item.title, { attributes: { type: "text" } }), ...entryLinks, (0, xml_js_1.el)("id", canonicalizeId(item.id)), (0, xml_js_1.el)("updated", entryUpdated), item.date ? (0, xml_js_1.el)("published", toIso(item.date)) : null, ...entryCategories, item.content ? (0, xml_js_1.el)("content", item.content, { attributes: { type: "html" } }) : null, item.summary ? (0, xml_js_1.el)("summary", item.summary, { attributes: { type: "text" } }) : null, ...renderAuthors(item.authors), ...((_d = (_c = item.extensions) === null || _c === void 0 ? void 0 : _c.xmlElements) !== null && _d !== void 0 ? _d : [])), }; }); const generatorNode = feed.generator ? { tag: "generator", children: [feed.generator] } : null; const feedAttrs = { xmlns: "http://www.w3.org/2005/Atom", }; if ((_e = feed.extensions) === null || _e === void 0 ? void 0 : _e.xmlNamespaces) { Object.assign(feedAttrs, feed.extensions.xmlNamespaces); } const feedNode = { tag: "feed", attributes: feedAttrs, children: (0, xml_js_1.nodes)((0, xml_js_1.el)("title", feed.title, { attributes: { type: "text" } }), feed.description ? (0, xml_js_1.el)("subtitle", feed.description, { attributes: { type: "text" } }) : null, feed.copyright ? (0, xml_js_1.el)("rights", feed.copyright, { attributes: { type: "text" } }) : null, ...feedLinks, (0, xml_js_1.el)("id", feedId), (0, xml_js_1.el)("updated", feedUpdated), generatorNode, ...categoryNodes, ...renderAuthors(feed.authors), ...((_g = (_f = feed.extensions) === null || _f === void 0 ? void 0 : _f.xmlElements) !== null && _g !== void 0 ? _g : []), ...entryNodes), }; const sep = compact ? "" : "\n"; const stylesheetPI = stylesheet ? `${sep}<?xml-stylesheet type="text/xsl" href="${(0, xml_js_1.escapeXml)(stylesheet)}"?>` : ""; return `${(0, xml_js_1.xmlDeclaration)()}${stylesheetPI}${sep}${(0, xml_js_1.renderXml)([feedNode], 0, compact)}`; }; exports.renderAtom = renderAtom;