TypeScript 55.4%
Python 43.2%
SQL 1.2%
1import { XMLParser } from "fast-xml-parser";23export const xmlParser = new XMLParser({4 ignoreAttributes: false,5 attributeNamePrefix: "@_",6 textNodeName: "#text",7 cdataPropName: "__cdata",8 trimValues: true,9 parseTagValue: false,10 parseAttributeValue: false,11 processEntities: true,12 htmlEntities: true,13 removeNSPrefix: false,14});1516export function parseXml(text: string): Record<string, unknown> {17 // Strip BOM and leading junk some feeds emit before the prolog.18 const cleaned = text.replace(/^/, "").replace(/^[^<]+/, "");19 return xmlParser.parse(cleaned) as Record<string, unknown>;20}2122export function asArray<T>(v: T | T[] | undefined | null): T[] {23 if (v === undefined || v === null) return [];24 return Array.isArray(v) ? v : [v];25}2627/** Text of an XML node that may be string, cdata object or {#text}. */28export function textOf(v: unknown): string {29 if (v === undefined || v === null) return "";30 if (typeof v === "string") return v.trim();31 if (typeof v === "number" || typeof v === "boolean") return String(v);32 if (typeof v === "object") {33 const o = v as Record<string, unknown>;34 if (typeof o.__cdata === "string") return o.__cdata.trim();35 if (typeof o["#text"] === "string") return (o["#text"] as string).trim();36 if (o.__cdata && typeof o.__cdata === "object") return textOf(o.__cdata);37 if (typeof o["@_href"] === "string") return o["@_href"].trim();38 }39 return "";40}4142export function stripHtml(s: string): string {43 return s44 .replace(/<script[\s\S]*?<\/script>/gi, " ")45 .replace(/<style[\s\S]*?<\/style>/gi, " ")46 .replace(/<[^>]+>/g, " ")47 .replace(/ /g, " ")48 .replace(/&/g, "&")49 .replace(/</g, "<")50 .replace(/>/g, ">")51 .replace(/"/g, '"')52 .replace(/'|'/g, "'")53 .replace(/\s+/g, " ")54 .trim();55}5657export function parseDate(v: unknown): Date | null {58 const s = textOf(v);59 if (!s) return null;60 const d = new Date(s);61 if (!Number.isNaN(d.getTime())) return d;62 // RFC 822 variants with odd zones like "PST"/"EDT" are handled by Date; try trimming63 const d2 = new Date(s.replace(/\s+[A-Z]{3,4}$/, ""));64 return Number.isNaN(d2.getTime()) ? null : d2;65}66