import { decodeHtmlEntities } from "../../../../../utils/html-entities"; export interface FeedElement { name: string; localName: string; namespace: string; namespaces: Record; attributes: Record; base: string; content: (FeedElement | string)[]; innerStart: number; innerEnd: number; } export function resolveFeedUrl(value: string, base: string): string { if (!value.trim()) return ""; try { return new URL(value.trim(), base).href; } catch { return ""; } } // Read the structure of a syndication document without executing declarations or // resolving entities. Descendant source/content metadata must not impersonate // an entry's direct children. This is deliberately not a validating XML parser. export function parseFeedXml(xml: string, base: string): FeedElement | null { const tokens = /"'\[]|"[^"]*"|'[^']*')*>|||<\?[\s\S]*?\?>|<\/?[A-Za-z_][\w.:-]*(?:[^<>"']|"[^"]*"|'[^']*')*>|[^<]+/g; const stack: FeedElement[] = []; let root: FeedElement | null = null; let offset = 0; for (const match of xml.matchAll(tokens)) { if (match.index !== offset) return null; const token = match[0]; offset += token.length; if (token.startsWith("