import CalendarBase from './CalendarBase' ; import { FORMAT } from './constants' ; import data from './utils/data' ; import ics from './utils/ics' ; import time from './utils/time' ; import CalendarOptions from './types/CalendarOptions' ; import ICSAlarm from './types/ICSAlarm' ; import ICSAttendeeOptions from './types/ICSAttendeeOptions' ; import ICSDuration from './types/ICSDuration' ; import ICSPropertyValue from './types/ICSPropertyValue' ; /**
 * Generates a downloadable ICS file.
 */ export default class ICalendar extends CalendarBase { /** List of additional ICalendar events to add. */ private additionalEvents : ICalendar [ ] = [ ] ; /** List of VEVENT property-value entries */ public properties : string [ ] = [ ] ; /** Key-value pair of basic calendar properties. */ private meta : Record < string , string > = { } ; constructor ( opts ) { super ( opts ) ; this . setInitialParams ( ) ; } /**
     * Sets the basic properties for the calendar instance.
     */ protected setInitialParams = ( ) : void => { this . setMeta ( 'UID' , ics . getUid ( ) ) . setMeta ( 'DTSTAMP' , time . getTimeCreated ( ) ) . setMeta ( 'PRODID' , ics . getProdId ( ) ) . addProperty ( 'CLASS' , 'PUBLIC' ) . addProperty ( 'DESCRIPTION' , ics . formatText ( this . description ) ) . addProperty ( 'LOCATION' , ics . formatText ( this . location ) ) . addProperty ( 'SUMMARY' , ics . formatText ( this . title ) ) . addProperty ( 'TRANSP' , 'TRANSPARENT' ) ; if ( this . isAllDay ) { this . addProperty ( 'DTSTART;VALUE=DATE' , time . formatDateNoUtc ( this . start , FORMAT . DATE ) ) . addProperty ( 'DTEND;VALUE=DATE' , time . formatDateNoUtc ( time . incrementDate ( this . start , 1 ) , FORMAT . DATE ) ) ; } else { this . addProperty ( 'DTSTART' , time . formatDate ( this . start , FORMAT . FULL ) ) . addProperty ( 'DTEND' , time . formatDate ( this . end , FORMAT . FULL ) ) ; } if ( this . recurrence ) { this . addProperty ( 'RRULE' , ics . getRrule ( this . recurrence ) ) ; } if ( this . attendees . length > 0 ) { this . attendees . forEach ( ( { email , name , icsOptions = { } } ) => { const params = this . getAttendeeParams ( icsOptions , name ) ; const mailto = `MAILTO:${ email }` ; this . addProperty ( params , mailto ) ; } ) ; } } ; param { ICSAttendeeOptions } options param { string } name returns { string } private getAttendeeParams = ( options , name ? ) : string => { const params = { } ; if ( name ) params [ 'CN' ] = name ; if ( options . delegatedFrom ) params [ 'DELEGATED-FROM' ] = options . delegatedFrom ; if ( options . partStat ) params [ 'PARTSTAT' ] = options . partStat ; if ( options . role ) params [ 'ROLE' ] = options . role ; if ( options . sentBy ) params [ 'SENT-BY' ] = options . sentBy ; params [ 'RSVP' ] = options . rsvp ? 'TRUE' : 'FALSE' ; const paramString = data . toParamString ( params , ';' ) ; return `ATTENDEE;${ paramString }` ; } ; example param { ICSDuration } duration returns { string } private getAlarmDuration = ( duration ) : string => { const features = [ `${ duration . weeks }W` , `${ duration . days }D` , `${ duration . hours }H` , `${ duration . minutes }M` , `${ duration . seconds }S` ] . filter ( ( s ) => /^[0-9]+[A-Z]$/ . exec ( s ) ) ; features . unshift ( duration . after ? 'PT' : '-PT' ) ; return features . join ( '' ) ; } ; param { string } key param { string } value returns { ICalendar } public setMeta = ( key , value ) : this => { this . meta [ key ] = value ; return this ; } ; param { ICalendar } event returns { ICalendar } public addEvent = ( event ) : this => { this . additionalEvents . push ( event ) ; return this ; } ; param { Alarm } alarm returns { ICalendar } public addProperty = ( key , value ) : this => { if ( typeof value === 'object' ) { this . properties . push ( `BEGIN:${ key }` ) ; for ( const k in value ) { this . addProperty ( k , value [ k ] ) ; } this . properties . push ( `END:${ key }` ) ; } else { this . properties . push ( `${ key }:${ value . toString ( ) }` ) ; } return this ; } ; param { Alarm } alarm returns { ICalendar } public addAlarm = ( alarm ) : this => { const value = { ACTION : alarm . action } ; if ( alarm . description ) value . DESCRIPTION = ics . formatText ( alarm . description ) ; if ( alarm . summary ) value . SUMMARY = ics . formatText ( alarm . summary ) ; if ( alarm . duration ) value . DURATION = this . getAlarmDuration ( alarm . duration ) ; if ( alarm . repeat ) value . REPEAT = alarm . repeat ; if ( alarm . attach ) { const key = alarm . attach . params ? `ATTACH;${ alarm . attach . params }` : 'ATTACH' ; value [ key ] = alarm . attach . url ; } if ( alarm . trigger instanceof Date ) { value [ 'TRIGGER;VALUE=DATE-TIME' ] = time . formatDate ( alarm . trigger , FORMAT . FULL ) ; } else { value [ 'TRIGGER' ] = this . getAlarmDuration ( alarm . trigger ) ; } return this . addProperty ( 'VALARM' , value ) ; } ; remark param { string } fileName public download = ( fileName ? ) : void => { ics . download ( fileName || ics . getFileName ( this . title ) , this . render ( ) ) ; } ; returns { string } public render = ( ) : string => { const vEvents = this . additionalEvents . concat ( this ) . reduce ( ( properties , calendar ) => [ ... properties , 'BEGIN:VEVENT' , ... calendar . properties , 'END:VEVENT' ] , [ ] ) ; const meta = Object . keys ( this . meta ) . map ( ( key ) => { return `${ key }:${ this . meta [ key ] }` ; } ) ; return [ 'BEGIN:VCALENDAR' , 'VERSION:2.0' , ... vEvents , 'END:VCALENDAR' , ... meta ] . join ( '\n' ) ; } ; }