rrule-rust
Version:
RRule implementation for browsers and Node.js written in Rust
457 lines (456 loc) • 15.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RRule = exports.Weekday = exports.Month = exports.Frequency = void 0;
const datetime_1 = require("./datetime");
const lib_1 = require("./lib");
/**
* Recurrence frequency enumeration.
*/
var Frequency;
(function (Frequency) {
Frequency[Frequency["Yearly"] = 0] = "Yearly";
Frequency[Frequency["Monthly"] = 1] = "Monthly";
Frequency[Frequency["Weekly"] = 2] = "Weekly";
Frequency[Frequency["Daily"] = 3] = "Daily";
Frequency[Frequency["Hourly"] = 4] = "Hourly";
Frequency[Frequency["Minutely"] = 5] = "Minutely";
Frequency[Frequency["Secondly"] = 6] = "Secondly";
})(Frequency || (exports.Frequency = Frequency = {}));
/**
* Month enumeration (1-based).
*/
var Month;
(function (Month) {
Month[Month["January"] = 1] = "January";
Month[Month["February"] = 2] = "February";
Month[Month["March"] = 3] = "March";
Month[Month["April"] = 4] = "April";
Month[Month["May"] = 5] = "May";
Month[Month["June"] = 6] = "June";
Month[Month["July"] = 7] = "July";
Month[Month["August"] = 8] = "August";
Month[Month["September"] = 9] = "September";
Month[Month["October"] = 10] = "October";
Month[Month["November"] = 11] = "November";
Month[Month["December"] = 12] = "December";
})(Month || (exports.Month = Month = {}));
/**
* Weekday enumeration (0-based, Monday = 0).
*/
var Weekday;
(function (Weekday) {
Weekday[Weekday["Monday"] = 0] = "Monday";
Weekday[Weekday["Tuesday"] = 1] = "Tuesday";
Weekday[Weekday["Wednesday"] = 2] = "Wednesday";
Weekday[Weekday["Thursday"] = 3] = "Thursday";
Weekday[Weekday["Friday"] = 4] = "Friday";
Weekday[Weekday["Saturday"] = 5] = "Saturday";
Weekday[Weekday["Sunday"] = 6] = "Sunday";
})(Weekday || (exports.Weekday = Weekday = {}));
/**
* Represents a recurrence rule (RRULE) according to RFC 5545.
*
* RRule defines a rule for generating recurring date/time values. It supports
* various frequencies (yearly, monthly, weekly, etc.) and provides fine-grained
* control through options like byWeekday, byMonth, byHour, etc.
*
* @example
* ```typescript
* // Daily recurrence
* const daily = new RRule(Frequency.Daily);
*
* // Every weekday
* const weekdays = new RRule({
* frequency: Frequency.Weekly,
* byWeekday: [Weekday.Monday, Weekday.Tuesday, Weekday.Wednesday, Weekday.Thursday, Weekday.Friday]
* });
*
* // First Monday of each month, 10 times
* const firstMonday = new RRule({
* frequency: Frequency.Monthly,
* byWeekday: [{ n: 1, weekday: Weekday.Monday }],
* count: 10
* });
*
* // Every 2 weeks on Tuesday and Thursday
* const biweekly = new RRule({
* frequency: Frequency.Weekly,
* interval: 2,
* byWeekday: [Weekday.Tuesday, Weekday.Thursday]
* });
* ```
*/
class RRule {
constructor(frequencyOrOptions) {
if (typeof frequencyOrOptions === 'object' && frequencyOrOptions !== null) {
this.frequency = frequencyOrOptions.frequency;
this.interval = frequencyOrOptions.interval;
this.until = frequencyOrOptions.until;
this.count = frequencyOrOptions.count;
this.byWeekday = frequencyOrOptions.byWeekday ?? [];
this.byHour = frequencyOrOptions.byHour ?? [];
this.byMinute = frequencyOrOptions.byMinute ?? [];
this.bySecond = frequencyOrOptions.bySecond ?? [];
this.byMonthday = frequencyOrOptions.byMonthday ?? [];
this.bySetpos = frequencyOrOptions.bySetpos ?? [];
this.byMonth = frequencyOrOptions.byMonth ?? [];
this.byWeekno = frequencyOrOptions.byWeekno ?? [];
this.byYearday = frequencyOrOptions.byYearday ?? [];
this.weekstart = frequencyOrOptions.weekstart;
}
else {
this.frequency = frequencyOrOptions;
this.until = undefined;
this.byWeekday = [];
this.byHour = [];
this.byMinute = [];
this.bySecond = [];
this.byMonthday = [];
this.bySetpos = [];
this.byMonth = [];
this.byWeekno = [];
this.byYearday = [];
}
}
/**
* Parses an RFC 5545 RRULE string into an RRule instance.
*
* @param str - RRULE string (e.g., "FREQ=DAILY;COUNT=10")
* @returns A new RRule instance
*
* @example
* ```typescript
* const rrule = RRule.fromString("FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=10");
* ```
*/
static fromString(str) {
const rust = lib_1.RRule.parse(str);
return this.fromRust(rust);
}
static fromPlain(rrule) {
return new this({
frequency: rrule.frequency,
interval: rrule.interval,
until: rrule.until && datetime_1.DateTime.fromPlain(rrule.until),
count: rrule.count,
byWeekday: rrule.byWeekday,
byHour: rrule.byHour,
byMinute: rrule.byMinute,
bySecond: rrule.bySecond,
byMonthday: rrule.byMonthday,
bySetpos: rrule.bySetpos,
byMonth: rrule.byMonth,
byWeekno: rrule.byWeekno,
byYearday: rrule.byYearday,
weekstart: rrule.weekstart,
});
}
/**
* @internal
*/
static fromRust(rust) {
const rrule = new this({
frequency: rust.frequency,
interval: rust.interval ?? undefined,
until: rust.until
? datetime_1.DateTime.fromInt32Array(rust.until)
: undefined,
count: rust.count ?? undefined,
byWeekday: rust.byWeekday,
byHour: rust.byHour,
byMinute: rust.byMinute,
bySecond: rust.bySecond,
byMonthday: rust.byMonthday,
bySetpos: rust.bySetpos,
byMonth: rust.byMonth,
byWeekno: rust.byWeekno,
byYearday: rust.byYearday,
weekstart: rust.weekstart ?? undefined,
});
rrule.rust = rust;
return rrule;
}
/**
* Creates a new RRule with a different frequency.
*
* @param frequency - The new frequency
* @returns A new RRule instance
*
* @example
* ```typescript
* const daily = new RRule(Frequency.Daily);
* const weekly = daily.setFrequency(Frequency.Weekly);
* ```
*/
setFrequency(frequency) {
return new RRule({ ...this.toOptions(), frequency });
}
/**
* Creates a new RRule with a different interval.
*
* @param interval - The new interval (e.g., 2 for every other occurrence)
* @returns A new RRule instance
*
* @example
* ```typescript
* const rrule = new RRule(Frequency.Weekly);
* const biweekly = rrule.setInterval(2); // Every 2 weeks
* ```
*/
setInterval(interval) {
return new RRule({ ...this.toOptions(), interval });
}
/**
* Creates a new RRule with a different count limit.
*
* @param count - Maximum number of occurrences
* @returns A new RRule instance
*
* @example
* ```typescript
* const rrule = new RRule(Frequency.Daily);
* const limited = rrule.setCount(10); // Only 10 occurrences
* ```
*/
setCount(count) {
return new RRule({ ...this.toOptions(), count });
}
/**
* Creates a new RRule with different weekday constraints.
*
* @param weekdays - List of weekdays or nth-weekday specifications
* @returns A new RRule instance
*
* @example
* ```typescript
* const rrule = new RRule(Frequency.Weekly);
* const weekdays = rrule.setByWeekday([Weekday.Monday, Weekday.Wednesday, Weekday.Friday]);
*
* // First and last Friday of the month
* const fridays = rrule.setByWeekday([
* { n: 1, weekday: Weekday.Friday },
* { n: -1, weekday: Weekday.Friday }
* ]);
* ```
*/
setByWeekday(weekdays) {
return new RRule({ ...this.toOptions(), byWeekday: weekdays });
}
/**
* Creates a new RRule with different hour constraints.
*
* @param hours - List of hours (0-23)
* @returns A new RRule instance
*
* @example
* ```typescript
* const rrule = new RRule(Frequency.Daily);
* const morningAndEvening = rrule.setByHour([9, 17]); // 9 AM and 5 PM
* ```
*/
setByHour(hours) {
return new RRule({ ...this.toOptions(), byHour: hours });
}
/**
* Creates a new RRule with different minute constraints.
*
* @param minutes - List of minutes (0-59)
* @returns A new RRule instance
*
* @example
* ```typescript
* const rrule = new RRule(Frequency.Hourly);
* const quarterHours = rrule.setByMinute([0, 15, 30, 45]);
* ```
*/
setByMinute(minutes) {
return new RRule({ ...this.toOptions(), byMinute: minutes });
}
/**
* Creates a new RRule with different second constraints.
*
* @param seconds - List of seconds (0-59)
* @returns A new RRule instance
*/
setBySecond(seconds) {
return new RRule({ ...this.toOptions(), bySecond: seconds });
}
/**
* Creates a new RRule with different month day constraints.
*
* @param days - List of days (1-31, negative for counting from end)
* @returns A new RRule instance
*
* @example
* ```typescript
* const rrule = new RRule(Frequency.Monthly);
* const firstAndLast = rrule.setByMonthday([1, -1]); // First and last day of month
* ```
*/
setByMonthday(days) {
return new RRule({ ...this.toOptions(), byMonthday: days });
}
/**
* Creates a new RRule with different set position constraints.
*
* @param poses - List of positions (1-based, negative for from end) to include after all other BY* parts
* @returns A new RRule instance
*
* @example
* ```typescript
* // Get only the first occurrence from each monthly set of Mondays and Tuesdays.
* // Without BYSETPOS this would include every Monday and Tuesday in every month.
* const rrule = new RRule({
* frequency: Frequency.Monthly,
* byWeekday: [Weekday.Monday, Weekday.Tuesday]
* });
* const first = rrule.setBySetpos([1]);
*
* // Resulting RRULE string:
* console.log(first.toString()); // "RRULE:FREQ=MONTHLY;BYDAY=MO,TU;BYSETPOS=1"
*
* // Effect:
* // For each month, all Mondays and Tuesdays are collected, then only the earliest
* // (the 1st in chronological order) is kept. This will usually be the first Monday
* // of the month unless the month starts on a Tuesday (e.g., if the 1st is Tuesday).
*
* // Another example: keep the first and last matching weekday in each month.
* const firstAndLast = rrule.setBySetpos([1, -1]);
* console.log(firstAndLast.toString()); // "RRULE:FREQ=MONTHLY;BYDAY=MO,TU;BYSETPOS=1,-1"
* ```
*/
setBySetpos(poses) {
return new RRule({ ...this.toOptions(), bySetpos: poses });
}
/**
* Creates a new RRule with different month constraints.
*
* @param months - List of months
* @returns A new RRule instance
*
* @example
* ```typescript
* const rrule = new RRule(Frequency.Yearly);
* const quarterly = rrule.setByMonth([Month.January, Month.April, Month.July, Month.October]);
* ```
*/
setByMonth(months) {
return new RRule({ ...this.toOptions(), byMonth: months });
}
/**
* Creates a new RRule with different week number constraints.
*
* @param weekNumbers - List of week numbers (1-53, negative for counting from end)
* @returns A new RRule instance
*/
setByWeekno(weekNumbers) {
return new RRule({ ...this.toOptions(), byWeekno: weekNumbers });
}
/**
* Creates a new RRule with different year day constraints.
*
* @param days - List of days of the year (1-366, negative for counting from end)
* @returns A new RRule instance
*
* @example
* ```typescript
* const rrule = new RRule(Frequency.Yearly);
* const firstAndLastDay = rrule.setByYearday([1, -1]); // Jan 1 and Dec 31
* ```
*/
setByYearday(days) {
return new RRule({ ...this.toOptions(), byYearday: days });
}
/**
* Creates a new RRule with a different week start day.
*
* @param day - The weekday that starts the week
* @returns A new RRule instance
*
* @example
* ```typescript
* const rrule = new RRule(Frequency.Weekly);
* const sundayStart = rrule.setWeekstart(Weekday.Sunday);
* ```
*/
setWeekstart(day) {
return new RRule({ ...this.toOptions(), weekstart: day });
}
/**
* Creates a new RRule with a different end date.
*
* @param until - The date/time at which to end the recurrence
* @returns A new RRule instance
*
* @example
* ```typescript
* const rrule = new RRule(Frequency.Daily);
* const limited = rrule.setUntil(DateTime.date(2024, 12, 31));
* ```
*/
setUntil(until) {
return new RRule({ ...this.toOptions(), until });
}
/**
* Converts the RRule to an RFC 5545 RRULE string.
*
* @returns RFC 5545 formatted string
*
* @example
* ```typescript
* const rrule = new RRule({
* frequency: Frequency.Weekly,
* byWeekday: [Weekday.Monday, Weekday.Wednesday],
* count: 10
* });
* console.log(rrule.toString()); // "RRULE:FREQ=WEEKLY;COUNT=10;BYDAY=MO,WE"
* ```
*/
toString() {
return this.toRust().toString();
}
/**
* @internal
*/
toRust() {
this.rust ??= new lib_1.RRule(this.frequency, this.interval, this.count, this.weekstart, this.until?.toInt32Array(), this.byWeekday, this.byHour, this.byMinute, this.bySecond, this.byMonthday, this.bySetpos, this.byMonth, this.byWeekno, this.byYearday);
return this.rust;
}
toPlain() {
return {
frequency: this.frequency,
interval: this.interval,
count: this.count,
byWeekday: this.byWeekday,
byHour: this.byHour,
byMinute: this.byMinute,
bySecond: this.bySecond,
byMonthday: this.byMonthday,
bySetpos: this.bySetpos,
byMonth: this.byMonth,
byWeekno: this.byWeekno,
byYearday: this.byYearday,
weekstart: this.weekstart,
until: this.until?.toPlain(),
};
}
toOptions() {
return {
frequency: this.frequency,
interval: this.interval,
count: this.count,
byWeekday: this.byWeekday,
byHour: this.byHour,
byMinute: this.byMinute,
bySecond: this.bySecond,
byMonthday: this.byMonthday,
bySetpos: this.bySetpos,
byMonth: this.byMonth,
byWeekno: this.byWeekno,
byYearday: this.byYearday,
weekstart: this.weekstart,
until: this.until,
};
}
}
exports.RRule = RRule;