// Remember The Milk CSV export, by Evan Hahn // // Copy-paste this whole file into a new MilkScript. // // See for more details. // // This code is licensed under the ACSL. See full license at . class MissingCaseError extends Error { constructor(_value){ super("This should be impossible"); } } const serializeString = (str)=>shouldFieldBeQuoted(str) ? `"${str.replace(/"/gm, '""')}"` : str; const serialize = (value)=>{ switch(typeof value){ case "string": return serializeString(value); case "number": return Number.isNaN(value) ? "" : String(value); case "bigint": case "boolean": return String(value); case "undefined": return ""; case "object": if (value === null) return ""; return serializeDate(value); default: throw new MissingCaseError(value); } }; const row = (values)=>values.map(serialize).join(","); const shouldFieldBeQuoted = (str)=>str.includes(",") || str.includes('"') || str.includes("\r\n"); const serializeDate = (date)=>isNaN(date.valueOf()) ? "" : date.toISOString(); const values = (obj, keys)=>keys.map((key)=>obj[key]); const stringify = ({ keys , objects })=>{ let result = ""; result += row(keys); for (const obj of objects){ result += "\r\n"; result += row(values(obj, keys)); } return result; }; const formatDateThatMightHaveTime = (date, hasTime)=>{ if (!date || isNaN(date.valueOf())) return null; return hasTime ? date : date.toISOString().slice(0, 10); }; const formatPriority = (priority)=>{ if (!priority) return null; const result = priority.toString(); return result === "NoPriority" ? null : result; }; const formatTask = (task)=>({ "Completed": task.isCompleted(), "Due Date": formatDateThatMightHaveTime(task.getDueDate(), task.hasDueTime()), "Estimate (minutes)": task.getEstimate()?.getMinutes() || null, Name: task.getName(), Priority: formatPriority(task.getPriority()) }); (()=>{ const tasks = rtm.getSelectedTasks(); if (!tasks.length) { return rtm.newMessage("No tasks selected", "Select 1 or more tasks to export as CSV."); } const csvData = stringify({ keys: [ "Name", "Completed", "Estimate (minutes)", "Due Date", "Priority" ], objects: tasks.map(formatTask) }); return rtm.newFile(csvData, rtm.MediaType.CSV, "remember_the_milk.csv"); })();