From 533c240c07c74cb97c6927789740d33e28f4416c Mon Sep 17 00:00:00 2001 From: sstent Date: Thu, 19 Feb 2026 07:12:41 -0800 Subject: [PATCH] conductor(checkpoint): Checkpoint end of Phase 4: Cleanup & Configuration --- icalendar.ts | 15 ++++++++------- icalendar_test.ts | 30 ++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/icalendar.ts b/icalendar.ts index 5c4fe86..9cb8768 100644 --- a/icalendar.ts +++ b/icalendar.ts @@ -74,12 +74,13 @@ function convertDatesToStrings(obj: T): any { // Configuration Functions // ============================================================================ -async function getSources(): Promise { +async function getSources(): Promise<{ sources: any[], syncWindowDays: number }> { try { const rawConfig = await config.get("icalendar", { sources: [] }) as any; console.log("[iCalendar] Raw config retrieved:", JSON.stringify(rawConfig)); let sources = rawConfig.sources || []; + const syncWindowDays = rawConfig.syncWindowDays || 365; if (sources && typeof sources === "object" && !Array.isArray(sources)) { const sourceArray = []; @@ -91,10 +92,10 @@ async function getSources(): Promise { sources = sourceArray; } - return sources; + return { sources, syncWindowDays }; } catch (e) { console.error("[iCalendar] Error in getSources:", e); - return []; + return { sources: [], syncWindowDays: 365 }; } } @@ -196,7 +197,7 @@ export function expandRecurrences(icsEvent: any, windowDays = 365): any[] { } } -async function fetchAndParseCalendar(source: any): Promise { +async function fetchAndParseCalendar(source: any, windowDays = 365): Promise { console.log(`[iCalendar] Fetching from: ${source.url}`); try { const response = await fetch(source.url); @@ -231,7 +232,7 @@ async function fetchAndParseCalendar(source: any): Promise { baseEvent.description = `(Warning: Unknown timezone "${rawTz}") ${baseEvent.description || ""}`; } - const expanded = expandRecurrences(baseEvent); + const expanded = expandRecurrences(baseEvent, windowDays); for (const occurrence of expanded) { const uniqueKey = `${occurrence.start}${occurrence.uid || occurrence.summary || ''}`; occurrence.ref = await sha256Hash(uniqueKey); @@ -247,13 +248,13 @@ async function fetchAndParseCalendar(source: any): Promise { export async function syncCalendars() { try { - const sources = await getSources(); + const { sources, syncWindowDays } = await getSources(); if (sources.length === 0) return; await editor.flashNotification("Syncing calendars...", "info"); const allEvents: any[] = []; for (const source of sources) { - const events = await fetchAndParseCalendar(source); + const events = await fetchAndParseCalendar(source, syncWindowDays); allEvents.push(...events); } await index.indexObjects("$icalendar", allEvents); diff --git a/icalendar_test.ts b/icalendar_test.ts index 4c1351f..8c1fca4 100644 --- a/icalendar_test.ts +++ b/icalendar_test.ts @@ -76,6 +76,32 @@ Deno.test("expandRecurrences - EXDATE exclusion", () => { Deno.test("fetchAndParseCalendar - filter cancelled events", async () => { // This requires mocking fetch or testing the inner loop logic. - // For now, let's just test that we skip them if we had a list of events. - // Since fetchAndParseCalendar is async and uses syscalls, we'll verify the logic in the code. +}); + +Deno.test("resolveEventStart - ignore tzShift", async () => { + const icsEvent = { + summary: "Ignore tzShift", + start: { + date: "2025-01-15T12:00:00.000", + local: { + date: "2025-01-15T07:00:00.000", + timezone: "Eastern Standard Time" + } + } + }; + + const result = await resolveEventStart(icsEvent); + assertEquals(result?.toISOString(), "2025-01-15T12:00:00.000Z"); +}); + +Deno.test("expandRecurrences - custom windowDays", () => { + const icsEvent = { + summary: "Daily Meeting", + start: "2025-01-01T10:00:00", + rrule: "FREQ=DAILY" + }; + + // 7 days window (Jan 1 to Jan 8) should give 8 occurrences if inclusive + const results = expandRecurrences(icsEvent, 7); + assertEquals(results.length, 8); });