HFU Digital Docs
CourseKitStarPlan

iCal Parser

Parse RFC 5545 VEVENTs from a raw iCal string into structured ParsedVEvent records

parseIcal reads a raw iCal string (typically returned from StarPlanClient.fetchIcal) and returns a ParsedVEvent[]. It is a tiny, dependency-free parser tailored for StarPlan's VEVENT output.

Usage

import { parseIcal, type ParsedVEvent } from '@hfu.digital/coursekit-starplan';

const events: ParsedVEvent[] = parseIcal(icalString);
// or with a custom study-block grid
const events2 = parseIcal(icalString, { studyBlocks: myCustomConfig });

ParsedVEvent

FieldTypeDescription
uidstringiCal UID, or a synthetic fallback if omitted
summarystringEvent title
descriptionstring | undefinedEvent description
dtstartDateLocal-time start instant (no timezone shift applied)
dtendDateLocal-time end instant
locationstring | undefinedFree-form LOCATION (pass to extractRoom)
rrulestring | nullRFC 5545 RRULE if present (e.g. FREQ=WEEKLY;BYDAY=MO;COUNT=14)
weekdaynumber0 = Sunday … 6 = Saturday
studyBlocknumber | null1-based study-block index, or null if outside the configured grid

Options — ParseIcalOptions

OptionTypeDefaultDescription
studyBlocksStudyBlockConfigHFU_STUDY_BLOCK_CONFIGDaily grid used to resolve studyBlock. See study-blocks.

Helpers

import { groupBySchedule, groupBySummary } from '@hfu.digital/coursekit-starplan';

// Group events by (summary + weekday + studyBlock + room)
const bySchedule = groupBySchedule(events);

// Group events by summary only
const bySummary = groupBySummary(events);

These produce Map<string, ParsedVEvent[]> results useful for de-duplication, snapshotting, and feeding detectChanges.

Notes

  • Times are parsed as local time — the parser does not apply timezone shifts. If you need timezone-aware comparison, normalize at write time.
  • dtstart falling exactly on a study-block boundary is inclusive of that block; the gap between two blocks (e.g. HFU 09:30–09:45) snaps forward to the next block.
  • If DTSTART or DTEND is missing or unparsable, the VEVENT is skipped silently.

On this page