@rschedule/ical-tools

The optional package @rschedule/ical-tools includes a new VEvent object for working with iCalendar VEVENT components, as well as serializeToICal() and parseICal() functions.

Important: If you are only interested in ICAL support, consider using rrulejs instead of rSchedule as it currently has greater support for ICAL recurrence rules.

Some limitations:

  • Parsing / serializing VCALENDAR components is not currently supported.
  • You can only parse / serialize VEvent objects.
  • VEvent#data is ignored.

Example:

const vEvent = new VEvent({
  start: new Date(),
});

const iCal = vEvent.toICal(); // => string

VEvent.fromICal(iCal); // => VEvent[]

Installation

@rschedule/ical-tools has a peer dependency on ical.js

yarn add @rschedule/ical-tools ical.js

# or

npm install @rschedule/ical-tools ical.js

Usage

VEvent objects allow iterating a occurrence schedule made up of RRULEs and/or EXRULEs as well as RDATEs and EXDATEs. VEvent objects are similar to Schedule objects, but VEvent objects follow the iCalendar VEVENT spec (e.g. dtstart time is the first occurrence, etc). As part of this support, VEvent objects make use of a special variation of Rule objects: RRule (i.e. import { RRule } from '@rschedule/ical-tools'). As with other rSchedule objects, VEvent is immutable.

Some rSchedule limitations:

  • Not all iCal rules are currently supported.
    • BYWEEKNO, BYYEARDAY, BYSETPOS are unsupported
  • Not all VEVENT properies of the ICAL spec are supported. The supported properties are RRULE, EXRULE, RDATE, EXDATE, DTSTART, DTEND and DURATION. Other properties are not supported.

Example usage:

const vEvent = VEvent.fromICal(
  `DTSTART:20120524T000000Z\nRRULE:FREQ=WEEKLY;UNTIL=20121131T000000Z`,
);

vEvent
  .occurrences()
  .toArray()
  .map(date => date.toISOString());

vEvent.toICal(); // `DTSTART:20120524T000000Z\nRRULE:FREQ=WEEKLY;UNTIL=20121131T000000Z`

How to work with "VALUE=DATE"

By default, creating a VEvent using the class constructor and then serializing that VEvent to ICal will result in the VEvent dates being serialized as ICal "DATE-TIME" values rather than "DATE" values. If you'd like to pass a date to VEvent and have it serialized as an ICal "VALUE=DATE" rather than "VALUE=DATE-TIME", then you need to create that date using the DateAdapter constructor like so.

Example:

const date = new StandardDateAdapter(new Date(), {
  metadata: {
    '@rschedule/ical-tools': {
      isICalType: 'date',
    },
  },
});

const vEvent = new VEvent({
  start: date,
});

If you are creating the VEvent object from ICal (i.e. VEvent.fromICal(icalString)) than this is done for you automatically.

Constructor

VEvent has the following constructor.

class VEvent<D = any> {
  static fromICal(iCal: string): VEvent<{ jCal: IJCalComponent }>;

  data!: D;
  readonly start: DateAdapter;
  readonly isInfinite: boolean;
  readonly duration?: number | DateAdapter;
  readonly hasDuration: boolean;
  readonly maxDuration?: number;
  readonly timezone: string | null;

  readonly rrules: ReadonlyArray<RRule> = [];
  readonly exrules: ReadonlyArray<RRule> = [];
  readonly rdates: Dates<T>;
  readonly exdates: Dates<T>;

  constructor(args: {
    start: DateInput;
    // accepts either the number of milliseconds of the duration or the end
    // datetime of the first occurrence (which will be used to calculate the
    // duration in milliseconds)
    duration?: number | DateInput;
    // The data property holds arbitrary data associated with the `VEvent`.
    // The data property is mutable.
    //
    // When iterating through a VEvent, you can access a list of the generator objects (i.e. Rules / Dates)
    // which generated any yielded date by accessing the `DateAdapter#generators` property.
    // In this way, for a given, yielded date, you can access the objects which generated
    // the date as well as the arbitrary data associated with those objects.
    // The data property is ignored when serializing to iCal.
    data?: D;
    rrules?: ReadonlyArray<IVEventRuleOptions | RRule>;
    exrules?: ReadonlyArray<IVEventRuleOptions | RRule>;
    rdates?: ReadonlyArray<DateInput> | Dates;
    exdates?: ReadonlyArray<DateInput> | Dates;
    maxDuration?: number;
  });

  add(prop: 'rrule' | 'exrule', value: RRule): VEvent<D>;
  add(prop: 'rdate' | 'exdate', value: DateInput): VEvent<D>;

  remove(prop: 'rrule' | 'exrule', value: RRule): VEvent<D>;
  remove(prop: 'rdate' | 'exdate', value: DateInput): VEvent<D>;

  set(prop: 'timezone', value: string | null, options?: { keepLocalTime?: boolean }): VEvent<D>;
  set(prop: 'start', value: DateInput): VEvent<D>;
  set(prop: 'rrules' | 'exrules', value: RRule[]): VEvent<D>;
  set(prop: 'rdates' | 'exdates', value: Dates<unknown>): VEvent<D>;

  toICal(): string;
}