UNPKG

feedsmith

Version:

Fast, all‑in‑one parser and generator for RSS, Atom, RDF, and JSON Feed, with support for Podcast, iTunes, Dublin Core, and OPML files.

1,232 lines (1,215 loc) 138 kB
//#region rolldown:runtime var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { key = keys[i]; if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: ((k) => from[k]).bind(null, key), enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); //#endregion let entities = require("entities"); entities = __toESM(entities); let fast_xml_parser = require("fast-xml-parser"); fast_xml_parser = __toESM(fast_xml_parser); //#region src/common/utils.ts const isPresent = (value) => { return value != null; }; const isObject = (value) => { return value != null && typeof value === "object" && !Array.isArray(value) && value.constructor === Object; }; const whitespaceOnlyRegex = /^\p{White_Space}*$/u; const isNonEmptyString = (value) => { return typeof value === "string" && value !== "" && !whitespaceOnlyRegex.test(value); }; const isNonEmptyStringOrNumber = (value) => { return typeof value === "number" || isNonEmptyString(value); }; const retrieveText = (value) => { return value?.["#text"] ?? value; }; const trimObject = (object) => { let result; for (const key in object) { const value = object[key]; if (isPresent(value)) { if (!result) result = {}; result[key] = value; } } return result; }; const trimArray = (value, parse$6) => { if (!Array.isArray(value) || value.length === 0) return; if (!parse$6) { let needsTrimming = false; for (let i = 0; i < value.length; i++) if (!isPresent(value[i])) { needsTrimming = true; break; } if (!needsTrimming) return value; } const result = []; for (let i = 0; i < value.length; i++) { const item = parse$6 ? parse$6(value[i]) : value[i]; if (isPresent(item)) result.push(item); } return result.length > 0 ? result : void 0; }; const cdataStartTag = "<![CDATA["; const cdataEndTag = "]]>"; const stripCdata = (text) => { if (typeof text !== "string") return text; let currentIndex = text.indexOf(cdataStartTag); if (currentIndex === -1) return text; let result = ""; let lastIndex = 0; while (currentIndex !== -1) { result += text.substring(lastIndex, currentIndex); lastIndex = text.indexOf(cdataEndTag, currentIndex + 9); if (lastIndex === -1) return text; result += text.substring(currentIndex + 9, lastIndex); lastIndex += 3; currentIndex = text.indexOf(cdataStartTag, lastIndex); } result += text.substring(lastIndex); return result; }; const hasEntities = (text) => { const ampIndex = text.indexOf("&"); return ampIndex !== -1 && text.indexOf(";", ampIndex) !== -1; }; const parseString = (value) => { if (typeof value === "string") { if (value === "") return; let string = value; if (value.indexOf(cdataStartTag) !== -1) string = stripCdata(value); string = string.trim(); if (string === "") return; if (hasEntities(string)) { string = (0, entities.decodeXML)(string); if (hasEntities(string)) string = (0, entities.decodeHTML)(string); } return string || void 0; } if (typeof value === "number") return value.toString(); }; const parseNumber = (value) => { if (typeof value === "number") return value; if (isNonEmptyString(value)) { const numeric = +value; return Number.isNaN(numeric) ? void 0 : numeric; } }; const trueRegex = /^\p{White_Space}*true\p{White_Space}*$/iu; const falseRegex = /^\p{White_Space}*false\p{White_Space}*$/iu; const yesRegex = /^\p{White_Space}*yes\p{White_Space}*$/iu; const parseBoolean = (value) => { if (typeof value === "boolean") return value; if (isNonEmptyString(value)) { if (trueRegex.test(value)) return true; if (falseRegex.test(value)) return false; } }; const parseYesNoBoolean = (value) => { const boolean = parseBoolean(value); if (boolean !== void 0) return boolean; if (isNonEmptyString(value)) return yesRegex.test(value); }; const parseDate = (value) => { return parseString(value); }; const parseArray = (value) => { if (Array.isArray(value)) return value; if (!isObject(value)) return; if (value.length) return Array.from(value); const keys = Object.keys(value); if (keys.length === 0) return; for (let i = 0; i < keys.length; i++) { const key = keys[i]; const n = Number(key); if (!Number.isInteger(n) || n !== i) return; } return Object.values(value); }; const parseArrayOf = (value, parse$6) => { const array = parseArray(value); if (array) return trimArray(array, parse$6); const parsed = parse$6(value); if (parsed) return [parsed]; }; const parseSingular = (value) => { return Array.isArray(value) ? value[0] : value; }; const parseSingularOf = (value, parse$6) => { return parse$6(parseSingular(value)); }; const parseCsvOf = (value, parse$6) => { if (!isNonEmptyStringOrNumber(value)) return; const items = parseString(value)?.split(","); if (items) return trimArray(items, parse$6); }; const generateCsvOf = (value, generate$4) => { if (!Array.isArray(value) || value.length === 0) return; return trimArray(value, generate$4)?.join(); }; const generateXmlStylesheet = (stylesheet) => { const generated = trimObject({ type: generatePlainString(stylesheet.type), href: generatePlainString(stylesheet.href), title: generatePlainString(stylesheet.title), media: generatePlainString(stylesheet.media), charset: generatePlainString(stylesheet.charset), alternate: generateYesNoBoolean(stylesheet.alternate) }); if (!generated) return; let attributes = ""; for (const key in generated) { const value = generated[key]; if (value !== void 0) attributes += ` ${key}="${value}"`; } return `<?xml-stylesheet${attributes}?>`; }; const generateXml = (builder$3, value, options) => { let body = builder$3.build(value); if (body.includes("&apos;")) body = body.replace(/&apos;/g, "'"); let declaration = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"; if (options?.stylesheets?.length) for (const stylesheetObject of options.stylesheets) { const stylesheetString = generateXmlStylesheet(stylesheetObject); if (stylesheetString) declaration += `\n${stylesheetString}`; } return `${declaration}\n${body}`; }; const generateRfc822Date = (value) => { if (!isPresent(value)) return; const isString = typeof value === "string"; if (isString && !isNonEmptyString(value)) return; const date = isString ? new Date(value) : value; if (!Number.isNaN(date.getTime())) return date.toUTCString(); if (isString) return value; }; const generateRfc3339Date = (value) => { if (!isPresent(value)) return; const isString = typeof value === "string"; if (isString && !isNonEmptyString(value)) return; const date = isString ? new Date(value) : value; if (!Number.isNaN(date.getTime())) return date.toISOString(); if (isString) return value; }; const generateBoolean = (value) => { if (typeof value === "boolean") return value; }; const generateYesNoBoolean = (value) => { if (typeof value !== "boolean") return; return value ? "yes" : "no"; }; const detectNamespaces = (value, recursive = false) => { const namespaces = /* @__PURE__ */ new Set(); const seenKeys = /* @__PURE__ */ new Set(); const traverse = (current) => { if (Array.isArray(current)) { for (const item of current) traverse(item); return; } if (isObject(current)) for (const key in current) { if (seenKeys.has(key)) continue; seenKeys.add(key); const keyWithoutAt = key.indexOf("@") === 0 ? key.slice(1) : key; const colonIndex = keyWithoutAt.indexOf(":"); if (colonIndex > 0) namespaces.add(keyWithoutAt.slice(0, colonIndex)); if (recursive) traverse(current[key]); } }; traverse(value); return namespaces; }; const generateCdataString = (value) => { if (!isNonEmptyString(value)) return; if (value.indexOf("<") !== -1 || value.indexOf(">") !== -1 || value.indexOf("&") !== -1 || value.indexOf("]]>") !== -1) return { "#cdata": value.trim() }; return value.trim(); }; const generatePlainString = (value) => { if (!isNonEmptyString(value)) return; return value.trim(); }; const generateNumber = (value) => { if (typeof value === "number" && Number.isFinite(value)) return value; }; const generateNamespaceAttrs = (value, namespaceUrls$1) => { if (!isObject(value)) return; let namespaceAttrs; const valueNamespaces = detectNamespaces(value, true); for (const slug in namespaceUrls$1) { if (!valueNamespaces.has(slug)) continue; if (!namespaceAttrs) namespaceAttrs = {}; namespaceAttrs[`@xmlns:${slug}`] = namespaceUrls$1[slug]; } return namespaceAttrs; }; const invertObject = (object) => { const inverted = {}; for (const key in object) inverted[object[key]] = key; return inverted; }; const createNamespaceNormalizator = (namespaceUrls$1, primaryNamespace) => { const namespacesMap = invertObject(namespaceUrls$1); const resolveNamespacePrefix = (uri, localName, fallback) => { if (primaryNamespace && uri === primaryNamespace) return localName; const standardPrefix = namespacesMap[uri]; if (standardPrefix) return `${standardPrefix}:${localName}`; return fallback; }; const extractNamespaceDeclarations = (element) => { const declarations = {}; if (isObject(element)) { for (const key in element) if (key === "@xmlns") declarations[""] = element[key]; else if (key.indexOf("@xmlns:") === 0) { const prefix = key.substring(7); declarations[prefix] = element[key]; } } return declarations; }; const normalizeWithContext = (name, context, useDefault = false) => { const colonIndex = name.indexOf(":"); if (colonIndex === -1) { if (useDefault && context[""]) return resolveNamespacePrefix(context[""], name, name); return name; } const prefix = name.substring(0, colonIndex); const unprefixedName = name.substring(colonIndex + 1); const uri = context[prefix]; if (uri) return resolveNamespacePrefix(uri, unprefixedName, name); return name; }; const normalizeKey = (key, context) => { if (key.indexOf("@") === 0) { const attrName = key.substring(1); return `@${normalizeWithContext(attrName, context, false)}`; } else return normalizeWithContext(key, context, true); }; const traverseAndNormalize = (object, parentContext = {}) => { if (!isObject(object)) return object; if (Array.isArray(object)) return object.map((item) => traverseAndNormalize(item, parentContext)); const normalizedObject = {}; const keyGroups = /* @__PURE__ */ new Map(); const declarations = extractNamespaceDeclarations(object); const currentContext = { ...parentContext, ...declarations }; for (const key in object) { const value = object[key]; if (key.indexOf("@xmlns") === 0) { normalizedObject[key] = value; continue; } const normalizedKey = normalizeKey(key, currentContext); const normalizedValue = traverseAndNormalize(value, currentContext); if (!keyGroups.has(normalizedKey)) keyGroups.set(normalizedKey, []); const group = keyGroups.get(normalizedKey); if (group) group.push(normalizedValue); } for (const [normalizedKey, values] of keyGroups) if (values.length === 1) normalizedObject[normalizedKey] = values[0]; else normalizedObject[normalizedKey] = values; return normalizedObject; }; const normalizeRoot = (object) => { if (!isObject(object)) return object; if (Array.isArray(object)) return object.map(normalizeRoot); const normalizedObject = {}; for (const key in object) { const value = object[key]; const declarations = extractNamespaceDeclarations(value); const normalizedKey = Object.keys(declarations).length ? normalizeKey(key, declarations) : key; normalizedObject[normalizedKey] = traverseAndNormalize(value); } return normalizedObject; }; return normalizeRoot; }; //#endregion //#region src/feeds/atom/detect/index.ts const detect = (value) => { if (!isNonEmptyString(value)) return false; if (!/(?:^|\s|>)\s*<(?:\w+:)?feed[\s>]/im.test(value)) return false; const hasAtomNamespace = value.includes("http://www.w3.org/2005/Atom"); const hasAtomElements = /(<(?:\w+:)?(entry|title|link|id|updated|summary)[\s>])/i.test(value); return hasAtomNamespace || hasAtomElements; }; //#endregion //#region src/common/config.ts const parserConfig = { trimValues: false, processEntities: false, htmlEntities: false, parseTagValue: false, parseAttributeValue: false, alwaysCreateTextNode: false, ignoreAttributes: false, ignorePiTags: true, ignoreDeclaration: true, attributeNamePrefix: "@", transformTagName: (name) => name.toLowerCase(), transformAttributeName: (name) => name.toLowerCase() }; const builderConfig = { processEntities: true, ignoreAttributes: false, suppressEmptyNode: true, suppressBooleanAttributes: false, attributeNamePrefix: "@", format: true, cdataPropName: "#cdata" }; const locales = { unrecognized: "Unrecognized feed format", invalid: "Invalid feed format" }; const namespaceUrls = { atom: "http://www.w3.org/2005/Atom", dc: "http://purl.org/dc/elements/1.1/", sy: "http://purl.org/rss/1.0/modules/syndication/", content: "http://purl.org/rss/1.0/modules/content/", slash: "http://purl.org/rss/1.0/modules/slash/", itunes: "http://www.itunes.com/dtds/podcast-1.0.dtd", podcast: "https://podcastindex.org/namespace/1.0", psc: "http://podlove.org/simple-chapters", media: "http://search.yahoo.com/mrss/", georss: "http://www.georss.org/georss/", thr: "http://purl.org/syndication/thread/1.0", dcterms: "http://purl.org/dc/terms/", wfw: "http://wellformedweb.org/CommentAPI/", source: "http://source.scripting.com/", yt: "http://www.youtube.com/xml/schemas/2015", rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#" }; //#endregion //#region src/feeds/atom/parse/config.ts const stopNodes$3 = [ "feed.author.name", "feed.author.uri", "feed.author.url", "feed.author.email", "feed.category", "feed.contributor.name", "feed.contributor.uri", "feed.contributor.url", "feed.contributor.email", "feed.generator", "feed.icon", "feed.id", "feed.link", "feed.logo", "feed.rights", "feed.subtitle", "feed.tagline", "feed.title", "feed.updated", "feed.modified", "feed.entry.author.name", "feed.entry.author.uri", "feed.entry.author.url", "feed.entry.author.email", "feed.entry.category", "feed.entry.content", "feed.entry.contributor.name", "feed.entry.contributor.uri", "feed.entry.contributor.url", "feed.entry.contributor.email", "feed.entry.id", "feed.entry.link", "feed.entry.published", "feed.entry.issued", "feed.entry.created", "feed.entry.rights", "feed.entry.source.author.name", "feed.entry.source.author.uri", "feed.entry.source.author.url", "feed.entry.source.author.email", "feed.entry.source.category", "feed.entry.source.contributor.name", "feed.entry.source.contributor.uri", "feed.entry.source.contributor.url", "feed.entry.source.contributor.email", "feed.entry.source.generator", "feed.entry.source.icon", "feed.entry.source.id", "feed.entry.source.link", "feed.entry.source.logo", "feed.entry.source.rights", "feed.entry.source.subtitle", "feed.entry.source.title,", "feed.entry.source.updated", "feed.entry.source.modified", "feed.entry.summary", "feed.entry.title", "feed.entry.updated", "feed.entry.modified" ]; const parser$3 = new fast_xml_parser.XMLParser({ ...parserConfig, stopNodes: stopNodes$3 }); //#endregion //#region src/namespaces/dc/parse/utils.ts const retrieveItemOrFeed = (value) => { if (!isObject(value)) return; const itemOrFeed = { title: parseSingularOf(value["dc:title"], (value$1) => parseString(retrieveText(value$1))), creator: parseSingularOf(value["dc:creator"], (value$1) => parseString(retrieveText(value$1))), subject: parseSingularOf(value["dc:subject"], (value$1) => parseString(retrieveText(value$1))), description: parseSingularOf(value["dc:description"], (value$1) => parseString(retrieveText(value$1))), publisher: parseSingularOf(value["dc:publisher"], (value$1) => parseString(retrieveText(value$1))), contributor: parseSingularOf(value["dc:contributor"], (value$1) => parseString(retrieveText(value$1))), date: parseSingularOf(value["dc:date"], (value$1) => parseDate(retrieveText(value$1))), type: parseSingularOf(value["dc:type"], (value$1) => parseString(retrieveText(value$1))), format: parseSingularOf(value["dc:format"], (value$1) => parseString(retrieveText(value$1))), identifier: parseSingularOf(value["dc:identifier"], (value$1) => parseString(retrieveText(value$1))), source: parseSingularOf(value["dc:source"], (value$1) => parseString(retrieveText(value$1))), language: parseSingularOf(value["dc:language"], (value$1) => parseString(retrieveText(value$1))), relation: parseSingularOf(value["dc:relation"], (value$1) => parseString(retrieveText(value$1))), coverage: parseSingularOf(value["dc:coverage"], (value$1) => parseString(retrieveText(value$1))), rights: parseSingularOf(value["dc:rights"], (value$1) => parseString(retrieveText(value$1))) }; return trimObject(itemOrFeed); }; //#endregion //#region src/namespaces/dcterms/parse/utils.ts const retrieveItemOrFeed$1 = (value) => { if (!isObject(value)) return; const itemOrFeed = { abstract: parseSingularOf(value["dcterms:abstract"], (value$1) => parseString(retrieveText(value$1))), accessRights: parseSingularOf(value["dcterms:accessrights"], (value$1) => parseString(retrieveText(value$1))), accrualMethod: parseSingularOf(value["dcterms:accrualmethod"], (value$1) => parseString(retrieveText(value$1))), accrualPeriodicity: parseSingularOf(value["dcterms:accrualperiodicity"], (value$1) => parseString(retrieveText(value$1))), accrualPolicy: parseSingularOf(value["dcterms:accrualpolicy"], (value$1) => parseString(retrieveText(value$1))), alternative: parseSingularOf(value["dcterms:alternative"], (value$1) => parseString(retrieveText(value$1))), audience: parseSingularOf(value["dcterms:audience"], (value$1) => parseString(retrieveText(value$1))), available: parseSingularOf(value["dcterms:available"], (value$1) => parseDate(retrieveText(value$1))), bibliographicCitation: parseSingularOf(value["dcterms:bibliographiccitation"], (value$1) => parseString(retrieveText(value$1))), conformsTo: parseSingularOf(value["dcterms:conformsto"], (value$1) => parseString(retrieveText(value$1))), contributor: parseSingularOf(value["dcterms:contributor"], (value$1) => parseString(retrieveText(value$1))), coverage: parseSingularOf(value["dcterms:coverage"], (value$1) => parseString(retrieveText(value$1))), created: parseSingularOf(value["dcterms:created"], (value$1) => parseDate(retrieveText(value$1))), creator: parseSingularOf(value["dcterms:creator"], (value$1) => parseString(retrieveText(value$1))), date: parseSingularOf(value["dcterms:date"], (value$1) => parseDate(retrieveText(value$1))), dateAccepted: parseSingularOf(value["dcterms:dateaccepted"], (value$1) => parseDate(retrieveText(value$1))), dateCopyrighted: parseSingularOf(value["dcterms:datecopyrighted"], (value$1) => parseDate(retrieveText(value$1))), dateSubmitted: parseSingularOf(value["dcterms:datesubmitted"], (value$1) => parseDate(retrieveText(value$1))), description: parseSingularOf(value["dcterms:description"], (value$1) => parseString(retrieveText(value$1))), educationLevel: parseSingularOf(value["dcterms:educationlevel"], (value$1) => parseString(retrieveText(value$1))), extent: parseSingularOf(value["dcterms:extent"], (value$1) => parseString(retrieveText(value$1))), format: parseSingularOf(value["dcterms:format"], (value$1) => parseString(retrieveText(value$1))), hasFormat: parseSingularOf(value["dcterms:hasformat"], (value$1) => parseString(retrieveText(value$1))), hasPart: parseSingularOf(value["dcterms:haspart"], (value$1) => parseString(retrieveText(value$1))), hasVersion: parseSingularOf(value["dcterms:hasversion"], (value$1) => parseString(retrieveText(value$1))), identifier: parseSingularOf(value["dcterms:identifier"], (value$1) => parseString(retrieveText(value$1))), instructionalMethod: parseSingularOf(value["dcterms:instructionalmethod"], (value$1) => parseString(retrieveText(value$1))), isFormatOf: parseSingularOf(value["dcterms:isformatof"], (value$1) => parseString(retrieveText(value$1))), isPartOf: parseSingularOf(value["dcterms:ispartof"], (value$1) => parseString(retrieveText(value$1))), isReferencedBy: parseSingularOf(value["dcterms:isreferencedby"], (value$1) => parseString(retrieveText(value$1))), isReplacedBy: parseSingularOf(value["dcterms:isreplacedby"], (value$1) => parseString(retrieveText(value$1))), isRequiredBy: parseSingularOf(value["dcterms:isrequiredby"], (value$1) => parseString(retrieveText(value$1))), issued: parseSingularOf(value["dcterms:issued"], (value$1) => parseDate(retrieveText(value$1))), isVersionOf: parseSingularOf(value["dcterms:isversionof"], (value$1) => parseString(retrieveText(value$1))), language: parseSingularOf(value["dcterms:language"], (value$1) => parseString(retrieveText(value$1))), license: parseSingularOf(value["dcterms:license"], (value$1) => parseString(retrieveText(value$1))), mediator: parseSingularOf(value["dcterms:mediator"], (value$1) => parseString(retrieveText(value$1))), medium: parseSingularOf(value["dcterms:medium"], (value$1) => parseString(retrieveText(value$1))), modified: parseSingularOf(value["dcterms:modified"], (value$1) => parseDate(retrieveText(value$1))), provenance: parseSingularOf(value["dcterms:provenance"], (value$1) => parseString(retrieveText(value$1))), publisher: parseSingularOf(value["dcterms:publisher"], (value$1) => parseString(retrieveText(value$1))), references: parseSingularOf(value["dcterms:references"], (value$1) => parseString(retrieveText(value$1))), relation: parseSingularOf(value["dcterms:relation"], (value$1) => parseString(retrieveText(value$1))), replaces: parseSingularOf(value["dcterms:replaces"], (value$1) => parseString(retrieveText(value$1))), requires: parseSingularOf(value["dcterms:requires"], (value$1) => parseString(retrieveText(value$1))), rights: parseSingularOf(value["dcterms:rights"], (value$1) => parseString(retrieveText(value$1))), rightsHolder: parseSingularOf(value["dcterms:rightsholder"], (value$1) => parseString(retrieveText(value$1))), source: parseSingularOf(value["dcterms:source"], (value$1) => parseString(retrieveText(value$1))), spatial: parseSingularOf(value["dcterms:spatial"], (value$1) => parseString(retrieveText(value$1))), subject: parseSingularOf(value["dcterms:subject"], (value$1) => parseString(retrieveText(value$1))), tableOfContents: parseSingularOf(value["dcterms:tableofcontents"], (value$1) => parseString(retrieveText(value$1))), temporal: parseSingularOf(value["dcterms:temporal"], (value$1) => parseString(retrieveText(value$1))), title: parseSingularOf(value["dcterms:title"], (value$1) => parseString(retrieveText(value$1))), type: parseSingularOf(value["dcterms:type"], (value$1) => parseString(retrieveText(value$1))), valid: parseSingularOf(value["dcterms:valid"], (value$1) => parseDate(retrieveText(value$1))) }; return trimObject(itemOrFeed); }; //#endregion //#region src/namespaces/georss/parse/utils.ts const parseLatLngPairs = (value, pairsCount) => { if (!isNonEmptyString(value)) return; const rawParts = value.split(/\s+/); const numericParts = parseArrayOf(rawParts, parseNumber); if (!numericParts || numericParts.length % 2 !== 0 || rawParts.length !== numericParts.length) return; const actualPairCount = numericParts.length / 2; if (pairsCount?.min && actualPairCount < pairsCount?.min || pairsCount?.max && actualPairCount > pairsCount?.max) return; const points = []; for (let i = 0; i < numericParts.length; i += 2) { const lat = numericParts[i]; const lng = numericParts[i + 1]; if (isPresent(lat) && isPresent(lng)) points.push({ lat, lng }); } return points.length > 0 ? points : void 0; }; const parsePoint = (value) => { return parseLatLngPairs(retrieveText(value), { min: 1, max: 1 })?.[0]; }; const parseLine = (value) => { const points = parseLatLngPairs(retrieveText(value), { min: 2 }); if (isPresent(points)) return { points }; }; const parsePolygon = (value) => { const points = parseLatLngPairs(retrieveText(value), { min: 4 }); if (isPresent(points)) return { points }; }; const parseBox = (value) => { const points = parseLatLngPairs(retrieveText(value), { min: 2, max: 2 }); const lowerCorner = points?.[0]; const upperCorner = points?.[1]; if (isPresent(lowerCorner) && isPresent(upperCorner)) return { lowerCorner, upperCorner }; }; const retrieveItemOrFeed$2 = (value) => { if (!isObject(value)) return; const itemOrFeed = { point: parseSingularOf(value["georss:point"], parsePoint), line: parseSingularOf(value["georss:line"], parseLine), polygon: parseSingularOf(value["georss:polygon"], parsePolygon), box: parseSingularOf(value["georss:box"], parseBox), featureTypeTag: parseSingularOf(value["georss:featuretypetag"], (value$1) => parseString(retrieveText(value$1))), relationshipTag: parseSingularOf(value["georss:relationshiptag"], (value$1) => parseString(retrieveText(value$1))), featureName: parseSingularOf(value["georss:featurename"], (value$1) => parseString(retrieveText(value$1))), elev: parseSingularOf(value["georss:elev"], (value$1) => parseNumber(retrieveText(value$1))), floor: parseSingularOf(value["georss:floor"], (value$1) => parseNumber(retrieveText(value$1))), radius: parseSingularOf(value["georss:radius"], (value$1) => parseNumber(retrieveText(value$1))) }; return trimObject(itemOrFeed); }; //#endregion //#region src/namespaces/itunes/parse/utils.ts const parseCategory$3 = (value) => { if (!isObject(value)) return; const category = { text: parseString(value["@text"]), categories: parseArrayOf(value["itunes:category"], parseCategory$3) }; return trimObject(category); }; const parseOwner = (value) => { if (!isObject(value)) return; const owner = { name: parseSingularOf(value["itunes:name"], (value$1) => parseString(retrieveText(value$1))), email: parseSingularOf(value["itunes:email"], (value$1) => parseString(retrieveText(value$1))) }; return trimObject(owner); }; const explicitOrYesRegex = /^\p{White_Space}*(explicit|yes)\p{White_Space}*$/iu; const parseExplicit = (value) => { const boolean = parseBoolean(value); if (boolean !== void 0) return boolean; if (typeof value === "string") return explicitOrYesRegex.test(value); }; const parseDuration = (value) => { const duration = parseNumber(value); if (duration !== void 0) return duration; if (typeof value !== "string") return; const match = value.match(/^(?:(\d+):)?(\d+):(\d+)$/); if (match) { const [, hours, minutes, seconds] = match; return Number(hours || 0) * 3600 + Number(minutes) * 60 + Number(seconds); } }; const parseImage$2 = (value) => { if (isNonEmptyStringOrNumber(value)) return parseString(value); if (!isObject(value)) return; return parseString(value["@href"]); }; const retrieveItem$1 = (value) => { if (!isObject(value)) return; const item = { duration: parseSingularOf(value["itunes:duration"], (value$1) => parseDuration(retrieveText(value$1))), image: parseSingularOf(value["itunes:image"], parseImage$2), explicit: parseSingularOf(value["itunes:explicit"], (value$1) => parseExplicit(retrieveText(value$1))), title: parseSingularOf(value["itunes:title"], (value$1) => parseString(retrieveText(value$1))), episode: parseSingularOf(value["itunes:episode"], (value$1) => parseNumber(retrieveText(value$1))), season: parseSingularOf(value["itunes:season"], (value$1) => parseNumber(retrieveText(value$1))), episodeType: parseSingularOf(value["itunes:episodetype"], (value$1) => parseString(retrieveText(value$1))), block: parseSingularOf(value["itunes:block"], (value$1) => parseYesNoBoolean(retrieveText(value$1))), summary: parseSingularOf(value["itunes:summary"], (value$1) => parseString(retrieveText(value$1))), subtitle: parseSingularOf(value["itunes:subtitle"], (value$1) => parseString(retrieveText(value$1))), keywords: parseSingularOf(value["itunes:keywords"], (value$1) => parseCsvOf(retrieveText(value$1), parseString)) }; return trimObject(item); }; const retrieveFeed$2 = (value) => { if (!isObject(value)) return; const feed = { image: parseSingularOf(value["itunes:image"], parseImage$2), explicit: parseSingularOf(value["itunes:explicit"], (value$1) => parseExplicit(retrieveText(value$1))), author: parseSingularOf(value["itunes:author"], (value$1) => parseString(retrieveText(value$1))), title: parseSingularOf(value["itunes:title"], (value$1) => parseString(retrieveText(value$1))), type: parseSingularOf(value["itunes:type"], (value$1) => parseString(retrieveText(value$1))), newFeedUrl: parseSingularOf(value["itunes:new-feed-url"], (value$1) => parseString(retrieveText(value$1))), block: parseSingularOf(value["itunes:block"], (value$1) => parseYesNoBoolean(retrieveText(value$1))), complete: parseSingularOf(value["itunes:complete"], (value$1) => parseYesNoBoolean(retrieveText(value$1))), applePodcastsVerify: parseSingularOf(value["itunes:applepodcastsverify"], (value$1) => parseString(retrieveText(value$1))), categories: parseArrayOf(value["itunes:category"], parseCategory$3), owner: parseSingularOf(value["itunes:owner"], parseOwner), summary: parseSingularOf(value["itunes:summary"], (value$1) => parseString(retrieveText(value$1))), subtitle: parseSingularOf(value["itunes:subtitle"], (value$1) => parseString(retrieveText(value$1))), keywords: parseSingularOf(value["itunes:keywords"], (value$1) => parseCsvOf(retrieveText(value$1), parseString)) }; return trimObject(feed); }; //#endregion //#region src/namespaces/media/parse/utils.ts const parseRating = (value) => { const rating = { value: ((value$1) => parseString(retrieveText(value$1)))(value), scheme: parseString(value?.["@scheme"]) }; return trimObject(rating); }; const retrieveRatings = (value) => { if (!isObject(value)) return; if (value["media:rating"]) return parseArrayOf(value["media:rating"], parseRating); if (value["media:adult"]) return [{ value: parseBoolean(retrieveText(value["media:adult"])) ? "adult" : "nonadult", scheme: "urn:simple" }]; }; const parseTitleOrDescription = (value) => { const title = { value: ((value$1) => parseString(retrieveText(value$1)))(value), type: parseString(value?.["@type"]) }; return trimObject(title); }; const parseThumbnail = (value) => { if (!isObject(value)) return; const thumbnail = { url: parseString(value["@url"]), height: parseNumber(value["@height"]), width: parseNumber(value["@width"]), time: parseString(value["@time"]) }; return trimObject(thumbnail); }; const parseCategory$2 = (value) => { const category = { name: ((value$1) => parseString(retrieveText(value$1)))(value), scheme: parseString(value?.["@scheme"]), label: parseString(value?.["@label"]) }; return trimObject(category); }; const parseHash = (value) => { const hash = { value: ((value$1) => parseString(retrieveText(value$1)))(value), algo: parseString(value?.["@algo"]) }; return trimObject(hash); }; const parsePlayer = (value) => { if (!isObject(value)) return; const player = { url: parseString(value["@url"]), height: parseNumber(value["@height"]), width: parseNumber(value["@width"]) }; return trimObject(player); }; const parseCredit = (value) => { const credit = { value: ((value$1) => parseString(retrieveText(value$1)))(value), role: parseString(value?.["@role"]), scheme: parseString(value?.["@scheme"]) }; return trimObject(credit); }; const parseCopyright = (value) => { const copyright = { value: ((value$1) => parseString(retrieveText(value$1)))(value), url: parseString(value?.["@url"]) }; return trimObject(copyright); }; const parseText = (value) => { const text = { value: ((value$1) => parseString(retrieveText(value$1)))(value), type: parseString(value?.["@type"]), lang: parseString(value?.["@lang"]), start: parseString(value?.["@start"]), end: parseString(value?.["@end"]) }; return trimObject(text); }; const parseRestriction = (value) => { if (!isObject(value)) return; const restriction = { value: ((value$1) => parseString(retrieveText(value$1)))(value), relationship: parseString(value["@relationship"]), type: parseString(value["@type"]) }; return trimObject(restriction); }; const parseCommunity = (value) => { if (!isObject(value)) return; const community = { starRating: parseSingularOf(value["media:starrating"], parseStarRating), statistics: parseSingularOf(value["media:statistics"], parseStatistics), tags: parseSingularOf(value["media:tags"], parseTags) }; return trimObject(community); }; const parseStarRating = (value) => { if (!isObject(value)) return; const starRating = { average: parseNumber(value["@average"]), count: parseNumber(value["@count"]), min: parseNumber(value["@min"]), max: parseNumber(value["@max"]) }; return trimObject(starRating); }; const parseStatistics = (value) => { if (!isObject(value)) return; const statistics = { views: parseNumber(value["@views"]), favorites: parseNumber(value["@favorites"]) }; return trimObject(statistics); }; const parseTags = (value) => { return parseCsvOf(value, (segment) => { const split = segment.split(":"); return { name: parseString(split[0]) ?? "", weight: parseNumber(split[1]) ?? 1 }; }); }; const parseComments = (value) => { return parseArrayOf(value?.["media:comment"], (value$1) => parseString(retrieveText(value$1))); }; const parseEmbed = (value) => { if (!isObject(value)) return; const embed = { url: parseString(value["@url"]), width: parseNumber(value["@width"]), height: parseNumber(value["@height"]), params: parseArrayOf(value["media:param"], parseParam) }; return trimObject(embed); }; const parseParam = (value) => { if (!isObject(value)) return; const param = { name: parseString(value["@name"]), value: ((value$1) => parseString(retrieveText(value$1)))(value) }; return trimObject(param); }; const parseResponses = (value) => { return parseArrayOf(value?.["media:response"], (value$1) => parseString(retrieveText(value$1))); }; const parseBackLinks = (value) => { return parseArrayOf(value?.["media:backlink"], (value$1) => parseString(retrieveText(value$1))); }; const parseStatus = (value) => { if (!isObject(value)) return; const status = { state: parseString(value["@state"]), reason: parseString(value["@reason"]) }; return trimObject(status); }; const parsePrice = (value) => { if (!isObject(value)) return; const price = { type: parseString(value["@type"]), info: parseString(value["@info"]), price: parseNumber(value["@price"]), currency: parseString(value["@currency"]) }; return trimObject(price); }; const parseLicense$1 = (value) => { const license = { name: ((value$1) => parseString(retrieveText(value$1)))(value), type: parseString(value?.["@type"]), href: parseString(value?.["@href"]) }; return trimObject(license); }; const parseSubTitle = (value) => { if (!isObject(value)) return; const subTitle = { type: parseString(value["@type"]), lang: parseString(value["@lang"]), href: parseString(value["@href"]) }; return trimObject(subTitle); }; const parsePeerLink = (value) => { if (!isObject(value)) return; const peerLink = { type: parseString(value["@type"]), href: parseString(value["@href"]) }; return trimObject(peerLink); }; const parseRights = (value) => { if (!isObject(value)) return; const rights = { status: parseString(value["@status"]) }; return trimObject(rights); }; const parseScene = (value) => { if (!isObject(value)) return; const scene = { title: parseSingularOf(value.scenetitle, (value$1) => parseString(retrieveText(value$1))), description: parseSingularOf(value.scenedescription, (value$1) => parseString(retrieveText(value$1))), startTime: parseSingularOf(value.scenestarttime, (value$1) => parseString(retrieveText(value$1))), endTime: parseSingularOf(value.sceneendtime, (value$1) => parseString(retrieveText(value$1))) }; return trimObject(scene); }; const parseScenes = (value) => { return parseArrayOf(value?.["media:scene"], parseScene); }; const parseLocation$1 = (value) => { if (isNonEmptyStringOrNumber(value) || isObject(value)) { const location = { description: ((value$1) => parseString(retrieveText(value$1)))(value) }; return trimObject(location); } }; const retrieveCommonElements = (value) => { if (!isObject(value)) return; const commonElements = { ratings: retrieveRatings(value), title: parseSingularOf(value["media:title"], parseTitleOrDescription), description: parseSingularOf(value["media:description"], parseTitleOrDescription), keywords: parseSingularOf(value["media:keywords"], (value$1) => parseCsvOf(retrieveText(value$1), parseString)), thumbnails: parseArrayOf(value["media:thumbnail"], parseThumbnail), categories: parseArrayOf(value["media:category"], parseCategory$2), hashes: parseArrayOf(value["media:hash"], parseHash), player: parseSingularOf(value["media:player"], parsePlayer), credits: parseArrayOf(value["media:credit"], parseCredit), copyright: parseSingularOf(value["media:copyright"], parseCopyright), texts: parseArrayOf(value["media:text"], parseText), restrictions: parseArrayOf(value["media:restriction"], parseRestriction), community: parseSingularOf(value["media:community"], parseCommunity), comments: parseSingularOf(value["media:comments"], parseComments), embed: parseSingularOf(value["media:embed"], parseEmbed), responses: parseSingularOf(value["media:responses"], parseResponses), backLinks: parseSingularOf(value["media:backlinks"], parseBackLinks), status: parseSingularOf(value["media:status"], parseStatus), prices: parseArrayOf(value["media:price"], parsePrice), licenses: parseArrayOf(value["media:license"], parseLicense$1), subTitles: parseArrayOf(value["media:subtitle"], parseSubTitle), peerLinks: parseArrayOf(value["media:peerlink"], parsePeerLink), locations: parseArrayOf(value["media:location"], parseLocation$1), rights: parseSingularOf(value["media:rights"], parseRights), scenes: parseSingularOf(value["media:scenes"], parseScenes) }; return trimObject(commonElements); }; const parseContent = (value) => { if (!isObject(value)) return; const content = { url: parseString(value["@url"]), fileSize: parseNumber(value["@filesize"]), type: parseString(value["@type"]), medium: parseString(value["@medium"]), isDefault: parseBoolean(value["@isdefault"]), expression: parseString(value["@expression"]), bitrate: parseNumber(value["@bitrate"]), framerate: parseNumber(value["@framerate"]), samplingrate: parseNumber(value["@samplingrate"]), channels: parseNumber(value["@channels"]), duration: parseNumber(value["@duration"]), height: parseNumber(value["@height"]), width: parseNumber(value["@width"]), lang: parseString(value["@lang"]), ...retrieveCommonElements(value) }; return trimObject(content); }; const parseGroup = (value) => { if (!isObject(value)) return; const group = { contents: parseArrayOf(value["media:content"], parseContent), ...retrieveCommonElements(value) }; return trimObject(group); }; const retrieveItemOrFeed$3 = (value) => { if (!isObject(value)) return; const itemOrFeed = { group: parseSingularOf(value["media:group"], parseGroup), contents: parseArrayOf(value["media:content"], parseContent), ...retrieveCommonElements(value) }; return trimObject(itemOrFeed); }; //#endregion //#region src/namespaces/psc/parse/utils.ts const parseChapter = (value) => { if (!isObject(value)) return; const chapter = { start: parseSingularOf(value["@start"], parseString), title: parseSingularOf(value["@title"], parseString), href: parseSingularOf(value["@href"], parseString), image: parseSingularOf(value["@image"], parseString) }; return trimObject(chapter); }; const parseChapters$1 = (value) => { return parseArrayOf(value?.["psc:chapter"], parseChapter); }; const retrieveItem$3 = (value) => { if (!isObject(value)) return; const item = { chapters: parseSingularOf(value["psc:chapters"], parseChapters$1) }; return trimObject(item); }; //#endregion //#region src/namespaces/slash/parse/utils.ts const parseHitParade = (value) => { return parseCsvOf(value, parseNumber); }; const retrieveItem$4 = (value) => { if (!isObject(value)) return; const item = { section: parseSingularOf(value["slash:section"], (value$1) => parseString(retrieveText(value$1))), department: parseSingularOf(value["slash:department"], (value$1) => parseString(retrieveText(value$1))), comments: parseSingularOf(value["slash:comments"], (value$1) => parseNumber(retrieveText(value$1))), hitParade: parseSingularOf(value["slash:hit_parade"], (value$1) => parseHitParade(retrieveText(value$1))) }; return trimObject(item); }; //#endregion //#region src/namespaces/sy/parse/utils.ts const retrieveFeed$5 = (value) => { if (!isObject(value)) return; const feed = { updatePeriod: parseSingularOf(value["sy:updateperiod"], (value$1) => parseString(retrieveText(value$1))), updateFrequency: parseSingularOf(value["sy:updatefrequency"], (value$1) => parseNumber(retrieveText(value$1))), updateBase: parseSingularOf(value["sy:updatebase"], (value$1) => parseDate(retrieveText(value$1))) }; return trimObject(feed); }; //#endregion //#region src/namespaces/thr/parse/utils.ts const parseInReplyTo = (value) => { if (!isObject(value)) return; const inReplyTo = { ref: parseString(value["@ref"]), href: parseString(value["@href"]), type: parseString(value["@type"]), source: parseString(value["@source"]) }; return trimObject(inReplyTo); }; const retrieveLink = (value) => { if (!isObject(value)) return; const link = { count: parseNumber(value["@thr:count"]), updated: parseDate(value["@thr:updated"]) }; return trimObject(link); }; const retrieveItem$6 = (value) => { if (!isObject(value)) return; const item = { total: parseSingularOf(value["thr:total"], (value$1) => parseNumber(retrieveText(value$1))), inReplyTos: parseArrayOf(value["thr:in-reply-to"], parseInReplyTo) }; return trimObject(item); }; //#endregion //#region src/namespaces/wfw/parse/utils.ts const retrieveItem$7 = (value) => { if (!isObject(value)) return; const item = { comment: parseSingularOf(value["wfw:comment"], (value$1) => parseString(retrieveText(value$1))), commentRss: parseSingularOf(value["wfw:commentrss"], (value$1) => parseString(retrieveText(value$1))) }; return trimObject(item); }; //#endregion //#region src/namespaces/yt/parse/utils.ts const retrieveItem$8 = (value) => { if (!isObject(value)) return; const item = { videoId: parseSingularOf(value["yt:videoid"], (value$1) => parseString(retrieveText(value$1))), channelId: parseSingularOf(value["yt:channelid"], (value$1) => parseString(retrieveText(value$1))) }; return trimObject(item); }; const retrieveFeed$8 = (value) => { if (!isObject(value)) return; const feed = { channelId: parseSingularOf(value["yt:channelid"], (value$1) => parseString(retrieveText(value$1))), playlistId: parseSingularOf(value["yt:playlistid"], (value$1) => parseString(retrieveText(value$1))) }; return trimObject(feed); }; //#endregion //#region src/feeds/atom/parse/utils.ts const createNamespaceGetter = (value, prefix) => { if (!prefix) return (key) => value[key]; const prefixedKeys = /* @__PURE__ */ new Map(); return (key) => { let prefixedKey = prefixedKeys.get(key); if (!prefixedKey) { prefixedKey = prefix + key; prefixedKeys.set(key, prefixedKey); } return value[prefixedKey]; }; }; const parseLink = (value) => { if (!isObject(value)) return; const link = { href: parseString(value["@href"]), rel: parseString(value["@rel"]), type: parseString(value["@type"]), hreflang: parseString(value["@hreflang"]), title: parseString(value["@title"]), length: parseNumber(value["@length"]), thr: retrieveLink(value) }; return trimObject(link); }; const retrievePersonUri = (value, options) => { if (!isObject(value)) return; const get = createNamespaceGetter(value, options?.prefix); const uri = parseSingularOf(get("uri"), (value$1) => parseString(retrieveText(value$1))); const url = parseSingularOf(get("url"), (value$1) => parseString(retrieveText(value$1))); return uri || url; }; const parsePerson$2 = (value, options) => { if (!isObject(value)) return; const get = createNamespaceGetter(value, options?.prefix); const person = { name: parseSingularOf(get("name"), (value$1) => parseString(retrieveText(value$1))), uri: retrievePersonUri(value, options), email: parseSingularOf(get("email"), (value$1) => parseString(retrieveText(value$1))) }; return trimObject(person); }; const parseCategory$1 = (value) => { if (!isObject(value)) return; const category = { term: parseString(value["@term"]), scheme: parseString(value["@scheme"]), label: parseString(value["@label"]) }; return trimObject(category); }; const retrieveGeneratorUri = (value) => { if (!isObject(value)) return; const uri = parseString(value["@uri"]); const url = parseString(value["@url"]); return uri || url; }; const parseGenerator = (value) => { const generator = { text: parseString(retrieveText(value)), uri: retrieveGeneratorUri(value), version: parseString(value?.["@version"]) }; return trimObject(generator); }; const parseSource$2 = (value, options) => { if (!isObject(value)) return; const get = createNamespaceGetter(value, options?.prefix); const source = { authors: parseArrayOf(get("author"), (value$1) => parsePerson$2(value$1, options)), categories: parseArrayOf(get("category"), (value$1) => parseCategory$1(value$1, options)), contributors: parseArrayOf(get("contributor"), (value$1) => parsePerson$2(value$1, options)), generator: parseSingularOf(get("generator"), (value$1) => parseGenerator(value$1, options)), icon: parseSingularOf(get("icon"), (value$1) => parseString(retrieveText(value$1))), id: parseSingularOf(get("id"), (value$1) => parseString(retrieveText(value$1))), links: parseArrayOf(get("link"), (value$1) => parseLink(value$1, options)), logo: parseSingularOf(get("logo"), (value$1) => parseString(retrieveText(value$1))), rights: parseSingularOf(get("rights"), (value$1) => parseString(retrieveText(value$1))), subtitle: parseSingularOf(get("subtitle"), (value$1) => parseString(retrieveText(value$1))), title: parseSingularOf(get("title"), (value$1) => parseString(retrieveText(value$1))), updated: retrieveUpdated(value) }; return trimObject(source); }; const retrievePublished = (value, options) => { if (!isObject(value)) return; const get = createNamespaceGetter(value, options?.prefix); const published = parseSingularOf(get("published"), (value$1) => parseDate(retrieveText(value$1))); const issued = parseSingularOf(get("issued"), (value$1) => parseDate(retrieveText(value$1))); const created = parseSingularOf(get("created"), (value$1) => parseDate(retrieveText(value$1))); return published || issued || created; }; const retrieveUpdated = (value, options) => { if (!isObject(value)) return; const get = createNamespaceGetter(value, options?.prefix); const updated = parseSingularOf(get("updated"), (value$1) => parseDate(retrieveText(value$1))); const modified = parseSingularOf(get("modified"), (value$1) => parseDate(retrieveText(value$1))); return updated || modified; }; const retrieveSubtitle = (value, options) => { if (!isObject(value)) return; const get = createNamespaceGetter(value, options?.prefix); const subtitle = parseSingularOf(get("subtitle"), (value$1) => parseString(retrieveText(value$1))); const tagline = parseSingularOf(get("tagline"), (value$1) => parseString(retrieveText(value$1))); return subtitle || tagline; }; const parseEntry = (value, options) => { if (!isObject(value)) return; const namespaces = options?.asNamespace ? void 0 : detectNamespaces(value); const get = createNamespaceGetter(value, options?.prefix); const entry = { authors: parseArrayOf(get("author"), (value$1) => parsePerson$2(value$1, options)), categories: parseArrayOf(get("category"), (value$1) => parseCategory$1(value$1, options)), content: parseSingularOf(get("content"), (value$1) => parseString(retrieveText(value$1))), contributors: parseArrayOf(get("contributor"), (value$1) => parsePerson$2(value$1, options)), id: parseSingularOf(get("id"), (value$1) => parseString(retrieveText(value$1))), links: parseArrayOf(get("link"), (value$1) => parseLink(value$1, options)), published: retrievePublished(value, options), rights: parseSingularOf(get("rights"), (value$1) => parseString(retrieveText(value$1))), source: parseSingularOf(get("source"), parseSource$2), summary: parseSingularOf(get("summary"), (value$1) => parseString(retrieveText(value$1))), title: parseSingularOf(get("title"), (value$1) => parseString(retrieveText(value$1))), updated: retrieveUpdated(value, options), dc: namespaces?.has("dc") ? retrieveItemOrFeed(value) : void 0, slash: namespaces?.has("slash") ? retrieveItem$4(value) : void 0, itunes: namespaces?.has("itunes") ? retrieveItem$1(value) : void 0, psc: namespaces?.has("psc") ? retrieveItem$3(value) : void 0, media: namespaces?.has("media") ? retrieveItemOrFeed$3(value) : void 0, georss: namespaces?.has("georss") ? retrieveItemOrFeed$2(value) : void 0, thr: namespaces?.has("thr") ? retrieveItem$6(value