const ICAL = require('ical.js'); const { STATUS_ICAL_TO_TUDUDI, icalToTududiPriority, } = require('./field-mappings'); const { parseRRULE } = require('./rrule-parser'); async function parseVTODOToTask(vtodoString) { try { const jcalData = ICAL.parse(vtodoString); const comp = new ICAL.Component(jcalData); const vtodo = comp.getFirstSubcomponent('vtodo'); if (!vtodo) { throw new Error('No VTODO component found'); } const task = { uid: null, name: null, note: null, due_date: null, defer_until: null, completed_at: null, status: 0, priority: 0, recurrence_type: 'none', recurrence_interval: null, recurrence_end_date: null, recurrence_weekdays: null, recurrence_month_day: null, recurrence_weekday: null, recurrence_week_of_month: null, parent_task_uid: null, project_uid: null, tag_names: [], habit_mode: false, habit_current_streak: 0, habit_total_completions: 0, order: null, }; const uid = vtodo.getFirstPropertyValue('uid'); if (uid) { task.uid = uid; } const summary = vtodo.getFirstPropertyValue('summary'); if (summary) { task.name = summary; } const description = vtodo.getFirstPropertyValue('description'); if (description) { task.note = description; } const status = vtodo.getFirstPropertyValue('status'); if (status) { task.status = STATUS_ICAL_TO_TUDUDI[status] || 0; } const priority = vtodo.getFirstPropertyValue('priority'); if (priority !== null && priority !== undefined) { task.priority = icalToTududiPriority(priority); } const due = vtodo.getFirstPropertyValue('due'); if (due) { if (due.isDate) { const year = due.year; const month = due.month - 1; const day = due.day; task.due_date = new Date( Date.UTC(year, month, day, 0, 0, 0, 0) ); } else { task.due_date = due.toJSDate(); } } const dtstart = vtodo.getFirstPropertyValue('dtstart'); if (dtstart) { if (dtstart.isDate) { const year = dtstart.year; const month = dtstart.month - 1; const day = dtstart.day; task.defer_until = new Date( Date.UTC(year, month, day, 0, 0, 0, 0) ); } else { task.defer_until = dtstart.toJSDate(); } } const completed = vtodo.getFirstPropertyValue('completed'); if (completed) { task.completed_at = completed.toJSDate(); } const rrule = vtodo.getFirstPropertyValue('rrule'); if (rrule) { const recurrenceData = parseRRULE(rrule.toString()); if (recurrenceData) { Object.assign(task, recurrenceData); } } const relatedTo = vtodo.getFirstPropertyValue('related-to'); if (relatedTo) { task.parent_task_uid = relatedTo; } const projectUid = vtodo.getFirstPropertyValue('x-tududi-project-uid'); if (projectUid) { task.project_uid = projectUid; } const categories = vtodo.getFirstPropertyValue('categories'); if (categories) { if (Array.isArray(categories)) { task.tag_names = categories; } else if (typeof categories === 'string') { task.tag_names = categories.split(',').map((t) => t.trim()); } else { task.tag_names = [categories]; } } const habitMode = vtodo.getFirstPropertyValue('x-tududi-habit-mode'); if (habitMode === 'true' || habitMode === true) { task.habit_mode = true; const streak = vtodo.getFirstPropertyValue('x-tududi-habit-streak'); if (streak) { task.habit_current_streak = parseInt(streak, 10) || 0; } const completions = vtodo.getFirstPropertyValue( 'x-tududi-habit-completions' ); if (completions) { task.habit_total_completions = parseInt(completions, 10) || 0; } } const order = vtodo.getFirstPropertyValue('x-tududi-order'); if (order) { task.order = parseInt(order, 10); } return task; } catch (error) { console.error('Error parsing VTODO:', error); throw new Error(`Failed to parse VTODO: ${error.message}`); } } async function parseRecurrenceOverride(vtodoString) { try { const jcalData = ICAL.parse(vtodoString); const comp = new ICAL.Component(jcalData); const vtodo = comp.getFirstSubcomponent('vtodo'); if (!vtodo) { throw new Error('No VTODO component found'); } const override = { uid: null, recurrence_id: null, name: null, due_date: null, status: 0, completed_at: null, }; const uid = vtodo.getFirstPropertyValue('uid'); if (uid) { override.uid = uid; } const recurrenceId = vtodo.getFirstPropertyValue('recurrence-id'); if (recurrenceId) { override.recurrence_id = recurrenceId.toJSDate(); } const summary = vtodo.getFirstPropertyValue('summary'); if (summary) { override.name = summary; } const due = vtodo.getFirstPropertyValue('due'); if (due) { if (due.isDate) { const year = due.year; const month = due.month - 1; const day = due.day; override.due_date = new Date( Date.UTC(year, month, day, 0, 0, 0, 0) ); } else { override.due_date = due.toJSDate(); } } const status = vtodo.getFirstPropertyValue('status'); if (status) { override.status = STATUS_ICAL_TO_TUDUDI[status] || 0; } const completed = vtodo.getFirstPropertyValue('completed'); if (completed) { override.completed_at = completed.toJSDate(); } return override; } catch (error) { console.error('Error parsing recurrence override:', error); throw new Error( `Failed to parse recurrence override: ${error.message}` ); } } module.exports = { parseVTODOToTask, parseRecurrenceOverride, };