Skip to content

Commit

Permalink
feat(Event): Support RRule objects and raw strings in repeating()
Browse files Browse the repository at this point in the history
Closes #190
  • Loading branch information
sebbo2002 committed Mar 23, 2021
1 parent 28d44df commit 4436785
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 30 deletions.
39 changes: 38 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"moment-timezone": "^0.5.33",
"nyc": "^15.1.0",
"portfinder": "^1.0.28",
"rrule": "^2.6.8",
"semantic-release": "^17.4.0",
"ts-node": "^9.1.1",
"typedoc": "^0.20.30",
Expand Down
43 changes: 32 additions & 11 deletions src/event.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';

import type {RRule} from 'rrule';
import uuid from 'uuid-random';
import {
addOrGetCustomAttributes,
Expand All @@ -9,7 +10,7 @@ import {
escape,
formatDate,
formatDateTZ,
generateCustomAttributes,
generateCustomAttributes, isRRule,
toDate,
toJSON
} from './tools';
Expand Down Expand Up @@ -56,7 +57,7 @@ export interface ICalEventData {
stamp?: ICalDateTimeValue,
allDay?: boolean,
floating?: boolean,
repeating?: ICalRepeatingOptions | null,
repeating?: ICalRepeatingOptions | RRule | string | null,
summary?: string,
location?: ICalLocation | string | null,
description?: ICalDescription | string | null,
Expand All @@ -83,7 +84,7 @@ export interface ICalEventInternalData {
stamp: ICalDateTimeValue,
allDay: boolean,
floating: boolean,
repeating: ICalEventInternalRepeatingData | null,
repeating: ICalEventInternalRepeatingData | RRule | string | null,
summary: string,
location: ICalLocation | null,
description: ICalDescription | null,
Expand Down Expand Up @@ -394,16 +395,20 @@ export default class ICalEvent {
* Set/Get the event's repeating stuff
* @since 0.2.0
*/
repeating(): ICalEventInternalRepeatingData | null;
repeating(repeating: ICalRepeatingOptions | null): this;
repeating(repeating?: ICalRepeatingOptions | null): this | ICalEventInternalRepeatingData | null {
repeating(): ICalEventInternalRepeatingData | RRule | string | null;
repeating(repeating: ICalRepeatingOptions | RRule | string | null): this;
repeating(repeating?: ICalRepeatingOptions | RRule | string | null): this | ICalEventInternalRepeatingData | RRule | string | null {
if (repeating === undefined) {
return this.data.repeating;
}
if (!repeating) {
this.data.repeating = null;
return this;
}
if(isRRule(repeating) || typeof repeating === 'string') {
this.data.repeating = repeating;
return this;
}

this.data.repeating = {
freq: checkEnum(ICalEventRepeatingFreq, repeating.freq) as ICalEventRepeatingFreq
Expand Down Expand Up @@ -814,17 +819,25 @@ export default class ICalEvent {
* @since 0.2.4
*/
toJSON(): ICalEventInternalData {
let repeating: ICalEventInternalRepeatingData | string | null = null;
if(isRRule(this.data.repeating) || typeof this.data.repeating === 'string') {
repeating = this.data.repeating.toString();
}
else if(this.data.repeating) {
repeating = Object.assign({}, this.data.repeating, {
until: toJSON(this.data.repeating.until),
exclude: this.data.repeating.exclude?.map(d => toJSON(d)),
});
}

return Object.assign({}, this.data, {
start: toJSON(this.data.start) || null,
end: toJSON(this.data.end) || null,
recurrenceId: toJSON(this.data.recurrenceId) || null,
stamp: toJSON(this.data.stamp) || null,
created: toJSON(this.data.created) || null,
lastModified: toJSON(this.data.lastModified) || null,
repeating: this.data.repeating ? Object.assign({}, this.data.repeating, {
until: toJSON(this.data.repeating.until),
exclude: this.data.repeating.exclude?.map(d => toJSON(d)),
}) : null,
repeating,
x: this.x()
});
}
Expand Down Expand Up @@ -866,7 +879,15 @@ export default class ICalEvent {
}

// REPEATING
if (this.data.repeating) {
if(isRRule(this.data.repeating) || typeof this.data.repeating === 'string') {
g += this.data.repeating
.toString()
.replace(/\r\n/g, '\n')
.split('\n')
.filter(l => l && !l.startsWith('DTSTART:'))
.join('\r\n') + '\r\n';
}
else if (this.data.repeating) {
g += 'RRULE:FREQ=' + this.data.repeating.freq;

if (this.data.repeating.count) {
Expand Down
8 changes: 8 additions & 0 deletions src/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type {Moment, Duration} from 'moment';
import type {Moment as MomentTZ} from 'moment-timezone';
import type {Dayjs} from 'dayjs';
import type {DateTime as LuxonDateTime} from 'luxon';
import type { RRule } from 'rrule';

import {ICalDateTimeValue, ICalOrganizer} from './types';

export function formatDate (timezone: string | null, d: ICalDateTimeValue, dateonly?: boolean, floating?: boolean): string {
Expand Down Expand Up @@ -326,6 +328,12 @@ export function isMomentDuration(value: unknown): value is Duration {
return value !== null && typeof value === 'object' && typeof value.asSeconds === 'function';
}

export function isRRule(value: unknown): value is RRule {

// @ts-ignore
return value !== null && typeof value === 'object' && typeof value.between === 'function' && typeof value.toString === 'function';
}

export function toJSON(value: ICalDateTimeValue | null | undefined): string | null | undefined {
if(!value) {
return value;
Expand Down
Loading

0 comments on commit 4436785

Please sign in to comment.