import Papa from "papaparse"; export async function loadExtensionsCSV(path, fetchOptions = {}) { const url = path + (path.includes("?") ? "&" : "?") + "t=" + Date.now(); const res = await fetch(url, fetchOptions); if (!res.ok) throw new Error(`Failed to load CSV: ${res.status} ${res.statusText}`); const text = await res.text(); const { data } = Papa.parse(text, { header: true, skipEmptyLines: true, transformHeader: (header) => header.trim(), }); return { rows: data.map(normalizeRow) }; } function normalizeRow(r) { const clone = { ...r }; clone.downloads_count = safeNumber(r.no_of_stars); // Using stars as downloads proxy clone.rating = safeNumber(r.no_of_stars) / 10; // Normalize rating clone.reviews_count = safeNumber(r.no_of_contributors); // Using contributors as reviews proxy clone.categories = typeof r.tags === "string" ? r.tags.trim() : ""; clone.publisher = typeof r.action_title === "string" && r.action_title.trim() !== "" ? r.action_title.trim() : "(unknown)"; clone.tags = typeof r.tags === "string" ? r.tags : ""; clone.ai_enabled = parseBool(r.is_action_verified); // Using verified as AI enabled proxy clone.name = r.action_title; clone.verified = parseBool(r.is_action_verified); clone.stars = safeNumber(r.no_of_stars); clone.contributors = safeNumber(r.no_of_contributors); return clone; } function safeNumber(v) { if (v === null || v === undefined || v === "") return 0; const cleaned = String(v).replace(/,/g, "").replace(/\s+/g, "").trim(); const n = Number(cleaned); return Number.isFinite(n) ? n : 0; } function parseBool(v) { if (v === true || v === 1) return true; if (!v) return false; const s = String(v).trim().toLowerCase(); return s === "true" || s === "1" || s === "yes" || s === "y"; }