refactor(calendar): extract ICS parser into shared ics-parser.js module

This commit is contained in:
Ulas Kalayci
2026-04-20 23:25:50 +02:00
parent faa3c0159b
commit 583a1bdf23
5 changed files with 210 additions and 187 deletions
+57
View File
@@ -0,0 +1,57 @@
import { unfoldLines, parseICS, expandRRULE } from './server/services/ics-parser.js';
let passed = 0, failed = 0;
function test(name, fn) {
try { fn(); console.log(`${name}`); passed++; }
catch (err) { console.error(`${name}: ${err.message}`); failed++; }
}
function assert(cond, msg) { if (!cond) throw new Error(msg || 'Assertion failed'); }
console.log('\n[ICS-Parser-Test]\n');
test('unfoldLines entfaltet Zeilenfortsetzungen', () => {
const result = unfoldLines('SUMMARY:Hallo\r\n Welt');
assert(result === 'SUMMARY:HalloWelt', `got: ${result}`);
});
test('parseICS: einfaches Ganztags-Event', () => {
const ics = 'BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nUID:test-1@x\r\nSUMMARY:Geburtstag\r\nDTSTART;VALUE=DATE:20260501\r\nDTEND;VALUE=DATE:20260502\r\nEND:VEVENT\r\nEND:VCALENDAR';
const events = parseICS(ics);
assert(events.length === 1, `expected 1, got ${events.length}`);
assert(events[0].uid === 'test-1@x', 'uid');
assert(events[0].dtstart === '2026-05-01', `dtstart: ${events[0].dtstart}`);
assert(events[0].dtend === '2026-05-01', `dtend: ${events[0].dtend}`);
assert(events[0].allDay === true, 'allDay');
});
test('parseICS: Event ohne UID wird übersprungen', () => {
const ics = 'BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nSUMMARY:Ohne UID\r\nDTSTART:20260601T100000Z\r\nEND:VEVENT\r\nEND:VCALENDAR';
assert(parseICS(ics).length === 0, 'should skip event without UID');
});
test('parseICS: UTC datetime', () => {
const ics = 'BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nUID:utc@x\r\nSUMMARY:Meeting\r\nDTSTART:20260615T140000Z\r\nDTEND:20260615T150000Z\r\nEND:VEVENT\r\nEND:VCALENDAR';
const [ev] = parseICS(ics);
assert(ev.dtstart === '2026-06-15T14:00:00Z', `dtstart: ${ev.dtstart}`);
assert(ev.allDay === false, 'allDay');
});
test('expandRRULE: WEEKLY 3-Wochen-Fenster', () => {
const vevent = {
uid: 'weekly@x', summary: 'Wöchentlich', description: null, location: null,
dtstart: '2026-04-13', dtend: '2026-04-13', rrule: 'RRULE:FREQ=WEEKLY;BYDAY=MO', allDay: true,
};
const occ = expandRRULE(vevent, '2026-04-13', '2026-05-04');
assert(occ.length >= 3, `expected >=3, got ${occ.length}`);
assert(occ[0].uid === 'weekly@x__2026-04-13', `uid: ${occ[0].uid}`);
assert(occ[0].rrule === null, 'expanded events have null rrule');
});
test('expandRRULE: null rrule → leeres Array', () => {
const v = { uid: 'x', summary: 'x', description: null, location: null,
dtstart: '2026-04-20', dtend: null, rrule: null, allDay: true };
assert(expandRRULE(v, '2026-01-01', '2026-12-31').length === 0);
});
console.log(`\n${passed} passed, ${failed} failed`);
if (failed > 0) process.exit(1);