"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getNextRecurrences = exports.Weekday = exports.RRule = exports.Frequency = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _momentTimezone = _interopRequireDefault(require("moment-timezone")); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ let Frequency; exports.Frequency = 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 || (exports.Frequency = Frequency = {})); let Weekday; exports.Weekday = Weekday; (function (Weekday) { Weekday[Weekday["MO"] = 1] = "MO"; Weekday[Weekday["TU"] = 2] = "TU"; Weekday[Weekday["WE"] = 3] = "WE"; Weekday[Weekday["TH"] = 4] = "TH"; Weekday[Weekday["FR"] = 5] = "FR"; Weekday[Weekday["SA"] = 6] = "SA"; Weekday[Weekday["SU"] = 7] = "SU"; })(Weekday || (exports.Weekday = Weekday = {})); const ISO_WEEKDAYS = [Weekday.MO, Weekday.TU, Weekday.WE, Weekday.TH, Weekday.FR, Weekday.SA, Weekday.SU]; const ALL_LIMIT = 10000; class RRule { constructor(options) { (0, _defineProperty2.default)(this, "options", void 0); this.options = options; if (isNaN(options.dtstart.getTime())) { throw new Error('Cannot create RRule: dtstart is an invalid date'); } if (options.until && isNaN(options.until.getTime())) { throw new Error('Cannot create RRule: until is an invalid date'); } if (typeof options.wkst === 'string') { this.options.wkst = Weekday[options.wkst]; } const weekdayParseResult = parseByWeekdayPos(options.byweekday); if (weekdayParseResult) { this.options.byweekday = weekdayParseResult[0]; this.options.bysetpos = weekdayParseResult[1]; } } *dateset(start, end) { const isAfterDtStart = current => current.getTime() >= this.options.dtstart.getTime(); const isInBounds = current => { const afterStart = !start || current.getTime() >= start.getTime(); const beforeEnd = !end || current.getTime() <= end.getTime(); return afterStart && beforeEnd; }; const { dtstart, tzid, count, until } = this.options; let isFirstIteration = true; let yieldedRecurrenceCount = 0; let current = (0, _momentTimezone.default)(dtstart !== null && dtstart !== void 0 ? dtstart : new Date()).tz(tzid).toDate(); const nextRecurrences = []; while (!count && !until || count && yieldedRecurrenceCount < count || until && current.getTime() < new Date(until).getTime()) { var _nextRecurrences$shif; const next = (_nextRecurrences$shif = nextRecurrences.shift()) === null || _nextRecurrences$shif === void 0 ? void 0 : _nextRecurrences$shif.toDate(); if (next) { current = next; if (!isAfterDtStart(current)) continue; yieldedRecurrenceCount++; if (isInBounds(current)) { yield current; } else if (start && current.getTime() > start.getTime()) { return null; } } else { getNextRecurrences({ refDT: (0, _momentTimezone.default)(current).tz(tzid), ...this.options, interval: isFirstIteration ? 0 : this.options.interval, wkst: this.options.wkst ? this.options.wkst : Weekday.MO }).forEach(r => nextRecurrences.push(r)); isFirstIteration = false; if (nextRecurrences.length === 0) { return null; } } } return null; } between(start, end) { const dates = this.dateset(start, end); return [...dates]; } before(dt) { const dates = [...this.dateset(this.options.dtstart, dt)]; return dates[dates.length - 1]; } after(dt) { const dates = this.dateset(dt); return dates.next().value; } all(limit = ALL_LIMIT) { const dateGenerator = this.dateset(); const dates = []; let next = dateGenerator.next(); for (let i = 0; i < limit; i++) { if (!next.done) dates.push(next.value);else break; next = dateGenerator.next(); } if (next.done) return dates;else { dates.hasMore = true; return dates; } } } exports.RRule = RRule; const parseByWeekdayPos = function (byweekday) { if (byweekday !== null && byweekday !== void 0 && byweekday.some(d => typeof d === 'string')) { const pos = []; const newByweekday = byweekday.map(d => { if (typeof d !== 'string') return d; if (Object.keys(Weekday).includes(d)) return Weekday[d]; const [sign, number, ...rest] = d.split(''); if (sign === '-') pos.push(-Number(number));else pos.push(Number(number)); return Weekday[rest.join('')]; }); return [newByweekday, pos]; } else return null; }; const getNextRecurrences = function ({ refDT, wkst = Weekday.MO, byyearday, bymonth, bymonthday, byweekday, byhour, byminute, bysecond, bysetpos, freq = Frequency.YEARLY, interval = 1 }) { const opts = { wkst, byyearday, bymonth, bymonthday, byweekday, byhour, byminute, bysecond, bysetpos }; // If the frequency is DAILY but there's a byweekday, or if the frequency is MONTHLY with a byweekday with no // corresponding bysetpos, use the WEEKLY code path to determine recurrences const derivedFreq = byweekday && (freq === Frequency.DAILY || freq === Frequency.MONTHLY && !(bysetpos !== null && bysetpos !== void 0 && bysetpos.length)) ? Frequency.WEEKLY : freq; switch (derivedFreq) { case Frequency.YEARLY: { const nextRef = (0, _momentTimezone.default)(refDT).add(interval, 'y'); return getYearOfRecurrences({ refDT: nextRef, ...opts }); } case Frequency.MONTHLY: { const nextRef = (0, _momentTimezone.default)(refDT).add(interval, 'M'); return getMonthOfRecurrences({ refDT: nextRef, ...opts }); } case Frequency.WEEKLY: { const nextRef = (0, _momentTimezone.default)(refDT).add(interval, 'w'); return getWeekOfRecurrences({ refDT: nextRef, ...opts }); } case Frequency.DAILY: { const nextRef = (0, _momentTimezone.default)(refDT).add(interval, 'd'); return getDayOfRecurrences({ refDT: nextRef, ...opts }); } case Frequency.HOURLY: { const nextRef = (0, _momentTimezone.default)(refDT).add(interval, 'h'); return getHourOfRecurrences({ refDT: nextRef, ...opts }); } case Frequency.MINUTELY: { const nextRef = (0, _momentTimezone.default)(refDT).add(interval, 'm'); return getMinuteOfRecurrences({ refDT: nextRef, ...opts }); } } }; exports.getNextRecurrences = getNextRecurrences; const sortByweekday = function ({ wkst, byweekday }) { const weekStart = wkst !== null && wkst !== void 0 ? wkst : Weekday.MO; const weekdays = ISO_WEEKDAYS.slice(weekStart - 1).concat(ISO_WEEKDAYS.slice(0, weekStart - 1)); return [...byweekday].sort((a, b) => weekdays.indexOf(a) - weekdays.indexOf(b)); }; const getYearOfRecurrences = function ({ refDT, wkst, byyearday, bymonth, bymonthday, byweekday, byhour, byminute, bysecond, bysetpos }) { const derivedByweekday = byweekday !== null && byweekday !== void 0 ? byweekday : ISO_WEEKDAYS; if (bymonth) { return bymonth.flatMap(month => { const currentMonth = (0, _momentTimezone.default)(refDT).month(month - 1); return getMonthOfRecurrences({ refDT: currentMonth, wkst, bymonthday, byweekday, byhour, byminute, bysecond, bysetpos }); }); } const derivedByyearday = byyearday !== null && byyearday !== void 0 ? byyearday : [refDT.dayOfYear()]; return derivedByyearday.flatMap(dayOfYear => { const currentDate = (0, _momentTimezone.default)(refDT).dayOfYear(dayOfYear); if (!derivedByweekday.includes(currentDate.isoWeekday())) return []; return getDayOfRecurrences({ refDT: currentDate, byhour, byminute, bysecond }); }); }; const getMonthOfRecurrences = function ({ refDT, wkst, bymonthday, bymonth, byweekday, byhour, byminute, bysecond, bysetpos }) { const derivedByweekday = byweekday !== null && byweekday !== void 0 ? byweekday : ISO_WEEKDAYS; const currentMonth = refDT.month(); if (bymonth && !bymonth.includes(currentMonth)) return []; let derivedBymonthday = bymonthday !== null && bymonthday !== void 0 ? bymonthday : [refDT.date()]; if (bysetpos) { const firstOfMonth = (0, _momentTimezone.default)(refDT).month(currentMonth).date(1); const dowLookup = { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [] }; const trackedDate = firstOfMonth; while (trackedDate.month() === currentMonth) { const currentDow = trackedDate.isoWeekday(); dowLookup[currentDow].push(trackedDate.date()); trackedDate.add(1, 'd'); } const sortedByweekday = sortByweekday({ wkst, byweekday: derivedByweekday }); const bymonthdayFromPos = bysetpos.map((pos, i) => { const correspondingWeekday = sortedByweekday[i]; const lookup = dowLookup[correspondingWeekday]; if (pos > 0) return [lookup[pos - 1], pos]; return [lookup.slice(pos)[0], pos]; }); const posPositions = [ // Start with positive numbers in ascending order ...bymonthdayFromPos.filter(([, p]) => p > 0).sort(([, a], [, b]) => a - b).map(([date]) => date)]; const negPositions = [ // then negative numbers in descending order] ...bymonthdayFromPos.filter(([, p]) => p < 0).sort(([, a], [, b]) => a - b).map(([date]) => date)]; derivedBymonthday = [...posPositions, ...negPositions]; } return derivedBymonthday.flatMap(date => { const currentDate = (0, _momentTimezone.default)(refDT).date(date); if (!derivedByweekday.includes(currentDate.isoWeekday())) return []; return getDayOfRecurrences({ refDT: currentDate, byhour, byminute, bysecond }); }); }; const getWeekOfRecurrences = function ({ refDT, wkst = Weekday.MO, byweekday, byhour, byminute, bysecond }) { const derivedByweekday = byweekday ? sortByweekday({ wkst, byweekday }) : [refDT.isoWeekday()]; return derivedByweekday.flatMap(day => { const currentDay = (0, _momentTimezone.default)(refDT).isoWeekday(day); return getDayOfRecurrences({ refDT: currentDay, byhour, byminute, bysecond }); }); }; const getDayOfRecurrences = function ({ refDT, byhour, byminute, bysecond }) { const derivedByhour = byhour !== null && byhour !== void 0 ? byhour : byminute || bysecond ? Array.from(Array(24), (_, i) => i) : [refDT.hour()]; return derivedByhour.flatMap(h => { const currentHour = (0, _momentTimezone.default)(refDT).hour(h); return getHourOfRecurrences({ refDT: currentHour, byminute, bysecond }); }); }; const getHourOfRecurrences = function ({ refDT, byminute, bysecond }) { const derivedByminute = byminute !== null && byminute !== void 0 ? byminute : bysecond ? Array.from(Array(60), (_, i) => i) : [refDT.minute()]; return derivedByminute.flatMap(m => { const currentMinute = (0, _momentTimezone.default)(refDT).minute(m); return getMinuteOfRecurrences({ refDT: currentMinute, bysecond }); }); }; const getMinuteOfRecurrences = function ({ refDT, bysecond }) { const derivedBysecond = bysecond !== null && bysecond !== void 0 ? bysecond : [refDT.second()]; return derivedBysecond.map(s => { return (0, _momentTimezone.default)(refDT).second(s); }); };